From 76e3162b702661bd083e77c5db838670383fb4dd Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Apr 2022 13:47:24 -0700 Subject: [PATCH 01/76] Basic GL Pipeline init for Windows --- .../Plasma/Apps/plClient/Mac-Cocoa/main.mm | 3 - .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 333 +++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLDevice.h | 33 +- .../FeatureLib/pfGLPipeline/plGLEnumerate.cpp | 15 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 76 +++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 + 6 files changed, 448 insertions(+), 13 deletions(-) diff --git a/Sources/Plasma/Apps/plClient/Mac-Cocoa/main.mm b/Sources/Plasma/Apps/plClient/Mac-Cocoa/main.mm index cafacfe541..beba05b48f 100644 --- a/Sources/Plasma/Apps/plClient/Mac-Cocoa/main.mm +++ b/Sources/Plasma/Apps/plClient/Mac-Cocoa/main.mm @@ -42,9 +42,6 @@ // System Frameworks #import -#ifdef PLASMA_PIPELINE_GL -#import -#endif #ifdef PLASMA_PIPELINE_METAL #import #endif diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 1c27752f61..288c2f4bab 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -40,11 +40,291 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ +#include + +#include "hsThread.h" + #include "plGLDevice.h" +#include "plGLPipeline.h" + +#include "plStatusLog/plStatusLog.h" + +#pragma region EGL_Init +#ifdef USE_EGL +#include + +void InitEGLDevice(plGLDevice* dev) +{ + EGLNativeDisplayType device = static_cast((void*)dev->fDevice); + EGLDisplay display = EGL_NO_DISPLAY; + EGLContext context = EGL_NO_CONTEXT; + EGLSurface surface = EGL_NO_SURFACE; + + do { + if (!eglBindAPI(EGL_OPENGL_API)) { + dev->fErrorMsg = "Could not bind to OpenGL API"; + break; + } + + /* Set up the display */ + display = eglGetDisplay(device); + if (display == EGL_NO_DISPLAY) { + dev->fErrorMsg = "Could not get the display"; + break; + } + + if (!eglInitialize(display, nullptr, nullptr)) { + dev->fErrorMsg = "Could not initialize the display"; + break; + } + + /* Set up the config attributes for EGL */ + EGLConfig config; + EGLint config_count; + EGLint config_attrs[] = { + EGL_BUFFER_SIZE, 24, + EGL_DEPTH_SIZE, 24, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; + + if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) { + dev->fErrorMsg = "Could not choose appropriate config"; + break; + } + + /* Set up the GL context */ + EGLint ctx_attrs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_NONE + }; + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); + if (context == EGL_NO_CONTEXT) { + dev->fErrorMsg = "Unable to create rendering context"; + break; + } + + /* Set up the rendering surface */ + surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)dev->fWindow, nullptr); + if (surface == EGL_NO_SURFACE) { + dev->fErrorMsg = "Unable to create rendering surface"; + break; + } + + /* Associate everything */ + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + dev->fErrorMsg = "Failed to attach EGL context to surface"; + break; + } + + // Successfully initialized: + dev->fDisplay = display; + dev->fContext = context; + dev->fSurface = surface; + dev->fContextType = plGLDevice::kEGL; + return; + } while (0); + + // Cleanup for failure case: + if (surface != EGL_NO_SURFACE) { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + } + + if (context != EGL_NO_CONTEXT) + eglDestroyContext(display, context); + + if (display != EGL_NO_DISPLAY) + eglTerminate(display); +} +#endif // USE_EGL +#pragma endregion EGL_Init + +#pragma region WGL_Init +#ifdef HS_BUILD_FOR_WIN32 +#include "hsWindows.h" +#include + +void InitWGLDevice(plGLDevice* dev) +{ + HDC dc = static_cast((HANDLE)dev->fDevice); + HGLRC ctx = nullptr; + + do { + PIXELFORMATDESCRIPTOR pfd{}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 24; + pfd.iLayerType = PFD_MAIN_PLANE; + + int format = ChoosePixelFormat(dc, &pfd); + if (!format) { + dev->fErrorMsg = "Could not find appropriate pixel config"; + break; + } + + if (!SetPixelFormat(dc, format, &pfd)) { + dev->fErrorMsg = "Could not set appropriate pixel config"; + break; + } + + ctx = wglCreateContext(dc); + if (!ctx) { + dev->fErrorMsg = "Unable to create rendering context"; + break; + } + + if (!wglMakeCurrent(dc, ctx)) { + dev->fErrorMsg = "Failed to attach WGL context to surface"; + break; + } + + // Successfully initialized: + dev->fContext = ctx; + dev->fContextType = plGLDevice::kWGL; + return; + } while (0); + + // Cleanup for failure case: + if (ctx) { + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(ctx); + } +} +#endif // HS_BUILD_FOR_WIN32 +#pragma endregion WGL_Init + +#pragma region CGL_Init +#ifdef HS_BUILD_FOR_MACOS +#include +#include +void InitCGLDevice(plGLDevice* dev) +{ + IGNORE_WARNINGS_BEGIN("deprecated-declarations") + + CGLPixelFormatObj pix = nullptr; + CGLContextObj ctx = nullptr; + + do { + CGLPixelFormatAttribute attribs[6] = { + kCGLPFAAccelerated, + kCGLPFANoRecovery, + kCGLPFADoubleBuffer, +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + // OpenGL profiles introduced in 10.7 + kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, +#endif + (CGLPixelFormatAttribute) 0 + }; + + int nPix = 0; + if (CGLChoosePixelFormat(attribs, &pix, &nPix) != kCGLNoError || nPix == 0) { + dev->fErrorMsg = "Could not choose appropriate config"; + break; + } + + if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) { + dev->fErrorMsg = "Unable to create rendering context"; + break; + } + + if (CGLSetCurrentContext(ctx) != kCGLNoError) { + dev->fErrorMsg = "Failed to attach CGL context to surface"; + break; + } + + CGLReleasePixelFormat(pix); + + // Successfully initialized: + dev->fContext = ctx; + dev->fContextType = plGLDevice::kCGL; + return; + } while (0); + + // Cleanup for failure case: + if (ctx) { + CGLSetCurrentContext(nullptr); + CGLReleaseContext(ctx); + } + + if (pix) + CGLReleasePixelFormat(pix); + + IGNORE_WARNINGS_END +} +#endif // HS_BUILD_FOR_MACOS +#pragma endregion CGL_Init + +#ifdef HS_DEBUGGING +static void GLAPIENTRY plGLDebugLog(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + if (severity <= GL_DEBUG_SEVERITY_MEDIUM) { // Yes, higher is a lower enum value + plStatusLog::AddLineSF("pipeline.log", "[GL] {}{}", (type == GL_DEBUG_TYPE_ERROR ? "** ERROR **: " : ""), message); + } +} +#endif plGLDevice::plGLDevice() - : fErrorMsg() + : fErrorMsg(), fPipeline(), fContextType(kNone), fWindow(), fDevice(), + fDisplay(), fSurface(), fContext(), fActiveThread() +{ +} + +bool plGLDevice::InitDevice() { +#ifdef USE_EGL + // The USE_EGL define tells us whether the epoxy library includes support + // for attempting to use EGL on the current platform, but we still need to + // check if EGL is actually available at runtime. + // + // On Windows, this may be true in cases like the PowerVR SDK or when using + // ANGLE. + // + // On Linux, this should be true with mesa or nvidia drivers. + if (epoxy_has_egl()) + InitEGLDevice(this); +#endif + +#ifdef HS_BUILD_FOR_WIN32 + if (fContextType == kNone) + InitWGLDevice(this); +#endif + +#ifdef HS_BUILD_FOR_MACOS + if (fContextType == kNone) + InitCGLDevice(this); +#endif + + // If we still don't have a valid context type set by this point, we've + // failed to initialize so we need to exit. + if (fContextType == kNone) + return false; + + plStatusLog::AddLineSF("pipeline.log", "Initialized with OpenGL {}", reinterpret_cast(glGetString(GL_VERSION))); + +#ifdef HS_DEBUGGING + if (epoxy_gl_version() >= 43) { + glEnable(GL_DEBUG_OUTPUT); + + // Turn off low-severity messages + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr, GL_FALSE); + glDebugMessageCallback(plGLDebugLog, 0); + } +#endif + + glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glEnable(GL_MULTISAMPLE); + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + + return true; } void plGLDevice::SetRenderTarget(plRenderTarget* target) @@ -55,6 +335,57 @@ void plGLDevice::SetViewport() { } +bool plGLDevice::BeginRender() +{ +#ifdef HS_BUILD_FOR_WIN32 + // Best practice, apparently, is to get and release the DC every time we need it. + // A DC is only valid on one thread at a time. + fDevice = static_cast((HANDLE)GetDC(fWindow)); +#endif + + if (fActiveThread == hsThread::ThisThreadHash()) { + return true; + } + + fActiveThread = hsThread::ThisThreadHash(); + + // Initialize OpenGL + if (!InitDevice()) { + plStatusLog::AddLineS("pipeline.log", GetErrorString()); + return false; + } + + return true; +} + +bool plGLDevice::EndRender() +{ + if (fPipeline->fCurrRenderTarget != nullptr) { + return true; + } + +#ifdef USE_EGL + if (fContextType == kEGL) { + if (eglSwapBuffers(static_cast(fDisplay), static_cast(fSurface)) == EGL_FALSE) { + fErrorMsg = "Failed to swap buffers"; + return false; + } + return true; + } else +#endif + +#ifdef HS_BUILD_FOR_WIN32 + if (fContextType == kWGL) { + SwapBuffers(static_cast((HANDLE)fDevice)); + } + + ReleaseDC(fWindow, static_cast((HANDLE)fDevice)); + fDevice = nullptr; +#endif + + return false; +} + void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) { } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index 2de62f4cfd..965450b46a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -51,13 +51,37 @@ class plRenderTarget; class plGLDevice { + friend class plGLPipeline; + friend void InitEGLDevice(plGLDevice* dev); + friend void InitWGLDevice(plGLDevice* dev); + friend void InitCGLDevice(plGLDevice* dev); + + enum ContextType { + kNone = 0, + kWGL, + kCGL, + kEGL + }; + protected: ST::string fErrorMsg; plGLPipeline* fPipeline; + ContextType fContextType; + hsWindowHndl fWindow; + hsWindowHndl fDevice; + void* fDisplay; + void* fSurface; + void* fContext; + size_t fActiveThread; public: plGLDevice(); + /** + * Initializes the OpenGL rendering context. + */ + bool InitDevice(); + /** * Set rendering to the specified render target. * @@ -66,9 +90,16 @@ class plGLDevice */ void SetRenderTarget(plRenderTarget* target); - /** Translate our viewport into a D3D viewport. */ + /** Translate our viewport into a GL viewport. */ void SetViewport(); + bool BeginRender(); + + /** + * Tell GL we're through rendering for this frame, and flip the back buffer + * to front. + */ + bool EndRender(); void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp index 55a0d076ca..cb02496d83 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp @@ -79,6 +79,7 @@ bool fillDeviceRecord(hsG3DDeviceRecord& devRec) } +#pragma region EGL_Enumerate #ifdef USE_EGL #include @@ -145,8 +146,10 @@ void plEGLEnumerate(std::vector& records) eglTerminate(display); } #endif // USE_EGL +#pragma endregion EGL_Enumerate +#pragma region WGL_Enumerate #ifdef HS_BUILD_FOR_WIN32 #include "hsWindows.h" #include @@ -164,7 +167,7 @@ void plWGLEnumerate(std::vector& records) tempClass.hInstance = GetModuleHandle(nullptr); tempClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); tempClass.lpszClassName = L"GLTestClass"; - tempClass.style = CS_OWNDC; + tempClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; cls = RegisterClassW(&tempClass); if (!cls) @@ -229,9 +232,12 @@ void plWGLEnumerate(std::vector& records) UnregisterClassW(reinterpret_cast(cls), GetModuleHandle(nullptr)); } #endif // HS_BUILD_FOR_WIN32 +#pragma endregion WGL_Enumerate +#pragma region CGL_Enumerate #ifdef HS_BUILD_FOR_MACOS +#include #include void plCGLEnumerate(std::vector& records) @@ -245,7 +251,10 @@ void plCGLEnumerate(std::vector& records) kCGLPFAAccelerated, kCGLPFANoRecovery, kCGLPFADoubleBuffer, +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + // OpenGL profiles introduced in 10.7 kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, +#endif (CGLPixelFormatAttribute) 0 }; @@ -256,7 +265,8 @@ void plCGLEnumerate(std::vector& records) if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) break; - CGLSetCurrentContext(ctx); + if (CGLSetCurrentContext(ctx) != kCGLNoError) + break; hsG3DDeviceRecord devRec; devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); @@ -277,6 +287,7 @@ void plCGLEnumerate(std::vector& records) IGNORE_WARNINGS_END } #endif // HS_BUILD_FOR_MACOS +#pragma endregion CGL_Enumerate void plGLEnumerate::Enumerate(std::vector& records) { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 4ed7e6b6a6..296c16c61c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -46,16 +46,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com // // /////////////////////////////////////////////////////////////////////////////// -#include "HeadSpin.h" -#include "hsWindows.h" - +#include #include -#include "plPipeline/hsWinRef.h" +#include "HeadSpin.h" +#include "hsWindows.h" #include "plGLPipeline.h" #include "plGLPlateManager.h" +#include "plPipeline/hsWinRef.h" +#include "plStatusLog/plStatusLog.h" + #ifdef HS_SIMD_INCLUDE # include HS_SIMD_INCLUDE #endif @@ -65,12 +67,30 @@ plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) : pl3DPipeline(devMode) { + plStatusLog::AddLineS("pipeline.log", "Constructing plGLPipeline"); + plStatusLog::AddLineSF("pipeline.log", "Driver vendor: {}", devMode->GetDevice()->GetDriverDesc()); + + fDevice.fWindow = window; + fDevice.fDevice = display; + fDevice.fPipeline = this; + fPlateMgr = new plGLPlateManager(this); } bool plGLPipeline::PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { - return false; + plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable); + if (!ds) + return false; + + if ((ds->GetType() & fView.GetDrawableTypeMask()) == 0) + return false; + + fView.GetVisibleSpans(ds, visList, visMgr); + + // TODO: Implement bounds debugging stuff here + + return !visList.empty(); } bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) @@ -132,12 +152,56 @@ plRenderTarget* plGLPipeline::PopRenderTarget() bool plGLPipeline::BeginRender() { + // TODO: Device Init/Reset stuff here + + // offset transform + RefreshScreenMatrices(); + + // If this is the primary BeginRender, make sure we're really ready. + if (fInSceneDepth++ == 0) { + fDevice.BeginRender(); + + hsColorRGBA clearColor = GetClearColor(); + + glDepthMask(GL_TRUE); + //glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + glClearColor(0.f, 0.f, 0.5f, 1.f); + glClearDepth(1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + fRenderCnt++; + + // Would probably rather this be an input. + fTime = hsTimer::GetSysSeconds(); + return false; } bool plGLPipeline::EndRender() { - return false; + bool retVal = false; + + // Actually end the scene + if (--fInSceneDepth == 0) { + retVal = fDevice.EndRender(); + + //TODO: IClearShadowSlaves(); + } + + // Do this last, after we've drawn everything + // Just letting go of things we're done with for the frame. + hsRefCnt_SafeUnRef(fCurrMaterial); + fCurrMaterial = nullptr; + + for (int i = 0; i < 8; i++) { + if (fLayerRef[i]) { + hsRefCnt_SafeUnRef(fLayerRef[i]); + fLayerRef[i] = nullptr; + } + } + + return retVal; } void plGLPipeline::RenderScreenElements() diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 55c895656e..8ddec1cc43 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -60,6 +60,7 @@ class plGLEnumerate class plGLPipeline : public pl3DPipeline { friend class plGLPlateManager; + friend class plGLDevice; public: plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode); From f9ffe45ae46c59e3d48c504b4adca86e642038bd Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 11 Aug 2023 21:13:39 -0700 Subject: [PATCH 02/76] Fixup formatting in pl3DPipeline --- .../PubUtilLib/plPipeline/pl3DPipeline.h | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 5827a1feb9..455f305141 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -107,7 +107,7 @@ static const float kPerspLayerTrans = 0.00002f; static const float kAvTexPoolShrinkThresh = 30.f; // seconds -template +template class pl3DPipeline : public plPipeline { protected: @@ -838,7 +838,7 @@ class pl3DPipeline : public plPipeline }; -template +template pl3DPipeline::pl3DPipeline(const hsG3DDeviceModeRecord* devModeRec) : fMaxLayersAtOnce(-1), fMaxPiggyBacks(), @@ -906,7 +906,7 @@ pl3DPipeline::pl3DPipeline(const hsG3DDeviceModeRecord* devModeRec) fVSync = fInitialPipeParams.VSync; } -template +template pl3DPipeline::~pl3DPipeline() { fCurrLay = nullptr; @@ -926,7 +926,7 @@ pl3DPipeline::~pl3DPipeline() } -template +template void pl3DPipeline::Render(plDrawable* d, const std::vector& visList) { // Reset here, since we can push/pop renderTargets after BeginRender() but @@ -941,7 +941,7 @@ void pl3DPipeline::Render(plDrawable* d, const std::vector& } -template +template void pl3DPipeline::Draw(plDrawable* d) { plDrawableSpans *ds = plDrawableSpans::ConvertNoRef(d); @@ -959,7 +959,7 @@ void pl3DPipeline::Draw(plDrawable* d) } -template +template void pl3DPipeline::RegisterLight(plLightInfo* liInfo) { if (liInfo->IsLinked()) @@ -971,7 +971,7 @@ void pl3DPipeline::RegisterLight(plLightInfo* liInfo) } -template +template void pl3DPipeline::UnRegisterLight(plLightInfo* liInfo) { liInfo->SetDeviceRef(nullptr); @@ -979,7 +979,7 @@ void pl3DPipeline::UnRegisterLight(plLightInfo* liInfo) } -template +template void pl3DPipeline::PushRenderTarget(plRenderTarget* target) { fCurrRenderTarget = target; @@ -995,7 +995,7 @@ void pl3DPipeline::PushRenderTarget(plRenderTarget* target) } -template +template plRenderTarget* pl3DPipeline::PopRenderTarget() { plRenderTarget* old = fRenderTargets.back(); @@ -1026,7 +1026,7 @@ plRenderTarget* pl3DPipeline::PopRenderTarget() } -template +template void pl3DPipeline::BeginVisMgr(plVisMgr* visMgr) { // Make Light Lists ///////////////////////////////////////////////////// @@ -1090,7 +1090,7 @@ void pl3DPipeline::BeginVisMgr(plVisMgr* visMgr) } -template +template void pl3DPipeline::EndVisMgr(plVisMgr* visMgr) { fCharLights.clear(); @@ -1098,7 +1098,7 @@ void pl3DPipeline::EndVisMgr(plVisMgr* visMgr) } -template +template bool pl3DPipeline::CheckResources() { if ((fClothingOutfits.size() <= 1 && fAvRTPool.size() > 1) || @@ -1112,7 +1112,7 @@ bool pl3DPipeline::CheckResources() } -template +template void pl3DPipeline::SetZBiasScale(float scale) { scale += 1.0f; @@ -1121,14 +1121,14 @@ void pl3DPipeline::SetZBiasScale(float scale) } -template +template float pl3DPipeline::GetZBiasScale() const { return (fTweaks.fPerspLayerScale / fTweaks.fDefaultPerspLayerScale) - 1.0f; } -template +template void pl3DPipeline::SetWorldToCamera(const hsMatrix44& w2c, const hsMatrix44& c2w) { plViewTransform& view_xform = fView.GetViewTransform(); @@ -1142,7 +1142,7 @@ void pl3DPipeline::SetWorldToCamera(const hsMatrix44& w2c, const hsM } -template +template void pl3DPipeline::ScreenToWorldPoint(int n, uint32_t stride, int32_t* scrX, int32_t* scrY, float dist, uint32_t strideOut, hsPoint3* worldOut) { while (n--) { @@ -1153,7 +1153,7 @@ void pl3DPipeline::ScreenToWorldPoint(int n, uint32_t stride, int32_ } -template +template void pl3DPipeline::RefreshScreenMatrices() { fView.fCullTreeDirty = true; @@ -1161,7 +1161,7 @@ void pl3DPipeline::RefreshScreenMatrices() } -template +template hsGMaterial* pl3DPipeline::PushOverrideMaterial(hsGMaterial* mat) { hsGMaterial* ret = GetOverrideMaterial(); @@ -1173,7 +1173,7 @@ hsGMaterial* pl3DPipeline::PushOverrideMaterial(hsGMaterial* mat) } -template +template void pl3DPipeline::PopOverrideMaterial(hsGMaterial* restore) { hsGMaterial *pop = fOverrideMat.back(); @@ -1185,7 +1185,7 @@ void pl3DPipeline::PopOverrideMaterial(hsGMaterial* restore) } -template +template plLayerInterface* pl3DPipeline::AppendLayerInterface(plLayerInterface* li, bool onAllLayers) { fForceMatHandle = true; @@ -1196,7 +1196,7 @@ plLayerInterface* pl3DPipeline::AppendLayerInterface(plLayerInterfac } -template +template plLayerInterface* pl3DPipeline::RemoveLayerInterface(plLayerInterface* li, bool onAllLayers) { fForceMatHandle = true; @@ -1214,7 +1214,7 @@ plLayerInterface* pl3DPipeline::RemoveLayerInterface(plLayerInterfac } -template +template hsGMatState pl3DPipeline::PushMaterialOverride(const hsGMatState& state, bool on) { hsGMatState ret = GetMaterialOverride(on); @@ -1230,7 +1230,7 @@ hsGMatState pl3DPipeline::PushMaterialOverride(const hsGMatState& st } -template +template hsGMatState pl3DPipeline::PushMaterialOverride(hsGMatState::StateIdx cat, uint32_t which, bool on) { hsGMatState ret = GetMaterialOverride(on); @@ -1246,7 +1246,7 @@ hsGMatState pl3DPipeline::PushMaterialOverride(hsGMatState::StateIdx } -template +template void pl3DPipeline::PopMaterialOverride(const hsGMatState& restore, bool on) { if (on) { @@ -1260,7 +1260,7 @@ void pl3DPipeline::PopMaterialOverride(const hsGMatState& restore, b } -template +template void pl3DPipeline::SubmitShadowSlave(plShadowSlave* slave) { // Check that it's a valid slave. @@ -1286,7 +1286,7 @@ void pl3DPipeline::SubmitShadowSlave(plShadowSlave* slave) } -template +template void pl3DPipeline::SubmitClothingOutfit(plClothingOutfit* co) { auto iter = std::find(fClothingOutfits.cbegin(), fClothingOutfits.cend(), co); @@ -1302,7 +1302,7 @@ void pl3DPipeline::SubmitClothingOutfit(plClothingOutfit* co) } -template +template plLayerInterface* pl3DPipeline::PushPiggyBackLayer(plLayerInterface* li) { fPiggyBackStack.push_back(li); @@ -1315,7 +1315,7 @@ plLayerInterface* pl3DPipeline::PushPiggyBackLayer(plLayerInterface* } -template +template plLayerInterface* pl3DPipeline::PopPiggyBackLayer(plLayerInterface* li) { auto iter = std::find(fPiggyBackStack.cbegin(), fPiggyBackStack.cend(), li); @@ -1332,7 +1332,7 @@ plLayerInterface* pl3DPipeline::PopPiggyBackLayer(plLayerInterface* } -template +template void pl3DPipeline::SetViewTransform(const plViewTransform& v) { fView.SetViewTransform(v); @@ -1351,7 +1351,7 @@ void pl3DPipeline::SetViewTransform(const plViewTransform& v) /*** PROTECTED METHODS *******************************************************/ -template +template void pl3DPipeline::IAttachSlaveToReceivers(size_t which, plDrawableSpans* drawable, const std::vector& visList) { plShadowSlave* slave = fShadows[which]; @@ -1399,7 +1399,7 @@ void pl3DPipeline::IAttachSlaveToReceivers(size_t which, plDrawableS } -template +template void pl3DPipeline::IAttachShadowsToReceivers(plDrawableSpans* drawable, const std::vector& visList) { for (size_t i = 0; i < fShadows.size(); i++) @@ -1407,7 +1407,7 @@ void pl3DPipeline::IAttachShadowsToReceivers(plDrawableSpans* drawab } -template +template bool pl3DPipeline::IAcceptsShadow(const plSpan* span, plShadowSlave* slave) { // The span's shadow bits records which shadow maps that span was rendered @@ -1416,7 +1416,7 @@ bool pl3DPipeline::IAcceptsShadow(const plSpan* span, plShadowSlave* } -template +template bool pl3DPipeline::IReceivesShadows(const plSpan* span, hsGMaterial* mat) { if (span->fProps & plSpan::kPropNoShadow) @@ -1437,7 +1437,7 @@ bool pl3DPipeline::IReceivesShadows(const plSpan* span, hsGMaterial* } -template +template void pl3DPipeline::ISetShadowFromGroup(plDrawableSpans* drawable, const plSpan* span, plLightInfo* liInfo) { hsGMaterial* mat = drawable->GetMaterial(span->fMaterialIdx); @@ -1462,7 +1462,7 @@ void pl3DPipeline::ISetShadowFromGroup(plDrawableSpans* drawable, co -template +template void pl3DPipeline::IClearClothingOutfits(std::vector* outfits) { while (!outfits->empty()) { @@ -1475,7 +1475,7 @@ void pl3DPipeline::IClearClothingOutfits(std::vector +template void pl3DPipeline::IFillAvRTPool() { fAvNextFreeRT = 0; @@ -1501,7 +1501,7 @@ void pl3DPipeline::IFillAvRTPool() } -template +template bool pl3DPipeline::IFillAvRTPool(uint16_t numRTs, uint16_t width) { fAvRTPool.resize(numRTs); @@ -1527,7 +1527,7 @@ bool pl3DPipeline::IFillAvRTPool(uint16_t numRTs, uint16_t width) } -template +template void pl3DPipeline::IReleaseAvRTPool() { for (plClothingOutfit* outfit : fClothingOutfits) @@ -1543,14 +1543,14 @@ void pl3DPipeline::IReleaseAvRTPool() } -template +template plRenderTarget *pl3DPipeline::IGetNextAvRT() { return fAvRTPool[fAvNextFreeRT++]; } -template +template void pl3DPipeline::IFreeAvRT(plRenderTarget* tex) { auto iter = std::find(fAvRTPool.begin(), fAvRTPool.end(), tex); @@ -1563,7 +1563,7 @@ void pl3DPipeline::IFreeAvRT(plRenderTarget* tex) } -template +template void pl3DPipeline::ICheckLighting(plDrawableSpans* drawable, std::vector& visList, plVisMgr* visMgr) { if (fView.fRenderState & kRenderNoLights) @@ -1794,7 +1794,7 @@ void pl3DPipeline::ICheckLighting(plDrawableSpans* drawable, std::ve } -template +template hsMatrix44 pl3DPipeline::IGetCameraToNDC() { hsMatrix44 cam2ndc = GetViewTransform().GetCameraToNDC(); @@ -1832,7 +1832,7 @@ hsMatrix44 pl3DPipeline::IGetCameraToNDC() } -template +template void pl3DPipeline::ISetLocalToWorld(const hsMatrix44& l2w, const hsMatrix44& w2l) { fView.SetLocalToWorld(l2w); @@ -1848,7 +1848,7 @@ void pl3DPipeline::ISetLocalToWorld(const hsMatrix44& l2w, const hsM -template +template void pl3DPipeline::ITransformsToDevice() { if (fView.fXformResetFlags & fView.kResetCamera) @@ -1862,14 +1862,14 @@ void pl3DPipeline::ITransformsToDevice() } -template +template void pl3DPipeline::IProjectionMatrixToDevice() { fDevice.SetProjectionMatrix(IGetCameraToNDC()); fView.fXformResetFlags &= ~fView.kResetProjection; } -template +template void pl3DPipeline::IWorldToCameraToDevice() { fDevice.SetWorldToCameraMatrix(fView.GetWorldToCamera()); @@ -1878,7 +1878,7 @@ void pl3DPipeline::IWorldToCameraToDevice() fFrame++; } -template +template void pl3DPipeline::ILocalToWorldToDevice() { fDevice.SetLocalToWorldMatrix(fView.GetLocalToWorld()); From 490b5521caf01b79adb0e8c26748d8137b225c24 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Apr 2022 19:47:55 -0700 Subject: [PATCH 03/76] Move IClearShadowSlaves to pl3DPipeline --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 12 ------------ .../FeatureLib/pfDXPipeline/plDXPipeline.h | 1 - .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 +- .../pfMetalPipeline/plMetalPipeline.cpp | 12 ------------ .../pfMetalPipeline/plMetalPipeline.h | 1 - .../Plasma/PubUtilLib/plPipeline/pl3DPipeline.h | 17 +++++++++++++++++ 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index ded0d4ffa9..1f620c931b 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -11450,18 +11450,6 @@ void plDXPipeline::IPreprocessShadows() plProfile_EndTiming(PrepShadows); } -// IClearShadowSlaves /////////////////////////////////////////////////////////////////////////// -// At EndRender(), we need to clear our list of shadow slaves. They are only valid for one frame. -void plDXPipeline::IClearShadowSlaves() -{ - for (plShadowSlave* shadow : fShadows) - { - const plShadowCaster* caster = shadow->fCaster; - caster->GetKey()->UnRefObject(); - } - fShadows.clear(); -} - // IRenderShadowsOntoSpan ///////////////////////////////////////////////////////////////////// // After doing the usual render for a span (all passes), we call the following. diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index 3b33cdcb44..4d5d0b8be4 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -480,7 +480,6 @@ class plDXPipeline : public pl3DPipeline /////// Shadow internals // Generation - void IClearShadowSlaves(); void IPreprocessShadows(); bool IPrepShadowCaster(const plShadowCaster* caster); void IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSpans* drawable, const plIcicle& span); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 296c16c61c..26938a918d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -186,7 +186,7 @@ bool plGLPipeline::EndRender() if (--fInSceneDepth == 0) { retVal = fDevice.EndRender(); - //TODO: IClearShadowSlaves(); + IClearShadowSlaves(); } // Do this last, after we've drawn everything diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 951fd2590a..83390958c8 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -2897,18 +2897,6 @@ void plMetalPipeline::FindFragFunction() return pipe; }*/ -// IClearShadowSlaves /////////////////////////////////////////////////////////////////////////// -// At EndRender(), we need to clear our list of shadow slaves. They are only valid for one frame. -void plMetalPipeline::IClearShadowSlaves() -{ - int i; - for (i = 0; i < fShadows.size(); i++) { - const plShadowCaster* caster = fShadows[i]->fCaster; - caster->GetKey()->UnRefObject(); - } - fShadows.clear(); -} - // Create all our video memory consuming D3D objects. bool plMetalPipeline::ICreateDynDeviceObjects() { diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 4d819490c7..09cfe01bdb 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -185,7 +185,6 @@ class plMetalPipeline : public pl3DPipeline void IPreprocessAvatarTextures(); void IDrawClothingQuad(float x, float y, float w, float h, float uOff, float vOff, plMipmap* tex); - void IClearShadowSlaves(); void ICreateDeviceObjects(); void IReleaseDynDeviceObjects(); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 455f305141..7104ce0c4c 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -768,6 +768,12 @@ class pl3DPipeline : public plPipeline */ void ISetShadowFromGroup(plDrawableSpans* drawable, const plSpan* span, plLightInfo* liInfo); + /** + * At EndRender(), we need to clear our list of shadow slaves. + * They are only valid for one frame. + */ + void IClearShadowSlaves(); + void IClearClothingOutfits(std::vector* outfits); void IFillAvRTPool(); @@ -1461,6 +1467,17 @@ void pl3DPipeline::ISetShadowFromGroup(plDrawableSpans* drawable, co } +template +void pl3DPipeline::IClearShadowSlaves() +{ + for (plShadowSlave* shadow : fShadows) + { + const plShadowCaster* caster = shadow->fCaster; + caster->GetKey()->UnRefObject(); + } + fShadows.clear(); +} + template void pl3DPipeline::IClearClothingOutfits(std::vector* outfits) From 5130a1760f2cb6bcc4da0bdecc2efa83c5725dc9 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 4 Jun 2022 22:32:50 -0700 Subject: [PATCH 04/76] Fix duplicate plProfile counter linking --- Sources/Plasma/FeatureLib/pfDXPipeline/plDXDeviceRefs.cpp | 6 +++--- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp | 6 +++--- .../Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp | 6 +++--- Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp | 3 +++ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDeviceRefs.cpp index a0b7606ba7..f5f3ead9b9 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDeviceRefs.cpp @@ -75,9 +75,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plProfile.h" #include "plStatusLog/plStatusLog.h" -plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); -plProfile_CreateMemCounter("Indices", "Memory", MemIndex); -plProfile_CreateMemCounter("Textures", "Memory", MemTexture); +plProfile_Extern(MemVertex); +plProfile_Extern(MemIndex); +plProfile_Extern(MemTexture); /////////////////////////////////////////////////////////////////////////////// //// Generic plDXDeviceRef Functions ///////////////////////////////////////// diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index 3302118a09..3c269d26fb 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -47,9 +47,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plProfile.h" #include "plStatusLog/plStatusLog.h" -plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); -plProfile_CreateMemCounter("Indices", "Memory", MemIndex); -plProfile_CreateMemCounter("Textures", "Memory", MemTexture); +plProfile_Extern(MemVertex); +plProfile_Extern(MemIndex); +plProfile_Extern(MemTexture); /***************************************************************************** diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp index 87d4f6181a..c493dfefb0 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDeviceRefs.cpp @@ -45,9 +45,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plProfile.h" #include "plStatusLog/plStatusLog.h" -plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); -plProfile_CreateMemCounter("Indices", "Memory", MemIndex); -plProfile_CreateMemCounter("Textures", "Memory", MemTexture); +plProfile_Extern(MemVertex); +plProfile_Extern(MemIndex); +plProfile_Extern(MemTexture); /***************************************************************************** ** Generic plGLDeviceRef Functions ** diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index 00ba9ca637..ff8e835864 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -66,6 +66,9 @@ plProfile_CreateCounter("Perms Found", "PipeC", FindLightsPerm); plProfile_CreateCounter("Polys", "General", DrawTriangles); plProfile_CreateCounter("Material Change", "Draw", MatChange); +plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); +plProfile_CreateMemCounter("Indices", "Memory", MemIndex); +plProfile_CreateMemCounter("Textures", "Memory", MemTexture); PipelineParams plPipeline::fDefaultPipeParams; PipelineParams plPipeline::fInitialPipeParams; From 8cb3541a8458272f7f9d85a514785380301c6c74 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 16 Aug 2015 17:11:18 -0700 Subject: [PATCH 05/76] Draw to the screen. Not accurately, but it does draw. --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 249 ++++++++++++++- .../FeatureLib/pfGLPipeline/plGLDevice.h | 17 +- .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 96 +++++- .../pfGLPipeline/plGLDeviceRefs.cpp | 6 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 287 +++++++++++++++--- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 16 +- 6 files changed, 609 insertions(+), 62 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 288c2f4bab..6c9c6b2b23 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -47,6 +47,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLDevice.h" #include "plGLPipeline.h" +#include "plDrawable/plGBufferGroup.h" #include "plStatusLog/plStatusLog.h" #pragma region EGL_Init @@ -269,9 +270,34 @@ static void GLAPIENTRY plGLDebugLog(GLenum source, GLenum type, GLuint id, GLenu } #endif +GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst) +{ + dst[0] = src.fMap[0][0]; + dst[1] = src.fMap[0][1]; + dst[2] = src.fMap[0][2]; + dst[3] = src.fMap[0][3]; + + dst[4] = src.fMap[1][0]; + dst[5] = src.fMap[1][1]; + dst[6] = src.fMap[1][2]; + dst[7] = src.fMap[1][3]; + + dst[8] = src.fMap[2][0]; + dst[9] = src.fMap[2][1]; + dst[10] = src.fMap[2][2]; + dst[11] = src.fMap[2][3]; + + dst[12] = src.fMap[3][0]; + dst[13] = src.fMap[3][1]; + dst[14] = src.fMap[3][2]; + dst[15] = src.fMap[3][3]; + + return dst; +} + plGLDevice::plGLDevice() : fErrorMsg(), fPipeline(), fContextType(kNone), fWindow(), fDevice(), - fDisplay(), fSurface(), fContext(), fActiveThread() + fDisplay(), fSurface(), fContext(), fActiveThread(), fProgram() { } @@ -324,15 +350,60 @@ bool plGLDevice::InitDevice() glFrontFace(GL_CCW); glCullFace(GL_BACK); + /* TEMP: Shader init stuff */ + const char* vs_src = "#version 130" + "\n" + "\n" "attribute vec3 position;" + "\n" "attribute vec4 color;" + "\n" + "\n" "uniform mat4 matrix_l2w;" + "\n" "uniform mat4 matrix_w2c;" + "\n" "uniform mat4 matrix_proj;" + "\n" + "\n" "varying vec4 v_color;" + "\n" + "\n" "void main() {" + "\n" " gl_Position = /* matrix_proj * */ matrix_w2c * matrix_l2w * vec4(position, 1.0);" + "\n" " v_color = color;" + "\n" "}"; + + const char* fs_src = "#version 130" + "\n" + "\n" "varying mediump vec4 v_color;" + "\n" + "\n" "void main() {" + "\n" " gl_FragColor = v_color;" + "\n" "}"; + + GLuint vshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vshader, 1, &vs_src, nullptr); + glCompileShader(vshader); + + GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fshader, 1, &fs_src, nullptr); + glCompileShader(fshader); + + fProgram = glCreateProgram(); + glAttachShader(fProgram, vshader); + glAttachShader(fProgram, fshader); + + glLinkProgram(fProgram); + glUseProgram(fProgram); + return true; } void plGLDevice::SetRenderTarget(plRenderTarget* target) { + SetViewport(); } void plGLDevice::SetViewport() { + glViewport(fPipeline->GetViewTransform().GetViewPortLeft(), + fPipeline->GetViewTransform().GetViewPortTop(), + fPipeline->GetViewTransform().GetViewPortWidth(), + fPipeline->GetViewTransform().GetViewPortHeight()); } bool plGLDevice::BeginRender() @@ -386,14 +457,190 @@ bool plGLDevice::EndRender() return false; } +void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef) +{ + uint8_t format = owner->GetVertexFormat(); + + // All indexed skinning is currently done on CPU, so the source data + // will have indices, but we strip them out for the D3D buffer. + if (format & plGBufferGroup::kSkinIndices) { + hsStatusMessage("Have to deal with skinning :("); +#if 0 + format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); + format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... + vRef->SetSkinned(true); + vRef->SetVolatile(true); +#endif + } + + + uint32_t vertSize = owner->GetVertexSize(); //IGetBufferFormatSize(format); // vertex stride + uint32_t numVerts = owner->GetVertBufferCount(idx); + + vRef->fOwner = owner; + vRef->fCount = numVerts; + vRef->fVertexSize = vertSize; + vRef->fFormat = format; + vRef->fRefTime = 0; + + vRef->SetDirty(true); + vRef->SetRebuiltSinceUsed(true); + vRef->fData = nullptr; + + vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); + + vRef->fIndex = idx; + + owner->SetVertexBufferRef(idx, vRef); + hsRefCnt_SafeUnRef(vRef); +} + +void plGLDevice::CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx) +{ + hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); + + if (!vRef->fRef) { + glGenBuffers(1, &vRef->fRef); + + // Fill in the vertex data. + FillStaticVertexBufferRef(vRef, owner, idx); + + // This is currently a no op, but this would let the buffer know it can + // unload the system memory copy, since we have a managed version now. + owner->PurgeVertBuffer(idx); + } +} + +void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) +{ + if (!ref->fRef) + // We most likely already warned about this earlier, best to just quietly return now + return; + + const uint32_t vertSize = ref->fVertexSize; + const uint32_t vertStart = group->GetVertBufferStart(idx) * vertSize; + const uint32_t size = group->GetVertBufferEnd(idx) * vertSize - vertStart; + if (!size) + return; + + glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); + + if (ref->fData) { + glBufferData(GL_ARRAY_BUFFER, size, ref->fData + vertStart, GL_STATIC_DRAW); + } else { + hsAssert(0 == vertStart, "Offsets on non-interleaved data not supported"); + hsAssert(group->GetVertBufferCount(idx) * vertSize == size, "Trailing dead space on non-interleaved data not supported"); + + uint8_t* buffer = new uint8_t[size]; + uint8_t* ptr = buffer; + const uint32_t vertSmallSize = group->GetVertexLiteStride() - sizeof(hsPoint3) * 2; + uint8_t* srcVPtr = group->GetVertBufferData(idx); + plGBufferColor* const srcCPtr = group->GetColorBufferData(idx); + + const int numCells = group->GetNumCells(idx); + for (int i = 0; i < numCells; i++) { + plGBufferCell* cell = group->GetCell(idx, i); + + if (cell->fColorStart == uint32_t(-1)) { + /// Interleaved, do straight copy + memcpy(ptr, srcVPtr + cell->fVtxStart, cell->fLength * vertSize); + ptr += cell->fLength * vertSize; + } else { + hsStatusMessage("Non interleaved data"); + + /// Separated, gotta interleave + uint8_t* tempVPtr = srcVPtr + cell->fVtxStart; + plGBufferColor* tempCPtr = srcCPtr + cell->fColorStart; + + for (int j = 0; j < cell->fLength; j++) + { + memcpy(ptr, tempVPtr, sizeof(hsPoint3) * 2); + ptr += sizeof(hsPoint3) * 2; + tempVPtr += sizeof(hsPoint3) * 2; + + memcpy(ptr, &tempCPtr->fDiffuse, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + memcpy(ptr, &tempCPtr->fSpecular, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + + memcpy(ptr, tempVPtr, vertSmallSize); + ptr += vertSmallSize; + tempVPtr += vertSmallSize; + tempCPtr++; + } + } + } + + glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW); + + delete[] buffer; + } + + /// Unlock and clean up + ref->SetRebuiltSinceUsed(true); + ref->SetDirty(false); +} + +void plGLDevice::SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) +{ + uint32_t numIndices = owner->GetIndexBufferCount(idx); + iRef->fCount = numIndices; + iRef->fOwner = owner; + iRef->fIndex = idx; + iRef->fRefTime = 0; + + iRef->SetDirty(true); + iRef->SetRebuiltSinceUsed(true); + + owner->SetIndexBufferRef(idx, iRef); + hsRefCnt_SafeUnRef(iRef); + + iRef->SetVolatile(owner->AreIdxVolatile()); +} + +void plGLDevice::CheckIndexBuffer(IndexBufferRef* iRef) +{ + if (!iRef->fRef && iRef->fCount) { + iRef->SetVolatile(false); + + glGenBuffers(1, &iRef->fRef); + + iRef->SetDirty(true); + iRef->SetRebuiltSinceUsed(true); + } +} + +void plGLDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) +{ + uint32_t startIdx = owner->GetIndexBufferStart(idx); + uint32_t size = (owner->GetIndexBufferEnd(idx) - startIdx) * sizeof(uint16_t); + + if (!size) + return; + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, owner->GetIndexBufferData(idx) + startIdx, GL_STATIC_DRAW); + + iRef->SetDirty(false); +} + void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) { + GLfloat mat[16]; + GLint uniform = glGetUniformLocation(fProgram, "matrix_proj"); + glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); } void plGLDevice::SetWorldToCameraMatrix(const hsMatrix44& src) { + GLfloat mat[16]; + GLint uniform = glGetUniformLocation(fProgram, "matrix_w2c"); + glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); } void plGLDevice::SetLocalToWorldMatrix(const hsMatrix44& src) { + GLfloat mat[16]; + GLint uniform = glGetUniformLocation(fProgram, "matrix_l2w"); + glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index 965450b46a..e26222d395 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -43,6 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define _plGLDevice_h_ #include "hsMatrix44.h" +#include "plGLDeviceRef.h" #include @@ -63,6 +64,10 @@ class plGLDevice kEGL }; +public: + typedef plGLVertexBufferRef VertexBufferRef; + typedef plGLIndexBufferRef IndexBufferRef; + protected: ST::string fErrorMsg; plGLPipeline* fPipeline; @@ -73,6 +78,7 @@ class plGLDevice void* fSurface; void* fContext; size_t fActiveThread; + GLuint fProgram; public: plGLDevice(); @@ -101,12 +107,19 @@ class plGLDevice */ bool EndRender(); + /* Device Ref Functions **************************************************/ + void SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef); + void CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx); + void FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx); + void FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx); + void SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef); + void CheckIndexBuffer(IndexBufferRef* iRef); + void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); + void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); - struct VertexBufferRef; - struct IndexBufferRef; struct TextureRef; ST::string GetErrorString() const { return fErrorMsg; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index c1d4e4f7bf..fe69e14e24 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -47,11 +47,14 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include +class plGBufferGroup; + class plGLDeviceRef : public hsGDeviceRef { -protected: - GLint fRef; +public: + GLuint fRef; +protected: plGLDeviceRef* fNext; plGLDeviceRef** fBack; @@ -61,13 +64,100 @@ class plGLDeviceRef : public hsGDeviceRef plGLDeviceRef* GetNext() { return fNext; } bool IsLinked() { return fBack != nullptr; } + bool HasFlag(uint32_t f) const { return 0 != (fFlags & f); } + void SetFlag(uint32_t f, bool on) { if(on) fFlags |= f; else fFlags &= ~f; } + virtual void Release() = 0; plGLDeviceRef(); - virtual ~plGLDeviceRef(); }; +class plGLVertexBufferRef : public plGLDeviceRef +{ +public: + uint32_t fCount; + uint32_t fIndex; + uint32_t fVertexSize; + int32_t fOffset; + uint8_t fFormat; + + plGBufferGroup* fOwner; + uint8_t* fData; + + uint32_t fRefTime; + + enum { + kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef + kVolatile = 0x20, + kSkinned = 0x40 + }; + + + bool RebuiltSinceUsed() const { return HasFlag(kRebuiltSinceUsed); } + void SetRebuiltSinceUsed(bool b) { SetFlag(kRebuiltSinceUsed, b); } + + bool Volatile() const { return HasFlag(kVolatile); } + void SetVolatile(bool b) { SetFlag(kVolatile, b); } + + bool Skinned() const { return HasFlag(kSkinned); } + void SetSkinned(bool b) { SetFlag(kSkinned, b); } + + bool Expired(uint32_t t) const { return Volatile() && (IsDirty() || (fRefTime != t)); } + void SetRefTime(uint32_t t) { fRefTime = t; } + + + void Link(plGLVertexBufferRef** back ) { plGLDeviceRef::Link((plGLDeviceRef**)back); } + plGLVertexBufferRef* GetNext() { return (plGLVertexBufferRef*)fNext; } + + + plGLVertexBufferRef() + : plGLDeviceRef(), fCount(), fIndex(), fVertexSize(), fOffset(), + fFormat(), fOwner(), fData(), fRefTime() + { } + + virtual ~plGLVertexBufferRef() {} + void Release() {} +}; + + +class plGLIndexBufferRef : public plGLDeviceRef +{ +public: + uint32_t fCount; + uint32_t fIndex; + int32_t fOffset; + plGBufferGroup* fOwner; + uint32_t fRefTime; + + enum { + kRebuiltSinceUsed = 0x10, // kDirty = 0x1 is in hsGDeviceRef + kVolatile = 0x20 + }; + + + bool RebuiltSinceUsed() const { return HasFlag(kRebuiltSinceUsed); } + void SetRebuiltSinceUsed(bool b) { SetFlag(kRebuiltSinceUsed, b); } + + bool Volatile() const { return HasFlag(kVolatile); } + void SetVolatile(bool b) { SetFlag(kVolatile, b); } + + bool Expired(uint32_t t) const { return Volatile() && (IsDirty() || (fRefTime != t)); } + void SetRefTime(uint32_t t) { fRefTime = t; } + + + void Link(plGLIndexBufferRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } + plGLIndexBufferRef* GetNext() { return (plGLIndexBufferRef*)fNext; } + + + plGLIndexBufferRef() + : plGLDeviceRef(), fCount(), fIndex(), fOffset(), fOwner(), fRefTime() + { } + + virtual ~plGLIndexBufferRef() {} + void Release() {} +}; + #endif // _plGLDeviceRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index 3c269d26fb..ed4906929d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -56,10 +56,8 @@ plProfile_Extern(MemTexture); ** Generic plGLDeviceRef Functions ** *****************************************************************************/ plGLDeviceRef::plGLDeviceRef() -{ - fNext = nullptr; - fBack = nullptr; -} + : fRef(), fNext(), fBack() +{ } plGLDeviceRef::~plGLDeviceRef() { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 26938a918d..413efbd2b8 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -62,6 +62,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com # include HS_SIMD_INCLUDE #endif +typedef plGLDevice DeviceType; + plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) @@ -95,11 +97,26 @@ bool plGLPipeline::PreRender(plDrawable* drawable, std::vector& visList bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { - return false; -} + plDrawableSpans* ice = plDrawableSpans::ConvertNoRef(drawable); + if (!ice) + return false; -void plGLPipeline::Render(plDrawable* d, const std::vector& visList) -{} + // Find our lights + ICheckLighting(ice, visList, visMgr); + + // Sort our faces + if (ice->GetNativeProperty(plDrawable::kPropSortFaces)) + ice->SortVisibleSpans(visList, this); + + // Prep for render. This is gives the drawable a chance to + // do any last minute updates for its buffers, including + // generating particle tri lists. + ice->PrepForRender(this); + + // Other stuff that we're ignoring for now... + + return true; +} plTextFont* plGLPipeline::MakeTextFont(ST::string face, uint16_t size) { @@ -107,10 +124,65 @@ plTextFont* plGLPipeline::MakeTextFont(ST::string face, uint16_t size) } void plGLPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) -{} +{ + // First, do we have a device ref at this index? + typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)owner->GetVertexBufferRef(idx); + + // If not + if (!vRef) { + // Make the blank ref + vRef = new typename DeviceType::VertexBufferRef(); + fDevice.SetupVertexBufferRef(owner, idx, vRef); + } + + if (!vRef->IsLinked()) + vRef->Link(&fVtxBuffRefList); + + // One way or another, we now have a vbufferref[idx] in owner. + // Now, does it need to be (re)filled? + // If the owner is volatile, then we hold off. It might not + // be visible, and we might need to refill it again if we + // have an overrun of our dynamic buffer. + if (!vRef->Volatile()) { + // If it's a static buffer, allocate a vertex buffer for it. + fDevice.CheckStaticVertexBuffer(vRef, owner, idx); + + // Might want to remove this assert, and replace it with a dirty check + // if we have static buffers that change very seldom rather than never. + hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); + } else { + // Make sure we're going to be ready to fill it. + +#if 0 + if (!vRef->fData && (vRef->fFormat != owner->GetVertexFormat())) + { + vRef->fData = new uint8_t[vRef->fCount * vRef->fVertexSize]; + fDevice.FillVolatileVertexBufferRef(vRef, owner, idx); + } +#endif + } +} void plGLPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) -{} +{ + typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)owner->GetIndexBufferRef(idx); + + if (!iRef) { + // Create one from scratch. + iRef = new typename DeviceType::IndexBufferRef(); + fDevice.SetupIndexBufferRef(owner, idx, iRef); + } + + if (!iRef->IsLinked()) + iRef->Link(&fIdxBuffRefList); + + // Make sure it has all resources created. + fDevice.CheckIndexBuffer(iRef); + + // If it's dirty, refill it. + if (iRef->IsDirty()) + fDevice.FillIndexBufferRef(iRef, owner, idx); +} bool plGLPipeline::OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) { @@ -135,17 +207,25 @@ void plGLPipeline::ClearRenderTarget(plDrawable* d) {} void plGLPipeline::ClearRenderTarget(const hsColorRGBA* col, const float* depth) -{} - -hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) { - return nullptr; -} + if (fView.fRenderState & (kRenderClearColor | kRenderClearDepth)) { + hsColorRGBA clearColor = col ? *col : GetClearColor(); + float clearDepth = depth ? *depth : fView.GetClearDepth(); -void plGLPipeline::PushRenderTarget(plRenderTarget* target) -{} + GLuint masks = 0; + if (fView.fRenderState & kRenderClearColor) + masks |= GL_COLOR_BUFFER_BIT; + if (fView.fRenderState & kRenderClearDepth) + masks |= GL_DEPTH_BUFFER_BIT; + + glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + glClearDepth(clearDepth); -plRenderTarget* plGLPipeline::PopRenderTarget() + glClear(masks); + } +} + +hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) { return nullptr; } @@ -212,39 +292,12 @@ bool plGLPipeline::IsFullScreen() const return false; } -uint32_t plGLPipeline::ColorDepth() const -{ - return 0; -} - void plGLPipeline::Resize(uint32_t width, uint32_t height) {} -bool plGLPipeline::CheckResources() -{ - return false; -} - void plGLPipeline::LoadResources() {} -void plGLPipeline::SetZBiasScale(float scale) -{} - -float plGLPipeline::GetZBiasScale() const -{ - return 0.0f; -} - -void plGLPipeline::SetWorldToCamera(const hsMatrix44& w2c, const hsMatrix44& c2w) -{} - -void plGLPipeline::RefreshScreenMatrices() -{} - -void plGLPipeline::SubmitClothingOutfit(plClothingOutfit* co) -{} - bool plGLPipeline::SetGamma(float eR, float eG, float eB) { return false; @@ -282,4 +335,154 @@ void plGLPipeline::ResetDisplayDevice(int Width, int Height, int ColorDepth, boo {} void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& visList) -{} +{ + //plProfile_BeginTiming(RenderSpan); + + hsMatrix44 lastL2W; + hsGMaterial* material; + const std::vector& spans = ice->GetSpanArray(); + + //plProfile_IncCount(EmptyList, !visList.GetCount()); + + /// Set this (*before* we do our TestVisibleWorld stuff...) + lastL2W.Reset(); + ISetLocalToWorld(lastL2W, lastL2W); // This is necessary; otherwise, we have to test for + // the first transform set, since this'll be identity + // but the actual device transform won't be (unless + // we do this) + + /// Loop through our spans, combining them when possible + for (size_t i = 0; i < visList.size(); ) + { + if (GetOverrideMaterial() != nullptr) + material = GetOverrideMaterial(); + else + material = ice->GetMaterial(spans[visList[i]]->fMaterialIdx); + + /// It's an icicle--do our icicle merge loop + plIcicle tempIce(*((plIcicle*)spans[visList[i]])); + + // Start at i + 1, look for as many spans as we can add to tempIce + size_t j; + for (j = i + 1; j < visList.size(); j++) + { + if (GetOverrideMaterial()) + tempIce.fMaterialIdx = spans[visList[j]]->fMaterialIdx; + + //plProfile_BeginTiming(MergeCheck); + if (!spans[visList[j]]->CanMergeInto(&tempIce)) { + //plProfile_EndTiming(MergeCheck); + break; + } + //plProfile_EndTiming(MergeCheck); + //plProfile_Inc(SpanMerge); + + //plProfile_BeginTiming(MergeSpan); + spans[visList[j]]->MergeInto(&tempIce); + //plProfile_EndTiming(MergeSpan); + } + + if (material != nullptr) { + // TODO: Figure out how to use VAOs properly :( + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + // What do we change? + + //plProfile_BeginTiming(SpanTransforms); + ISetupTransforms(ice, tempIce, lastL2W); + //plProfile_EndTiming(SpanTransforms); + + // Turn on this spans lights and turn off the rest. + //IEnableLights( &tempIce ); + + // Check that the underlying buffers are ready to go. + //plProfile_BeginTiming(CheckDyn); + //ICheckDynBuffers(drawable, drawable->GetBufferGroup(tempIce.fGroupIdx), &tempIce); + //plProfile_EndTiming(CheckDyn); + + //plProfile_BeginTiming(CheckStat); + CheckVertexBufferRef(ice->GetBufferGroup(tempIce.fGroupIdx), tempIce.fVBufferIdx); + CheckIndexBufferRef(ice->GetBufferGroup(tempIce.fGroupIdx), tempIce.fIBufferIdx); + //plProfile_EndTiming(CheckStat); + + // Draw this span now + IRenderBufferSpan( tempIce, + ice->GetVertexRef( tempIce.fGroupIdx, tempIce.fVBufferIdx ), + ice->GetIndexRef( tempIce.fGroupIdx, tempIce.fIBufferIdx ), + material, + tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range + tempIce.fIPackedIdx, tempIce.fILength ); + } + + // Restart our search... + i = j; + } + + //plProfile_EndTiming(RenderSpan); + /// All done! +} + + +void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W) +{ + if (span.fNumMatrices) { + if (span.fNumMatrices <= 2) { + ISetLocalToWorld(span.fLocalToWorld, span.fWorldToLocal); + lastL2W = span.fLocalToWorld; + } else { + lastL2W.Reset(); + ISetLocalToWorld(lastL2W, lastL2W); + fView.fLocalToWorldLeftHanded = span.fLocalToWorld.GetParity(); + } + } else if (lastL2W != span.fLocalToWorld) { + ISetLocalToWorld(span.fLocalToWorld, span.fWorldToLocal); + lastL2W = span.fLocalToWorld; + } else { + fView.fLocalToWorldLeftHanded = lastL2W.GetParity(); + } + +#if 0 + if (span.fNumMatrices == 2) { + D3DXMATRIX mat; + IMatrix44ToD3DMatrix(mat, drawable->GetPaletteMatrix(span.fBaseMatrix+1)); + fD3DDevice->SetTransform(D3DTS_WORLDMATRIX(1), &mat); + fD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS); + } else { + fD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + } +#endif +} + +void plGLPipeline::IRenderBufferSpan(const plIcicle& span, + hsGDeviceRef* vb, hsGDeviceRef* ib, + hsGMaterial* material, + uint32_t vStart, uint32_t vLength, + uint32_t iStart, uint32_t iLength) +{ + typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)vb; + typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)ib; + + if (!vRef->fRef || !iRef->fRef) { + hsAssert(false, "Trying to render a nil buffer pair!"); + return; + } + + /* Vertex Buffer stuff */ + glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); + + GLint posAttrib = glGetAttribLocation(fDevice.fProgram, "position"); + GLint colAttrib = glGetAttribLocation(fDevice.fProgram, "color"); + glEnableVertexAttribArray(posAttrib); + glEnableVertexAttribArray(colAttrib); + + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); + glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); + + + /* Index Buffer stuff and drawing */ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); + + glDrawElements(GL_TRIANGLES, iRef->fCount, GL_UNSIGNED_SHORT, 0); +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 8ddec1cc43..45d9a434f6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -46,6 +46,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPipeline/pl3DPipeline.h" #include "plPipeline/hsG3DDeviceSelector.h" +class plIcicle; + class plGLEnumerate { public: @@ -77,7 +79,6 @@ class plGLPipeline : public pl3DPipeline /*** VIRTUAL METHODS ***/ bool PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; bool PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; - void Render(plDrawable* d, const std::vector& visList) override; plTextFont* MakeTextFont(ST::string face, uint16_t size) override; void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; @@ -89,21 +90,12 @@ class plGLPipeline : public pl3DPipeline void ClearRenderTarget(plDrawable* d) override; void ClearRenderTarget(const hsColorRGBA* col = nullptr, const float* depth = nullptr) override; hsGDeviceRef* MakeRenderTargetRef(plRenderTarget* owner) override; - void PushRenderTarget(plRenderTarget* target) override; - plRenderTarget* PopRenderTarget() override; bool BeginRender() override; bool EndRender() override; void RenderScreenElements() override; bool IsFullScreen() const override; - uint32_t ColorDepth() const override; void Resize(uint32_t width, uint32_t height) override; - bool CheckResources() override; void LoadResources() override; - void SetZBiasScale(float scale) override; - float GetZBiasScale() const override; - void SetWorldToCamera(const hsMatrix44& w2c, const hsMatrix44& c2w) override; - void RefreshScreenMatrices() override; - void SubmitClothingOutfit(plClothingOutfit* co) override; bool SetGamma(float eR, float eG, float eB) override; bool SetGamma(const uint16_t* const tabR, const uint16_t* const tabG, const uint16_t* const tabB) override; bool CaptureScreen(plMipmap* dest, bool flipVertical = false, uint16_t desiredWidth = 0, uint16_t desiredHeight = 0) override; @@ -114,6 +106,10 @@ class plGLPipeline : public pl3DPipeline void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool vSync = false ) override; void RenderSpans(plDrawableSpans* ice, const std::vector& visList) override; +protected: + void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); + void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, hsGDeviceRef* ib, hsGMaterial* material, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength); + private: static plGLEnumerate enumerator; }; From c26e14c94a869b6818872fb603b0bb4ac36e0e0e Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 13 Jul 2014 00:48:05 -0700 Subject: [PATCH 06/76] Actually rendering something coherent now --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 6c9c6b2b23..5b87858db7 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -270,29 +270,19 @@ static void GLAPIENTRY plGLDebugLog(GLenum source, GLenum type, GLuint id, GLenu } #endif +static float kIdentityMatrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst) { - dst[0] = src.fMap[0][0]; - dst[1] = src.fMap[0][1]; - dst[2] = src.fMap[0][2]; - dst[3] = src.fMap[0][3]; - - dst[4] = src.fMap[1][0]; - dst[5] = src.fMap[1][1]; - dst[6] = src.fMap[1][2]; - dst[7] = src.fMap[1][3]; - - dst[8] = src.fMap[2][0]; - dst[9] = src.fMap[2][1]; - dst[10] = src.fMap[2][2]; - dst[11] = src.fMap[2][3]; - - dst[12] = src.fMap[3][0]; - dst[13] = src.fMap[3][1]; - dst[14] = src.fMap[3][2]; - dst[15] = src.fMap[3][3]; - - return dst; + if (src.fFlags & hsMatrix44::kIsIdent) + return (GLfloat*)(memcpy(dst, kIdentityMatrix, sizeof(GLfloat) * 16)); + else + return (GLfloat*)(src.fMap); } plGLDevice::plGLDevice() @@ -346,6 +336,7 @@ bool plGLDevice::InitDevice() glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); glFrontFace(GL_CCW); glCullFace(GL_BACK); @@ -363,7 +354,11 @@ bool plGLDevice::InitDevice() "\n" "varying vec4 v_color;" "\n" "\n" "void main() {" - "\n" " gl_Position = /* matrix_proj * */ matrix_w2c * matrix_l2w * vec4(position, 1.0);" + "\n" " vec4 pos = matrix_l2w * vec4(position, 1.0);" + "\n" " pos = matrix_w2c * pos;" + "\n" " pos = matrix_proj * pos;" + "\n" + "\n" " gl_Position = pos;" "\n" " v_color = color;" "\n" "}"; @@ -628,19 +623,19 @@ void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) { GLfloat mat[16]; GLint uniform = glGetUniformLocation(fProgram, "matrix_proj"); - glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); + glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); } void plGLDevice::SetWorldToCameraMatrix(const hsMatrix44& src) { GLfloat mat[16]; GLint uniform = glGetUniformLocation(fProgram, "matrix_w2c"); - glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); + glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); } void plGLDevice::SetLocalToWorldMatrix(const hsMatrix44& src) { GLfloat mat[16]; GLint uniform = glGetUniformLocation(fProgram, "matrix_l2w"); - glUniformMatrix4fv(uniform, 1, GL_FALSE, hsMatrix2GL(src, mat)); + glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); } From d804dd1dc2e34b24309fa63f3d895caff315981f Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 13 Jul 2014 11:58:11 -0700 Subject: [PATCH 07/76] Fix vertex colours --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 5b87858db7..d27ef6c798 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -359,7 +359,7 @@ bool plGLDevice::InitDevice() "\n" " pos = matrix_proj * pos;" "\n" "\n" " gl_Position = pos;" - "\n" " v_color = color;" + "\n" " v_color = color.zyxw;" "\n" "}"; const char* fs_src = "#version 130" From 31ce78523fce069bf76918f9cc3a5fd454e83825 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Thu, 16 Oct 2014 21:46:02 -0700 Subject: [PATCH 08/76] Minor fixes that don't actually make it render correctly --- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 413efbd2b8..19cf46250c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -198,10 +198,75 @@ void plGLPipeline::CheckTextureRef(plLayerInterface* lay) {} void plGLPipeline::PushRenderRequest(plRenderRequest* req) -{} +{ + // Save these, since we want to copy them to our current view + hsMatrix44 l2w = fView.GetLocalToWorld(); + hsMatrix44 w2l = fView.GetWorldToLocal(); + + plFogEnvironment defFog = fView.GetDefaultFog(); + + fViewStack.push(fView); + + SetViewTransform(req->GetViewTransform()); + + PushRenderTarget(req->GetRenderTarget()); + fView.fRenderState = req->GetRenderState(); + + fView.fRenderRequest = req; + hsRefCnt_SafeRef(fView.fRenderRequest); + + SetDrawableTypeMask(req->GetDrawableMask()); + SetSubDrawableTypeMask(req->GetSubDrawableMask()); + + float depth = req->GetClearDepth(); + fView.SetClear(&req->GetClearColor(), &depth); + +#if 0 + if (req->GetFogStart() < 0) + { + fView.SetDefaultFog(defFog); + } + else + { + defFog.Set(req->GetYon() * (1.f - req->GetFogStart()), req->GetYon(), 1.f, &req->GetClearColor()); + fView.SetDefaultFog(defFog); + fCurrFog.fEnvPtr = nullptr; + } +#endif + + if (req->GetOverrideMat()) + PushOverrideMaterial(req->GetOverrideMat()); + + // Set from our saved ones... + fView.SetWorldToLocal(w2l); + fView.SetLocalToWorld(l2w); + + RefreshMatrices(); + + if (req->GetIgnoreOccluders()) + fView.SetMaxCullNodes(0); + + fView.fCullTreeDirty = true; +} void plGLPipeline::PopRenderRequest(plRenderRequest* req) -{} +{ + if (req->GetOverrideMat()) + PopOverrideMaterial(nullptr); + + hsRefCnt_SafeUnRef(fView.fRenderRequest); + fView = fViewStack.top(); + fViewStack.pop(); + +#if 0 + // Force the next thing drawn to update the fog settings. + fD3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + fCurrFog.fEnvPtr = nullptr; +#endif + + PopRenderTarget(); + fView.fXformResetFlags = fView.kResetProjection | fView.kResetCamera; +} void plGLPipeline::ClearRenderTarget(plDrawable* d) {} From e8b258bb27bdc84a7923be795267ccba2a6451d9 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 19 Oct 2014 16:52:15 -0700 Subject: [PATCH 09/76] Fix geometry rendering --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 22 ++++----- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 1 + .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 47 +++++++++++++------ .../pfMetalPipeline/plMetalPipeline.cpp | 22 ++++----- .../PubUtilLib/plPipeline/pl3DPipeline.cpp | 12 +++++ 5 files changed, 67 insertions(+), 37 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 1f620c931b..475143cd88 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -292,17 +292,17 @@ plProfile_CreateTimer("PrepDrawable", "PipeT", PrepDrawable); plProfile_CreateTimer(" Skin", "PipeT", Skin); plProfile_CreateTimer(" AvSort", "PipeT", AvatarSort); plProfile_CreateTimer(" ClearLights", "PipeT", ClearLights); -plProfile_CreateTimer("RenderSpan", "PipeT", RenderSpan); -plProfile_CreateTimer(" MergeCheck", "PipeT", MergeCheck); -plProfile_CreateTimer(" MergeSpan", "PipeT", MergeSpan); -plProfile_CreateTimer(" SpanTransforms", "PipeT", SpanTransforms); -plProfile_CreateTimer(" SpanFog", "PipeT", SpanFog); -plProfile_CreateTimer(" SelectLights", "PipeT", SelectLights); -plProfile_CreateTimer(" SelectProj", "PipeT", SelectProj); -plProfile_CreateTimer(" CheckDyn", "PipeT", CheckDyn); -plProfile_CreateTimer(" CheckStat", "PipeT", CheckStat); -plProfile_CreateTimer(" RenderBuff", "PipeT", RenderBuff); -plProfile_CreateTimer(" RenderPrim", "PipeT", RenderPrim); +plProfile_Extern(RenderSpan); +plProfile_Extern(MergeCheck); +plProfile_Extern(MergeSpan); +plProfile_Extern(SpanTransforms); +plProfile_Extern(SpanFog); +plProfile_Extern(SelectLights); +plProfile_Extern(SelectProj); +plProfile_Extern(CheckDyn); +plProfile_Extern(CheckStat); +plProfile_Extern(RenderBuff); +plProfile_Extern(RenderPrim); plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); plProfile_CreateTimer("DebugText", "PipeT", DebugText); plProfile_CreateTimer("Reset", "PipeT", Reset); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index d27ef6c798..c9f6edf24e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -566,6 +566,7 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* } } + hsAssert((ptr - buffer) == size, "Didn't fill the buffer?"); glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW); delete[] buffer; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 19cf46250c..65e230aa11 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -55,6 +55,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLPipeline.h" #include "plGLPlateManager.h" +#include "plProfile.h" #include "plPipeline/hsWinRef.h" #include "plStatusLog/plStatusLog.h" @@ -64,6 +65,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com typedef plGLDevice DeviceType; +plProfile_Extern(RenderSpan); +plProfile_Extern(MergeCheck); +plProfile_Extern(MergeSpan); +plProfile_Extern(SpanTransforms); +plProfile_Extern(SpanFog); +plProfile_Extern(SelectLights); +plProfile_Extern(SelectProj); +plProfile_Extern(CheckDyn); +plProfile_Extern(CheckStat); +plProfile_Extern(RenderBuff); +plProfile_Extern(RenderPrim); + plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) @@ -401,13 +414,16 @@ void plGLPipeline::ResetDisplayDevice(int Width, int Height, int ColorDepth, boo void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& visList) { - //plProfile_BeginTiming(RenderSpan); + plProfile_BeginTiming(RenderSpan); + + if (ice->GetRenderLevel() != 0) + return; hsMatrix44 lastL2W; hsGMaterial* material; const std::vector& spans = ice->GetSpanArray(); - //plProfile_IncCount(EmptyList, !visList.GetCount()); + //plProfile_IncCount(EmptyList, visList.empty()); /// Set this (*before* we do our TestVisibleWorld stuff...) lastL2W.Reset(); @@ -434,17 +450,17 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& if (GetOverrideMaterial()) tempIce.fMaterialIdx = spans[visList[j]]->fMaterialIdx; - //plProfile_BeginTiming(MergeCheck); + plProfile_BeginTiming(MergeCheck); if (!spans[visList[j]]->CanMergeInto(&tempIce)) { - //plProfile_EndTiming(MergeCheck); + plProfile_EndTiming(MergeCheck); break; } - //plProfile_EndTiming(MergeCheck); + plProfile_EndTiming(MergeCheck); //plProfile_Inc(SpanMerge); - //plProfile_BeginTiming(MergeSpan); + plProfile_BeginTiming(MergeSpan); spans[visList[j]]->MergeInto(&tempIce); - //plProfile_EndTiming(MergeSpan); + plProfile_EndTiming(MergeSpan); } if (material != nullptr) { @@ -455,9 +471,9 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& // What do we change? - //plProfile_BeginTiming(SpanTransforms); + plProfile_BeginTiming(SpanTransforms); ISetupTransforms(ice, tempIce, lastL2W); - //plProfile_EndTiming(SpanTransforms); + plProfile_EndTiming(SpanTransforms); // Turn on this spans lights and turn off the rest. //IEnableLights( &tempIce ); @@ -467,10 +483,11 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& //ICheckDynBuffers(drawable, drawable->GetBufferGroup(tempIce.fGroupIdx), &tempIce); //plProfile_EndTiming(CheckDyn); - //plProfile_BeginTiming(CheckStat); - CheckVertexBufferRef(ice->GetBufferGroup(tempIce.fGroupIdx), tempIce.fVBufferIdx); - CheckIndexBufferRef(ice->GetBufferGroup(tempIce.fGroupIdx), tempIce.fIBufferIdx); - //plProfile_EndTiming(CheckStat); + plProfile_BeginTiming(CheckStat); + plGBufferGroup* grp = ice->GetBufferGroup(tempIce.fGroupIdx); + CheckVertexBufferRef(grp, tempIce.fVBufferIdx); + CheckIndexBufferRef(grp, tempIce.fIBufferIdx); + plProfile_EndTiming(CheckStat); // Draw this span now IRenderBufferSpan( tempIce, @@ -485,7 +502,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& i = j; } - //plProfile_EndTiming(RenderSpan); + plProfile_EndTiming(RenderSpan); /// All done! } @@ -549,5 +566,5 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Index Buffer stuff and drawing */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); - glDrawElements(GL_TRIANGLES, iRef->fCount, GL_UNSIGNED_SHORT, 0); + glDrawElements(GL_TRIANGLES, iLength, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * iStart)); } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 83390958c8..e2d11b9fb6 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -96,17 +96,17 @@ plProfile_Extern(MatChange); plProfile_CreateTimer("PrepShadows", "PipeT", PrepShadows); plProfile_CreateTimer("PrepDrawable", "PipeT", PrepDrawable); plProfile_CreateTimer(" Skin", "PipeT", Skin); -plProfile_CreateTimer("RenderSpan", "PipeT", RenderSpan); -plProfile_CreateTimer(" MergeCheck", "PipeT", MergeCheck); -plProfile_CreateTimer(" MergeSpan", "PipeT", MergeSpan); -plProfile_CreateTimer(" SpanTransforms", "PipeT", SpanTransforms); -plProfile_CreateTimer(" SpanFog", "PipeT", SpanFog); -plProfile_CreateTimer(" SelectLights", "PipeT", SelectLights); -plProfile_CreateTimer(" SelectProj", "PipeT", SelectProj); -plProfile_CreateTimer(" CheckDyn", "PipeT", CheckDyn); -plProfile_CreateTimer(" CheckStat", "PipeT", CheckStat); -plProfile_CreateTimer(" RenderBuff", "PipeT", RenderBuff); -plProfile_CreateTimer(" RenderPrim", "PipeT", RenderPrim); +plProfile_Extern(RenderSpan); +plProfile_Extern(MergeCheck); +plProfile_Extern(MergeSpan); +plProfile_Extern(SpanTransforms); +plProfile_Extern(SpanFog); +plProfile_Extern(SelectLights); +plProfile_Extern(SelectProj); +plProfile_Extern(CheckDyn); +plProfile_Extern(CheckStat); +plProfile_Extern(RenderBuff); +plProfile_Extern(RenderPrim); plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); plProfile_CreateTimer("DebugText", "PipeT", DebugText); plProfile_CreateTimer("Reset", "PipeT", Reset); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index ff8e835864..b23188e162 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -46,6 +46,18 @@ plProfile_CreateTimer("RenderScene", "PipeT", RenderScene); plProfile_CreateTimer("VisEval", "PipeT", VisEval); plProfile_CreateTimer("VisSelect", "PipeT", VisSelect); +plProfile_CreateTimer("RenderSpan", "PipeT", RenderSpan); +plProfile_CreateTimer(" MergeCheck", "PipeT", MergeCheck); +plProfile_CreateTimer(" MergeSpan", "PipeT", MergeSpan); +plProfile_CreateTimer(" SpanTransforms", "PipeT", SpanTransforms); +plProfile_CreateTimer(" SpanFog", "PipeT", SpanFog); +plProfile_CreateTimer(" SelectLights", "PipeT", SelectLights); +plProfile_CreateTimer(" SelectProj", "PipeT", SelectProj); +plProfile_CreateTimer(" CheckDyn", "PipeT", CheckDyn); +plProfile_CreateTimer(" CheckStat", "PipeT", CheckStat); +plProfile_CreateTimer(" RenderBuff", "PipeT", RenderBuff); +plProfile_CreateTimer(" RenderPrim", "PipeT", RenderPrim); + plProfile_CreateTimer("FindSceneLights", "PipeT", FindSceneLights); plProfile_CreateTimer(" Find Lights", "PipeT", FindLights); plProfile_CreateTimer(" Find Perms", "PipeT", FindPerm); From 9e99e62fc2d37b25e660ee07d496f0b1674defdc Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 19 Oct 2014 20:07:39 -0700 Subject: [PATCH 10/76] Fix rendering: Solid geometry renders correctly now --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 ++ Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index c9f6edf24e..209afb1f9a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -338,6 +338,8 @@ bool plGLDevice::InitDevice() glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_TRUE); glFrontFace(GL_CCW); glCullFace(GL_BACK); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 65e230aa11..62334ae476 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -416,9 +416,6 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& { plProfile_BeginTiming(RenderSpan); - if (ice->GetRenderLevel() != 0) - return; - hsMatrix44 lastL2W; hsGMaterial* material; const std::vector& spans = ice->GetSpanArray(); From 4a1524e7d0d66c99b12b73092cca4bd3874e5b6e Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 3 Jan 2015 23:27:00 -0800 Subject: [PATCH 11/76] Refactor some GL pipeline stuff --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 55 ++++++------------- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 9 --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 31 +++++------ .../FeatureLib/pfGLPipeline/plGLDevice.h | 5 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 52 +++++++++++++++++- .../pfMetalPipeline/plMetalPipeline.cpp | 35 ++++-------- .../pfMetalPipeline/plMetalPipeline.h | 13 +---- .../PubUtilLib/plPipeline/pl3DPipeline.cpp | 4 ++ .../PubUtilLib/plPipeline/pl3DPipeline.h | 55 +++++++++++++++++++ 9 files changed, 156 insertions(+), 103 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 475143cd88..17c8930051 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -278,10 +278,10 @@ const int kMaxProjectors = 100; plProfile_CreateMemCounter("Pipeline Surfaces", "Memory", MemPipelineSurfaces); plProfile_Extern(MemVertex); plProfile_Extern(MemIndex); -plProfile_CreateCounter("Feed Triangles", "Draw", DrawFeedTriangles); -plProfile_CreateCounter("Draw Prim Static", "Draw", DrawPrimStatic); -plProfile_CreateMemCounter("Total Texture Size", "Draw", TotalTexSize); -plProfile_CreateCounter("Layer Change", "Draw", LayChange); +plProfile_Extern(DrawFeedTriangles); +plProfile_Extern(DrawPrimStatic); +plProfile_Extern(TotalTexSize); +plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); @@ -478,43 +478,24 @@ void plDXPipeline::ProfilePoolMem(D3DPOOL poolType, uint32_t size, bool add, con // First, Declarations. // Adding a nil RenderPrim for turning off drawing -class plRenderNilFunc : public plRenderPrimFunc -{ -public: - plRenderNilFunc() {} - - bool RenderPrims() const override { return false; } -}; static plRenderNilFunc sRenderNil; -class plRenderTriListFunc : public plRenderPrimFunc +class plDXRenderTriListFunc : public plRenderTriListFunc { -protected: - LPDIRECT3DDEVICE9 fD3DDevice; - int fBaseVertexIndex; - int fVStart; - int fVLength; - int fIStart; - int fNumTris; public: - plRenderTriListFunc(LPDIRECT3DDEVICE9 d3dDevice, int baseVertexIndex, + plDXRenderTriListFunc(LPDIRECT3DDEVICE9 d3dDevice, int baseVertexIndex, int vStart, int vLength, int iStart, int iNumTris) - : fD3DDevice(d3dDevice), fBaseVertexIndex(baseVertexIndex), fVStart(vStart), fVLength(vLength), fIStart(iStart), fNumTris(iNumTris) {} - - bool RenderPrims() const override; -}; + : plRenderTriListFunc(d3dDevice, baseVertexIndex, vStart, vLength, iStart, iNumTris) {} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Implementations - -bool plRenderTriListFunc::RenderPrims() const -{ - plProfile_IncCount(DrawFeedTriangles, fNumTris); - plProfile_IncCount(DrawTriangles, fNumTris); - plProfile_Inc(DrawPrimStatic); + bool RenderPrims() const override + { + plProfile_IncCount(DrawFeedTriangles, fNumTris); + plProfile_IncCount(DrawTriangles, fNumTris); + plProfile_Inc(DrawPrimStatic); - return FAILED( fD3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, fBaseVertexIndex, fVStart, fVLength, fIStart, fNumTris ) ); -} + return FAILED( fDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, fBaseVertexIndex, fVStart, fVLength, fIStart, fNumTris ) ); + } +}; //// Constructor & Destructor ///////////////////////////////////////////////// @@ -9237,7 +9218,7 @@ void plDXPipeline::IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux) r = fD3DDevice->SetIndices( iRef->fD3DBuffer ); hsAssert( r == D3D_OK, "Error trying to set the indices!" ); - plRenderTriListFunc render(fD3DDevice, iRef->fOffset, aux->fVStartIdx, aux->fVLength, aux->fIStartIdx, aux->fILength/3); + plDXRenderTriListFunc render(fD3DDevice, iRef->fOffset, aux->fVStartIdx, aux->fVLength, aux->fIStartIdx, aux->fILength/3); // Now just loop through the aux material, rendering in as many passes as it takes. hsGMaterial* material = aux->fMaterial; @@ -9359,7 +9340,7 @@ void plDXPipeline::IRenderBufferSpan( const plIcicle& span, iRef->SetRebuiltSinceUsed(false); } - plRenderTriListFunc render(fD3DDevice, iRef->fOffset, vStart, vLength, iStart, iLength/3); + plDXRenderTriListFunc render(fD3DDevice, iRef->fOffset, vStart, vLength, iStart, iLength/3); plProfile_EndTiming(RenderBuff); ILoopOverLayers(render, material, span); @@ -10814,7 +10795,7 @@ void plDXPipeline::IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSpans uint32_t iStart = span.fIPackedIdx; uint32_t iLength= span.fILength; - plRenderTriListFunc render(fD3DDevice, iRef->fOffset, vStart, vLength, iStart, iLength/3); + plDXRenderTriListFunc render(fD3DDevice, iRef->fOffset, vStart, vLength, iStart, iLength/3); static hsMatrix44 emptyMatrix; hsMatrix44 m = emptyMatrix; diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index 4d5d0b8be4..ff9104cdbb 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -118,15 +118,6 @@ typedef LPDIRECT3D9 (WINAPI * Direct3DCreateProc)( UINT sdkVersion ); //// Helper Classes /////////////////////////////////////////////////////////// -//// The RenderPrimFunc lets you have one function which does a lot of stuff -// around the actual call to render whatever type of primitives you have, instead -// of duplicating everything because the one line to render is different. -class plRenderPrimFunc -{ -public: - virtual bool RenderPrims() const = 0; // return true on error -}; - //// DX-specific Plate Manager implementation class plDXPlateManager : public plPlateManager { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 209afb1f9a..3200e919af 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -280,15 +280,18 @@ static float kIdentityMatrix[16] = { GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst) { if (src.fFlags & hsMatrix44::kIsIdent) - return (GLfloat*)(memcpy(dst, kIdentityMatrix, sizeof(GLfloat) * 16)); + return static_cast(memcpy(dst, kIdentityMatrix, sizeof(GLfloat) * 16)); else - return (GLfloat*)(src.fMap); + return static_cast(memcpy(dst, src.fMap, sizeof(GLfloat) * 16)); } plGLDevice::plGLDevice() : fErrorMsg(), fPipeline(), fContextType(kNone), fWindow(), fDevice(), - fDisplay(), fSurface(), fContext(), fActiveThread(), fProgram() + fDisplay(), fSurface(), fContext(), fActiveThread(), fCurrentProgram() { + memcpy(fMatrixL2W, kIdentityMatrix, sizeof(GLfloat) * 16); + memcpy(fMatrixW2C, kIdentityMatrix, sizeof(GLfloat) * 16); + memcpy(fMatrixProj, kIdentityMatrix, sizeof(GLfloat) * 16); } bool plGLDevice::InitDevice() @@ -380,12 +383,12 @@ bool plGLDevice::InitDevice() glShaderSource(fshader, 1, &fs_src, nullptr); glCompileShader(fshader); - fProgram = glCreateProgram(); - glAttachShader(fProgram, vshader); - glAttachShader(fProgram, fshader); + fCurrentProgram = glCreateProgram(); + glAttachShader(fCurrentProgram, vshader); + glAttachShader(fCurrentProgram, fshader); - glLinkProgram(fProgram); - glUseProgram(fProgram); + glLinkProgram(fCurrentProgram); + glUseProgram(fCurrentProgram); return true; } @@ -624,21 +627,15 @@ void plGLDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) { - GLfloat mat[16]; - GLint uniform = glGetUniformLocation(fProgram, "matrix_proj"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); + hsMatrix2GL(src, fMatrixProj); } void plGLDevice::SetWorldToCameraMatrix(const hsMatrix44& src) { - GLfloat mat[16]; - GLint uniform = glGetUniformLocation(fProgram, "matrix_w2c"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); + hsMatrix2GL(src, fMatrixW2C); } void plGLDevice::SetLocalToWorldMatrix(const hsMatrix44& src) { - GLfloat mat[16]; - GLint uniform = glGetUniformLocation(fProgram, "matrix_l2w"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, hsMatrix2GL(src, mat)); + hsMatrix2GL(src, fMatrixL2W); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index e26222d395..37e97c1696 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -78,7 +78,10 @@ class plGLDevice void* fSurface; void* fContext; size_t fActiveThread; - GLuint fProgram; + GLuint fCurrentProgram; + GLfloat fMatrixL2W[16]; + GLfloat fMatrixW2C[16]; + GLfloat fMatrixProj[16]; public: plGLDevice(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 62334ae476..5a34ba0f36 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -55,6 +55,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLPipeline.h" #include "plGLPlateManager.h" +#include "plPipeDebugFlags.h" #include "plProfile.h" #include "plPipeline/hsWinRef.h" #include "plStatusLog/plStatusLog.h" @@ -65,6 +66,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com typedef plGLDevice DeviceType; +plProfile_Extern(DrawFeedTriangles); +plProfile_Extern(DrawPrimStatic); +plProfile_Extern(TotalTexSize); +plProfile_Extern(LayChange); +plProfile_Extern(DrawTriangles); +plProfile_Extern(MatChange); plProfile_Extern(RenderSpan); plProfile_Extern(MergeCheck); plProfile_Extern(MergeSpan); @@ -77,6 +84,27 @@ plProfile_Extern(CheckStat); plProfile_Extern(RenderBuff); plProfile_Extern(RenderPrim); +// Adding a nil RenderPrim for turning off drawing +static plRenderNilFunc sRenderNil; + +class plGLRenderTriListFunc : public plRenderTriListFunc +{ +public: + plGLRenderTriListFunc(plGLDevice* device, int baseVertexIndex, int vStart, int vLength, int iStart, int iNumTris) + : plRenderTriListFunc(device, baseVertexIndex, vStart, vLength, iStart, iNumTris) {} + + bool RenderPrims() const override + { + plProfile_IncCount(DrawFeedTriangles, fNumTris); + plProfile_IncCount(DrawTriangles, fNumTris); + plProfile_Inc(DrawPrimStatic); + + glDrawElements(GL_TRIANGLES, fNumTris, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * fIStart)); + return true; // TODO: Check for GL Error + } +}; + + plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) @@ -540,10 +568,14 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength) { + plProfile_BeginTiming(RenderBuff); + typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)vb; typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)ib; if (!vRef->fRef || !iRef->fRef) { + plProfile_EndTiming(RenderBuff); + hsAssert(false, "Trying to render a nil buffer pair!"); return; } @@ -551,8 +583,17 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Vertex Buffer stuff */ glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); - GLint posAttrib = glGetAttribLocation(fDevice.fProgram, "position"); - GLint colAttrib = glGetAttribLocation(fDevice.fProgram, "color"); + GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_proj"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixProj); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_l2w"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_w2c"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); + + GLint posAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "position"); + GLint colAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "color"); glEnableVertexAttribArray(posAttrib); glEnableVertexAttribArray(colAttrib); @@ -563,5 +604,10 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Index Buffer stuff and drawing */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); - glDrawElements(GL_TRIANGLES, iLength, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * iStart)); + plGLRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength); + + plProfile_EndTiming(RenderBuff); + + // TEMP + render.RenderPrims(); } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index e2d11b9fb6..b5c6564eb0 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -86,10 +86,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com uint32_t fDbgSetupInitFlags; // HACK temp only -plProfile_CreateCounter("Feed Triangles", "Draw", DrawFeedTriangles); -plProfile_CreateCounter("Draw Prim Static", "Draw", DrawPrimStatic); -plProfile_CreateMemCounter("Total Texture Size", "Draw", TotalTexSize); -plProfile_CreateCounter("Layer Change", "Draw", LayChange); +plProfile_Extern(DrawFeedTriangles); +plProfile_Extern(DrawPrimStatic); +plProfile_Extern(TotalTexSize); +plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); @@ -120,30 +120,17 @@ plProfile_CreateCounter("NumSkin", "PipeC", NumSkin); plMetalEnumerate plMetalPipeline::enumerator; -class plRenderTriListFunc : public plRenderPrimFunc +class plMetalRenderTriListFunc : public plRenderTriListFunc { -protected: - plMetalDevice* fDevice; - int fBaseVertexIndex; - int fVStart; - int fVLength; - int fIStart; - int fNumTris; - public: - plRenderTriListFunc(plMetalDevice* device, int baseVertexIndex, + plMetalRenderTriListFunc(plMetalDevice* device, int baseVertexIndex, int vStart, int vLength, int iStart, int iNumTris) - : fDevice(device), - fBaseVertexIndex(baseVertexIndex), - fVStart(vStart), - fVLength(vLength), - fIStart(iStart), - fNumTris(iNumTris) {} + : plRenderTriListFunc(device, baseVertexIndex, vStart, vLength, iStart, iNumTris) {} bool RenderPrims() const override; }; -bool plRenderTriListFunc::RenderPrims() const +bool plMetalRenderTriListFunc::RenderPrims() const { plProfile_IncCount(DrawFeedTriangles, fNumTris); plProfile_IncCount(DrawTriangles, fNumTris); @@ -1183,7 +1170,7 @@ void plMetalPipeline::IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, /* Index Buffer stuff and drawing */ - plRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength / 3); + plMetalRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength / 3); plProfile_EndTiming(RenderBuff); @@ -1478,7 +1465,7 @@ void plMetalPipeline::IRenderAuxSpan(const plSpan& span, const plAuxSpan* aux) fState.fCurrentVertexBuffer = vRef->GetBuffer(); fDevice.fCurrentIndexBuffer = iRef->GetBuffer(); - plRenderTriListFunc render(&fDevice, 0, aux->fVStartIdx, aux->fVLength, aux->fIStartIdx, aux->fILength / 3); + plMetalRenderTriListFunc render(&fDevice, 0, aux->fVStartIdx, aux->fVLength, aux->fIStartIdx, aux->fILength / 3); for (int32_t pass = 0; pass < mRef->GetNumPasses(); pass++) { IHandleMaterialPass(material, pass, &span, vRef); @@ -3698,7 +3685,7 @@ void plMetalPipeline::IRenderShadowCasterSpan(plShadowSlave* slave, plDrawableSp uint32_t iStart = span.fIPackedIdx; uint32_t iLength = span.fILength; - plRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength / 3); + plMetalRenderTriListFunc render(&fDevice, 0, vStart, vLength, iStart, iLength / 3); static hsMatrix44 emptyMatrix; hsMatrix44 m = emptyMatrix; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 09cfe01bdb..a9eef17ab3 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -73,17 +73,6 @@ class plMetalEnumerate static void Enumerate(std::vector& records); }; -//// Helper Classes /////////////////////////////////////////////////////////// - -//// The RenderPrimFunc lets you have one function which does a lot of stuff -// around the actual call to render whatever type of primitives you have, instead -// of duplicating everything because the one line to render is different. -class plRenderPrimFunc -{ -public: - virtual bool RenderPrims() const = 0; // return true on error -}; - class plMetalPipeline : public pl3DPipeline { public: @@ -94,7 +83,7 @@ class plMetalPipeline : public pl3DPipeline friend class plMetalDevice; friend class plMetalPlateManager; friend class plMetalMaterialShaderRef; - friend class plRenderTriListFunc; + friend class plMetalRenderTriListFunc; friend class plMetalTextFont; plMetalMaterialShaderRef* fMatRefList; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index b23188e162..4966a9033c 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -77,7 +77,11 @@ plProfile_CreateCounter("Perms Found", "PipeC", FindLightsPerm); plProfile_CreateCounter("Polys", "General", DrawTriangles); plProfile_CreateCounter("Material Change", "Draw", MatChange); +plProfile_CreateCounter("Feed Triangles", "Draw", DrawFeedTriangles); +plProfile_CreateCounter("Draw Prim Static", "Draw", DrawPrimStatic); +plProfile_CreateCounter("Layer Change", "Draw", LayChange); +plProfile_CreateMemCounter("Total Texture Size", "Draw", TotalTexSize); plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); plProfile_CreateMemCounter("Indices", "Memory", MemIndex); plProfile_CreateMemCounter("Textures", "Memory", MemTexture); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 7104ce0c4c..0d8ff9c708 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -107,6 +107,61 @@ static const float kPerspLayerTrans = 0.00002f; static const float kAvTexPoolShrinkThresh = 30.f; // seconds +//// Helper Classes /////////////////////////////////////////////////////////// + +/** + * The RenderPrimFunc lets you have one function which does a lot of stuff + * around the actual call to render whatever type of primitives you have, + * instead of duplicating everything because the one line to render is + * different. + * + * These allow the same setup code path to be followed, no matter what the + * primitive type (i.e. data-type/draw-call is going to happen once the render + * state is set. + * Originally useful to make one code path for trilists, tri-patches, and + * rect-patches, but we've since dropped support for patches. We still use the + * RenderNil function to allow the code to go through all the state setup + * without knowing whether a render call is going to come out the other end. + * + * Would allow easy extension for supporting tristrips or pointsprites, but + * we've never had a strong reason to use either. + */ +class plRenderPrimFunc +{ +public: + virtual bool RenderPrims() const = 0; // return true on error +}; + + +class plRenderNilFunc : public plRenderPrimFunc +{ +public: + plRenderNilFunc() {} + + virtual bool RenderPrims() const { return false; } +}; + + +template +class plRenderTriListFunc : public plRenderPrimFunc +{ +protected: + DeviceType* fDevice; + int fBaseVertexIndex; + int fVStart; + int fVLength; + int fIStart; + int fNumTris; + +public: + plRenderTriListFunc(DeviceType* device, int baseVertexIndex, int vStart, int vLength, int iStart, int iNumTris) + : fDevice(device), fBaseVertexIndex(baseVertexIndex), fVStart(vStart), + fVLength(vLength), fIStart(iStart), fNumTris(iNumTris) {} +}; + + +//// Class Definition ///////////////////////////////////////////////////////// + template class pl3DPipeline : public plPipeline { From 2b231c6b42a5923f10fd1f2ba5af27cf655b73d4 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Wed, 7 Jan 2015 23:17:48 -0800 Subject: [PATCH 12/76] Generate per-material shaders for GLPipeline --- .../FeatureLib/pfGLPipeline/CMakeLists.txt | 2 + .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 44 ----- .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 14 +- .../pfGLPipeline/plGLDeviceRefs.cpp | 39 +++++ .../pfGLPipeline/plGLMaterialShaderRef.cpp | 163 ++++++++++++++++++ .../pfGLPipeline/plGLMaterialShaderRef.h | 75 ++++++++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 45 +++-- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 4 + .../PubUtilLib/plSurface/hsGMaterial.cpp | 12 +- .../Plasma/PubUtilLib/plSurface/hsGMaterial.h | 19 +- 10 files changed, 338 insertions(+), 79 deletions(-) create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index b5e3dd5575..8d11468779 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -2,6 +2,7 @@ set(pfGLPipeline_SOURCES plGLDevice.cpp plGLEnumerate.cpp plGLDeviceRefs.cpp + plGLMaterialShaderRef.cpp plGLPipeline.cpp plGLPlateManager.cpp ) @@ -9,6 +10,7 @@ set(pfGLPipeline_SOURCES set(pfGLPipeline_HEADERS plGLDevice.h plGLDeviceRef.h + plGLMaterialShaderRef.h plGLPipeline.h pfGLPipelineCreatable.h plGLPlateManager.h diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 3200e919af..a7fc1fdca5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -346,50 +346,6 @@ bool plGLDevice::InitDevice() glFrontFace(GL_CCW); glCullFace(GL_BACK); - /* TEMP: Shader init stuff */ - const char* vs_src = "#version 130" - "\n" - "\n" "attribute vec3 position;" - "\n" "attribute vec4 color;" - "\n" - "\n" "uniform mat4 matrix_l2w;" - "\n" "uniform mat4 matrix_w2c;" - "\n" "uniform mat4 matrix_proj;" - "\n" - "\n" "varying vec4 v_color;" - "\n" - "\n" "void main() {" - "\n" " vec4 pos = matrix_l2w * vec4(position, 1.0);" - "\n" " pos = matrix_w2c * pos;" - "\n" " pos = matrix_proj * pos;" - "\n" - "\n" " gl_Position = pos;" - "\n" " v_color = color.zyxw;" - "\n" "}"; - - const char* fs_src = "#version 130" - "\n" - "\n" "varying mediump vec4 v_color;" - "\n" - "\n" "void main() {" - "\n" " gl_FragColor = v_color;" - "\n" "}"; - - GLuint vshader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vshader, 1, &vs_src, nullptr); - glCompileShader(vshader); - - GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fshader, 1, &fs_src, nullptr); - glCompileShader(fshader); - - fCurrentProgram = glCreateProgram(); - glAttachShader(fCurrentProgram, vshader); - glAttachShader(fCurrentProgram, fshader); - - glLinkProgram(fCurrentProgram); - glUseProgram(fCurrentProgram); - return true; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index fe69e14e24..7f393eaf9e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -67,7 +67,7 @@ class plGLDeviceRef : public hsGDeviceRef bool HasFlag(uint32_t f) const { return 0 != (fFlags & f); } void SetFlag(uint32_t f, bool on) { if(on) fFlags |= f; else fFlags &= ~f; } - virtual void Release() = 0; + virtual void Release() = 0; plGLDeviceRef(); virtual ~plGLDeviceRef(); @@ -114,10 +114,10 @@ class plGLVertexBufferRef : public plGLDeviceRef plGLVertexBufferRef() : plGLDeviceRef(), fCount(), fIndex(), fVertexSize(), fOffset(), fFormat(), fOwner(), fData(), fRefTime() - { } + {} - virtual ~plGLVertexBufferRef() {} - void Release() {} + virtual ~plGLVertexBufferRef(); + void Release(); }; @@ -152,10 +152,10 @@ class plGLIndexBufferRef : public plGLDeviceRef plGLIndexBufferRef() : plGLDeviceRef(), fCount(), fIndex(), fOffset(), fOwner(), fRefTime() - { } + {} - virtual ~plGLIndexBufferRef() {} - void Release() {} + virtual ~plGLIndexBufferRef(); + void Release(); }; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index ed4906929d..87003d84b6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -87,3 +87,42 @@ void plGLDeviceRef::Link(plGLDeviceRef** back) fBack = back; *back = this; } + + +/***************************************************************************** + ** Vertex buffer cleanup Functions ** + *****************************************************************************/ + +plGLVertexBufferRef::~plGLVertexBufferRef() +{ + Release(); +} + + +void plGLVertexBufferRef::Release() +{ + if (fRef) { + glDeleteBuffers(1, &fRef); + fRef = 0; + } + SetDirty(true); +} + + +/***************************************************************************** + ** Index buffer cleanup Functions ** + *****************************************************************************/ + +plGLIndexBufferRef::~plGLIndexBufferRef() +{ + Release(); +} + +void plGLIndexBufferRef::Release() +{ + if (fRef) { + glDeleteBuffers(1, &fRef); + fRef = 0; + } + SetDirty(true); +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp new file mode 100644 index 0000000000..b3248da220 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -0,0 +1,163 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plGLMaterialShaderRef.h" + +#include + +#include "HeadSpin.h" +#include "plSurface/hsGMaterial.h" + +plGLMaterialShaderRef::~plGLMaterialShaderRef() +{ + Release(); +} + +void plGLMaterialShaderRef::Release() +{ + if (fVertShaderRef) { + glDeleteShader(fVertShaderRef); + fVertShaderRef = 0; + } + + if (fFragShaderRef) { + glDeleteShader(fFragShaderRef); + fFragShaderRef = 0; + } + + if (fRef) { + glDeleteProgram(fRef); + fRef = 0; + } + + SetDirty(true); +} + + +void plGLMaterialShaderRef::ICompile() +{ + const char* vs_src = "#version 100" + "\n" + "\n" "uniform mat4 uMatrixL2W;" + "\n" "uniform mat4 uMatrixW2C;" + "\n" "uniform mat4 uMatrixProj;" + "\n" + "\n" "attribute vec3 aVtxPosition;" + "\n" "attribute vec3 aVtxNormal;" + "\n" "attribute vec4 aVtxColor;" + "\n" + "\n" "varying vec3 vVtxNormal;" + "\n" "varying vec4 vVtxColor;" + "\n" + "\n" "void main() {" + "\n" " vVtxNormal = aVtxNormal;" + "\n" " vVtxColor = aVtxColor.zyxw;" + "\n" + "\n" " vec4 pos = uMatrixL2W * vec4(aVtxPosition, 1.0);" + "\n" " pos = uMatrixW2C * pos;" + "\n" " pos = uMatrixProj * pos;" + "\n" + "\n" " gl_Position = pos;" + "\n" "}"; + + const char* fs_src = "#version 100" + "\n" + "\n" "varying lowp vec3 vVtxNormal;" + "\n" "varying mediump vec4 vVtxColor;" + "\n" + "\n" "void main() {" + "\n" " gl_FragColor = vVtxColor;" + "\n" "}"; + + fVertShaderRef = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(fVertShaderRef, 1, &vs_src, nullptr); + glCompileShader(fVertShaderRef); + +#ifdef HS_DEBUGGING + { + GLint compiled = 0; + glGetShaderiv(fVertShaderRef, GL_COMPILE_STATUS, &compiled); + if (compiled == 0) { + GLint length = 0; + glGetShaderiv(fVertShaderRef, GL_INFO_LOG_LENGTH, &length); + if (length) { + char* log = new char[length]; + glGetShaderInfoLog(fVertShaderRef, length, &length, log); + hsStatusMessage(log); + } + } + } +#endif + + fFragShaderRef = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fFragShaderRef, 1, &fs_src, nullptr); + glCompileShader(fFragShaderRef); + +#ifdef HS_DEBUGGING + { + GLint compiled = 0; + glGetShaderiv(fFragShaderRef, GL_COMPILE_STATUS, &compiled); + if (compiled == 0) { + GLint length = 0; + glGetShaderiv(fFragShaderRef, GL_INFO_LOG_LENGTH, &length); + if (length) { + char* log = new char[length]; + glGetShaderInfoLog(fFragShaderRef, length, &length, log); + hsStatusMessage(log); + } + } + } +#endif + + fRef = glCreateProgram(); + glAttachShader(fRef, fVertShaderRef); + glAttachShader(fRef, fFragShaderRef); + + glLinkProgram(fRef); + +#ifdef HS_DEBUGGING + GLenum e; + if ((e = glGetError()) != GL_NO_ERROR) { + hsStatusMessage(ST::format("Prg Link failed {}", uint32_t(e)).c_str()); + } +#endif +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h new file mode 100644 index 0000000000..5bb70f7b90 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -0,0 +1,75 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#ifndef _plGLMaterialShaderRef_inc_ +#define _plGLMaterialShaderRef_inc_ + +#include "plGLDeviceRef.h" + +class hsGMaterial; + +class plGLMaterialShaderRef : public plGLDeviceRef +{ +protected: + hsGMaterial* fMaterial; + GLuint fVertShaderRef; + GLuint fFragShaderRef; + +public: + void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } + plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } + + plGLMaterialShaderRef(hsGMaterial* mat) + : plGLDeviceRef(), fMaterial(mat), fVertShaderRef(), fFragShaderRef() + { + ICompile(); + } + + virtual ~plGLMaterialShaderRef(); + + void Release(); + +protected: + void ICompile(); +}; + +#endif // _plGLMaterialShaderRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 5a34ba0f36..63666d65b1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -52,6 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsWindows.h" +#include "plGLMaterialShaderRef.h" #include "plGLPipeline.h" #include "plGLPlateManager.h" @@ -108,7 +109,7 @@ class plGLRenderTriListFunc : public plRenderTriListFunc plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) - : pl3DPipeline(devMode) + : pl3DPipeline(devMode), fMatRefList() { plStatusLog::AddLineS("pipeline.log", "Constructing plGLPipeline"); plStatusLog::AddLineSF("pipeline.log", "Driver vendor: {}", devMode->GetDevice()->GetDriverDesc()); @@ -489,6 +490,23 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& } if (material != nullptr) { + // First, do we have a device ref at this index? + plGLMaterialShaderRef* mRef = static_cast(material->GetDeviceRef()); + + if (mRef == nullptr) { + mRef = new plGLMaterialShaderRef(material); + material->SetDeviceRef(mRef); + + glUseProgram(mRef->fRef); + fDevice.fCurrentProgram = mRef->fRef; + } + + if (!mRef->IsLinked()) + mRef->Link(&fMatRefList); + + glUseProgram(mRef->fRef); + fDevice.fCurrentProgram = mRef->fRef; + // TODO: Figure out how to use VAOs properly :( GLuint vao; glGenVertexArrays(1, &vao); @@ -560,6 +578,18 @@ void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& spa fD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); } #endif + + if (fDevice.fCurrentProgram) { + /* Push the matrices into the GLSL shader now */ + GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixProj"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixProj); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2C"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); + } } void plGLPipeline::IRenderBufferSpan(const plIcicle& span, @@ -583,17 +613,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Vertex Buffer stuff */ glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); - GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_proj"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixProj); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_l2w"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "matrix_w2c"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); - - GLint posAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "position"); - GLint colAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "color"); + GLint posAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxPosition"); + GLint colAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxColor"); glEnableVertexAttribArray(posAttrib); glEnableVertexAttribArray(colAttrib); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 45d9a434f6..4f048a5222 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -47,6 +47,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPipeline/hsG3DDeviceSelector.h" class plIcicle; +class plGLMaterialShaderRef; class plGLEnumerate { @@ -64,6 +65,9 @@ class plGLPipeline : public pl3DPipeline friend class plGLPlateManager; friend class plGLDevice; +protected: + plGLMaterialShaderRef* fMatRefList; + public: plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode); virtual ~plGLPipeline() = default; diff --git a/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.cpp b/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.cpp index e344d3e19d..e61d54f08c 100644 --- a/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.cpp +++ b/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.cpp @@ -47,6 +47,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "plProfile.h" #include "hsResMgr.h" +#include "hsGDeviceRef.h" #include "plLayer.h" #include "plLayerInterface.h" @@ -61,18 +62,17 @@ plLayer defaultLayer; ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// -hsGMaterial::hsGMaterial() : -fLOD(0), -fCompFlags(0), -fLoadFlags(0), -fLastUpdateTime(0), -fDeviceRef() +hsGMaterial::hsGMaterial() + : fLOD(), fCompFlags(), fLoadFlags(), fLastUpdateTime(), fDeviceRef() { } hsGMaterial::~hsGMaterial() { IClearLayers(); + + if (fDeviceRef != nullptr) + hsRefCnt_SafeUnRef(fDeviceRef); } plLayerInterface* hsGMaterial::GetPiggyBack(size_t which) diff --git a/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.h b/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.h index 2f411d1b4a..e17353f9fc 100644 --- a/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.h +++ b/Sources/Plasma/PubUtilLib/plSurface/hsGMaterial.h @@ -52,7 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com class hsScene; class hsResMgr; -class hsG3DDevice; +class hsGDeviceRef; class plLayerInterface; class plLayer; @@ -84,15 +84,14 @@ class hsGMaterial : public plSynchedObject }; protected: - uint32_t fLOD; - std::vector fLayers; - std::vector fPiggyBacks; + uint32_t fLOD; + std::vector fLayers; + std::vector fPiggyBacks; - uint32_t fCompFlags; - uint32_t fLoadFlags; + uint32_t fCompFlags; + uint32_t fLoadFlags; - float fLastUpdateTime; - + float fLastUpdateTime; hsGDeviceRef* fDeviceRef; void IClearLayers(); @@ -131,8 +130,8 @@ class hsGMaterial : public plSynchedObject bool IsDynamic() const { return (fCompFlags & kCompDynamic); } bool IsDecal() const { return (fCompFlags & kCompDecal); } bool NeedsBlendChannel() { return (fCompFlags & kCompNeedsBlendChannel); } - - + + void SetDeviceRef(hsGDeviceRef* ref) { hsRefCnt_SafeAssign(fDeviceRef, ref); } hsGDeviceRef* GetDeviceRef() const { return fDeviceRef; } From 2f217c5e71c81e28d87eb0c18391208692dc7749 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 7 Jun 2015 00:10:53 -0700 Subject: [PATCH 13/76] Totally hacky, but working, textures --- .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 36 ++- .../pfGLPipeline/plGLDeviceRefs.cpp | 19 ++ .../pfGLPipeline/plGLMaterialShaderRef.cpp | 258 +++++++++++++++--- .../pfGLPipeline/plGLMaterialShaderRef.h | 5 + .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 43 ++- 5 files changed, 314 insertions(+), 47 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index 7f393eaf9e..46f77e0aa6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -47,7 +47,22 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include +// Helper macro for logging GL Errors +#ifdef HS_DEBUGGING +# include "plStatusLog/plStatusLog.h" +# define LOG_GL_ERROR_CHECK(message) \ + do { \ + GLenum e; \ + if ((e = glGetError()) != GL_NO_ERROR) { \ + plStatusLog::AddLineSF("pipeline.log", message ": {}", uint32_t(e)); \ + } \ + } while(0); +#else +# define LOG_GL_ERROR_CHECK(message) +#endif + class plGBufferGroup; +class plMipmap; class plGLDeviceRef : public hsGDeviceRef { @@ -117,7 +132,7 @@ class plGLVertexBufferRef : public plGLDeviceRef {} virtual ~plGLVertexBufferRef(); - void Release(); + void Release() override; }; @@ -155,7 +170,24 @@ class plGLIndexBufferRef : public plGLDeviceRef {} virtual ~plGLIndexBufferRef(); - void Release(); + void Release() override; +}; + + +class plGLTextureRef : public plGLDeviceRef +{ +public: + plMipmap* fOwner; + + void Link(plGLTextureRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } + plGLTextureRef* GetNext() { return (plGLTextureRef*)fNext; } + + plGLTextureRef() + : plGLDeviceRef(), fOwner() + {} + + virtual ~plGLTextureRef(); + void Release() override; }; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index 87003d84b6..65cc1bc185 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -126,3 +126,22 @@ void plGLIndexBufferRef::Release() } SetDirty(true); } + + +/***************************************************************************** + ** Texture Reference cleanup Functions ** + *****************************************************************************/ + +plGLTextureRef::~plGLTextureRef() +{ + Release(); +} + + +void plGLTextureRef::Release() +{ + if (fRef) { + glDeleteTextures(1, &fRef); + fRef = 0; + } +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index b3248da220..47423b56ed 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -41,11 +41,19 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ #include "plGLMaterialShaderRef.h" +#include "plGLDevice.h" #include +#include +#include #include "HeadSpin.h" +#include "hsBitVector.h" + +#include "plDrawable/plGBufferGroup.h" +#include "plGImage/plMipmap.h" #include "plSurface/hsGMaterial.h" +#include "plSurface/plLayerInterface.h" plGLMaterialShaderRef::~plGLMaterialShaderRef() { @@ -72,44 +80,213 @@ void plGLMaterialShaderRef::Release() SetDirty(true); } +void plGLMaterialShaderRef::SetupTextureRefs() +{ + int32_t numTextures = 0; + + for (size_t i = 0; i < fMaterial->GetNumLayers(); i++) { + plLayerInterface* layer = fMaterial->GetLayer(i); + if (!layer) + continue; + + if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { + // Now we have a different problem... + continue; + } + + // Load the image + plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); + if (!img) + continue; + + GLenum e; + plGLTextureRef* texRef = static_cast(img->GetDeviceRef()); + + if (!texRef->fRef) + continue; + + LOG_GL_ERROR_CHECK("PRE-Active Texture failed") + + glActiveTexture(GL_TEXTURE0 + numTextures); + LOG_GL_ERROR_CHECK("Active Texture failed") + + glBindTexture(GL_TEXTURE_2D, texRef->fRef); + LOG_GL_ERROR_CHECK("Bind Texture failed") + + ST::string name = ST::format("uTexture{}", numTextures); + + GLint texture = glGetUniformLocation(fRef, name.c_str()); + glUniform1i(texture, numTextures); + LOG_GL_ERROR_CHECK("Uniform Texture failed") + + numTextures++; + } +} + void plGLMaterialShaderRef::ICompile() { - const char* vs_src = "#version 100" - "\n" - "\n" "uniform mat4 uMatrixL2W;" - "\n" "uniform mat4 uMatrixW2C;" - "\n" "uniform mat4 uMatrixProj;" - "\n" - "\n" "attribute vec3 aVtxPosition;" - "\n" "attribute vec3 aVtxNormal;" - "\n" "attribute vec4 aVtxColor;" - "\n" - "\n" "varying vec3 vVtxNormal;" - "\n" "varying vec4 vVtxColor;" - "\n" - "\n" "void main() {" - "\n" " vVtxNormal = aVtxNormal;" - "\n" " vVtxColor = aVtxColor.zyxw;" - "\n" - "\n" " vec4 pos = uMatrixL2W * vec4(aVtxPosition, 1.0);" - "\n" " pos = uMatrixW2C * pos;" - "\n" " pos = uMatrixProj * pos;" - "\n" - "\n" " gl_Position = pos;" - "\n" "}"; - - const char* fs_src = "#version 100" - "\n" - "\n" "varying lowp vec3 vVtxNormal;" - "\n" "varying mediump vec4 vVtxColor;" - "\n" - "\n" "void main() {" - "\n" " gl_FragColor = vVtxColor;" - "\n" "}"; + hsBitVector uvLayers; + fNumUVs = 0; + int32_t numTextures = 0; + + for (size_t i = 0; i < fMaterial->GetNumLayers(); i++) { + plLayerInterface* layer = fMaterial->GetLayer(i); + if (!layer) + continue; + + if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { + // Now we have a different problem... + continue; + } + + uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; + + if (!uvLayers.IsBitSet(uv)) { + fNumUVs++; + uvLayers.SetBit(uv); + } + + + // Load the image + plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); + if (!img) + continue; + + numTextures++; + + plGLTextureRef* texRef = new plGLTextureRef(); + texRef->fOwner = img; + img->SetDeviceRef(texRef); + + GLenum e; + + glGenTextures(1, &texRef->fRef); + LOG_GL_ERROR_CHECK("Gen Texture failed") + + glBindTexture(GL_TEXTURE_2D, texRef->fRef); + LOG_GL_ERROR_CHECK("Bind Texture failed") + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (img->IsCompressed()) { + GLuint dxCompression = 0; + uint8_t compType = img->fDirectXInfo.fCompressionType; + + if (compType == plBitmap::DirectXInfo::kDXT1) + dxCompression = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + else if (compType == plBitmap::DirectXInfo::kDXT5) + dxCompression = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + + for (uint8_t i = 0; i < img->GetNumLevels(); i++) { + img->SetCurrLevel(i); + + if (img->GetCurrWidth() < 4 || img->GetCurrHeight() < 4) + continue; + + glCompressedTexImage2D(GL_TEXTURE_2D, i, dxCompression, + img->GetCurrWidth(), img->GetCurrHeight(), + 0, img->GetCurrLevelSize(), img->GetCurrLevelPtr()); + +#ifdef HS_DEBUGGING + if ((e = glGetError()) != GL_NO_ERROR) { + plStatusLog::AddLineSF("pipeline.log", "Texture Image failed: {}, at level {}", uint32_t(e), i); + } +#endif + } + } + } + + ST::string_stream vs_src; + + vs_src << "#version 100" << "\n"; + vs_src << "\n"; + vs_src << "uniform mat4 uMatrixL2W;" << "\n"; + vs_src << "uniform mat4 uMatrixW2C;" << "\n"; + vs_src << "uniform mat4 uMatrixProj;" << "\n"; + vs_src << "\n"; + vs_src << "attribute vec3 aVtxPosition;" << "\n"; + vs_src << "attribute vec3 aVtxNormal;" << "\n"; + vs_src << "attribute vec4 aVtxColor;" << "\n"; + for (int32_t i = 0; i < fNumUVs; i++) { + vs_src << "attribute vec3 aVtxUVWSrc" << i << ";" << "\n"; + } + vs_src << "\n"; + vs_src << "varying vec3 vVtxNormal;" << "\n"; + vs_src << "varying vec4 vVtxColor;" << "\n"; + for (int32_t i = 0; i < fNumUVs; i++) { + vs_src << "varying vec3 vVtxUVWSrc" << i << ";" << "\n"; + } + vs_src << "\n"; + vs_src << "void main() {" << "\n"; + vs_src << " vVtxNormal = aVtxNormal;" << "\n"; + vs_src << " vVtxColor = aVtxColor.zyxw;" << "\n"; + for (int32_t i = 0; i < fNumUVs; i++) { + vs_src << " vVtxUVWSrc" << i << " = aVtxUVWSrc" << i << ";" << "\n"; + } + vs_src << "\n"; + vs_src << " vec4 pos = uMatrixL2W * vec4(aVtxPosition, 1.0);" << "\n"; + vs_src << " pos = uMatrixW2C * pos;" << "\n"; + vs_src << " pos = uMatrixProj * pos;" << "\n"; + vs_src << "\n"; + vs_src << " gl_Position = pos;" << "\n"; + vs_src << "}"; + + + + ST::string_stream fs_src; + fs_src << "#version 100" << "\n"; + fs_src << "\n"; + for (int32_t i = 0; i < numTextures; i++) { + fs_src << "uniform sampler2D uTexture" << i << ";" << "\n"; + } + fs_src << "\n"; + fs_src << "varying lowp vec3 vVtxNormal;" << "\n"; + fs_src << "varying mediump vec4 vVtxColor;" << "\n"; + for (int32_t i = 0; i < fNumUVs; i++) { + fs_src << "varying mediump vec3 vVtxUVWSrc" << i << ";" << "\n"; + } + fs_src << "\n"; + fs_src << "void main() {" << "\n"; + fs_src << " mediump vec4 color = vVtxColor;" << "\n"; + /*if (numTextures > 0) { + fs_src << " color *= texture2D(uTexture0, vec2(vVtxUVWSrc0.x, vVtxUVWSrc0.y));" << "\n"; + }*/ + + for (int32_t i = 0, tex = 0; i < fMaterial->GetNumLayers(); i++) { + plLayerInterface* layer = fMaterial->GetLayer(i); + if (!layer) + continue; + + if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { + // Now we have a different problem... + continue; + } + + plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); + if (!img) + continue; + + uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; + + fs_src << " color *= texture2D(uTexture" << tex << ", vec2(vVtxUVWSrc" << uv << ".x, vVtxUVWSrc" << uv << ".y));" << "\n"; + tex++; + } + + fs_src << " gl_FragColor = color;" << "\n"; + fs_src << "}"; + + ST::string vtx = vs_src.to_string(); + ST::string frg = fs_src.to_string(); + + const char* vs_code = vtx.c_str(); + const char* fs_code = frg.c_str(); fVertShaderRef = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(fVertShaderRef, 1, &vs_src, nullptr); + glShaderSource(fVertShaderRef, 1, &vs_code, nullptr); glCompileShader(fVertShaderRef); #ifdef HS_DEBUGGING @@ -129,7 +306,7 @@ void plGLMaterialShaderRef::ICompile() #endif fFragShaderRef = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fFragShaderRef, 1, &fs_src, nullptr); + glShaderSource(fFragShaderRef, 1, &fs_code, nullptr); glCompileShader(fFragShaderRef); #ifdef HS_DEBUGGING @@ -149,15 +326,14 @@ void plGLMaterialShaderRef::ICompile() #endif fRef = glCreateProgram(); + LOG_GL_ERROR_CHECK("Create Program failed") + glAttachShader(fRef, fVertShaderRef); + LOG_GL_ERROR_CHECK("Attach Vertex Shader failed") + glAttachShader(fRef, fFragShaderRef); + LOG_GL_ERROR_CHECK("Attach Fragment Shader failed") glLinkProgram(fRef); - -#ifdef HS_DEBUGGING - GLenum e; - if ((e = glGetError()) != GL_NO_ERROR) { - hsStatusMessage(ST::format("Prg Link failed {}", uint32_t(e)).c_str()); - } -#endif + LOG_GL_ERROR_CHECK("Link Program failed") } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 5bb70f7b90..3f09084efd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -46,6 +46,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLDeviceRef.h" class hsGMaterial; +class plGLDevice; class plGLMaterialShaderRef : public plGLDeviceRef { @@ -53,6 +54,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef hsGMaterial* fMaterial; GLuint fVertShaderRef; GLuint fFragShaderRef; + int32_t fNumUVs; public: void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } @@ -67,6 +69,9 @@ class plGLMaterialShaderRef : public plGLDeviceRef virtual ~plGLMaterialShaderRef(); void Release(); + void SetupTextureRefs(); + + int32_t GetNumUVs() const { return fNumUVs; } protected: void ICompile(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 63666d65b1..c885228fad 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -497,8 +497,8 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& mRef = new plGLMaterialShaderRef(material); material->SetDeviceRef(mRef); - glUseProgram(mRef->fRef); - fDevice.fCurrentProgram = mRef->fRef; + //glUseProgram(mRef->fRef); + //fDevice.fCurrentProgram = mRef->fRef; } if (!mRef->IsLinked()) @@ -506,6 +506,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& glUseProgram(mRef->fRef); fDevice.fCurrentProgram = mRef->fRef; + LOG_GL_ERROR_CHECK("Use Program failed") // TODO: Figure out how to use VAOs properly :( GLuint vao; @@ -602,6 +603,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)vb; typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)ib; + plGLMaterialShaderRef* mRef = static_cast(material->GetDeviceRef()); if (!vRef->fRef || !iRef->fRef) { plProfile_EndTiming(RenderBuff); @@ -610,13 +612,44 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, return; } + LOG_GL_ERROR_CHECK("PRE Render failed"); + + mRef->SetupTextureRefs(); + /* Vertex Buffer stuff */ glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); GLint posAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxPosition"); + if (posAttrib != -1) { + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); + } + + GLint norAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxNormal"); + if (norAttrib != -1) { + glEnableVertexAttribArray(norAttrib); + glVertexAttribPointer(norAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); + } + GLint colAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxColor"); - glEnableVertexAttribArray(posAttrib); - glEnableVertexAttribArray(colAttrib); + if (colAttrib != -1) { + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); + } + + LOG_GL_ERROR_CHECK("Vertex Attributes failed") + + for (int i = 0; i < mRef->GetNumUVs(); i++) { + ST::string name = ST::format("aVtxUVWSrc{}", i); + + GLint uvwAttrib = glGetAttribLocation(fDevice.fCurrentProgram, name.c_str()); + if (uvwAttrib != -1) { + glEnableVertexAttribArray(uvwAttrib); + glVertexAttribPointer(uvwAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); + } + + LOG_GL_ERROR_CHECK("UVW Attributes failed") + } glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); @@ -631,4 +664,6 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, // TEMP render.RenderPrims(); + + LOG_GL_ERROR_CHECK("Render failed") } From d2bab103fab6311188a8cd7683208446ffce0c0c Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 23 Jun 2015 22:20:30 -0700 Subject: [PATCH 14/76] Handling initial blend modes and Z flags --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 - .../pfGLPipeline/plGLMaterialShaderRef.cpp | 167 ++++++++++++++++++ .../pfGLPipeline/plGLMaterialShaderRef.h | 36 +++- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 134 +++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 2 + 5 files changed, 329 insertions(+), 12 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index a7fc1fdca5..4f86a870d5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -341,8 +341,6 @@ bool plGLDevice::InitDevice() glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); - glDepthFunc(GL_LEQUAL); - glDepthMask(GL_TRUE); glFrontFace(GL_CCW); glCullFace(GL_BACK); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 47423b56ed..96a787c58a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -50,6 +50,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsBitVector.h" +#include "plPipeline.h" +#include "plPipeDebugFlags.h" + #include "plDrawable/plGBufferGroup.h" #include "plGImage/plMipmap.h" #include "plSurface/hsGMaterial.h" @@ -337,3 +340,167 @@ void plGLMaterialShaderRef::ICompile() glLinkProgram(fRef); LOG_GL_ERROR_CHECK("Link Program failed") } + + +bool plGLMaterialShaderRef::ILoopOverLayers() +{ + size_t j = 0; + for (j = 0; j < fMaterial->GetNumLayers(); ) + { + size_t iCurrMat = j; + hsGMatState currState; + + j = IHandleMaterial(iCurrMat, currState); + + if (j == -1) + break; + + fPasses++; + fPassStates.push_back(currState); + +#if 0 + ISetFogParameters(fMaterial->GetLayer(iCurrMat)); +#endif + } + + return false; +} + + +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& state) +{ + if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) + return -1; + + if (false /*ISkipBumpMap(fMaterial, layer)*/) + return -1; + + // Ignoring the bit about ATI Radeon and UVW limits + + if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNoDecals) && (fMaterial->GetCompositeFlags() & hsGMaterial::kCompDecal)) + return -1; + + // Ignoring the bit about self-rendering cube maps + + plLayerInterface* currLay = /*IPushOverBaseLayer*/ fMaterial->GetLayer(layer); + + if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW) && (currLay->GetMiscFlags() & hsGMatState::kMiscBumpDu)) + currLay = fMaterial->GetLayer(++layer); + + //currLay = IPushOverAllLayer(currLay); + + state = currLay->GetState(); + + if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagDisableSpecular)) + state.fShadeFlags &= ~hsGMatState::kShadeSpecular; + + if (state.fZFlags & hsGMatState::kZIncLayer) { + // Set the Z-bias + //ISetLayer(1); + } else { + // Clear any Z-bias + //IBottomLayer(); + } + + if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNoAlphaBlending)) + state.fBlendFlags &= ~hsGMatState::kBlendMask; + + if ((fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpUV) || fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW)) && (state.fMiscFlags & hsGMatState::kMiscBumpChans) ) { + switch (state.fMiscFlags & hsGMatState::kMiscBumpChans) + { + case hsGMatState::kMiscBumpDu: + break; + case hsGMatState::kMiscBumpDv: + if (!(fMaterial->GetLayer(layer-2)->GetBlendFlags() & hsGMatState::kBlendAdd)) + { + state.fBlendFlags &= ~hsGMatState::kBlendMask; + state.fBlendFlags |= hsGMatState::kBlendMADD; + } + break; + case hsGMatState::kMiscBumpDw: + if (!(fMaterial->GetLayer(layer-1)->GetBlendFlags() & hsGMatState::kBlendAdd)) + { + state.fBlendFlags &= ~hsGMatState::kBlendMask; + state.fBlendFlags |= hsGMatState::kBlendMADD; + } + break; + default: + break; + } + } + + uint32_t currNumLayers = ILayersAtOnce(layer); + +#if 0 + ICalcLighting(currLay); +#endif + + if (state.fMiscFlags & (hsGMatState::kMiscBumpDu | hsGMatState::kMiscBumpDw)) { + //ISetBumpMatrices(currLay); + } + + return layer + currNumLayers; +} + + +uint32_t plGLMaterialShaderRef::ILayersAtOnce(uint32_t which) +{ + uint32_t currNumLayers = 1; + + plLayerInterface* lay = fMaterial->GetLayer(which); + + if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNoMultitexture)) + return currNumLayers; + + if ((fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpUV) || fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW)) && (lay->GetMiscFlags() & hsGMatState::kMiscBumpChans)) { + currNumLayers = 2; + return currNumLayers; + } + + if ((lay->GetBlendFlags() & hsGMatState::kBlendNoColor) || (lay->GetMiscFlags() & hsGMatState::kMiscTroubledLoner)) + return currNumLayers; + + int i; + int maxLayers = 8; + if (which + maxLayers > fMaterial->GetNumLayers()) + maxLayers = fMaterial->GetNumLayers() - which; + + for (i = currNumLayers; i < maxLayers; i++) { + plLayerInterface* lay = fMaterial->GetLayer(which + i); + + // Ignoring max UVW limit + + if ((lay->GetMiscFlags() & hsGMatState::kMiscBindNext) && (i+1 >= maxLayers)) + break; + + if (lay->GetMiscFlags() & hsGMatState::kMiscRestartPassHere) + break; + + if (!(fMaterial->GetLayer(which + i - 1)->GetMiscFlags() & hsGMatState::kMiscBindNext) && !ICanEatLayer(lay)) + break; + + currNumLayers++; + } + + return currNumLayers; +} + + +bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) +{ + if (!lay->GetTexture()) + return false; + + if ((lay->GetBlendFlags() & hsGMatState::kBlendNoColor) || + (lay->GetBlendFlags() & hsGMatState::kBlendAddColorTimesAlpha) || + (lay->GetMiscFlags() & hsGMatState::kMiscTroubledLoner)) + return false; + + if ((lay->GetBlendFlags() & hsGMatState::kBlendAlpha) && (lay->GetAmbientColor().a < 1.f)) + return false; + + if (!(lay->GetZFlags() & hsGMatState::kZNoZWrite)) + return false; + + return true; +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 3f09084efd..d06685426b 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -45,24 +45,37 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLDeviceRef.h" +#include + +#include "hsGMatState.h" + class hsGMaterial; -class plGLDevice; +class plPipeline; +class plLayerInterface; class plGLMaterialShaderRef : public plGLDeviceRef { protected: - hsGMaterial* fMaterial; - GLuint fVertShaderRef; - GLuint fFragShaderRef; - int32_t fNumUVs; + hsGMaterial* fMaterial; + plPipeline* fPipeline; + GLuint fVertShaderRef; + GLuint fFragShaderRef; + + uint32_t fPasses; + std::vector fPassStates; + + int32_t fNumUVs; public: void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } - plGLMaterialShaderRef(hsGMaterial* mat) - : plGLDeviceRef(), fMaterial(mat), fVertShaderRef(), fFragShaderRef() + plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe) + : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(), fFragShaderRef(), fPasses() { + ILoopOverLayers(); + + // TODO: Remove ICompile(); } @@ -72,9 +85,18 @@ class plGLMaterialShaderRef : public plGLDeviceRef void SetupTextureRefs(); int32_t GetNumUVs() const { return fNumUVs; } + uint32_t GetNumPasses() const { return fPasses; } + hsGMatState GetPassState(uint32_t which) const { return fPassStates[which]; } protected: void ICompile(); + + bool ILoopOverLayers(); + uint32_t IHandleMaterial(uint32_t layer, hsGMatState& state); + uint32_t ILayersAtOnce(uint32_t which); + bool ICanEatLayer(plLayerInterface* lay); + //void IHandleFirstTextureStage(plLayerInterface* layer); + //void IHandleFirstStageBlend(const hsGMatState& layerState); }; #endif // _plGLMaterialShaderRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index c885228fad..001111b88d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -494,7 +494,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& plGLMaterialShaderRef* mRef = static_cast(material->GetDeviceRef()); if (mRef == nullptr) { - mRef = new plGLMaterialShaderRef(material); + mRef = new plGLMaterialShaderRef(material, this); material->SetDeviceRef(mRef); //glUseProgram(mRef->fRef); @@ -662,8 +662,136 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plProfile_EndTiming(RenderBuff); - // TEMP - render.RenderPrims(); + for (uint32_t pass = 0; pass < mRef->GetNumPasses(); pass++) { + // Set uniform to pass + + hsGMatState s = mRef->GetPassState(pass); + IHandleZMode(s); + IHandleBlendMode(s); + + // TEMP + render.RenderPrims(); + } LOG_GL_ERROR_CHECK("Render failed") } + +void plGLPipeline::IHandleZMode(hsGMatState flags) +{ + switch (flags.fZFlags & hsGMatState::kZMask) + { + case hsGMatState::kZClearZ: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + break; + case hsGMatState::kZNoZRead: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + break; + case hsGMatState::kZNoZWrite: + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_FALSE); + break; + case hsGMatState::kZNoZRead | hsGMatState::kZClearZ: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + break; + case hsGMatState::kZNoZRead | hsGMatState::kZNoZWrite: + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + break; + case 0: + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_TRUE); + break; + case hsGMatState::kZClearZ | hsGMatState::kZNoZWrite: + case hsGMatState::kZClearZ | hsGMatState::kZNoZWrite | hsGMatState::kZNoZRead: + hsAssert(false, "Illegal combination of Z Buffer modes (Clear but don't write)"); + break; + } +} + +void plGLPipeline::IHandleBlendMode(hsGMatState flags) +{ + // No color, just writing out Z values. + if (flags.fBlendFlags & hsGMatState::kBlendNoColor) { + glBlendFunc(GL_ZERO, GL_ONE); + flags.fBlendFlags |= 0x80000000; + } else { + switch (flags.fBlendFlags & hsGMatState::kBlendMask) + { + // Detail is just a special case of alpha, handled in construction of the texture + // mip chain by making higher levels of the chain more transparent. + case hsGMatState::kBlendDetail: + case hsGMatState::kBlendAlpha: + if (flags.fBlendFlags & hsGMatState::kBlendInvertFinalAlpha) { + if (flags.fBlendFlags & hsGMatState::kBlendAlphaPremultiplied) { + glBlendFunc(GL_ONE, GL_SRC_ALPHA); + } else { + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + } + } else { + if (flags.fBlendFlags & hsGMatState::kBlendAlphaPremultiplied) { + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + } + break; + + // Multiply the final color onto the frame buffer. + case hsGMatState::kBlendMult: + if (flags.fBlendFlags & hsGMatState::kBlendInvertFinalColor) { + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + } else { + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + } + break; + + // Add final color to FB. + case hsGMatState::kBlendAdd: + glBlendFunc(GL_ONE, GL_ONE); + break; + + // Multiply final color by FB color and add it into the FB. + case hsGMatState::kBlendMADD: + glBlendFunc(GL_DST_COLOR, GL_ONE); + break; + + // Final color times final alpha, added into the FB. + case hsGMatState::kBlendAddColorTimesAlpha: + if (flags.fBlendFlags & hsGMatState::kBlendInvertFinalAlpha) { + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + break; + + // Overwrite final color onto FB + case 0: + glBlendFunc(GL_ONE, GL_ZERO); + break; + + default: + { + hsAssert(false, "Too many blend modes specified in material"); + +#if 0 + plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); + if( lay ) + { + if( lay->GetBlendFlags() & hsGMatState::kBlendAlpha ) + { + lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAlpha); + } + else + { + lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAdd); + } + } +#endif + } + break; + } + } +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 4f048a5222..7f7657cab4 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -113,6 +113,8 @@ class plGLPipeline : public pl3DPipeline protected: void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, hsGDeviceRef* ib, hsGMaterial* material, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength); + void IHandleZMode(hsGMatState flags); + void IHandleBlendMode(hsGMatState flags); private: static plGLEnumerate enumerator; From 7c86cdb9b31df3c305ad012c605d1af5378804b2 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 28 Jun 2015 19:36:53 -0700 Subject: [PATCH 15/76] Better shader generation pipeline --- .../FeatureLib/pfGLPipeline/CMakeLists.txt | 2 + .../pfGLPipeline/plGLMaterialShaderRef.cpp | 698 +++++++++++++++--- .../pfGLPipeline/plGLMaterialShaderRef.h | 83 ++- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 47 +- .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 241 ++++++ .../FeatureLib/pfGLPipeline/plShaderNode.h | 281 +++++++ 6 files changed, 1196 insertions(+), 156 deletions(-) create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index 8d11468779..92934cbf75 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -5,6 +5,7 @@ set(pfGLPipeline_SOURCES plGLMaterialShaderRef.cpp plGLPipeline.cpp plGLPlateManager.cpp + plShaderNode.cpp ) set(pfGLPipeline_HEADERS @@ -14,6 +15,7 @@ set(pfGLPipeline_HEADERS plGLPipeline.h pfGLPipelineCreatable.h plGLPlateManager.h + plShaderNode.h ) plasma_library(pfGLPipeline SOURCES ${pfGLPipeline_SOURCES} ${pfGLPipeline_HEADERS}) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 96a787c58a..454a9d3cb6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -54,10 +54,24 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPipeDebugFlags.h" #include "plDrawable/plGBufferGroup.h" +#include "plGImage/plCubicEnvironmap.h" #include "plGImage/plMipmap.h" #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" +// From plGLDevice.cpp +extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); + +plGLMaterialShaderRef::plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe) + : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(0), fFragShaderRef(0) +{ + ISetupShaderContexts(); + ILoopOverLayers(); + ICompile(); + ISetShaderVariableLocs(); + ICleanupShaderContexts(); +} + plGLMaterialShaderRef::~plGLMaterialShaderRef() { Release(); @@ -92,11 +106,6 @@ void plGLMaterialShaderRef::SetupTextureRefs() if (!layer) continue; - if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { - // Now we have a different problem... - continue; - } - // Load the image plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); if (!img) @@ -116,10 +125,13 @@ void plGLMaterialShaderRef::SetupTextureRefs() glBindTexture(GL_TEXTURE_2D, texRef->fRef); LOG_GL_ERROR_CHECK("Bind Texture failed") - ST::string name = ST::format("uTexture{}", numTextures); + if (this->uLayerMat[i] != -1) { + GLfloat matrix[16]; + glUniformMatrix4fv(this->uLayerMat[i], 1, GL_TRUE, hsMatrix2GL(layer->GetTransform(), matrix)); + } - GLint texture = glGetUniformLocation(fRef, name.c_str()); - glUniform1i(texture, numTextures); + if (this->uTexture[i] != -1) + glUniform1i(this->uTexture[i], numTextures); LOG_GL_ERROR_CHECK("Uniform Texture failed") numTextures++; @@ -129,33 +141,22 @@ void plGLMaterialShaderRef::SetupTextureRefs() void plGLMaterialShaderRef::ICompile() { - hsBitVector uvLayers; - fNumUVs = 0; int32_t numTextures = 0; + hsBitVector usedUVWs; for (size_t i = 0; i < fMaterial->GetNumLayers(); i++) { plLayerInterface* layer = fMaterial->GetLayer(i); if (!layer) continue; - if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { - // Now we have a different problem... - continue; - } - - uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; - - if (!uvLayers.IsBitSet(uv)) { - fNumUVs++; - uvLayers.SetBit(uv); - } - - // Load the image plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); if (!img) continue; + uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; + usedUVWs.SetBit(uv); + numTextures++; plGLTextureRef* texRef = new plGLTextureRef(); @@ -173,7 +174,8 @@ void plGLMaterialShaderRef::ICompile() glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, std::max(0, img->GetNumLevels() - 3)); if (img->IsCompressed()) { GLuint dxCompression = 0; @@ -203,87 +205,8 @@ void plGLMaterialShaderRef::ICompile() } } - ST::string_stream vs_src; - - vs_src << "#version 100" << "\n"; - vs_src << "\n"; - vs_src << "uniform mat4 uMatrixL2W;" << "\n"; - vs_src << "uniform mat4 uMatrixW2C;" << "\n"; - vs_src << "uniform mat4 uMatrixProj;" << "\n"; - vs_src << "\n"; - vs_src << "attribute vec3 aVtxPosition;" << "\n"; - vs_src << "attribute vec3 aVtxNormal;" << "\n"; - vs_src << "attribute vec4 aVtxColor;" << "\n"; - for (int32_t i = 0; i < fNumUVs; i++) { - vs_src << "attribute vec3 aVtxUVWSrc" << i << ";" << "\n"; - } - vs_src << "\n"; - vs_src << "varying vec3 vVtxNormal;" << "\n"; - vs_src << "varying vec4 vVtxColor;" << "\n"; - for (int32_t i = 0; i < fNumUVs; i++) { - vs_src << "varying vec3 vVtxUVWSrc" << i << ";" << "\n"; - } - vs_src << "\n"; - vs_src << "void main() {" << "\n"; - vs_src << " vVtxNormal = aVtxNormal;" << "\n"; - vs_src << " vVtxColor = aVtxColor.zyxw;" << "\n"; - for (int32_t i = 0; i < fNumUVs; i++) { - vs_src << " vVtxUVWSrc" << i << " = aVtxUVWSrc" << i << ";" << "\n"; - } - vs_src << "\n"; - vs_src << " vec4 pos = uMatrixL2W * vec4(aVtxPosition, 1.0);" << "\n"; - vs_src << " pos = uMatrixW2C * pos;" << "\n"; - vs_src << " pos = uMatrixProj * pos;" << "\n"; - vs_src << "\n"; - vs_src << " gl_Position = pos;" << "\n"; - vs_src << "}"; - - - - ST::string_stream fs_src; - fs_src << "#version 100" << "\n"; - fs_src << "\n"; - for (int32_t i = 0; i < numTextures; i++) { - fs_src << "uniform sampler2D uTexture" << i << ";" << "\n"; - } - fs_src << "\n"; - fs_src << "varying lowp vec3 vVtxNormal;" << "\n"; - fs_src << "varying mediump vec4 vVtxColor;" << "\n"; - for (int32_t i = 0; i < fNumUVs; i++) { - fs_src << "varying mediump vec3 vVtxUVWSrc" << i << ";" << "\n"; - } - fs_src << "\n"; - fs_src << "void main() {" << "\n"; - fs_src << " mediump vec4 color = vVtxColor;" << "\n"; - /*if (numTextures > 0) { - fs_src << " color *= texture2D(uTexture0, vec2(vVtxUVWSrc0.x, vVtxUVWSrc0.y));" << "\n"; - }*/ - - for (int32_t i = 0, tex = 0; i < fMaterial->GetNumLayers(); i++) { - plLayerInterface* layer = fMaterial->GetLayer(i); - if (!layer) - continue; - - if (layer->GetUVWSrc() & (plLayerInterface::kUVWNormal | plLayerInterface::kUVWPosition | plLayerInterface::kUVWReflect)) { - // Now we have a different problem... - continue; - } - - plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); - if (!img) - continue; - - uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; - - fs_src << " color *= texture2D(uTexture" << tex << ", vec2(vVtxUVWSrc" << uv << ".x, vVtxUVWSrc" << uv << ".y));" << "\n"; - tex++; - } - - fs_src << " gl_FragColor = color;" << "\n"; - fs_src << "}"; - - ST::string vtx = vs_src.to_string(); - ST::string frg = fs_src.to_string(); + ST::string vtx = fVertexShader->Render(); + ST::string frg = fFragmentShader->Render(); const char* vs_code = vtx.c_str(); const char* fs_code = frg.c_str(); @@ -342,32 +265,135 @@ void plGLMaterialShaderRef::ICompile() } -bool plGLMaterialShaderRef::ILoopOverLayers() +void plGLMaterialShaderRef::ISetupShaderContexts() +{ + fVertexShader = std::make_shared(kVertex, kShaderVersion); + fFragmentShader = std::make_shared(kFragment, kShaderVersion); + + // Helper function to invert colour + auto invColor = std::make_shared("invColor", "vec3"); + auto argColor = std::make_shared("color", "vec3", 0); + invColor->PushOp(RETURN(SUB(CONSTANT("1.0"), argColor))); + + // Helper function to invert alpha + auto invAlpha = std::make_shared("invAlpha", "float"); + auto argAlpha = std::make_shared("alpha", "float", 0); + invAlpha->PushOp(RETURN(SUB(CONSTANT("1.0"), argAlpha))); + + fFragmentShader->PushFunction(invColor); + fFragmentShader->PushFunction(invAlpha); +} + + +void plGLMaterialShaderRef::ISetShaderVariableLocs() +{ + // Store the attribute locations for later + aVtxPosition = glGetAttribLocation(fRef, "aVtxPosition"); + aVtxNormal = glGetAttribLocation(fRef, "aVtxNormal"); + aVtxColor = glGetAttribLocation(fRef, "aVtxColor"); + + aVtxUVWSrc.assign(16, -1); + for (size_t i = 0; i < 16; i++) { + ST::string name = ST::format("aVtxUVWSrc{}", i); + aVtxUVWSrc[i] = glGetAttribLocation(fRef, name.c_str()); + } + + size_t layerCount = fMaterial->GetNumLayers(); + + uLayerMat.assign(layerCount, -1); + for (size_t i = 0; i < layerCount; i++) { + ST::string name = ST::format("uLayerMat{}", i); + uLayerMat[i] = glGetUniformLocation(fRef, name.c_str()); + } + + uTexture.assign(layerCount, -1); + for (size_t i = 0; i < layerCount; i++) { + ST::string name = ST::format("uTexture{}", i); + uTexture[i] = glGetUniformLocation(fRef, name.c_str()); + } +} + + +void plGLMaterialShaderRef::ICleanupShaderContexts() +{ + fVariables.clear(); + + fVertexShader.reset(); + fFragmentShader.reset(); +} + + +void plGLMaterialShaderRef::ILoopOverLayers() { size_t j = 0; + size_t pass = 1; for (j = 0; j < fMaterial->GetNumLayers(); ) { size_t iCurrMat = j; hsGMatState currState; - j = IHandleMaterial(iCurrMat, currState); + std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "void"); + + j = IHandleMaterial(iCurrMat, currState, fragPass); if (j == -1) break; - fPasses++; + pass++; fPassStates.push_back(currState); + fFragmentShader->PushFunction(fragPass); + #if 0 ISetFogParameters(fMaterial->GetLayer(iCurrMat)); #endif } - return false; + // Build the fragment shader main function with the right passes + std::shared_ptr fragMain = std::make_shared("main", "void"); + if (pass == 2) { + fragMain->PushOp(CALL("pass1")); // Cheat for now + } else { + fragMain->PushOp(CALL("pass2")); // Cheat for now + } + fFragmentShader->PushFunction(fragMain); + + + // Build the vertex shader main function to assign to the varying vars + std::shared_ptr vertMain = std::make_shared("main", "void"); + for (const auto& pair : fVariables) { + if (pair.second->klass == kVarying) { + std::shared_ptr vary = std::static_pointer_cast(pair.second); + + ST::string name = ST::format("a{}", vary->name.substr(1)); + std::shared_ptr attr = std::make_shared(name, vary->type); + + if (name == "aVtxColor") { + // Need to swizzle to color around + vertMain->PushOp(ASSIGN(vary, PROP(attr, "zyxw"))); + } else { + vertMain->PushOp(ASSIGN(vary, attr)); + } + } + } + + // Set the vertex transforms now + std::shared_ptr pos = std::make_shared("pos", "vec4"); + std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); + std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); + std::shared_ptr mW2C = IFindVariable("uMatrixW2C", "mat4"); + std::shared_ptr mProj = IFindVariable("uMatrixProj", "mat4"); + + vertMain->PushOp(ASSIGN(pos, MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))); + vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); + vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); + vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); + + fVertexShader->PushFunction(vertMain); } -uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& state) +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& state, std::shared_ptr fn) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) return -1; @@ -439,6 +465,49 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& sta //ISetBumpMatrices(currLay); } + ShaderBuilder sb; + sb.fFunction = fn; + sb.fIteration = 0; + + IBuildBaseAlpha(currLay, &sb); + + for (int32_t i = 0; i < currNumLayers; i++) { + sb.fIteration = i; + sb.fCurrColor.reset(); + sb.fCurrAlpha.reset(); + sb.fCurrCoord.reset(); + sb.fCurrImage.reset(); + + plLayerInterface* layPtr = fMaterial->GetLayer(layer + i); + if (!layPtr) + return -1; + + IBuildLayerTransform(layer + i, layPtr, &sb); + IBuildLayerTexture(layer + i, layPtr, &sb); + IBuildLayerBlend(layPtr, &sb); + + sb.fPrevColor = sb.fCurrColor; + sb.fPrevAlpha = sb.fCurrAlpha; + } + + //IHandleTextureMode(layer); + //IHandleShadeMode(layer); + //IHandleZMode(); + //IHandleMiscMode() + //IHandleTextureStage(0, layer); + + // Multiply in the vertex color at the end (but alpha is premultiplied!) + std::shared_ptr vtx_color = IFindVariable("vVtxColor", "vec4"); + std::shared_ptr finalColor; + + if (sb.fCurrColor) { + finalColor = MUL(PROP(vtx_color, "rgb"), sb.fCurrColor, true); + } else { + finalColor = PROP(vtx_color, "rgb"); + } + + sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragColor"), CALL("vec4", finalColor, sb.fCurrAlpha))); + return layer + currNumLayers; } @@ -504,3 +573,412 @@ bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) return true; } + + +void plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb) +{ + // Local variable to store the starting alpha value + std::shared_ptr base = std::make_shared("baseAlpha", "float"); + + std::shared_ptr vtxAlpha = IFindVariable("vVtxColor", "vec4"); + + + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { + // base = 1.0 - vVtxColor.a + sb->fFunction->PushOp(ASSIGN(base, CALL("invAlpha", PROP(vtxAlpha, "a")))); + } else { + // base = vVtxColor.a + sb->fFunction->PushOp(ASSIGN(base, PROP(vtxAlpha, "a"))); + } + + sb->fPrevAlpha = base; +} + + +void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) +{ + std::shared_ptr matrix; + +#if 0 + if (layer->GetMiscFlags() & (hsGMatState::kMiscUseReflectionXform | hsGMatState::kMiscUseRefractionXform)) { + } else if (layer->GetMiscFlags() & hsGMatState::kMiscCam2Screen) { + } else if (layer->GetMiscFlags() & hsGMatState::kMiscProjection) { + ST::string matName = ST::format("uLayerMat{}", idx); + std::shared_ptr layMat = IFindVariable(matName, "mat4"); + } else if (layer->GetMiscFlags() & hsGMatState::kMiscBumpChans) { + } else +#endif + { + ST::string matName = ST::format("uLayerMat{}", idx); + matrix = IFindVariable(matName, "mat4"); + } + + uint32_t uvwSrc = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; + + ST::string uvwName = ST::format("vVtxUVWSrc{}", uvwSrc); + std::shared_ptr layUVW = IFindVariable(uvwName, "vec3"); + + // Local variable to store the mesh uvw * layer matrix + ST::string coordName = ST::format("coords{}", idx); + std::shared_ptr coords = std::make_shared(coordName, "vec4"); + + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", layUVW, CONSTANT("1.0"))))); + + sb->fCurrCoord = coords; +} + + +void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) +{ + plBitmap* texture = layer->GetTexture(); + + if (texture != nullptr && sb->fCurrCoord) { + plMipmap* mip; + plCubicEnvironmap* cube; + + // Local variable to store the mesh uvw * layer matrix + ST::string imgName = ST::format("image{}", idx); + std::shared_ptr img = std::make_shared(imgName, "vec4"); + + sb->fCurrImage = img; + + if ((mip = plMipmap::ConvertNoRef(texture)) != nullptr) { + ST::string samplerName = ST::format("uTexture{}", idx); + std::shared_ptr sampler = IFindVariable(samplerName, "sampler2D"); + + // image = texture2D(sampler, coords.xy) + sb->fFunction->PushOp(ASSIGN(img, CALL("texture2D", sampler, PROP(sb->fCurrCoord, "xy")))); + } + +#if 0 + if ((cube = plCubicEnvironmap::ConvertNoRef(texture)) != nullptr) { + ST::string samplerName = ST::format("uTexture{}", idx); + std::shared_ptr sampler = IFindVariable(samplerName, "sampler3D"); + + // image = texture3D(sampler, coords.xyz) + sb->fFunction->PushOp(ASSIGN(img, CALL("texture3D", sampler, PROP(sb->fCurrCoord, "xyz")))); + } +#endif + } +} + + +void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb) +{ + if (!sb->fCurrImage) { + hsStatusMessage("Got a layer with no image"); + sb->fCurrColor = sb->fPrevColor; + sb->fCurrAlpha = sb->fPrevAlpha; + return; + } + + // Local variable to store the color value + ST::string colName = ST::format("color{}", sb->fIteration); + std::shared_ptr col = std::make_shared(colName, "vec3"); + + // Local variable to store the alpha value + ST::string alphaName = ST::format("alpha{}", sb->fIteration); + std::shared_ptr alpha = std::make_shared(alphaName, "float"); + + std::shared_ptr texCol; + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertColor) { + // color = 1.0 - texture.rgb + texCol = CALL("invColor", PROP(sb->fCurrImage, "rgb")); + } else { + // color = texture.rgb + texCol = PROP(sb->fCurrImage, "rgb"); + } + + + if (sb->fIteration == 0) { + // Leave fCurrColor null if we are blending without texture color + if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { + sb->fCurrColor = sb->fPrevColor; + } else { + sb->fFunction->PushOp(ASSIGN(col, texCol)); + sb->fCurrColor = col; + } + + std::shared_ptr alphaVal; + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + // 1.0 - texture.a + alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); + } else { + // texture.a + alphaVal = PROP(sb->fCurrImage, "a"); + } + + + if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha) { + // Only use texture alpha + sb->fFunction->PushOp(ASSIGN(alpha, alphaVal)); + + sb->fCurrAlpha = alpha; + } else if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) { + // Only use vertex alpha (prev alpha) + sb->fCurrAlpha = sb->fPrevAlpha; + } else { + // Vertex alpha * base texture alpha + sb->fFunction->PushOp(ASSIGN(alpha, MUL(alphaVal, sb->fPrevAlpha))); + sb->fCurrAlpha = alpha; + } + } else { + switch (layer->GetBlendFlags() & hsGMatState::kBlendMask) + { + + case hsGMatState::kBlendAddColorTimesAlpha: + hsAssert(false, "Blend mode unsupported on upper layers"); + break; + + case hsGMatState::kBlendAlpha: + { + if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { + // color = prev + sb->fCurrColor = sb->fPrevColor; + } else { + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + // color = texture.rgb + (texture.a * prev) + sb->fFunction->PushOp(ASSIGN(col, ADD(texCol, MUL(PROP(sb->fCurrImage, "a"), sb->fPrevColor, true)))); + sb->fCurrColor = col; + } else { + // color = mix(prev, texture.rgb, texture.a) + sb->fFunction->PushOp(ASSIGN(col, CALL("mix", sb->fPrevColor, texCol, PROP(sb->fCurrImage, "a")))); + sb->fCurrColor = col; + } + } + + + std::shared_ptr alphaVal; + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + // 1.0 - texture.a + alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); + } else { + // texture.a + alphaVal = PROP(sb->fCurrImage, "a"); + } + + if (layer->GetBlendFlags() & hsGMatState::kBlendAlphaAdd) { + // alpha = alphaVal + prev + sb->fFunction->PushOp(ASSIGN(alpha, ADD(alphaVal, sb->fPrevAlpha))); + sb->fCurrAlpha = alpha; + } else if (layer->GetBlendFlags() & hsGMatState::kBlendAlphaMult) { + // alpha = alphaVal * prev + sb->fFunction->PushOp(ASSIGN(alpha, MUL(alphaVal, sb->fPrevAlpha))); + sb->fCurrAlpha = alpha; + } else { + // alpha = prev + sb->fCurrAlpha = sb->fPrevAlpha; + } + break; + } + + case hsGMatState::kBlendAdd: + { + // color = texture.rgb + prev + sb->fFunction->PushOp(ASSIGN(col, ADD(texCol, sb->fPrevColor))); + sb->fCurrColor = col; + + // alpha = prev + sb->fCurrAlpha = sb->fPrevAlpha; + break; + } + + case hsGMatState::kBlendMult: + { + // color = color * prev + sb->fFunction->PushOp(ASSIGN(col, MUL(texCol, sb->fPrevColor))); + sb->fCurrColor = col; + + // alpha = prev + sb->fCurrAlpha = sb->fPrevAlpha; + break; + } + + case hsGMatState::kBlendDot3: + { + hsStatusMessage("Blend DOT3"); + // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) + // alpha = prev + //break; + } + + case hsGMatState::kBlendAddSigned: + { + hsStatusMessage("Blend AddSigned"); + // color = color + prev - 0.5 + // alpha = prev + //break; + } + + case hsGMatState::kBlendAddSigned2X: + { + hsStatusMessage("Blend AddSigned2X"); + // color = (color + prev - 0.5) << 1 + // alpha = prev + //break; + } + + case 0: + { + // color = texture.rgb + sb->fFunction->PushOp(ASSIGN(col, texCol)); + sb->fCurrColor = col; + + // alpha = texture.a + sb->fFunction->PushOp(ASSIGN(alpha, PROP(sb->fCurrImage, "a"))); + sb->fCurrAlpha = alpha; + break; + } + } + } + +} + + +#if 0 +void plGLMaterialShaderRef::IHandleTextureMode(plLayerInterface* layer) +{ + plBitmap* bitmap = layer->GetTexture(); + + if (bitmap) { + // EnvBumpNext is unused in production -- ignoring for now + + + if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { + // color = null + } else { + if (lay->GetBlendFlags() & hsGMatState::kBlendInvertColor) { + // color = 1.0 - texture.rgb + } else { + // color = texture.rgb + } + } + + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + // alpha1 = 1.0 - texture.a + } else { + // alpha1 = texture.a + } + + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { + // alpha2 = 1.0 - vVtxColor.a + } else { + // alpha2 = vVtxColor.a + } + + if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha) { + // alpha = alpha1 + } else if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) { + // alpha = alpha2 + } else { + // alpha = alpha1 * alpha2 + } + } else if (piggybacks) { + // Plasma says it selects the vertex colours, but actually selects an + // undefined arg2. We're going to assume that's wrong and select the + // vertex colours. + + // color = vVtxColor.rgb + // alpha = vVtxColor.a + } else { + // color = vVtxColor.rgb + if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { + // alpha = 1.0 - vVtxColor.a + } else { + // alpha = vVtxColor.a + } + } +} + +void plGLMaterialShaderRef::IHandleStageBlend(const hsGMatState& state) +{ + const uint32_t blendFlags = state.fBlendFlags; + + if (blendFlags & hsGMatState::kBlendInvertColor) { + // color = 1.0 - texture.rgb + } else { + // color = texture.rgb + } + + // Ignoring the unused kBlendEnvBumpNext + + switch (blendFlags & hsGMatState::kBlendMask) + { + case hsGMatState::kBlendAlpha: + { + if (blendFlags & hsGMatState::kBlendNoTexColor) { + // if (prev) { color = prev } + } else { + if (blendFlags & hsGMatState::kBlendInvertAlpha) { + // color = color.rgb + (texture.a * prev.rgb) + } else { + // color = mix(prev.rgb, color.rgb, texture.a) + } + } + + if (blendFlags & hsGMatState::kBlendAlphaAdd) { + if (blendFlags & hsGMatState::kBlendInvertAlpha) { + // alpha = (1.0 - texture.a) + prev + } else { + // alpha = texture.a + prev + } + } else if (blendFlags & hsGMatState::kBlendAlphaMult) { + if (blendFlags & hsGMatState::kBlendInvertAlpha) { + // alpha = (1.0 - texture.a) * prev + } else { + // alpha = texture.a * prev + } + } else { + // alpha = prev + } + break; + } + + case hsGMatState::kBlendAdd: + { + // color = color + prev + // alpha = prev + break; + } + + case hsGMatState::kBlendMult: + { + // color = color * prev + // alpha = prev + break; + } + + case hsGMatState::kBlendDot3: + { + // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) + // alpha = prev + break; + } + + case hsGMatState::kBlendAddSigned: + { + // color = color + prev - 0.5 + // alpha = prev + break; + } + + case hsGMatState::kBlendAddSigned2X: + { + // color = (color + prev - 0.5) << 1 + // alpha = prev + break; + } + + case hsGMatState::kBlendAddColorTimesAlpha: + hsAssert(false, "Blend mode unsupported on upper layers"); + break; + + case 0: + { + // color = color + // alpha = prev + break; + } + } +} +#endif diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index d06685426b..747dcefdb0 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -44,7 +44,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define _plGLMaterialShaderRef_inc_ #include "plGLDeviceRef.h" +#include "plShaderNode.h" +#include #include #include "hsGMatState.h" @@ -55,46 +57,87 @@ class plLayerInterface; class plGLMaterialShaderRef : public plGLDeviceRef { + typedef std::map> plShaderVarLookup; + + enum { + kShaderVersion = 100 + }; + + struct ShaderBuilder { + std::shared_ptr fFunction; + uint32_t fIteration; + + std::shared_ptr fPrevColor; + std::shared_ptr fPrevAlpha; + + std::shared_ptr fCurrColor; + std::shared_ptr fCurrAlpha; + std::shared_ptr fCurrCoord; + std::shared_ptr fCurrImage; + }; + protected: - hsGMaterial* fMaterial; - plPipeline* fPipeline; - GLuint fVertShaderRef; - GLuint fFragShaderRef; + hsGMaterial* fMaterial; + plPipeline* fPipeline; + GLuint fVertShaderRef; + GLuint fFragShaderRef; - uint32_t fPasses; - std::vector fPassStates; + std::vector fPassStates; - int32_t fNumUVs; + std::shared_ptr fVertexShader; + std::shared_ptr fFragmentShader; + plShaderVarLookup fVariables; public: + // These are named to match the GLSL variable names and are public vars + GLuint aVtxPosition; + GLuint aVtxNormal; + GLuint aVtxColor; + std::vector aVtxUVWSrc; // These are indexed by UV chan + std::vector uLayerMat; // These are indexed by layer + std::vector uTexture; // These are indexed by layer + GLuint uPassNumber; + void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } - plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe) - : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(), fFragShaderRef(), fPasses() - { - ILoopOverLayers(); - - // TODO: Remove - ICompile(); - } - + plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe); virtual ~plGLMaterialShaderRef(); void Release(); void SetupTextureRefs(); - int32_t GetNumUVs() const { return fNumUVs; } - uint32_t GetNumPasses() const { return fPasses; } + uint32_t GetNumPasses() const { return fPassStates.size(); } hsGMatState GetPassState(uint32_t which) const { return fPassStates[which]; } protected: void ICompile(); - bool ILoopOverLayers(); - uint32_t IHandleMaterial(uint32_t layer, hsGMatState& state); + void ISetupShaderContexts(); + void ISetShaderVariableLocs(); + void ICleanupShaderContexts(); + + template + std::shared_ptr IFindVariable(const ST::string& name, const ST::string& type) + { + auto it = fVariables.find(name); + if (it == fVariables.end()) { + std::shared_ptr var = std::make_shared(name, type); + fVariables[name] = var; + return var; + } else { + return std::static_pointer_cast(it->second); + } + } + + void ILoopOverLayers(); + uint32_t IHandleMaterial(uint32_t layer, hsGMatState& state, std::shared_ptr fn); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); + void IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb); + void IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); + void IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); + void IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb); //void IHandleFirstTextureStage(plLayerInterface* layer); //void IHandleFirstStageBlend(const hsGMatState& layerState); }; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 001111b88d..b9b084b4ff 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -619,41 +619,30 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Vertex Buffer stuff */ glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); - GLint posAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxPosition"); - if (posAttrib != -1) { - glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); + if (mRef->aVtxPosition != -1) { + glEnableVertexAttribArray(mRef->aVtxPosition); + glVertexAttribPointer(mRef->aVtxPosition, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); } - GLint norAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxNormal"); - if (norAttrib != -1) { - glEnableVertexAttribArray(norAttrib); - glVertexAttribPointer(norAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); + if (mRef->aVtxNormal != -1) { + glEnableVertexAttribArray(mRef->aVtxNormal); + glVertexAttribPointer(mRef->aVtxNormal, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); } - GLint colAttrib = glGetAttribLocation(fDevice.fCurrentProgram, "aVtxColor"); - if (colAttrib != -1) { - glEnableVertexAttribArray(colAttrib); - glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); + if (mRef->aVtxColor != -1) { + glEnableVertexAttribArray(mRef->aVtxColor); + glVertexAttribPointer(mRef->aVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); } - LOG_GL_ERROR_CHECK("Vertex Attributes failed") - - for (int i = 0; i < mRef->GetNumUVs(); i++) { - ST::string name = ST::format("aVtxUVWSrc{}", i); - - GLint uvwAttrib = glGetAttribLocation(fDevice.fCurrentProgram, name.c_str()); - if (uvwAttrib != -1) { - glEnableVertexAttribArray(uvwAttrib); - glVertexAttribPointer(uvwAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); + int numUVs = vRef->fOwner->GetNumUVs(); + for (int i = 0; i < numUVs; i++) { + if (mRef->aVtxUVWSrc[i] != -1) { + glEnableVertexAttribArray(mRef->aVtxUVWSrc[i]); + glVertexAttribPointer(mRef->aVtxUVWSrc[i], 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); } - - LOG_GL_ERROR_CHECK("UVW Attributes failed") } - glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); - glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); - + LOG_GL_ERROR_CHECK("Vertex Attributes failed") /* Index Buffer stuff and drawing */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); @@ -669,6 +658,12 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, IHandleZMode(s); IHandleBlendMode(s); + if (s.fMiscFlags & hsGMatState::kMiscTwoSided) { + glDisable(GL_CULL_FACE); + } else { + glEnable(GL_CULL_FACE); + } + // TEMP render.RenderPrims(); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp new file mode 100644 index 0000000000..6da93179ed --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -0,0 +1,241 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plShaderNode.h" +#include + +using namespace std; + +bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr b) +{ + return a->pos < b->pos; +} + +ST::string plShaderContext::RenderNode(std::shared_ptr node, std::shared_ptr fn) +{ + switch (node->klass) + { + case kConstant: + { + std::shared_ptr c = static_pointer_cast(node); + + return c->value; + } + break; + + case kAttribute: + { + std::shared_ptr attr = static_pointer_cast(node); + + this->attributes.insert(attr); + + return attr->name; + } + break; + + case kUniform: + { + std::shared_ptr uni = static_pointer_cast(node); + + this->uniforms.insert(uni); + + return uni->name; + } + break; + + case kVarying: + { + std::shared_ptr var = static_pointer_cast(node); + + this->varyings.insert(var); + + return var->name; + } + break; + + case kTempVar: + { + std::shared_ptr tmp = static_pointer_cast(node); + + fn->temps.insert(tmp); + + return tmp->name; + } + break; + + case kArgument: + { + std::shared_ptr arg = static_pointer_cast(node); + + fn->args.insert(arg); + + return arg->name; + } + break; + + case kOutput: + { + std::shared_ptr out = static_pointer_cast(node); + + return out->name; + } + break; + + case kOperator: + { + std::shared_ptr op = static_pointer_cast(node); + + if (op->op == ".") { + return ST::format("{}{}{}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + } else if (op->parens) { + return ST::format("({} {} {})", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + } else { + return ST::format("{} {} {}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + } + } + break; + + case kAssignment: + { + std::shared_ptr asn = static_pointer_cast(node); + + return ST::format("{} = {}", this->RenderNode(asn->lhs, fn), this->RenderNode(asn->rhs, fn)); + } + break; + + case kReturn: + { + std::shared_ptr ret = static_pointer_cast(node); + + return ST::format("return {}", this->RenderNode(ret->var, fn)); + } + break; + + case kFnCall: + { + std::shared_ptr call = static_pointer_cast(node); + + std::vector params; + + for (std::shared_ptr arg : call->args) { + params.push_back(this->RenderNode(arg, fn)); + } + + ST::string_stream out; + out << call->function << "("; + + for (size_t i = 0; i < call->args.size(); i++) { + if (i > 0) { + out << ", "; + } + out << params[i]; + } + out << ")"; + + return out.to_string(); + } + break; + + default: + return ""; + } +} + +ST::string plShaderContext::Render() +{ + std::vector lines; + + for (std::shared_ptr fn : this->funcs) { + for (std::shared_ptr node : fn->nodes) { + fn->output.push_back(this->RenderNode(node, fn)); + } + } + + + ST::string_stream out; + + out << ST::format("#version {}\n", this->version); + + if (this->type == kFragment) + out << "precision mediump float;\n"; + + for (std::shared_ptr node : this->attributes) + out << ST::format("attribute {} {};\n", node->type, node->name); + + for (std::shared_ptr node : this->uniforms) + out << ST::format("uniform {} {};\n", node->type, node->name); + + for (std::shared_ptr node : this->varyings) + out << ST::format("varying {} {};\n", node->type, node->name); + + + for (std::shared_ptr fn : this->funcs) { + out << ST::format("\n{} {}(", fn->type, fn->name); + + size_t i = 0; + for (std::shared_ptr arg : fn->args) { + if (i > 0) + out << ", "; + + out << ST::format("{} {}", arg->type, arg->name); + i++; + } + + out << ") {\n"; + + + for (std::shared_ptr node : fn->temps) + out << "\t" << ST::format("{} {};\n", node->type, node->name); + + + if (fn->temps.size()) + out << "\n"; + + + for (ST::string ln : fn->output) + out << "\t" << ln << ";\n"; + + out << "}\n"; + } + + return out.to_string(); +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h new file mode 100644 index 0000000000..52585db398 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -0,0 +1,281 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#ifndef _plShaderNode_h_ +#define _plShaderNode_h_ + +#include +#include +#include +#include +#include + +enum NodeType { + kInvalid, + + kConstant, + kOutput, + kOperator, + kReturn, + kAssignment, + kAttribute, + kVarying, + kUniform, + kTempVar, + kArgument, + kFnCall +}; + + +class plShaderNode : public std::enable_shared_from_this { +public: + NodeType klass; + + plShaderNode(NodeType klass) + : klass(klass) { } +}; + + +class plConstantNode : public plShaderNode { +public: + ST::string value; + + plConstantNode(ST::string value) + : plShaderNode(kConstant), + value(value) { } +}; + + +class plOutputNode : public plShaderNode { +public: + ST::string name; + + plOutputNode(ST::string name) + : plShaderNode(kOutput), + name(name) { } +}; + + +// ABSTRACT +class plVariableNode : public plShaderNode { +public: + ST::string name; + ST::string type; + + plVariableNode(NodeType klass, ST::string name, ST::string type) + : plShaderNode(klass), + name(name), + type(type) { } +}; + + +// ABSTRACT +class plGlobalVariableNode : public plVariableNode { +public: + plGlobalVariableNode(NodeType klass, ST::string name, ST::string type) + : plVariableNode(klass, name, type) { } +}; + + +class plAttributeNode : public plGlobalVariableNode { +public: + plAttributeNode(ST::string name, ST::string type) + : plGlobalVariableNode(kAttribute, name, type) { } +}; + +class plUniformNode : public plGlobalVariableNode { +public: + plUniformNode(ST::string name, ST::string type) + : plGlobalVariableNode(kUniform, name, type) { } +}; + +class plVaryingNode : public plGlobalVariableNode { +public: + plVaryingNode(ST::string name, ST::string type) + : plGlobalVariableNode(kVarying, name, type) { } +}; + + +class plTempVariableNode : public plVariableNode { +public: + plTempVariableNode(ST::string name, ST::string type) + : plVariableNode(kTempVar, name, type) { } +}; + +class plArgumentNode : public plVariableNode { +public: + int pos; + + plArgumentNode(ST::string name, ST::string type, int pos) + : plVariableNode(kArgument, name, type), + pos(pos) { } +}; + + +// ABSTRACT +class plOperationNode : public plShaderNode { +public: + std::shared_ptr lhs; + std::shared_ptr rhs; + + plOperationNode(NodeType klass, std::shared_ptr lhs, std::shared_ptr rhs) + : plShaderNode(klass), + lhs(lhs), + rhs(rhs) { } +}; + + +class plOperatorNode : public plOperationNode { +public: + ST::string op; + bool parens; + + plOperatorNode(ST::string op, std::shared_ptr lhs, std::shared_ptr rhs, bool parens=false) + : plOperationNode(kOperator, lhs, rhs), + op(op), + parens(parens) { } +}; + + +class plAssignmentNode : public plOperationNode { +public: + plAssignmentNode(std::shared_ptr lhs, std::shared_ptr rhs) + : plOperationNode(kAssignment, lhs, rhs) { } +}; + + +class plReturnNode : public plShaderNode { +public: + std::shared_ptr var; + + plReturnNode(std::shared_ptr var) + : plShaderNode(kReturn), + var(var) { } +}; + + +class plCallNode : public plShaderNode { +public: + ST::string function; + std::vector> args; + + plCallNode(ST::string function, std::initializer_list> args) + : plShaderNode(kFnCall), + function(function), + args(args) { } +}; + + +bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr b); + +class plShaderFunction : public std::enable_shared_from_this +{ + + friend class plShaderContext; + + ST::string type; + ST::string name; + + std::vector> nodes; + std::set> temps; + std::set, decltype(&plArgumentNodeSorterFunc)> args; + + std::vector output; + +public: + plShaderFunction(ST::string name, ST::string type) + : name(name), + type(type), + args(plArgumentNodeSorterFunc) { } + + void PushOp(std::shared_ptr op) { + nodes.push_back(op); + } +}; + + + + +enum CtxType { + kVertex, + kFragment +}; + +class plShaderContext : public std::enable_shared_from_this +{ + std::vector> funcs; + CtxType type; + int32_t version; + + std::set> attributes; + std::set> uniforms; + std::set> varyings; + +public: + plShaderContext(CtxType type, int32_t version) : type(type), version(version) { } + + void PushFunction(std::shared_ptr fn) { + funcs.push_back(fn); + } + + ST::string Render(); + +private: + ST::string RenderNode(std::shared_ptr node, std::shared_ptr fn); +}; + + +// Helper Macros +#define CONSTANT(v) std::make_shared(v) +#define OUTPUT(n) std::make_shared(n) +#define ASSIGN(l, r) std::make_shared(l, r) +#define ADD(...) std::make_shared("+", __VA_ARGS__) +#define SUB(...) std::make_shared("-", __VA_ARGS__) +#define MUL(...) std::make_shared("*", __VA_ARGS__) +#define DIV(...) std::make_shared("/", __VA_ARGS__) +#define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) +#define RETURN(n) std::make_shared(n) + +// This one is a bit special because of the initializer_list +#define CALL(fn, ...) std::shared_ptr(new plCallNode(fn, { __VA_ARGS__ })) + +#endif From d0263853aaaa6ac4e1042da482ae6b7fe5f1e408 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Wed, 1 Jul 2015 12:57:39 -0700 Subject: [PATCH 16/76] Slightly hacky fixes for texture blending --- .../FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 454a9d3cb6..9cc37aaaec 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -171,8 +171,10 @@ void plGLMaterialShaderRef::ICompile() glBindTexture(GL_TEXTURE_2D, texRef->fRef); LOG_GL_ERROR_CHECK("Bind Texture failed") - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (!(layer->GetClampFlags() & hsGMatState::kClampTexture)) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, std::max(0, img->GetNumLevels() - 3)); @@ -709,7 +711,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil } - if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha) { + if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha || !sb->fPrevAlpha) { // Only use texture alpha sb->fFunction->PushOp(ASSIGN(alpha, alphaVal)); From 1dd688cfacc52d04ad621fface6b113a7c8275b0 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Wed, 1 Jul 2015 13:35:43 -0700 Subject: [PATCH 17/76] Properly handle multiple passes --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 23 +++++++++++-------- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 ++ .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 8 +++++++ .../FeatureLib/pfGLPipeline/plShaderNode.h | 23 +++++++++++++++---- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 9cc37aaaec..6681813ae5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -294,6 +294,8 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() aVtxNormal = glGetAttribLocation(fRef, "aVtxNormal"); aVtxColor = glGetAttribLocation(fRef, "aVtxColor"); + uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); + aVtxUVWSrc.assign(16, -1); for (size_t i = 0; i < 16; i++) { ST::string name = ST::format("aVtxUVWSrc{}", i); @@ -328,7 +330,12 @@ void plGLMaterialShaderRef::ICleanupShaderContexts() void plGLMaterialShaderRef::ILoopOverLayers() { size_t j = 0; - size_t pass = 1; + size_t pass = 0; + + // Build the fragment shader main function with the right passes + std::shared_ptr fragMain = std::make_shared("main", "void"); + std::shared_ptr uPass = IFindVariable("uPassNumber", "int"); + for (j = 0; j < fMaterial->GetNumLayers(); ) { size_t iCurrMat = j; @@ -341,23 +348,19 @@ void plGLMaterialShaderRef::ILoopOverLayers() if (j == -1) break; + fFragmentShader->PushFunction(fragPass); + + // if (uPassNumber == curpass) { curpass(); } + fragMain->PushOp(COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass))), CALL(fragPass->name))); + pass++; fPassStates.push_back(currState); - fFragmentShader->PushFunction(fragPass); - #if 0 ISetFogParameters(fMaterial->GetLayer(iCurrMat)); #endif } - // Build the fragment shader main function with the right passes - std::shared_ptr fragMain = std::make_shared("main", "void"); - if (pass == 2) { - fragMain->PushOp(CALL("pass1")); // Cheat for now - } else { - fragMain->PushOp(CALL("pass2")); // Cheat for now - } fFragmentShader->PushFunction(fragMain); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index b9b084b4ff..b16f4070cd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -653,6 +653,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, for (uint32_t pass = 0; pass < mRef->GetNumPasses(); pass++) { // Set uniform to pass + if (mRef->uPassNumber != -1) + glUniform1i(mRef->uPassNumber, pass); hsGMatState s = mRef->GetPassState(pass); IHandleZMode(s); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp index 6da93179ed..0ff968466e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -175,6 +175,14 @@ ST::string plShaderContext::RenderNode(std::shared_ptr node, std:: } break; + case kConditional: + { + std::shared_ptr cond = static_pointer_cast(node); + + return ST::format("if ({}) {{ {}; }", this->RenderNode(cond->condition, fn), this->RenderNode(cond->body, fn)); + } + break; + default: return ""; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index 52585db398..b570816bfe 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -62,7 +62,8 @@ enum NodeType { kUniform, kTempVar, kArgument, - kFnCall + kFnCall, + kConditional }; @@ -205,6 +206,18 @@ class plCallNode : public plShaderNode { }; +class plConditionNode : public plShaderNode { +public: + std::shared_ptr condition; + std::shared_ptr body; + + plConditionNode(std::shared_ptr condition, std::shared_ptr body) + : plShaderNode(kConditional), + condition(condition), + body(body) { } +}; + + bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr b); class plShaderFunction : public std::enable_shared_from_this @@ -212,9 +225,6 @@ class plShaderFunction : public std::enable_shared_from_this friend class plShaderContext; - ST::string type; - ST::string name; - std::vector> nodes; std::set> temps; std::set, decltype(&plArgumentNodeSorterFunc)> args; @@ -222,6 +232,9 @@ class plShaderFunction : public std::enable_shared_from_this std::vector output; public: + ST::string type; + ST::string name; + plShaderFunction(ST::string name, ST::string type) : name(name), type(type), @@ -273,7 +286,9 @@ class plShaderContext : public std::enable_shared_from_this #define MUL(...) std::make_shared("*", __VA_ARGS__) #define DIV(...) std::make_shared("/", __VA_ARGS__) #define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) +#define IS_EQ(...) std::make_shared("==", __VA_ARGS__) #define RETURN(n) std::make_shared(n) +#define COND(...) std::make_shared(__VA_ARGS__) // This one is a bit special because of the initializer_list #define CALL(fn, ...) std::shared_ptr(new plCallNode(fn, { __VA_ARGS__ })) From 7f71882368248cfaa8c8ec76e699e9a0188a0943 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 3 Jul 2015 21:54:24 -0700 Subject: [PATCH 18/76] Properly using (some) layer colours Doesn't handle diffuse or specular yet because those are complicated by lighting. --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 72 ++++++--- .../pfGLPipeline/plGLMaterialShaderRef.h | 22 ++- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 137 +++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 + 4 files changed, 205 insertions(+), 27 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 6681813ae5..d10030c614 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -296,6 +296,17 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); + // Material inputs + uGlobalAmbient = glGetUniformLocation(fRef, "uGlobalAmb"); + uMatAmbientCol = glGetUniformLocation(fRef, "uAmbientCol"); + uMatAmbientSrc = glGetUniformLocation(fRef, "uAmbientSrc"); + uMatDiffuseCol = glGetUniformLocation(fRef, "uDiffuseCol"); + uMatDiffuseSrc = glGetUniformLocation(fRef, "uDiffuseSrc"); + uMatEmissiveCol = glGetUniformLocation(fRef, "uEmissiveCol"); + uMatEmissiveSrc = glGetUniformLocation(fRef, "uEmissiveSrc"); + uMatSpecularCol = glGetUniformLocation(fRef, "uSpecularCol"); + uMatSpecularSrc = glGetUniformLocation(fRef, "uSpecularSrc"); + aVtxUVWSrc.assign(16, -1); for (size_t i = 0; i < 16; i++) { ST::string name = ST::format("aVtxUVWSrc{}", i); @@ -339,11 +350,9 @@ void plGLMaterialShaderRef::ILoopOverLayers() for (j = 0; j < fMaterial->GetNumLayers(); ) { size_t iCurrMat = j; - hsGMatState currState; - std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "void"); - j = IHandleMaterial(iCurrMat, currState, fragPass); + j = IHandleMaterial(iCurrMat, fragPass); if (j == -1) break; @@ -354,7 +363,7 @@ void plGLMaterialShaderRef::ILoopOverLayers() fragMain->PushOp(COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass))), CALL(fragPass->name))); pass++; - fPassStates.push_back(currState); + fPassIndices.push_back(iCurrMat); #if 0 ISetFogParameters(fMaterial->GetLayer(iCurrMat)); @@ -398,7 +407,7 @@ void plGLMaterialShaderRef::ILoopOverLayers() } -uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& state, std::shared_ptr fn) +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr fn) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) return -1; @@ -420,7 +429,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& sta //currLay = IPushOverAllLayer(currLay); - state = currLay->GetState(); + hsGMatState state = currLay->GetState(); if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagDisableSpecular)) state.fShadeFlags &= ~hsGMatState::kShadeSpecular; @@ -462,10 +471,6 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& sta uint32_t currNumLayers = ILayersAtOnce(layer); -#if 0 - ICalcLighting(currLay); -#endif - if (state.fMiscFlags & (hsGMatState::kMiscBumpDu | hsGMatState::kMiscBumpDw)) { //ISetBumpMatrices(currLay); } @@ -502,13 +507,12 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, hsGMatState& sta //IHandleTextureStage(0, layer); // Multiply in the vertex color at the end (but alpha is premultiplied!) - std::shared_ptr vtx_color = IFindVariable("vVtxColor", "vec4"); std::shared_ptr finalColor; if (sb.fCurrColor) { - finalColor = MUL(PROP(vtx_color, "rgb"), sb.fCurrColor, true); + finalColor = MUL(PROP(sb.fMatValues, "rgb"), sb.fCurrColor, true); } else { - finalColor = PROP(vtx_color, "rgb"); + finalColor = PROP(sb.fMatValues, "rgb"); } sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragColor"), CALL("vec4", finalColor, sb.fCurrAlpha))); @@ -582,18 +586,48 @@ bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) void plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb) { - // Local variable to store the starting alpha value - std::shared_ptr base = std::make_shared("baseAlpha", "float"); + std::shared_ptr vtxValue = IFindVariable("vVtxColor", "vec4"); + + std::shared_ptr uGlobalAmb = IFindVariable("uGlobalAmb", "vec4"); + std::shared_ptr uAmbientCol = IFindVariable("uAmbientCol", "vec4"); + std::shared_ptr uAmbientSrc = IFindVariable("uAmbientSrc", "float"); + + std::shared_ptr uDiffuseCol = IFindVariable("uDiffuseCol", "vec4"); + std::shared_ptr uDiffuseSrc = IFindVariable("uDiffuseSrc", "float"); - std::shared_ptr vtxAlpha = IFindVariable("vVtxColor", "vec4"); + std::shared_ptr uEmissiveCol = IFindVariable("uEmissiveCol", "vec4"); + std::shared_ptr uEmissiveSrc = IFindVariable("uEmissiveSrc", "float"); + std::shared_ptr uSpecularCol = IFindVariable("uSpecularCol", "vec4"); + std::shared_ptr uSpecularSrc = IFindVariable("uSpecularSrc", "float"); + + // Local vars for the 4 material values + std::shared_ptr diffuse = std::make_shared("diffuse", "vec4"); + std::shared_ptr ambient = std::make_shared("ambient", "vec4"); + std::shared_ptr emissive = std::make_shared("emissive", "vec4"); + std::shared_ptr specular = std::make_shared("specular", "vec4"); + + sb->fFunction->PushOp(ASSIGN(ambient, MUL(uGlobalAmb, CALL("mix", vtxValue, uAmbientCol, uAmbientSrc)))); + sb->fFunction->PushOp(ASSIGN(diffuse, CALL("mix", vtxValue, uDiffuseCol, uDiffuseSrc))); + sb->fFunction->PushOp(ASSIGN(emissive, CALL("mix", vtxValue, uEmissiveCol, uEmissiveSrc))); + sb->fFunction->PushOp(ASSIGN(specular, CALL("mix", vtxValue, uSpecularCol, uSpecularSrc))); + + std::shared_ptr matValues = std::make_shared("material", "vec4"); + + //sb->fFunction->PushOp(ASSIGN(matValues, CALL("clamp", ADD(emissive, ADD(ambient, diffuse)), CONSTANT("0.0"), CONSTANT("1.0")))); + sb->fFunction->PushOp(ASSIGN(matValues, CALL("clamp", ADD(emissive, ambient), CONSTANT("0.0"), CONSTANT("1.0")))); + + sb->fMatValues = matValues; + + // Local variable to store the starting alpha value + std::shared_ptr base = std::make_shared("baseAlpha", "float"); if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { // base = 1.0 - vVtxColor.a - sb->fFunction->PushOp(ASSIGN(base, CALL("invAlpha", PROP(vtxAlpha, "a")))); + sb->fFunction->PushOp(ASSIGN(base, CALL("invAlpha", PROP(diffuse, "a")))); } else { // base = vVtxColor.a - sb->fFunction->PushOp(ASSIGN(base, PROP(vtxAlpha, "a"))); + sb->fFunction->PushOp(ASSIGN(base, PROP(diffuse, "a"))); } sb->fPrevAlpha = base; @@ -661,7 +695,7 @@ void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* l std::shared_ptr sampler = IFindVariable(samplerName, "sampler3D"); // image = texture3D(sampler, coords.xyz) - sb->fFunction->PushOp(ASSIGN(img, CALL("texture3D", sampler, PROP(sb->fCurrCoord, "xyz")))); + sb->fFunction->PushOp(ASSIGN(img, CALL("textureCube", sampler, PROP(sb->fCurrCoord, "xyz")))); } #endif } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 747dcefdb0..4c39413a83 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -67,12 +67,14 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::shared_ptr fFunction; uint32_t fIteration; + std::shared_ptr fMatValues; + std::shared_ptr fPrevColor; std::shared_ptr fPrevAlpha; std::shared_ptr fCurrColor; std::shared_ptr fCurrAlpha; - std::shared_ptr fCurrCoord; + std::shared_ptr fCurrCoord; std::shared_ptr fCurrImage; }; @@ -82,7 +84,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef GLuint fVertShaderRef; GLuint fFragShaderRef; - std::vector fPassStates; + std::vector fPassIndices; std::shared_ptr fVertexShader; std::shared_ptr fFragmentShader; @@ -96,6 +98,15 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::vector aVtxUVWSrc; // These are indexed by UV chan std::vector uLayerMat; // These are indexed by layer std::vector uTexture; // These are indexed by layer + GLuint uGlobalAmbient; + GLuint uMatAmbientCol; + GLuint uMatAmbientSrc; + GLuint uMatDiffuseCol; + GLuint uMatDiffuseSrc; + GLuint uMatEmissiveCol; + GLuint uMatEmissiveSrc; + GLuint uMatSpecularCol; + GLuint uMatSpecularSrc; GLuint uPassNumber; void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } @@ -107,8 +118,9 @@ class plGLMaterialShaderRef : public plGLDeviceRef void Release(); void SetupTextureRefs(); - uint32_t GetNumPasses() const { return fPassStates.size(); } - hsGMatState GetPassState(uint32_t which) const { return fPassStates[which]; } + size_t GetNumPasses() const { return fPassIndices.size(); } + size_t GetPassIndex(size_t which) const { return fPassIndices[which]; } + hsGMaterial* GetMaterial() const { return fMaterial; } protected: void ICompile(); @@ -131,7 +143,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef } void ILoopOverLayers(); - uint32_t IHandleMaterial(uint32_t layer, hsGMatState& state, std::shared_ptr fn); + uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr fn); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); void IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index b16f4070cd..f6c2cf30ad 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -651,16 +651,20 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plProfile_EndTiming(RenderBuff); - for (uint32_t pass = 0; pass < mRef->GetNumPasses(); pass++) { + for (size_t pass = 0; pass < mRef->GetNumPasses(); pass++) { // Set uniform to pass if (mRef->uPassNumber != -1) glUniform1i(mRef->uPassNumber, pass); - hsGMatState s = mRef->GetPassState(pass); + plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); + + ICalcLighting(mRef, lay, &span); + + hsGMatState s = lay->GetState(); IHandleZMode(s); IHandleBlendMode(s); - if (s.fMiscFlags & hsGMatState::kMiscTwoSided) { + if (lay->GetMiscFlags() & hsGMatState::kMiscTwoSided) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); @@ -792,3 +796,130 @@ void plGLPipeline::IHandleBlendMode(hsGMatState flags) } } } + + +void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan) +{ + //plProfile_Inc(MatLightState); + + GLint e; + + if (IsDebugFlagSet(plPipeDbg::kFlagAllBright)) { + glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); + + glUniform4f(mRef->uMatAmbientCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatDiffuseCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatEmissiveCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatSpecularCol, 1.0, 1.0, 1.0, 1.0); + + glUniform1f(mRef->uMatAmbientSrc, 1.0); + glUniform1f(mRef->uMatDiffuseSrc, 1.0); + glUniform1f(mRef->uMatEmissiveSrc, 1.0); + glUniform1f(mRef->uMatSpecularSrc, 1.0); + + return; + } + + hsGMatState state = currLayer->GetState(); + uint32_t mode = (currSpan != nullptr) ? (currSpan->fProps & plSpan::kLiteMask) : plSpan::kLiteMaterial; + + if (state.fMiscFlags & hsGMatState::kMiscBumpChans) { + mode = plSpan::kLiteMaterial; + state.fShadeFlags |= hsGMatState::kShadeNoShade | hsGMatState::kShadeWhite; + } + + /// Select one of our three lighting methods + switch (mode) { + case plSpan::kLiteMaterial: // Material shading + { + if (state.fShadeFlags & hsGMatState::kShadeWhite) { + glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatAmbientCol, 1.0, 1.0, 1.0, 1.0); + } else if (IsDebugFlagSet(plPipeDbg::kFlagNoPreShade)) { + glUniform4f(mRef->uGlobalAmbient, 0.0, 0.0, 0.0, 1.0); + glUniform4f(mRef->uMatAmbientCol, 0.0, 0.0, 0.0, 1.0); + } else { + hsColorRGBA amb = currLayer->GetPreshadeColor(); + glUniform4f(mRef->uGlobalAmbient, amb.r, amb.g, amb.b, 1.0); + glUniform4f(mRef->uMatAmbientCol, amb.r, amb.g, amb.b, 1.0); + } + + hsColorRGBA dif = currLayer->GetRuntimeColor(); + glUniform4f(mRef->uMatDiffuseCol, dif.r, dif.g, dif.b, currLayer->GetOpacity()); + + hsColorRGBA em = currLayer->GetAmbientColor(); + glUniform4f(mRef->uMatEmissiveCol, em.r, em.g, em.b, 1.0); + + // Set specular properties + if (state.fShadeFlags & hsGMatState::kShadeSpecular) { + hsColorRGBA spec = currLayer->GetSpecularColor(); + glUniform4f(mRef->uMatSpecularCol, spec.r, spec.g, spec.b, 1.0); +#if 0 + mat.Power = currLayer->GetSpecularPower(); +#endif + } else { + glUniform4f(mRef->uMatSpecularCol, 0.0, 0.0, 0.0, 0.0); + } + + glUniform1f(mRef->uMatDiffuseSrc, 1.0); + glUniform1f(mRef->uMatEmissiveSrc, 1.0); + glUniform1f(mRef->uMatSpecularSrc, 1.0); + + if (state.fShadeFlags & hsGMatState::kShadeNoShade) { + glUniform1f(mRef->uMatAmbientSrc, 1.0); + } else { + glUniform1f(mRef->uMatAmbientSrc, 0.0); + } + + break; + } + + case plSpan::kLiteVtxPreshaded: // Vtx preshaded + { + glUniform4f(mRef->uGlobalAmbient, 0.0, 0.0, 0.0, 0.0); + glUniform4f(mRef->uMatAmbientCol, 0.0, 0.0, 0.0, 0.0); + glUniform4f(mRef->uMatDiffuseCol, 0.0, 0.0, 0.0, 0.0); + glUniform4f(mRef->uMatEmissiveCol, 0.0, 0.0, 0.0, 0.0); + glUniform4f(mRef->uMatSpecularCol, 0.0, 0.0, 0.0, 0.0); + + glUniform1f(mRef->uMatDiffuseSrc, 0.0); + glUniform1f(mRef->uMatAmbientSrc, 1.0); + glUniform1f(mRef->uMatSpecularSrc, 1.0); + + if (state.fShadeFlags & hsGMatState::kShadeEmissive) + glUniform1f(mRef->uMatEmissiveSrc, 0.0); + else + glUniform1f(mRef->uMatEmissiveSrc, 1.0); + break; + } + + case plSpan::kLiteVtxNonPreshaded: // Vtx non-preshaded + { + glUniform4f(mRef->uMatAmbientCol, 0.0, 0.0, 0.0, 0.0); + glUniform4f(mRef->uMatDiffuseCol, 0.0, 0.0, 0.0, 0.0); + + hsColorRGBA em = currLayer->GetAmbientColor(); + glUniform4f(mRef->uMatEmissiveCol, em.r, em.g, em.b, 1.0); + + // Set specular properties + if (state.fShadeFlags & hsGMatState::kShadeSpecular) { + hsColorRGBA spec = currLayer->GetSpecularColor(); + glUniform4f(mRef->uMatSpecularCol, spec.r, spec.g, spec.b, 1.0); +#if 0 + mat.Power = currLayer->GetSpecularPower(); +#endif + } else { + glUniform4f(mRef->uMatSpecularCol, 0.0, 0.0, 0.0, 0.0); + } + + hsColorRGBA amb = currLayer->GetPreshadeColor(); + glUniform4f(mRef->uGlobalAmbient, amb.r, amb.g, amb.b, amb.a); + + glUniform1f(mRef->uMatAmbientSrc, 0.0); + glUniform1f(mRef->uMatDiffuseSrc, 0.0); + glUniform1f(mRef->uMatEmissiveSrc, 1.0); + glUniform1f(mRef->uMatSpecularSrc, 1.0); + break; + } + } +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 7f7657cab4..418e3ada5a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -115,6 +115,7 @@ class plGLPipeline : public pl3DPipeline void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, hsGDeviceRef* ib, hsGMaterial* material, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength); void IHandleZMode(hsGMatState flags); void IHandleBlendMode(hsGMatState flags); + void ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); private: static plGLEnumerate enumerator; From 6a3764595d71b7e5ab94b985f16cb4121718f598 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 4 Jul 2015 01:01:27 -0700 Subject: [PATCH 19/76] Hacky temp fix for non-DXT textures --- .../FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index d10030c614..bbd9c29953 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -204,6 +204,16 @@ void plGLMaterialShaderRef::ICompile() } #endif } + } else { + GLenum data_type = GL_UNSIGNED_BYTE; + GLenum data_format = GL_BGRA; + GLenum internal_format = GL_RGBA; + + for (uint8_t i = 0; i < img->GetNumLevels(); i++) { + img->SetCurrLevel(i); + + glTexImage2D(GL_TEXTURE_2D, i, internal_format, img->GetCurrWidth(), img->GetCurrHeight(), 0, data_format, data_type, img->GetCurrLevelPtr()); + } } } From 84b49631efd2715ff315216bbc54827d2c739a8d Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 29 Aug 2015 20:43:04 -0700 Subject: [PATCH 20/76] Move some buffer stuff up to pl3DPipeline --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 5 ++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 61 --------------- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 2 - .../PubUtilLib/plPipeline/pl3DPipeline.h | 78 ++++++++++++++++++- 4 files changed, 81 insertions(+), 65 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 4f86a870d5..2fcf6cd040 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -536,6 +536,11 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* ref->SetDirty(false); } +void plGLDevice::FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) +{ + hsStatusMessage("Trying to fill volatile vertex buffer ref!"); +} + void plGLDevice::SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) { uint32_t numIndices = owner->GetIndexBufferCount(idx); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index f6c2cf30ad..7a3fdfb5f6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -165,67 +165,6 @@ plTextFont* plGLPipeline::MakeTextFont(ST::string face, uint16_t size) return nullptr; } -void plGLPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - // First, do we have a device ref at this index? - typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)owner->GetVertexBufferRef(idx); - - // If not - if (!vRef) { - // Make the blank ref - vRef = new typename DeviceType::VertexBufferRef(); - fDevice.SetupVertexBufferRef(owner, idx, vRef); - } - - if (!vRef->IsLinked()) - vRef->Link(&fVtxBuffRefList); - - // One way or another, we now have a vbufferref[idx] in owner. - // Now, does it need to be (re)filled? - // If the owner is volatile, then we hold off. It might not - // be visible, and we might need to refill it again if we - // have an overrun of our dynamic buffer. - if (!vRef->Volatile()) { - // If it's a static buffer, allocate a vertex buffer for it. - fDevice.CheckStaticVertexBuffer(vRef, owner, idx); - - // Might want to remove this assert, and replace it with a dirty check - // if we have static buffers that change very seldom rather than never. - hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); - } else { - // Make sure we're going to be ready to fill it. - -#if 0 - if (!vRef->fData && (vRef->fFormat != owner->GetVertexFormat())) - { - vRef->fData = new uint8_t[vRef->fCount * vRef->fVertexSize]; - fDevice.FillVolatileVertexBufferRef(vRef, owner, idx); - } -#endif - } -} - -void plGLPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)owner->GetIndexBufferRef(idx); - - if (!iRef) { - // Create one from scratch. - iRef = new typename DeviceType::IndexBufferRef(); - fDevice.SetupIndexBufferRef(owner, idx, iRef); - } - - if (!iRef->IsLinked()) - iRef->Link(&fIdxBuffRefList); - - // Make sure it has all resources created. - fDevice.CheckIndexBuffer(iRef); - - // If it's dirty, refill it. - if (iRef->IsDirty()) - fDevice.FillIndexBufferRef(iRef, owner, idx); -} - bool plGLPipeline::OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) { return false; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 418e3ada5a..53b83e2ef1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -84,8 +84,6 @@ class plGLPipeline : public pl3DPipeline bool PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; bool PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr=nullptr) override; plTextFont* MakeTextFont(ST::string face, uint16_t size) override; - void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) override; bool CloseAccess(plAccessSpan& acc) override; void CheckTextureRef(plLayerInterface* lay) override; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 0d8ff9c708..1881769f9d 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -297,8 +297,19 @@ class pl3DPipeline : public plPipeline //virtual plTextFont* MakeTextFont(ST::string face, uint16_t size) = 0; - //virtual void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) = 0; - //virtual void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) = 0; + + /** + * Make sure the buffer group has a vertex buffer ref and that its data is + * current. + */ + void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; + + /** + * Make sure the buffer group has an index buffer ref and that its data is + * current. + */ + void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; + //virtual bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) = 0; //virtual bool CloseAccess(plAccessSpan& acc) = 0; //virtual void CheckTextureRef(plLayerInterface* lay) = 0; @@ -1020,6 +1031,69 @@ void pl3DPipeline::Draw(plDrawable* d) } +template +void pl3DPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) +{ + // First, do we have a device ref at this index? + typename DeviceType::VertexBufferRef* vRef = static_cast(owner->GetVertexBufferRef(idx)); + + // If not + if (!vRef) { + // Make the blank ref + vRef = new typename DeviceType::VertexBufferRef(); + fDevice.SetupVertexBufferRef(owner, idx, vRef); + } + + if (!vRef->IsLinked()) + vRef->Link(&fVtxBuffRefList); + + // One way or another, we now have a vbufferref[idx] in owner. + // Now, does it need to be (re)filled? + // If the owner is volatile, then we hold off. It might not + // be visible, and we might need to refill it again if we + // have an overrun of our dynamic buffer. + if (!vRef->Volatile()) { + // If it's a static buffer, allocate a vertex buffer for it. + fDevice.CheckStaticVertexBuffer(vRef, owner, idx); + + // Might want to remove this assert, and replace it with a dirty check + // if we have static buffers that change very seldom rather than never. + hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); + } + else + { + // Make sure we're going to be ready to fill it. + if (!vRef->fData && (vRef->fFormat != owner->GetVertexFormat())) { + vRef->fData = new uint8_t[vRef->fCount * vRef->fVertexSize]; + fDevice.FillVolatileVertexBufferRef(vRef, owner, idx); + } + } +} + + +template +void pl3DPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) +{ + typename DeviceType::IndexBufferRef* iRef = static_cast(owner->GetIndexBufferRef(idx)); + + if (!iRef) { + // Create one from scratch. + iRef = new typename DeviceType::IndexBufferRef(); + fDevice.SetupIndexBufferRef(owner, idx, iRef); + } + + if (!iRef->IsLinked()) + iRef->Link(&fIdxBuffRefList); + + // Make sure it has all resources created. + fDevice.CheckIndexBuffer(iRef); + + // If it's dirty, refill it. + if (iRef->IsDirty()) + fDevice.FillIndexBufferRef(iRef, owner, idx); +} + + template void pl3DPipeline::RegisterLight(plLightInfo* liInfo) { From a57a85e4d9505b6a1bf807dbf1bc14de3d425316 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Mon, 6 Jun 2022 23:21:32 -0700 Subject: [PATCH 21/76] DirectX & Metal side of moving the buffer code --- .../FeatureLib/pfDXPipeline/plDXDevice.cpp | 302 ++++++++++++- .../FeatureLib/pfDXPipeline/plDXDevice.h | 27 ++ .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 417 +----------------- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 22 +- .../pfMetalPipeline/plMetalPipeline.cpp | 87 ---- .../pfMetalPipeline/plMetalPipeline.h | 4 - .../PubUtilLib/plPipeline/plNullPipeline.h | 26 +- 7 files changed, 365 insertions(+), 520 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.cpp index 0722bfbb4f..50798c0f90 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.cpp @@ -65,6 +65,32 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define WEAK_ERROR_CHECK( cond ) cond #endif + +/// Macros for getting/setting data in a D3D vertex buffer +template +static inline void inlCopy(uint8_t*& src, uint8_t*& dst) +{ + T* src_ptr = reinterpret_cast(src); + T* dst_ptr = reinterpret_cast(dst); + *dst_ptr = *src_ptr; + src += sizeof(T); + dst += sizeof(T); +} + +static inline void inlCopy(const uint8_t*& src, uint8_t*& dst, size_t sz) +{ + memcpy(dst, src, sz); + src += sz; + dst += sz; +} + +template +static inline void inlSkip(uint8_t*& src) +{ + src += sizeof(T) * N; +} + + static D3DMATRIX d3dIdentityMatrix{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -72,7 +98,6 @@ static D3DMATRIX d3dIdentityMatrix{ 0.0f, 0.0f, 0.0f, 1.0f }; - D3DMATRIX& IMatrix44ToD3DMatrix(D3DMATRIX& dst, const hsMatrix44& src) { if (src.fFlags & hsMatrix44::kIsIdent) { @@ -104,11 +129,8 @@ D3DMATRIX& IMatrix44ToD3DMatrix(D3DMATRIX& dst, const hsMatrix44& src) plDXDevice::plDXDevice() -: fD3DDevice(nullptr), - fD3DMainSurface(nullptr), - fD3DDepthSurface(nullptr), - fD3DBackBuff(nullptr), - fCurrCullMode(D3DCULL_CW) +: fD3DDevice(), fD3DMainSurface(), fD3DDepthSurface(), fD3DBackBuff(), + fCurrCullMode(D3DCULL_CW), fManagedAlloced(), fAllocUnManaged() { } @@ -163,6 +185,257 @@ void plDXDevice::SetViewport() WEAK_ERROR_CHECK(fD3DDevice->SetViewport(&vp)); } +/** + * Calculate the vertex stride from the given format. + */ +static uint32_t GetBufferFormatSize(uint8_t format) +{ + uint32_t size = sizeof(float) * 6 + sizeof(uint32_t) * 2; // Position and normal, and two packed colors + + switch (format & plGBufferGroup::kSkinWeightMask) { + case plGBufferGroup::kSkinNoWeights: + break; + case plGBufferGroup::kSkin1Weight: + size += sizeof(float); + break; + default: + hsAssert(false, "Invalid skin weight value in GetBufferFormatSize()"); + } + + size += sizeof(float) * 3 * plGBufferGroup::CalcNumUVs(format); + + return size; +} + +void plDXDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef) +{ + // Initialize to nullptr, in case something goes wrong. + vRef->fD3DBuffer = nullptr; + + uint8_t format = owner->GetVertexFormat(); + + // All indexed skinning is currently done on CPU, so the source data + // will have indices, but we strip them out for the D3D buffer. + if (format & plGBufferGroup::kSkinIndices) { + format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); + format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... + vRef->SetSkinned(true); + vRef->SetVolatile(true); + } + + uint32_t vertSize = GetBufferFormatSize(format); // vertex stride + uint32_t numVerts = owner->GetVertBufferCount(idx); + + vRef->fDevice = fD3DDevice; + + vRef->fOwner = owner; + vRef->fCount = numVerts; + vRef->fVertexSize = vertSize; + vRef->fFormat = format; + vRef->fRefTime = 0; + + vRef->SetDirty(true); + vRef->SetRebuiltSinceUsed(true); + vRef->fData = nullptr; + + vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); + + vRef->fIndex = idx; + + owner->SetVertexBufferRef(idx, vRef); + hsRefCnt_SafeUnRef(vRef); +} + +void plDXDevice::CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx) +{ + if (fAllocUnManaged) + return; + + hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); + + if (!vRef->fD3DBuffer) { + // Okay, haven't done this one. + DWORD fvfFormat = fPipeline->IGetBufferD3DFormat(vRef->fFormat); + + D3DPOOL poolType = D3DPOOL_MANAGED; + //DWORD usage = D3DUSAGE_WRITEONLY; + DWORD usage = 0; + const int numVerts = vRef->fCount; + const int vertSize = vRef->fVertexSize; + fManagedAlloced = true; + + if (FAILED(fD3DDevice->CreateVertexBuffer(numVerts * vertSize, + usage, + fvfFormat, + poolType, + &vRef->fD3DBuffer, nullptr))) + { + hsAssert(false, "CreateVertexBuffer() call failed!"); + vRef->fD3DBuffer = nullptr; + return; + } + PROFILE_POOL_MEM(poolType, numVerts * vertSize, true, ST_LITERAL("VtxBuff")); + + // Fill in the vertex data. + FillStaticVertexBufferRef(vRef, owner, idx); + + // This is currently a no op, but this would let the buffer know it can + // unload the system memory copy, since we have a managed version now. + owner->PurgeVertBuffer(idx); + } +} + +void plDXDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) +{ + IDirect3DVertexBuffer9* vertexBuff = ref->fD3DBuffer; + + if (!vertexBuff) + // We most likely already warned about this earlier, best to just quietly return now + return; + + const uint32_t vertSize = ref->fVertexSize; + const uint32_t vertStart = group->GetVertBufferStart(idx) * vertSize; + const uint32_t size = group->GetVertBufferEnd(idx) * vertSize - vertStart; + if (!size) + return; + + /// Lock the buffer + uint8_t* ptr; + if (FAILED(vertexBuff->Lock(vertStart, size, (void **)&ptr, group->AreVertsVolatile() ? D3DLOCK_DISCARD : 0))) + hsAssert(false, "Failed to lock vertex buffer for writing"); + + if (ref->fData) { + memcpy(ptr, ref->fData + vertStart, size); + } else { + hsAssert(0 == vertStart, "Offsets on non-interleaved data not supported"); + hsAssert(group->GetVertBufferCount(idx) * vertSize == size, "Trailing dead space on non-interleaved data not supported"); + + const uint32_t vertSmallSize = group->GetVertexLiteStride() - sizeof(hsPoint3) * 2; + uint8_t* srcVPtr = group->GetVertBufferData(idx); + plGBufferColor* const srcCPtr = group->GetColorBufferData(idx); + + const int numCells = group->GetNumCells(idx); + for (int i = 0; i < numCells; i++) { + plGBufferCell *cell = group->GetCell(idx, i); + + if (cell->fColorStart == uint32_t(-1)) { + /// Interleaved, do straight copy + memcpy(ptr, srcVPtr + cell->fVtxStart, cell->fLength * vertSize); + ptr += cell->fLength * vertSize; + } else { + /// Separated, gotta interleave + uint8_t* tempVPtr = srcVPtr + cell->fVtxStart; + plGBufferColor* tempCPtr = srcCPtr + cell->fColorStart; + + for (int j = 0; j < cell->fLength; j++) { + memcpy(ptr, tempVPtr, sizeof(hsPoint3) * 2); + ptr += sizeof(hsPoint3) * 2; + tempVPtr += sizeof(hsPoint3) * 2; + + memcpy(ptr, &tempCPtr->fDiffuse, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + memcpy(ptr, &tempCPtr->fSpecular, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + + memcpy(ptr, tempVPtr, vertSmallSize); + ptr += vertSmallSize; + tempVPtr += vertSmallSize; + tempCPtr++; + } + } + } + } + + /// Unlock and clean up + vertexBuff->Unlock(); + ref->SetRebuiltSinceUsed(true); + ref->SetDirty(false); +} + +void plDXDevice::FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) +{ + uint8_t* dst = ref->fData; + uint8_t* src = group->GetVertBufferData(idx); + + size_t uvChanSize = plGBufferGroup::CalcNumUVs(group->GetVertexFormat()) * sizeof(float) * 3; + uint8_t numWeights = (group->GetVertexFormat() & plGBufferGroup::kSkinWeightMask) >> 4; + + for (uint32_t i = 0; i < ref->fCount; ++i) { + inlCopy(src, dst); // pre-pos + src += numWeights * sizeof(float); // weights + if (group->GetVertexFormat() & plGBufferGroup::kSkinIndices) + inlSkip(src); // indices + inlCopy(src, dst); // pre-normal + inlCopy(src, dst); // diffuse + inlCopy(src, dst); // specular + + // UVWs + memcpy(dst, src, uvChanSize); + src += uvChanSize; + dst += uvChanSize; + } +} + +void plDXDevice::SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) +{ + uint32_t numIndices = owner->GetIndexBufferCount(idx); + iRef->fCount = numIndices; + iRef->fOwner = owner; + iRef->fIndex = idx; + iRef->fRefTime = 0; + + iRef->SetDirty(true); + iRef->SetRebuiltSinceUsed(true); + + owner->SetIndexBufferRef(idx, iRef); + hsRefCnt_SafeUnRef(iRef); + + iRef->SetVolatile(owner->AreIdxVolatile()); +} + +void plDXDevice::CheckIndexBuffer(IndexBufferRef* iRef) +{ + if (!iRef->fD3DBuffer && iRef->fCount) { + D3DPOOL poolType = fAllocUnManaged ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; + DWORD usage = D3DUSAGE_WRITEONLY; + iRef->SetVolatile(false); + if (FAILED(fD3DDevice->CreateIndexBuffer(sizeof(uint16_t) * iRef->fCount, + usage, + D3DFMT_INDEX16, + poolType, + &iRef->fD3DBuffer, nullptr))) + { + hsAssert(false, "CreateIndexBuffer() call failed!"); + iRef->fD3DBuffer = nullptr; + return; + } + PROFILE_POOL_MEM(poolType, sizeof(uint16_t) * iRef->fCount, true, ST_LITERAL("IndexBuff")); + + iRef->fPoolType = poolType; + iRef->SetDirty(true); + iRef->SetRebuiltSinceUsed(true); + } +} + +void plDXDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) +{ + uint32_t startIdx = owner->GetIndexBufferStart(idx); + uint32_t size = (owner->GetIndexBufferEnd(idx) - startIdx) * sizeof(uint16_t); + if (!size) + return; + + DWORD lockFlags = iRef->Volatile() ? D3DLOCK_DISCARD : 0; + uint16_t* destPtr = nullptr; + if (FAILED(iRef->fD3DBuffer->Lock(startIdx * sizeof(uint16_t), size, (void **)&destPtr, lockFlags))) { + hsAssert(false, "Cannot lock index buffer for writing"); + return; + } + + memcpy(destPtr, owner->GetIndexBufferData(idx) + startIdx, size); + + iRef->fD3DBuffer->Unlock(); + iRef->SetDirty(false); +} void plDXDevice::SetProjectionMatrix(const hsMatrix44& src) { @@ -195,3 +468,20 @@ ST::string plDXDevice::GetErrorString() const { return fPipeline->fSettings.fErrorStr; } + +void plDXDevice::BeginAllocUnManaged() +{ + // Flush out all managed resources to make room for unmanaged resources. + fD3DDevice->EvictManagedResources(); + + fManagedAlloced = false; + fAllocUnManaged = true; // we're currently only allocating POOL_DEFAULT +} + +void plDXDevice::EndAllocUnManaged() +{ + fAllocUnManaged = false; + + // Flush the (should be empty) resource manager to reset its internal allocation pool. + fD3DDevice->EvictManagedResources(); +} diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h index f34354760b..310f318761 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h @@ -51,6 +51,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include class plDXPipeline; +class plGBufferGroup; class plRenderTarget; struct IDirect3DDevice9; struct IDirect3DSurface9; @@ -77,6 +78,9 @@ class plDXDevice D3DCULL fCurrCullMode; + bool fManagedAlloced; + bool fAllocUnManaged; + public: plDXDevice(); @@ -94,12 +98,35 @@ class plDXDevice /** Translate our viewport into a D3D viewport. */ void SetViewport(); + /* Device Ref Functions **************************************************/ + void SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef); + void CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx); + void FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx); + void FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx); + + void SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef); + void CheckIndexBuffer(IndexBufferRef* iRef); + void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); ST::string GetErrorString() const; + + /** + * Before allocating anything into POOL_DEFAULT, we must evict managed memory. + * + * See plDXPipeline::LoadResources. + */ + void BeginAllocUnManaged(); + + /** + * Before allocating anything into POOL_DEFAULT, we must evict managed memory. + * + * See plDXPipeline::LoadResources. + */ + void EndAllocUnManaged(); }; #endif diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 17c8930051..12a2656a7f 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -505,9 +505,7 @@ uint32_t plDXPipeline::fVtxUsed(0); uint32_t plDXPipeline::fVtxManaged(0); plDXPipeline::plDXPipeline( hsWinRef hWnd, const hsG3DDeviceModeRecord *devModeRec ) -: pl3DPipeline(devModeRec), - fManagedAlloced(false), - fAllocUnManaged(false) +: pl3DPipeline(devModeRec) { hsAssert(D3DTSS_TCI_PASSTHRU == plLayerInterface::kUVWPassThru, "D3D Enum has changed. Notify graphics department."); hsAssert(D3DTSS_TCI_CAMERASPACENORMAL == plLayerInterface::kUVWNormal, "D3D Enum has changed. Notify graphics department."); @@ -1713,8 +1711,8 @@ void plDXPipeline::IReleaseDeviceObjects() fD3DDevice = nullptr; } - fManagedAlloced = false; - fAllocUnManaged = false; + fDevice.fManagedAlloced = false; + fDevice.fAllocUnManaged = false; } // IReleaseDynamicBuffers ///////////////////////////////////////////////// @@ -1807,7 +1805,7 @@ void plDXPipeline::ICreateDynamicBuffers() fVtxRefTime++; DWORD usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; - hsAssert(!fManagedAlloced, "Alloc default with managed alloc'd"); + hsAssert(!fDevice.fManagedAlloced, "Alloc default with managed alloc'd"); D3DPOOL poolType = D3DPOOL_DEFAULT; if( fDynVtxSize ) { @@ -1971,7 +1969,7 @@ bool plDXPipeline::IResetDevice() } fSettings.fCurrFVFFormat = 0; fSettings.fCurrVertexShader = nullptr; - fManagedAlloced = false; + fDevice.fManagedAlloced = false; ICreateDynDeviceObjects(); IInitDeviceState(); @@ -2187,7 +2185,7 @@ void plDXPipeline::Resize( uint32_t width, uint32_t height ) IReleaseDynDeviceObjects(); HRESULT hr = fD3DDevice->Reset(&fSettings.fPresentParams); - fManagedAlloced = false; + fDevice.fManagedAlloced = false; if( !FAILED(hr) ) { ICreateDynDeviceObjects(); @@ -2729,7 +2727,7 @@ bool plDXPipeline::ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* g } if( iRef->IsDirty() ) { - IFillIndexBufferRef(iRef, group, span->fIBufferIdx); + fDevice.FillIndexBufferRef(iRef, group, span->fIBufferIdx); iRef->SetRebuiltSinceUsed(true); } @@ -3463,7 +3461,7 @@ hsGDeviceRef *plDXPipeline::MakeRenderTargetRef( plRenderTarget *owner ) D3DRESOURCETYPE resType; plCubicRenderTarget *cubicRT; - hsAssert(!fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); + hsAssert(!fDevice.fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); // If we have Shader Model 3 and support non-POT textures, let's make reflections the pipe size plDynamicCamMap* camMap = plDynamicCamMap::ConvertNoRef(owner); @@ -3698,7 +3696,7 @@ hsGDeviceRef* plDXPipeline::SharedRenderTargetRef(plRenderTarget* share, plRende if( !share ) return MakeRenderTargetRef(owner); - hsAssert(!fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); + hsAssert(!fDevice.fManagedAlloced, "Allocating non-managed resource with managed resources alloc'd"); #ifdef HS_DEBUGGING // Check out the validity of the match. Debug only. @@ -3748,7 +3746,7 @@ hsGDeviceRef* plDXPipeline::SharedRenderTargetRef(plRenderTarget* share, plRende else ref = new plDXRenderTargetRef( surfFormat, 0, owner ); - hsAssert(!fManagedAlloced, "Alloc default with managed alloc'd"); + hsAssert(!fDevice.fManagedAlloced, "Alloc default with managed alloc'd"); if( !FAILED( fD3DDevice->CreateCubeTexture( owner->GetWidth(), 1, D3DUSAGE_RENDERTARGET, surfFormat, D3DPOOL_DEFAULT, (IDirect3DCubeTexture9 **)&cTexture, nullptr))) { @@ -3795,7 +3793,7 @@ hsGDeviceRef* plDXPipeline::SharedRenderTargetRef(plRenderTarget* share, plRende else ref = new plDXRenderTargetRef( surfFormat, 0, owner ); - hsAssert(!fManagedAlloced, "Alloc default with managed alloc'd"); + hsAssert(!fDevice.fManagedAlloced, "Alloc default with managed alloc'd"); if( !FAILED( fD3DDevice->CreateTexture( owner->GetWidth(), owner->GetHeight(), 1, D3DUSAGE_RENDERTARGET, surfFormat, D3DPOOL_DEFAULT, (IDirect3DTexture9 **)&texture, nullptr))) { @@ -7249,7 +7247,7 @@ IDirect3DTexture9 *plDXPipeline::IMakeD3DTexture( plDXTextureRef *ref, D3DFORM { D3DPOOL poolType = D3DPOOL_MANAGED; IDirect3DTexture9 *texPtr; - fManagedAlloced = true; + fDevice.fManagedAlloced = true; if( FAILED( fSettings.fDXError = fD3DDevice->CreateTexture( ref->fMaxWidth, ref->fMaxHeight, ref->fMMLvs, IGetD3DTextureUsage(ref), @@ -7316,7 +7314,7 @@ IDirect3DCubeTexture9 *plDXPipeline::IMakeD3DCubeTexture( plDXTextureRef *ref, { D3DPOOL poolType = D3DPOOL_MANAGED; IDirect3DCubeTexture9 *texPtr = nullptr; - fManagedAlloced = true; + fDevice.fManagedAlloced = true; WEAK_ERROR_CHECK(fD3DDevice->CreateCubeTexture( ref->fMaxWidth, ref->fMMLvs, 0, formatType, poolType, &texPtr, nullptr)); PROFILE_POOL_MEM(poolType, ref->fDataSize, true, ref->fOwner && ref->fOwner->GetKey() ? ref->fOwner->GetKey()->GetUoid().GetObjectName() : ST_LITERAL("(UnknownTexture)")); fTexManaged += ref->fDataSize; @@ -8046,200 +8044,6 @@ void plDXPipeline::ISetCullMode(bool flip) } } -// ISetupVertexBufferRef ///////////////////////////////////////////////////////// -// Initialize input vertex buffer ref according to source. -void plDXPipeline::ISetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, plDXVertexBufferRef* vRef) -{ - // Initialize to nullptr, in case something goes wrong. - vRef->fD3DBuffer = nullptr; - - uint8_t format = owner->GetVertexFormat(); - - // All indexed skinning is currently done on CPU, so the source data - // will have indices, but we strip them out for the D3D buffer. - if( format & plGBufferGroup::kSkinIndices ) - { - format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); - format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... - vRef->SetSkinned(true); - vRef->SetVolatile(true); - } - - uint32_t vertSize = IGetBufferFormatSize(format); // vertex stride - uint32_t numVerts = owner->GetVertBufferCount(idx); - - vRef->fDevice = fD3DDevice; - - vRef->fOwner = owner; - vRef->fCount = numVerts; - vRef->fVertexSize = vertSize; - vRef->fFormat = format; - vRef->fRefTime = 0; - - vRef->SetDirty(true); - vRef->SetRebuiltSinceUsed(true); - vRef->fData = nullptr; - - vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); - - vRef->fIndex = idx; - - owner->SetVertexBufferRef(idx, vRef); - hsRefCnt_SafeUnRef(vRef); -} - -// ICheckStaticVertexBuffer /////////////////////////////////////////////////////////////////////// -// Ensure a static vertex buffer has any D3D resources necessary for rendering created and filled -// with proper vertex data. -void plDXPipeline::ICheckStaticVertexBuffer(plDXVertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx) -{ - hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); - - if( !vRef->fD3DBuffer ) - { - // Okay, haven't done this one. - - DWORD fvfFormat = IGetBufferD3DFormat(vRef->fFormat); - - - D3DPOOL poolType = D3DPOOL_MANAGED; -// DWORD usage = D3DUSAGE_WRITEONLY; - DWORD usage = 0; - const int numVerts = vRef->fCount; - const int vertSize = vRef->fVertexSize; - fManagedAlloced = true; - if( FAILED( fD3DDevice->CreateVertexBuffer( numVerts * vertSize, - usage, - fvfFormat, - poolType, - &vRef->fD3DBuffer, nullptr))) - { - hsAssert( false, "CreateVertexBuffer() call failed!" ); - vRef->fD3DBuffer = nullptr; - return; - } - PROFILE_POOL_MEM(poolType, numVerts * vertSize, true, ST_LITERAL("VtxBuff")); - - // Record that we've allocated this into managed memory, in case we're - // fighting that NVidia driver bug. Search for OSVERSION for mor info. - AllocManagedVertex(numVerts * vertSize); - - // Fill in the vertex data. - IFillStaticVertexBufferRef(vRef, owner, idx); - - // This is currently a no op, but this would let the buffer know it can - // unload the system memory copy, since we have a managed version now. - owner->PurgeVertBuffer(idx); - } -} - -// IFillStaticVertexBufferRef ////////////////////////////////////////////////// -// BufferRef is set up, just copy the data in. -// This is uglied up hugely by the insane non-interleaved data case with cells -// and whatever else. -void plDXPipeline::IFillStaticVertexBufferRef(plDXVertexBufferRef *ref, plGBufferGroup *group, uint32_t idx) -{ - IDirect3DVertexBuffer9* vertexBuff = ref->fD3DBuffer; - - if( !vertexBuff ) - { - // We most likely already warned about this earlier, best to just quietly return now - return; - } - - const uint32_t vertSize = ref->fVertexSize; - const uint32_t vertStart = group->GetVertBufferStart(idx) * vertSize; - const uint32_t size = group->GetVertBufferEnd(idx) * vertSize - vertStart; - if( !size ) - return; - - /// Lock the buffer - uint8_t* ptr; - if( FAILED( vertexBuff->Lock( vertStart, size, (void **)&ptr, group->AreVertsVolatile() ? D3DLOCK_DISCARD : 0 ) ) ) - { - hsAssert( false, "Failed to lock vertex buffer for writing" ); - } - - if( ref->fData ) - { - memcpy(ptr, ref->fData + vertStart, size); - } - else - { - hsAssert(0 == vertStart, "Offsets on non-interleaved data not supported"); - hsAssert(group->GetVertBufferCount(idx) * vertSize == size, "Trailing dead space on non-interleaved data not supported"); - - const uint32_t vertSmallSize = group->GetVertexLiteStride() - sizeof( hsPoint3 ) * 2; - uint8_t* srcVPtr = group->GetVertBufferData(idx); - plGBufferColor* const srcCPtr = group->GetColorBufferData( idx ); - - const int numCells = group->GetNumCells(idx); - int i; - for( i = 0; i < numCells; i++ ) - { - plGBufferCell *cell = group->GetCell( idx, i ); - - if( cell->fColorStart == (uint32_t)-1 ) - { - /// Interleaved, do straight copy - memcpy( ptr, srcVPtr + cell->fVtxStart, cell->fLength * vertSize ); - ptr += cell->fLength * vertSize; - } - else - { - /// Separated, gotta interleave - uint8_t* tempVPtr = srcVPtr + cell->fVtxStart; - plGBufferColor* tempCPtr = srcCPtr + cell->fColorStart; - int j; - for( j = 0; j < cell->fLength; j++ ) - { - memcpy( ptr, tempVPtr, sizeof( hsPoint3 ) * 2 ); - ptr += sizeof( hsPoint3 ) * 2; - tempVPtr += sizeof( hsPoint3 ) * 2; - - memcpy( ptr, &tempCPtr->fDiffuse, sizeof( uint32_t ) ); - ptr += sizeof( uint32_t ); - memcpy( ptr, &tempCPtr->fSpecular, sizeof( uint32_t ) ); - ptr += sizeof( uint32_t ); - - memcpy( ptr, tempVPtr, vertSmallSize ); - ptr += vertSmallSize; - tempVPtr += vertSmallSize; - tempCPtr++; - } - } - } - } - - /// Unlock and clean up - vertexBuff->Unlock(); - ref->SetRebuiltSinceUsed(true); - ref->SetDirty(false); -} - -void plDXPipeline::IFillVolatileVertexBufferRef(plDXVertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) -{ - uint8_t* dst = ref->fData; - uint8_t* src = group->GetVertBufferData(idx); - - size_t uvChanSize = plGBufferGroup::CalcNumUVs(group->GetVertexFormat()) * sizeof(float) * 3; - uint8_t numWeights = (group->GetVertexFormat() & plGBufferGroup::kSkinWeightMask) >> 4; - - for (uint32_t i = 0; i < ref->fCount; ++i) { - inlCopy(src, dst); // pre-pos - src += numWeights * sizeof(float); // weights - if (group->GetVertexFormat() & plGBufferGroup::kSkinIndices) - inlSkip(src); // indices - inlCopy(src, dst); // pre-normal - inlCopy(src, dst); // diffuse - inlCopy(src, dst); // specular - - // UVWs - memcpy(dst, src, uvChanSize); - src += uvChanSize; - dst += uvChanSize; - } -} // OpenAccess //////////////////////////////////////////////////////////////////////////////////////// // Lock the managed buffer and setup the accessSpan to point into the buffers data. @@ -8352,150 +8156,6 @@ bool plDXPipeline::CloseAccess(plAccessSpan& dst) return true; } -// CheckVertexBufferRef ///////////////////////////////////////////////////// -// Make sure the buffer group has a valid buffer ref and that it is up to date. -void plDXPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - // First, do we have a device ref at this index? - plDXVertexBufferRef* vRef = (plDXVertexBufferRef*)owner->GetVertexBufferRef(idx); - // If not - if( !vRef ) - { - // Make the blank ref - vRef = new plDXVertexBufferRef; - - ISetupVertexBufferRef(owner, idx, vRef); - - } - if( !vRef->IsLinked() ) - vRef->Link( &fVtxBuffRefList ); - - // One way or another, we now have a vbufferref[idx] in owner. - // Now, does it need to be (re)filled? - // If the owner is volatile, then we hold off. It might not - // be visible, and we might need to refill it again if we - // have an overrun of our dynamic D3D buffer. - if( !vRef->Volatile() ) - { - if( fAllocUnManaged ) - return; - - // If it's a static buffer, allocate a D3D vertex buffer for it. Otherwise, it'll - // be sharing the global D3D dynamic buffer, and marked as volatile. - ICheckStaticVertexBuffer(vRef, owner, idx); - - // Might want to remove this assert, and replace it with a dirty check if - // we have static buffers that change very seldom rather than never. - hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); - } - else - { - // Make sure we're going to be ready to fill it. - - if( !vRef->fData && (vRef->fFormat != owner->GetVertexFormat()) ) - { - vRef->fData = new uint8_t[vRef->fCount * vRef->fVertexSize]; - IFillVolatileVertexBufferRef(vRef, owner, idx); - } - } -} - -// CheckIndexBufferRef ///////////////////////////////////////////////////// -// Make sure the buffer group has an index buffer ref and that its data is current. -void plDXPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - plDXIndexBufferRef* iRef = (plDXIndexBufferRef*)owner->GetIndexBufferRef(idx); - if( !iRef ) - { - // Create one from scratch. - - iRef = new plDXIndexBufferRef; - - ISetupIndexBufferRef(owner, idx, iRef); - - } - if( !iRef->IsLinked() ) - iRef->Link(&fIdxBuffRefList); - - // Make sure it has all D3D resources created. - ICheckIndexBuffer(iRef); - - // If it's dirty, refill it. - if( iRef->IsDirty() ) - IFillIndexBufferRef(iRef, owner, idx); -} - -// IFillIndexBufferRef //////////////////////////////////////////////////////////// -// Refresh the D3D index buffer from the plasma index buffer. -void plDXPipeline::IFillIndexBufferRef(plDXIndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) -{ - uint32_t startIdx = owner->GetIndexBufferStart(idx); - uint32_t size = (owner->GetIndexBufferEnd(idx) - startIdx) * sizeof(uint16_t); - if( !size ) - return; - - DWORD lockFlags = iRef->Volatile() ? D3DLOCK_DISCARD : 0; - uint16_t* destPtr = nullptr; - if( FAILED( iRef->fD3DBuffer->Lock(startIdx * sizeof(uint16_t), size, (void **)&destPtr, lockFlags) ) ) - { - hsAssert( false, "Cannot lock index buffer for writing" ); - return; - } - - memcpy( destPtr, owner->GetIndexBufferData(idx) + startIdx, size ); - - iRef->fD3DBuffer->Unlock(); - - iRef->SetDirty( false ); - -} - -// ICheckIndexBuffer //////////////////////////////////////////////////////// -// Make sure index buffer ref has any D3D resources it needs. -void plDXPipeline::ICheckIndexBuffer(plDXIndexBufferRef* iRef) -{ - if( !iRef->fD3DBuffer && iRef->fCount ) - { - D3DPOOL poolType = fAllocUnManaged ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; - DWORD usage = D3DUSAGE_WRITEONLY; - iRef->SetVolatile(false); - if( FAILED( fD3DDevice->CreateIndexBuffer( sizeof( uint16_t ) * iRef->fCount, - usage, - D3DFMT_INDEX16, - poolType, - &iRef->fD3DBuffer, nullptr))) - { - hsAssert( false, "CreateIndexBuffer() call failed!" ); - iRef->fD3DBuffer = nullptr; - return; - } - PROFILE_POOL_MEM(poolType, sizeof(uint16_t) * iRef->fCount, true, ST_LITERAL("IndexBuff")); - - iRef->fPoolType = poolType; - iRef->SetDirty(true); - iRef->SetRebuiltSinceUsed(true); - } -} - -// ISetupIndexBufferRef //////////////////////////////////////////////////////////////// -// Initialize the index buffer ref, but don't create anything for it. -void plDXPipeline::ISetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, plDXIndexBufferRef* iRef) -{ - uint32_t numIndices = owner->GetIndexBufferCount(idx); - iRef->fCount = numIndices; - iRef->fOwner = owner; - iRef->fIndex = idx; - iRef->fRefTime = 0; - - iRef->SetDirty(true); - iRef->SetRebuiltSinceUsed(true); - - owner->SetIndexBufferRef(idx, iRef); - hsRefCnt_SafeUnRef(iRef); - - iRef->SetVolatile(owner->AreIdxVolatile()); -} - //// ISoftwareVertexBlend /////////////////////////////////////////////////////// // Emulate matrix palette operations in software. The big difference between the hardware // and software versions is we only want to lock the vertex buffer once and blend all the @@ -8603,29 +8263,6 @@ bool plDXPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const st return true; } -// IBeginAllocUnmanaged /////////////////////////////////////////////////////////////////// -// Before allocating anything into POOL_DEFAULT, we must evict managed memory. -// See LoadResources. -void plDXPipeline::IBeginAllocUnManaged() -{ - // Flush out all managed resources to make room for unmanaged resources. - fD3DDevice->EvictManagedResources(); - - fManagedAlloced = false; - fAllocUnManaged = true; // we're currently only allocating POOL_DEFAULT -} - -// IEndAllocUnManged. -// Before allocating anything into POOL_DEFAULT, we must evict managed memory. -// See LoadResources. -void plDXPipeline::IEndAllocUnManaged() -{ - fAllocUnManaged = false; - - // Flush the (should be empty) resource manager to reset its internal allocation pool. - fD3DDevice->EvictManagedResources(); -} - // LoadResources /////////////////////////////////////////////////////////////////////// // Basically, we have to load anything that goes into POOL_DEFAULT before // anything into POOL_MANAGED, or the memory manager gets confused. @@ -8645,7 +8282,7 @@ void plDXPipeline::LoadResources() IInitDeviceState(); // 9700 THRASH // Evict mananged memory. - IBeginAllocUnManaged(); + fDevice.BeginAllocUnManaged(); // Release everything we have in POOL_DEFAULT. IReleaseDynamicBuffers(); @@ -8669,7 +8306,7 @@ void plDXPipeline::LoadResources() IFillAvRTPool(); // We should have everything POOL_DEFAULT we need now. - IEndAllocUnManaged(); + fDevice.EndAllocUnManaged(); // Force a create of all our static D3D vertex buffers. #define MF_PRELOAD_MANAGEDBUFFERS @@ -9642,28 +9279,6 @@ long plDXPipeline::IGetBufferD3DFormat( uint8_t format ) const return fmt; } -//// IGetBufferFormatSize ///////////////////////////////////////////////////// -// Calculate the vertex stride from the given format. -uint32_t plDXPipeline::IGetBufferFormatSize( uint8_t format ) const -{ - uint32_t size = sizeof( float ) * 6 + sizeof( uint32_t ) * 2; // Position and normal, and two packed colors - - - switch( format & plGBufferGroup::kSkinWeightMask ) - { - case plGBufferGroup::kSkinNoWeights: - break; - case plGBufferGroup::kSkin1Weight: - size += sizeof(float); - break; - default: - hsAssert( false, "Invalid skin weight value in IGetBufferFormatSize()" ); - } - - size += sizeof( float ) * 3 * plGBufferGroup::CalcNumUVs( format ); - - return size; -} /////////////////////////////////////////////////////////////////////////////// //// Plate and PlateManager Functions ///////////////////////////////////////// @@ -11170,7 +10785,7 @@ bool plDXPipeline::IPopShadowCastState(plShadowSlave* slave) // must be created before we start creating things in POOL_MANAGED. void plDXPipeline::IMakeRenderTargetPools() { - hsAssert(!fManagedAlloced, "Allocating rendertargets with managed resources alloced"); + hsAssert(!fDevice.fManagedAlloced, "Allocating rendertargets with managed resources alloced"); IReleaseRenderTargetPools(); // Just to be sure. // Numbers of render targets to be created for each size. diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index ff9104cdbb..538e3e0c86 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -168,6 +168,8 @@ class plStatusLogDrawer; class plDXPipeline : public pl3DPipeline { + friend class plDXDevice; + protected: enum { kCapsNone = 0x00000000, @@ -208,9 +210,6 @@ class plDXPipeline : public pl3DPipeline uint32_t fNextDynVtx; uint32_t fDynVtxSize; IDirect3DVertexBuffer9* fDynVtxBuff; - bool fManagedAlloced; - bool fAllocUnManaged; - // States plDXGeneralSettings fSettings; @@ -276,19 +275,9 @@ class plDXPipeline : public pl3DPipeline bool fForceDeviceReset; - void IBeginAllocUnManaged(); - void IEndAllocUnManaged(); - bool IRefreshDynVertices(plGBufferGroup* group, plDXVertexBufferRef* vRef); bool ICheckAuxBuffers(const plAuxSpan* span); bool ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* group, const plSpan* span); - void ICheckStaticVertexBuffer(plDXVertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx); - void ICheckIndexBuffer(plDXIndexBufferRef* iRef); - void IFillStaticVertexBufferRef(plDXVertexBufferRef *ref, plGBufferGroup *group, uint32_t idx); - void IFillVolatileVertexBufferRef(plDXVertexBufferRef* ref, plGBufferGroup* group, uint32_t idx); - void IFillIndexBufferRef(plDXIndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); - void ISetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, plDXVertexBufferRef* vRef); - void ISetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, plDXIndexBufferRef* iRef); void ICreateDynamicBuffers(); void IReleaseDynamicBuffers(); @@ -298,7 +287,6 @@ class plDXPipeline : public pl3DPipeline // Rendering bool IFlipSurface(); long IGetBufferD3DFormat(uint8_t format) const; - uint32_t IGetBufferFormatSize(uint8_t format) const; void IGetVisibleSpans(plDrawableSpans* drawable, std::vector& visList, plVisMgr* visMgr); bool ILoopOverLayers(const plRenderPrimFunc& render, hsGMaterial* material, const plSpan& span); void IRenderBufferSpan( const plIcicle& span, @@ -549,10 +537,6 @@ class plDXPipeline : public pl3DPipeline // Create a debug text font object plTextFont* MakeTextFont(ST::string face, uint16_t size) override; - // Create and/or Refresh geometry buffers - void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) override; bool CloseAccess(plAccessSpan& acc) override; @@ -587,7 +571,7 @@ class plDXPipeline : public pl3DPipeline /// Error handling ST::string GetErrorString() override; - bool ManagedAlloced() const { return fManagedAlloced; } + bool ManagedAlloced() const { return fDevice.fManagedAlloced; } virtual void GetSupportedColorDepths(std::vector &ColorDepths); void GetSupportedDisplayModes(std::vector *res, int ColorDepth = 32) override; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index b5c6564eb0..33fe50a9cf 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -4260,93 +4260,6 @@ void plMetalPipeline::IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref) } } -// CheckVertexBufferRef ///////////////////////////////////////////////////// -// Make sure the buffer group has a valid buffer ref and that it is up to date. -void plMetalPipeline::CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - // First, do we have a device ref at this index? - plMetalVertexBufferRef* vRef = static_cast(owner->GetVertexBufferRef(idx)); - - // If not - if (!vRef) { - // Make the blank ref - vRef = new plMetalVertexBufferRef(); - - fDevice.SetupVertexBufferRef(owner, idx, vRef); - } - - if (!vRef->IsLinked()) { - vRef->Link(&fVtxBuffRefList); - } - - // One way or another, we now have a vbufferref[idx] in owner. - // Now, does it need to be (re)filled? - // If the owner is volatile, then we hold off. It might not - // be visible, and we might need to refill it again if we - // have an overrun of our dynamic buffer. - if (!vRef->Volatile()) { - // If it's a static buffer, allocate a vertex buffer for it. - fDevice.CheckStaticVertexBuffer(vRef, owner, idx); - - // Might want to remove this assert, and replace it with a dirty check - // if we have static buffers that change very seldom rather than never. - hsAssert(!vRef->IsDirty(), "Non-volatile vertex buffers should never get dirty"); - } else { - // Make sure we're going to be ready to fill it. - if (!vRef->fData && (vRef->fFormat != owner->GetVertexFormat())) { - vRef->fData = new uint8_t[vRef->fCount * vRef->fVertexSize]; - fDevice.FillVolatileVertexBufferRef(vRef, owner, idx); - } - } -} - -// CheckIndexBufferRef ///////////////////////////////////////////////////// -// Make sure the buffer group has an index buffer ref and that its data is current. -void plMetalPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) -{ - plMetalIndexBufferRef* iRef = static_cast(owner->GetIndexBufferRef(idx)); - - if (!iRef) { - // Create one from scratch. - iRef = new plMetalIndexBufferRef(); - - fDevice.SetupIndexBufferRef(owner, idx, iRef); - } - - if (!iRef->IsLinked()) { - iRef->Link(&fIdxBuffRefList); - } - - // Make sure it has all resources created. - fDevice.CheckIndexBuffer(iRef); - - // If it's dirty, refill it. - if (iRef->IsDirty()) { - fDevice.FillIndexBufferRef(iRef, owner, idx); - } -} - -//// IGetBufferFormatSize ///////////////////////////////////////////////////// -// Calculate the vertex stride from the given format. -uint32_t plMetalPipeline::IGetBufferFormatSize(uint8_t format) const -{ - uint32_t size = sizeof(float) * 6 + sizeof(uint32_t) * 2; // Position and normal, and two packed colors - - switch (format & plGBufferGroup::kSkinWeightMask) { - case plGBufferGroup::kSkinNoWeights: - break; - case plGBufferGroup::kSkin1Weight: - size += sizeof(float); - break; - default: - hsAssert(false, "Invalid skin weight value in IGetBufferFormatSize()"); - } - - size += sizeof(float) * 3 * plGBufferGroup::CalcNumUVs(format); - - return size; -} - void plMetalPipeline::plMetalPipelineCurrentState::Reset() { fCurrentPipelineState = nullptr; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index a9eef17ab3..a181b10775 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -141,15 +141,11 @@ class plMetalPipeline : public pl3DPipeline plMetalDevice* GetMetalDevice() const; // Create and/or Refresh geometry buffers - void CheckVertexBufferRef(plGBufferGroup* owner, uint32_t idx) override; - void CheckIndexBufferRef(plGBufferGroup* owner, uint32_t idx) override; void CheckTextureRef(plLayerInterface* lay) override; void CheckTextureRef(plBitmap* bitmap); hsGDeviceRef* MakeTextureRef(plBitmap* bitmap); void IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref); - uint32_t IGetBufferFormatSize(uint8_t format) const; - plRenderTarget* PopRenderTarget() override; MTL::PixelFormat GetFramebufferFormat() { return fDevice.GetFramebufferFormat(); }; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h index 72c29391c0..176cb687d3 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h @@ -48,14 +48,34 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com class plNullPipelineDevice { + class NullDeviceRef : public hsGDeviceRef + { + public: + void* fData; + uint32_t fCount; + uint32_t fVertexSize; + uint32_t fFormat; + + void Link(NullDeviceRef** back) { } + bool IsLinked() { return true; } + bool Volatile() const { return false; } + }; + public: - typedef void VertexBufferRef; - typedef void IndexBufferRef; - typedef void TextureRef; + typedef NullDeviceRef VertexBufferRef; + typedef NullDeviceRef IndexBufferRef; + typedef NullDeviceRef TextureRef; bool InitDevice() { return true; } void SetRenderTarget(plRenderTarget* target) { } void SetViewport() { } + void SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef) { } + void CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* owner, uint32_t idx) { } + void FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) { } + void FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) { } + void SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) { } + void CheckIndexBuffer(IndexBufferRef* iRef) { } + void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) { } void SetProjectionMatrix(const hsMatrix44& src) { } void SetWorldToCameraMatrix(const hsMatrix44& src) { } void SetLocalToWorldMatrix(const hsMatrix44& src) { } From ac857865d4656809bbb1e782dd753eff2e26429d Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 8 Jan 2016 00:27:44 -0800 Subject: [PATCH 22/76] Refactor the texture loading --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 158 ++++++++++++++++++ .../FeatureLib/pfGLPipeline/plGLDevice.h | 14 +- .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 13 +- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 83 +-------- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 10 +- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 - .../pfMetalPipeline/plMetalDevice.cpp | 6 +- .../pfMetalPipeline/plMetalDevice.h | 6 +- .../pfMetalPipeline/plMetalPipeline.cpp | 17 +- .../pfMetalPipeline/plMetalPipeline.h | 1 - .../PubUtilLib/plPipeline/pl3DPipeline.h | 40 ++++- 11 files changed, 239 insertions(+), 110 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 2fcf6cd040..59f669c202 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -48,6 +48,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLPipeline.h" #include "plDrawable/plGBufferGroup.h" +#include "plGImage/plMipmap.h" +#include "plGImage/plCubicEnvironmap.h" #include "plStatusLog/plStatusLog.h" #pragma region EGL_Init @@ -584,6 +586,162 @@ void plGLDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, iRef->SetDirty(false); } +void plGLDevice::SetupTextureRef(plLayerInterface* layer, plBitmap* img, TextureRef* tRef) +{ + tRef->fOwner = img; + + if (img->IsCompressed()) { + switch (img->fDirectXInfo.fCompressionType) { + case plBitmap::DirectXInfo::kDXT1: + tRef->fFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case plBitmap::DirectXInfo::kDXT5: + tRef->fFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + } + } else { + switch (img->fUncompressedInfo.fType) { + case plBitmap::UncompressedInfo::kRGB8888: + tRef->fFormat = GL_RGBA; + tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataFormat = GL_BGRA; + break; + case plBitmap::UncompressedInfo::kRGB4444: + tRef->fFormat = GL_RGBA; + tRef->fDataType = GL_UNSIGNED_SHORT_4_4_4_4; + tRef->fDataFormat = GL_BGRA; + break; + case plBitmap::UncompressedInfo::kRGB1555: + tRef->fFormat = GL_RGBA; + tRef->fDataType = GL_UNSIGNED_SHORT_5_5_5_1; + tRef->fDataFormat = GL_BGRA; + break; + case plBitmap::UncompressedInfo::kInten8: + tRef->fFormat = GL_LUMINANCE; + tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataFormat = GL_LUMINANCE; + break; + case plBitmap::UncompressedInfo::kAInten88: + tRef->fFormat = GL_LUMINANCE_ALPHA; + tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataFormat = GL_LUMINANCE_ALPHA; + break; + } + } + + tRef->SetDirty(true); + + img->SetDeviceRef(tRef); + hsRefCnt_SafeUnRef(tRef); +} + +void plGLDevice::CheckTexture(TextureRef* tRef) +{ + if (!tRef->fRef) { + glGenTextures(1, &tRef->fRef); + + tRef->SetDirty(true); + } +} + +void plGLDevice::BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping) +{ + GLuint e = GL_NO_ERROR; + + glBindTexture(tRef->fMapping, tRef->fRef); + LOG_GL_ERROR_CHECK("Bind Texture failed"); + + tRef->fLevels = img->GetNumLevels() - 1; + + if (img->IsCompressed()) { + // Hack around the smallest levels being unusable + img->SetCurrLevel(tRef->fLevels); + while ((img->GetCurrWidth() | img->GetCurrHeight()) & 0x03) { + tRef->fLevels--; + hsAssert(tRef->fLevels >= 0, "How was this ever compressed?" ); + img->SetCurrLevel(tRef->fLevels); + } + + for (GLuint lvl = 0; lvl <= tRef->fLevels; lvl++) { + img->SetCurrLevel(lvl); + + glCompressedTexImage2D(mapping, lvl, tRef->fFormat, img->GetCurrWidth(), img->GetCurrHeight(), 0, img->GetCurrLevelSize(), img->GetCurrLevelPtr()); + LOG_GL_ERROR_CHECK(ST::format("Texture Image failed at level {}", lvl)); + } + } else { + for (GLuint lvl = 0; lvl <= tRef->fLevels; lvl++) { + img->SetCurrLevel(lvl); + + glTexImage2D(mapping, lvl, tRef->fFormat, img->GetCurrWidth(), img->GetCurrHeight(), 0, tRef->fDataFormat, tRef->fDataType, img->GetCurrLevelPtr()); + LOG_GL_ERROR_CHECK(ST::format("non-DXT Texture Image failed at level {}", lvl)); + } + } +} + +void plGLDevice::MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img) +{ + tRef->fMapping = GL_TEXTURE_2D; + BindTexture(tRef, img, tRef->fMapping); + + switch(layer->GetClampFlags()) { + case hsGMatState::kClampTextureU: + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case hsGMatState::kClampTextureV: + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + case hsGMatState::kClampTexture: + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + default: + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + glTexParameteri(tRef->fMapping, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (tRef->fLevels) { + glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(tRef->fMapping, GL_TEXTURE_MAX_LEVEL, tRef->fLevels); + } else { + glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + LOG_GL_ERROR_CHECK(ST::format("Mipmap Texture \"{}\" failed", img->GetKeyName())); +} + +void plGLDevice::MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img) +{ + static const GLenum kFaceMapping[] = { + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // kLeftFace + GL_TEXTURE_CUBE_MAP_POSITIVE_X, // kRightFace + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // kFrontFace + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, // kBackFace + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // kTopFace + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y // kBottomFace + }; + + tRef->fMapping = GL_TEXTURE_CUBE_MAP; + + for (size_t i = 0; i < 6; i++) { + BindTexture(tRef, img->GetFace(i), kFaceMapping[i]); + } + + glTexParameteri(tRef->fMapping, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (tRef->fLevels) { + glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(tRef->fMapping, GL_TEXTURE_MAX_LEVEL, tRef->fLevels); + } else { + glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + LOG_GL_ERROR_CHECK(ST::format("Cubic Environ Texture \"{}\" failed", img->GetKeyName())); +} + void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) { hsMatrix2GL(src, fMatrixProj); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index 37e97c1696..d07c60af09 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -47,7 +47,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include +class plBitmap; +class plCubicEnvironmap; class plGLPipeline; +class plLayerInterface; +class plMipmap; class plRenderTarget; class plGLDevice @@ -67,6 +71,7 @@ class plGLDevice public: typedef plGLVertexBufferRef VertexBufferRef; typedef plGLIndexBufferRef IndexBufferRef; + typedef plGLTextureRef TextureRef; protected: ST::string fErrorMsg; @@ -118,14 +123,19 @@ class plGLDevice void SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef); void CheckIndexBuffer(IndexBufferRef* iRef); void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); + void SetupTextureRef(plLayerInterface* layer, plBitmap* img, TextureRef* tRef); + void CheckTexture(TextureRef* tRef); + void MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img); + void MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img); void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); - struct TextureRef; - ST::string GetErrorString() const { return fErrorMsg; } + +private: + void BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping); }; #endif diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index 46f77e0aa6..e6944a335d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -54,7 +54,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com do { \ GLenum e; \ if ((e = glGetError()) != GL_NO_ERROR) { \ - plStatusLog::AddLineSF("pipeline.log", message ": {}", uint32_t(e)); \ + plStatusLog::AddLineSF("pipeline.log", "{}: {}", message, uint32_t(e)); \ } \ } while(0); #else @@ -62,7 +62,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #endif class plGBufferGroup; -class plMipmap; +class plBitmap; class plGLDeviceRef : public hsGDeviceRef { @@ -177,13 +177,18 @@ class plGLIndexBufferRef : public plGLDeviceRef class plGLTextureRef : public plGLDeviceRef { public: - plMipmap* fOwner; + plBitmap* fOwner; + uint32_t fLevels; + GLuint fMapping; + GLuint fFormat; + GLuint fDataType; + GLuint fDataFormat; void Link(plGLTextureRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLTextureRef* GetNext() { return (plGLTextureRef*)fNext; } plGLTextureRef() - : plGLDeviceRef(), fOwner() + : plGLDeviceRef(), fOwner(), fLevels(1), fMapping(), fFormat(), fDataType(), fDataFormat() {} virtual ~plGLTextureRef(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index bbd9c29953..a476f191f6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -107,11 +107,8 @@ void plGLMaterialShaderRef::SetupTextureRefs() continue; // Load the image - plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); - if (!img) - continue; + plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); - GLenum e; plGLTextureRef* texRef = static_cast(img->GetDeviceRef()); if (!texRef->fRef) @@ -122,7 +119,7 @@ void plGLMaterialShaderRef::SetupTextureRefs() glActiveTexture(GL_TEXTURE0 + numTextures); LOG_GL_ERROR_CHECK("Active Texture failed") - glBindTexture(GL_TEXTURE_2D, texRef->fRef); + glBindTexture(texRef->fMapping, texRef->fRef); LOG_GL_ERROR_CHECK("Bind Texture failed") if (this->uLayerMat[i] != -1) { @@ -141,6 +138,8 @@ void plGLMaterialShaderRef::SetupTextureRefs() void plGLMaterialShaderRef::ICompile() { + LOG_GL_ERROR_CHECK("Begin Compile failed") + int32_t numTextures = 0; hsBitVector usedUVWs; @@ -149,72 +148,8 @@ void plGLMaterialShaderRef::ICompile() if (!layer) continue; - // Load the image - plMipmap* img = plMipmap::ConvertNoRef(layer->GetTexture()); - if (!img) - continue; - - uint32_t uv = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; - usedUVWs.SetBit(uv); - - numTextures++; - - plGLTextureRef* texRef = new plGLTextureRef(); - texRef->fOwner = img; - img->SetDeviceRef(texRef); - - GLenum e; - - glGenTextures(1, &texRef->fRef); - LOG_GL_ERROR_CHECK("Gen Texture failed") - - glBindTexture(GL_TEXTURE_2D, texRef->fRef); - LOG_GL_ERROR_CHECK("Bind Texture failed") - - if (!(layer->GetClampFlags() & hsGMatState::kClampTexture)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, std::max(0, img->GetNumLevels() - 3)); - - if (img->IsCompressed()) { - GLuint dxCompression = 0; - uint8_t compType = img->fDirectXInfo.fCompressionType; - - if (compType == plBitmap::DirectXInfo::kDXT1) - dxCompression = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - else if (compType == plBitmap::DirectXInfo::kDXT5) - dxCompression = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - - for (uint8_t i = 0; i < img->GetNumLevels(); i++) { - img->SetCurrLevel(i); - - if (img->GetCurrWidth() < 4 || img->GetCurrHeight() < 4) - continue; - - glCompressedTexImage2D(GL_TEXTURE_2D, i, dxCompression, - img->GetCurrWidth(), img->GetCurrHeight(), - 0, img->GetCurrLevelSize(), img->GetCurrLevelPtr()); - -#ifdef HS_DEBUGGING - if ((e = glGetError()) != GL_NO_ERROR) { - plStatusLog::AddLineSF("pipeline.log", "Texture Image failed: {}, at level {}", uint32_t(e), i); - } -#endif - } - } else { - GLenum data_type = GL_UNSIGNED_BYTE; - GLenum data_format = GL_BGRA; - GLenum internal_format = GL_RGBA; - - for (uint8_t i = 0; i < img->GetNumLevels(); i++) { - img->SetCurrLevel(i); - - glTexImage2D(GL_TEXTURE_2D, i, internal_format, img->GetCurrWidth(), img->GetCurrHeight(), 0, data_format, data_type, img->GetCurrLevelPtr()); - } - } + fPipeline->CheckTextureRef(layer); + LOG_GL_ERROR_CHECK(ST::format("Check Texture Ref on layer \"{}\" failed", layer->GetKeyName())); } ST::string vtx = fVertexShader->Render(); @@ -226,6 +161,7 @@ void plGLMaterialShaderRef::ICompile() fVertShaderRef = glCreateShader(GL_VERTEX_SHADER); glShaderSource(fVertShaderRef, 1, &vs_code, nullptr); glCompileShader(fVertShaderRef); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); #ifdef HS_DEBUGGING { @@ -246,6 +182,7 @@ void plGLMaterialShaderRef::ICompile() fFragShaderRef = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fFragShaderRef, 1, &fs_code, nullptr); glCompileShader(fFragShaderRef); + LOG_GL_ERROR_CHECK("Fragment Shader compile failed"); #ifdef HS_DEBUGGING { @@ -699,15 +636,13 @@ void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* l sb->fFunction->PushOp(ASSIGN(img, CALL("texture2D", sampler, PROP(sb->fCurrCoord, "xy")))); } -#if 0 if ((cube = plCubicEnvironmap::ConvertNoRef(texture)) != nullptr) { ST::string samplerName = ST::format("uTexture{}", idx); - std::shared_ptr sampler = IFindVariable(samplerName, "sampler3D"); + std::shared_ptr sampler = IFindVariable(samplerName, "samplerCube"); // image = texture3D(sampler, coords.xyz) sb->fFunction->PushOp(ASSIGN(img, CALL("textureCube", sampler, PROP(sb->fCurrCoord, "xyz")))); } -#endif } } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 7a3fdfb5f6..395458d3d6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -175,9 +175,6 @@ bool plGLPipeline::CloseAccess(plAccessSpan& acc) return false; } -void plGLPipeline::CheckTextureRef(plLayerInterface* lay) -{} - void plGLPipeline::PushRenderRequest(plRenderRequest* req) { // Save these, since we want to copy them to our current view @@ -428,6 +425,8 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& plProfile_EndTiming(MergeSpan); } + LOG_GL_ERROR_CHECK("RenderSpans pre-material failed"); + if (material != nullptr) { // First, do we have a device ref at this index? plGLMaterialShaderRef* mRef = static_cast(material->GetDeviceRef()); @@ -435,9 +434,6 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& if (mRef == nullptr) { mRef = new plGLMaterialShaderRef(material, this); material->SetDeviceRef(mRef); - - //glUseProgram(mRef->fRef); - //fDevice.fCurrentProgram = mRef->fRef; } if (!mRef->IsLinked()) @@ -445,7 +441,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& glUseProgram(mRef->fRef); fDevice.fCurrentProgram = mRef->fRef; - LOG_GL_ERROR_CHECK("Use Program failed") + LOG_GL_ERROR_CHECK(ST::format("Use Program with material \"{}\" failed", material->GetKeyName())); // TODO: Figure out how to use VAOs properly :( GLuint vao; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 53b83e2ef1..e8a15ef7f6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -86,7 +86,6 @@ class plGLPipeline : public pl3DPipeline plTextFont* MakeTextFont(ST::string face, uint16_t size) override; bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) override; bool CloseAccess(plAccessSpan& acc) override; - void CheckTextureRef(plLayerInterface* lay) override; void PushRenderRequest(plRenderRequest* req) override; void PopRenderRequest(plRenderRequest* req) override; void ClearRenderTarget(plDrawable* d) override; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp index b117fcd5c5..93c2330578 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.cpp @@ -733,7 +733,7 @@ void plMetalDevice::FillIndexBufferRef(plMetalDevice::IndexBufferRef* iRef, plGB iRef->SetDirty(false); } -void plMetalDevice::SetupTextureRef(plBitmap* img, plMetalDevice::TextureRef* tRef) +void plMetalDevice::SetupTextureRef(plLayerInterface* layer, plBitmap* img, plMetalDevice::TextureRef* tRef) { tRef->fOwner = img; @@ -908,7 +908,7 @@ void plMetalDevice::PopulateTexture(plMetalDevice::TextureRef* tRef, plMipmap* i tRef->SetDirty(false); } -void plMetalDevice::MakeTextureRef(plMetalDevice::TextureRef* tRef, plMipmap* img) +void plMetalDevice::MakeTextureRef(plMetalDevice::TextureRef* tRef, plLayerInterface* layer, plMipmap* img) { if (!img->GetImage()) { return; @@ -944,7 +944,7 @@ void plMetalDevice::MakeTextureRef(plMetalDevice::TextureRef* tRef, plMipmap* im tRef->SetDirty(false); } -void plMetalDevice::MakeCubicTextureRef(plMetalDevice::TextureRef* tRef, plCubicEnvironmap* img) +void plMetalDevice::MakeCubicTextureRef(plMetalDevice::TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img) { MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::textureCubeDescriptor(tRef->fFormat, img->GetFace(0)->GetWidth(), tRef->fLevels != 0); diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h index 4aec911ed0..e1e971d6c6 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalDevice.h @@ -136,10 +136,10 @@ class plMetalDevice void CheckIndexBuffer(IndexBufferRef* iRef); void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); - void SetupTextureRef(plBitmap* img, TextureRef* tRef); + void SetupTextureRef(plLayerInterface* layer, plBitmap* img, TextureRef* tRef); void CheckTexture(TextureRef* tRef); - void MakeTextureRef(TextureRef* tRef, plMipmap* img); - void MakeCubicTextureRef(TextureRef* tRef, plCubicEnvironmap* img); + void MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img); + void MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img); ST::string GetErrorString() const { return fErrorMsg; } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 33fe50a9cf..c6c4295853 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -4196,17 +4196,6 @@ void plMetalPipeline::IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, // Resource checking -// CheckTextureRef ////////////////////////////////////////////////////// -// Make sure the given layer's texture has background D3D resources allocated. -void plMetalPipeline::CheckTextureRef(plLayerInterface* layer) -{ - plBitmap* bitmap = layer->GetTexture(); - - if (bitmap) { - CheckTextureRef(bitmap); - } -} - void plMetalPipeline::CheckTextureRef(plBitmap* bitmap) { plMetalTextureRef* tRef = static_cast(bitmap->GetDeviceRef()); @@ -4228,7 +4217,7 @@ hsGDeviceRef* plMetalPipeline::MakeTextureRef(plBitmap* bitmap) if (!tRef) { tRef = new plMetalTextureRef(); - fDevice.SetupTextureRef(bitmap, tRef); + fDevice.SetupTextureRef(nullptr, bitmap, tRef); } if (!tRef->IsLinked()) { @@ -4249,13 +4238,13 @@ void plMetalPipeline::IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref) { plMipmap* mip = plMipmap::ConvertNoRef(bitmap); if (mip) { - fDevice.MakeTextureRef(ref, mip); + fDevice.MakeTextureRef(ref, nullptr, mip); return; } plCubicEnvironmap* cubic = plCubicEnvironmap::ConvertNoRef(bitmap); if (cubic) { - fDevice.MakeCubicTextureRef(ref, cubic); + fDevice.MakeCubicTextureRef(ref, nullptr, cubic); return; } } diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index a181b10775..484a182d9e 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -141,7 +141,6 @@ class plMetalPipeline : public pl3DPipeline plMetalDevice* GetMetalDevice() const; // Create and/or Refresh geometry buffers - void CheckTextureRef(plLayerInterface* lay) override; void CheckTextureRef(plBitmap* bitmap); hsGDeviceRef* MakeTextureRef(plBitmap* bitmap); void IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 1881769f9d..6fb5783f50 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -312,7 +312,8 @@ class pl3DPipeline : public plPipeline //virtual bool OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) = 0; //virtual bool CloseAccess(plAccessSpan& acc) = 0; - //virtual void CheckTextureRef(plLayerInterface* lay) = 0; + + void CheckTextureRef(plLayerInterface* lay) override; void SetDefaultFogEnviron(plFogEnvironment* fog) override { fView.SetDefaultFog(*fog); @@ -922,6 +923,7 @@ pl3DPipeline::pl3DPipeline(const hsG3DDeviceModeRecord* devModeRec) fActivePiggyBacks(), fVtxBuffRefList(), fIdxBuffRefList(), + fTextureRefList(), fCurrMaterial(), fCurrLay(), fCurrNumLayers(), @@ -1093,6 +1095,42 @@ void pl3DPipeline::CheckIndexBufferRef(plGBufferGroup* owner, uint32 fDevice.FillIndexBufferRef(iRef, owner, idx); } +template +void pl3DPipeline::CheckTextureRef(plLayerInterface* layer) +{ + plBitmap* bitmap = layer->GetTexture(); + + if (bitmap) { + typename DeviceType::TextureRef* tRef = static_cast(bitmap->GetDeviceRef()); + + if (!tRef) { + tRef = new typename DeviceType::TextureRef(); + fDevice.SetupTextureRef(layer, bitmap, tRef); + } + + if (!tRef->IsLinked()) + tRef->Link(&fTextureRefList); + + // Make sure it has all resources created. + fDevice.CheckTexture(tRef); + + // If it's dirty, refill it. + if (tRef->IsDirty()) { + plMipmap* mip = plMipmap::ConvertNoRef(bitmap); + if (mip) { + fDevice.MakeTextureRef(tRef, layer, mip); + return; + } + + plCubicEnvironmap* cubic = plCubicEnvironmap::ConvertNoRef(bitmap); + if (cubic) { + fDevice.MakeCubicTextureRef(tRef, layer, cubic); + return; + } + } + } +} + template void pl3DPipeline::RegisterLight(plLightInfo* liInfo) From 5902b6eceb759f2d2e6750b24553377ad6de9711 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 7 Jun 2022 22:37:47 -0700 Subject: [PATCH 23/76] DirectX device stub for the texture stuff The DirectX texture handling is just different enough that it doesn't quite refactor nicely, so I'm just leaving it as-is for now, and I suspect the OpenGL will evolve to be closer to the DX side in complexity further down the line. --- Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h | 7 +++++++ .../Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp | 12 ++++-------- .../Plasma/PubUtilLib/plPipeline/plNullPipeline.h | 4 ++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h index 310f318761..68c86364ac 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXDevice.h @@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsWindows.h" #include +class plCubicEnvironmap; class plDXPipeline; class plGBufferGroup; class plRenderTarget; @@ -108,6 +109,12 @@ class plDXDevice void CheckIndexBuffer(IndexBufferRef* iRef); void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx); + // Texture stuff is all handled in plDXPipeline, not in plDXDevice + void SetupTextureRef(plLayerInterface* layer, plBitmap* img, TextureRef* tRef) {} + void CheckTexture(TextureRef* tRef) {} + void MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img) {} + void MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img) {} + void SetProjectionMatrix(const hsMatrix44& src); void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 12a2656a7f..3eba65eb65 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -5869,22 +5869,18 @@ void plDXPipeline::IHandleTextureStage( uint32_t stage, plLayerInterface *lay void plDXPipeline::CheckTextureRef(plLayerInterface* layer) { plBitmap* bitmap = layer->GetTexture(); - if( bitmap ) - { + if (bitmap) { hsGDeviceRef* ref = bitmap->GetDeviceRef(); - if( !ref ) - { + if (!ref) { plMipmap* mip = plMipmap::ConvertNoRef(bitmap); - if( mip ) - { + if (mip) { MakeTextureRef(layer, mip); return; } plCubicEnvironmap* cubic = plCubicEnvironmap::ConvertNoRef(bitmap); - if( cubic ) - { + if (cubic) { IMakeCubicTextureRef(layer, cubic); return; } diff --git a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h index 176cb687d3..846b2e3edb 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h @@ -76,6 +76,10 @@ class plNullPipelineDevice void SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) { } void CheckIndexBuffer(IndexBufferRef* iRef) { } void FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, uint32_t idx) { } + void SetupTextureRef(plLayerInterface* layer, plBitmap* img, TextureRef* tRef) {} + void CheckTexture(TextureRef* tRef) {} + void MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img) {} + void MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, plCubicEnvironmap* img) {} void SetProjectionMatrix(const hsMatrix44& src) { } void SetWorldToCameraMatrix(const hsMatrix44& src) { } void SetLocalToWorldMatrix(const hsMatrix44& src) { } From 264029d05d53802c52a12c6355b9a02167e39ce7 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Jan 2016 01:24:07 -0800 Subject: [PATCH 24/76] Possibly working Envmaps --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 40 ++--- .../FeatureLib/pfGLPipeline/plGLDevice.h | 1 + .../pfGLPipeline/plGLMaterialShaderRef.cpp | 141 ++++++++++++++++-- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 5 + .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 8 +- .../FeatureLib/pfGLPipeline/plShaderNode.h | 1 + 6 files changed, 161 insertions(+), 35 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 59f669c202..6e38c0d50a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -646,9 +646,6 @@ void plGLDevice::CheckTexture(TextureRef* tRef) void plGLDevice::BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping) { - GLuint e = GL_NO_ERROR; - - glBindTexture(tRef->fMapping, tRef->fRef); LOG_GL_ERROR_CHECK("Bind Texture failed"); tRef->fLevels = img->GetNumLevels() - 1; @@ -681,24 +678,17 @@ void plGLDevice::BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping) void plGLDevice::MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMipmap* img) { tRef->fMapping = GL_TEXTURE_2D; + + if (!img->GetImage()) { + glBindTexture(tRef->fMapping, 0); + return; + } + + glBindTexture(tRef->fMapping, tRef->fRef); BindTexture(tRef, img, tRef->fMapping); - switch(layer->GetClampFlags()) { - case hsGMatState::kClampTextureU: - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); - break; - case hsGMatState::kClampTextureV: - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; - case hsGMatState::kClampTexture: - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; - default: - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (epoxy_gl_version() >= 43) { + glObjectLabel(GL_TEXTURE, tRef->fRef, -1, img->GetKeyName().c_str()); } glTexParameteri(tRef->fMapping, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -725,11 +715,19 @@ void plGLDevice::MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, }; tRef->fMapping = GL_TEXTURE_CUBE_MAP; + glBindTexture(tRef->fMapping, tRef->fRef); for (size_t i = 0; i < 6; i++) { BindTexture(tRef, img->GetFace(i), kFaceMapping[i]); } + if (epoxy_gl_version() >= 43) { + glObjectLabel(GL_TEXTURE, tRef->fRef, -1, img->GetKeyName().c_str()); + } + + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(tRef->fMapping, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(tRef->fMapping, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (tRef->fLevels) { @@ -749,7 +747,11 @@ void plGLDevice::SetProjectionMatrix(const hsMatrix44& src) void plGLDevice::SetWorldToCameraMatrix(const hsMatrix44& src) { + hsMatrix44 inv; + src.GetInverse(&inv); + hsMatrix2GL(src, fMatrixW2C); + hsMatrix2GL(inv, fMatrixC2W); } void plGLDevice::SetLocalToWorldMatrix(const hsMatrix44& src) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index d07c60af09..a459356fee 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -86,6 +86,7 @@ class plGLDevice GLuint fCurrentProgram; GLfloat fMatrixL2W[16]; GLfloat fMatrixW2C[16]; + GLfloat fMatrixC2W[16]; GLfloat fMatrixProj[16]; public: diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index a476f191f6..cbabe83c2c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -120,7 +120,28 @@ void plGLMaterialShaderRef::SetupTextureRefs() LOG_GL_ERROR_CHECK("Active Texture failed") glBindTexture(texRef->fMapping, texRef->fRef); - LOG_GL_ERROR_CHECK("Bind Texture failed") + LOG_GL_ERROR_CHECK("Bind Texture failed"); + + if (texRef->fMapping == GL_TEXTURE_2D) { + // Ewww, but the same texture might be used by multiple layers with different clamping flags :( + switch (layer->GetClampFlags()) { + case hsGMatState::kClampTextureU: + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case hsGMatState::kClampTextureV: + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + case hsGMatState::kClampTexture: + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + default: + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(texRef->fMapping, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + } if (this->uLayerMat[i] != -1) { GLfloat matrix[16]; @@ -326,6 +347,10 @@ void plGLMaterialShaderRef::ILoopOverLayers() if (pair.second->klass == kVarying) { std::shared_ptr vary = std::static_pointer_cast(pair.second); + if (vary->name == "vCamPosition" || vary->name == "vCamNormal") { + continue; + } + ST::string name = ST::format("a{}", vary->name.substr(1)); std::shared_ptr attr = std::make_shared(name, vary->type); @@ -341,12 +366,20 @@ void plGLMaterialShaderRef::ILoopOverLayers() // Set the vertex transforms now std::shared_ptr pos = std::make_shared("pos", "vec4"); std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); + std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); std::shared_ptr mW2C = IFindVariable("uMatrixW2C", "mat4"); std::shared_ptr mProj = IFindVariable("uMatrixProj", "mat4"); + std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); + std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); + vertMain->PushOp(ASSIGN(pos, MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))); vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); + + vertMain->PushOp(ASSIGN(vCamPos, pos)); + vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("0.0")))))); + vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); @@ -585,30 +618,105 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* { std::shared_ptr matrix; -#if 0 if (layer->GetMiscFlags() & (hsGMatState::kMiscUseReflectionXform | hsGMatState::kMiscUseRefractionXform)) { + std::shared_ptr mC2W = IFindVariable("uMatrixC2W", "mat4"); + + ST::string matName = ST::format("LayerMat{}", idx); + matrix = std::make_shared(matName, "mat4"); + + ST::string tempName = ST::format("t{}", idx); + std::shared_ptr temp = std::make_shared(tempName, "float"); + + sb->fFunction->PushOp(ASSIGN(matrix, mC2W)); + + // mat[0][3] = mat[1][3] = mat[2][3] = 0 + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "3"), + ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "3"), + ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "3"), + CONSTANT("0.0"))))); + + // This is just a rotation about X of Pi/2 (y = z, z = -y), + // followed by flipping Z to reflect back towards us (z = -z). + + // swap mat[1][0] and mat[2][0] + sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "0"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "0"), SUBVAL(SUBVAL(matrix, "2"), "0"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "0"), temp)); + + // swap mat[1][1] and mat[2][1] + sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "1"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "1"), SUBVAL(SUBVAL(matrix, "2"), "1"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "1"), temp)); + + // swap mat[1][2] and mat[2][2] + sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "2"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "2"), SUBVAL(SUBVAL(matrix, "2"), "2"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), temp)); + + if (layer->GetMiscFlags() & hsGMatState::kMiscUseRefractionXform) { + // Same as reflection, but then matrix = matrix * scaleMatNegateZ. + + // mat[0][2] = -mat[0][2]; + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "0"), "2")))); + + // mat[1][2] = -mat[1][2]; + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "1"), "2")))); + + // mat[2][2] = -mat[2][2]; + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "2"), "2")))); + } + +#if 0 } else if (layer->GetMiscFlags() & hsGMatState::kMiscCam2Screen) { } else if (layer->GetMiscFlags() & hsGMatState::kMiscProjection) { ST::string matName = ST::format("uLayerMat{}", idx); std::shared_ptr layMat = IFindVariable(matName, "mat4"); } else if (layer->GetMiscFlags() & hsGMatState::kMiscBumpChans) { - } else #endif - { + } else { ST::string matName = ST::format("uLayerMat{}", idx); matrix = IFindVariable(matName, "mat4"); } - uint32_t uvwSrc = layer->GetUVWSrc() & plGBufferGroup::kUVCountMask; - - ST::string uvwName = ST::format("vVtxUVWSrc{}", uvwSrc); - std::shared_ptr layUVW = IFindVariable(uvwName, "vec3"); + uint32_t uvwSrc = layer->GetUVWSrc(); // Local variable to store the mesh uvw * layer matrix ST::string coordName = ST::format("coords{}", idx); std::shared_ptr coords = std::make_shared(coordName, "vec4"); - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", layUVW, CONSTANT("1.0"))))); + switch (uvwSrc) { + case plLayerInterface::kUVWNormal: + { + std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, vCamNor))); + } + break; + case plLayerInterface::kUVWPosition: + { + std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, vCamPos))); + } + break; + case plLayerInterface::kUVWReflect: + { + std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); + std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); + std::shared_ptr mC2W = IFindVariable("uMatrixC2W", "mat4"); + + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, MUL(mC2W, CALL("reflect", CALL("normalize", vCamPos), CALL("normalize", vCamNor)))))); + } + break; + default: + { + uvwSrc &= plGBufferGroup::kUVCountMask; + + ST::string uvwName = ST::format("vVtxUVWSrc{}", uvwSrc); + std::shared_ptr layUVW = IFindVariable(uvwName, "vec3"); + + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", layUVW, CONSTANT("1.0"))))); + } + break; + } sb->fCurrCoord = coords; } @@ -782,24 +890,31 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil { hsStatusMessage("Blend DOT3"); // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) + // alpha = prev - //break; + sb->fCurrAlpha = sb->fPrevAlpha; + break; } case hsGMatState::kBlendAddSigned: { - hsStatusMessage("Blend AddSigned"); // color = color + prev - 0.5 + sb->fFunction->PushOp(ASSIGN(col, SUB(ADD(texCol, sb->fPrevColor), CONSTANT("0.5")))); + sb->fCurrColor = col; + // alpha = prev - //break; + sb->fCurrAlpha = sb->fPrevAlpha; + break; } case hsGMatState::kBlendAddSigned2X: { hsStatusMessage("Blend AddSigned2X"); // color = (color + prev - 0.5) << 1 + // alpha = prev - //break; + sb->fCurrAlpha = sb->fPrevAlpha; + break; } case 0: diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 395458d3d6..90b5347589 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -523,6 +523,11 @@ void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& spa uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2C"); glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixC2W"); + if (uniform != -1) { + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixC2W); + } + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp index 0ff968466e..10a66031f5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -125,11 +125,13 @@ ST::string plShaderContext::RenderNode(std::shared_ptr node, std:: std::shared_ptr op = static_pointer_cast(node); if (op->op == ".") { - return ST::format("{}{}{}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + return ST::format("{}{}{}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + } else if (op->op == "[") { + return ST::format("{}{}{}]", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); } else if (op->parens) { - return ST::format("({} {} {})", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + return ST::format("({} {} {})", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); } else { - return ST::format("{} {} {}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); + return ST::format("{} {} {}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); } } break; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index b570816bfe..23d969bb68 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -286,6 +286,7 @@ class plShaderContext : public std::enable_shared_from_this #define MUL(...) std::make_shared("*", __VA_ARGS__) #define DIV(...) std::make_shared("/", __VA_ARGS__) #define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) +#define SUBVAL(n, p) std::make_shared("[", n, CONSTANT(p)) #define IS_EQ(...) std::make_shared("==", __VA_ARGS__) #define RETURN(n) std::make_shared(n) #define COND(...) std::make_shared(__VA_ARGS__) From 8c01b03a5696a6b2d1e1c7db414991486b035c9a Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Jan 2016 15:13:14 -0800 Subject: [PATCH 25/76] Fix the alpha blend textures --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 8 ++++---- .../FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 6e38c0d50a..794368cd7a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -603,7 +603,7 @@ void plGLDevice::SetupTextureRef(plLayerInterface* layer, plBitmap* img, Texture switch (img->fUncompressedInfo.fType) { case plBitmap::UncompressedInfo::kRGB8888: tRef->fFormat = GL_RGBA; - tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataType = GL_UNSIGNED_BYTE; tRef->fDataFormat = GL_BGRA; break; case plBitmap::UncompressedInfo::kRGB4444: @@ -618,12 +618,12 @@ void plGLDevice::SetupTextureRef(plLayerInterface* layer, plBitmap* img, Texture break; case plBitmap::UncompressedInfo::kInten8: tRef->fFormat = GL_LUMINANCE; - tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataType = GL_UNSIGNED_BYTE; tRef->fDataFormat = GL_LUMINANCE; break; case plBitmap::UncompressedInfo::kAInten88: tRef->fFormat = GL_LUMINANCE_ALPHA; - tRef->fDataType = GL_UNSIGNED_SHORT; + tRef->fDataType = GL_UNSIGNED_BYTE; tRef->fDataFormat = GL_LUMINANCE_ALPHA; break; } @@ -670,7 +670,7 @@ void plGLDevice::BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping) img->SetCurrLevel(lvl); glTexImage2D(mapping, lvl, tRef->fFormat, img->GetCurrWidth(), img->GetCurrHeight(), 0, tRef->fDataFormat, tRef->fDataType, img->GetCurrLevelPtr()); - LOG_GL_ERROR_CHECK(ST::format("non-DXT Texture Image failed at level {}", lvl)); + LOG_GL_ERROR_CHECK(ST::format("non-DXT Texture Image \"{}\" failed at level {}", (img->GetKey() ? img->GetKeyName() : ""), lvl)); } } } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index cbabe83c2c..b03f2d14d2 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -109,6 +109,9 @@ void plGLMaterialShaderRef::SetupTextureRefs() // Load the image plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); + if (!img) + continue; + plGLTextureRef* texRef = static_cast(img->GetDeviceRef()); if (!texRef->fRef) From 6e0bdd913e8f09e7d7a7114e9e87b4515045d040 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Jan 2016 17:58:53 -0800 Subject: [PATCH 26/76] Implement quick & hacky Z-bias offset --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 25 ++++++++++++------- .../pfGLPipeline/plGLMaterialShaderRef.h | 1 + .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 11 ++++++++ .../FeatureLib/pfGLPipeline/plShaderNode.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index b03f2d14d2..f877d603dd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -265,7 +265,8 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() aVtxNormal = glGetAttribLocation(fRef, "aVtxNormal"); aVtxColor = glGetAttribLocation(fRef, "aVtxColor"); - uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); + uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); + uAlphaThreshold = glGetUniformLocation(fRef, "uAlphaThreshold"); // Material inputs uGlobalAmbient = glGetUniformLocation(fRef, "uGlobalAmb"); @@ -417,14 +418,6 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagDisableSpecular)) state.fShadeFlags &= ~hsGMatState::kShadeSpecular; - if (state.fZFlags & hsGMatState::kZIncLayer) { - // Set the Z-bias - //ISetLayer(1); - } else { - // Clear any Z-bias - //IBottomLayer(); - } - if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNoAlphaBlending)) state.fBlendFlags &= ~hsGMatState::kBlendMask; @@ -462,6 +455,14 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< sb.fFunction = fn; sb.fIteration = 0; + if (state.fZFlags & hsGMatState::kZIncLayer) { + // Set the Z-bias + sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), ADD(CONSTANT("gl_FragCoord.z"), CONSTANT("-0.0001")))); + } else { + // Clear any Z-bias + sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), CONSTANT("gl_FragCoord.z"))); + } + IBuildBaseAlpha(currLay, &sb); for (int32_t i = 0; i < currNumLayers; i++) { @@ -489,6 +490,12 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< //IHandleMiscMode() //IHandleTextureStage(0, layer); + // Handle High Alpha Threshold + std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); + + // if (final.a < alphaThreshold) { discard; } + sb.fFunction->PushOp(COND(IS_LESS(sb.fCurrAlpha, alphaThreshold), CONSTANT("discard"))); + // Multiply in the vertex color at the end (but alpha is premultiplied!) std::shared_ptr finalColor; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 4c39413a83..36ee648f2e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -108,6 +108,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef GLuint uMatSpecularCol; GLuint uMatSpecularSrc; GLuint uPassNumber; + GLuint uAlphaThreshold; void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 90b5347589..4cc5a03b7f 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -604,6 +604,17 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, IHandleZMode(s); IHandleBlendMode(s); + // AlphaTestHigh is used for reducing sort artifacts on textures that + // are mostly opaque or transparent, but have regions of translucency + // in transition. Like a texture for a bush billboard. It lets there be + // some transparency falloff, but quit drawing before it gets so + // transparent that draw order problems (halos) become apparent. + if (lay->GetBlendFlags() & hsGMatState::kBlendAlphaTestHigh) { + glUniform1f(mRef->uAlphaThreshold, 0.25); + } else { + glUniform1f(mRef->uAlphaThreshold, 0.0); + } + if (lay->GetMiscFlags() & hsGMatState::kMiscTwoSided) { glDisable(GL_CULL_FACE); } else { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index 23d969bb68..8149e84b91 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -288,6 +288,7 @@ class plShaderContext : public std::enable_shared_from_this #define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) #define SUBVAL(n, p) std::make_shared("[", n, CONSTANT(p)) #define IS_EQ(...) std::make_shared("==", __VA_ARGS__) +#define IS_LESS(...) std::make_shared("<", __VA_ARGS__) #define RETURN(n) std::make_shared(n) #define COND(...) std::make_shared(__VA_ARGS__) From 3fb61736cd762a3a963107d58018c79da51226ec Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 7 Jun 2022 23:29:41 -0700 Subject: [PATCH 27/76] Clean up GL context stuff when shutting down --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 58 +++++++++++++++++++ .../FeatureLib/pfGLPipeline/plGLDevice.h | 4 ++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 5 ++ .../FeatureLib/pfGLPipeline/plGLPipeline.h | 2 +- 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 794368cd7a..5d7562843c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -142,6 +142,22 @@ void InitEGLDevice(plGLDevice* dev) if (display != EGL_NO_DISPLAY) eglTerminate(display); } + +void FiniEGLDevice(plGLDevice* dev) +{ + EGLSurface surface = static_cast(dev->fSurface); + EGLContext context = static_cast(dev->fContext); + EGLDisplay display = static_cast(dev->fDisplay); + + if (surface != EGL_NO_SURFACE) + eglDestroySurface(display, surface); + + if (context != EGL_NO_CONTEXT) + eglDestroyContext(display, context); + + if (display != EGL_NO_DISPLAY) + eglTerminate(display); +} #endif // USE_EGL #pragma endregion EGL_Init @@ -199,6 +215,16 @@ void InitWGLDevice(plGLDevice* dev) wglDeleteContext(ctx); } } + +void FiniWGLDevice(plGLDevice* dev) +{ + HGLRC ctx = static_cast(dev->fContext); + + if (ctx) { + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(ctx); + } +} #endif // HS_BUILD_FOR_WIN32 #pragma endregion WGL_Init @@ -260,6 +286,20 @@ void InitCGLDevice(plGLDevice* dev) IGNORE_WARNINGS_END } + +void FiniCGLDevice(plGLDevice* dev) +{ + IGNORE_WARNINGS_BEGIN("deprecated-declarations") + + CGLContextObj ctx = static_cast(dev->fContext); + + if (ctx) { + CGLSetCurrentContext(nullptr); + CGLReleaseContext(ctx); + } + + IGNORE_WARNINGS_END +} #endif // HS_BUILD_FOR_MACOS #pragma endregion CGL_Init @@ -349,6 +389,24 @@ bool plGLDevice::InitDevice() return true; } +void plGLDevice::Shutdown() +{ +#ifdef USE_EGL + if (fContextType == kEGL) { + FiniEGLDevice(this); + return; + } +#endif + +#ifdef HS_BUILD_FOR_WIN32 + FiniWGLDevice(this); +#endif + +#ifdef HS_BUILD_FOR_MACOS + FiniCGLDevice(this); +#endif +} + void plGLDevice::SetRenderTarget(plRenderTarget* target) { SetViewport(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index a459356fee..1c94c4b997 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -58,8 +58,11 @@ class plGLDevice { friend class plGLPipeline; friend void InitEGLDevice(plGLDevice* dev); + friend void FiniEGLDevice(plGLDevice* dev); friend void InitWGLDevice(plGLDevice* dev); + friend void FiniWGLDevice(plGLDevice* dev); friend void InitCGLDevice(plGLDevice* dev); + friend void FiniCGLDevice(plGLDevice* dev); enum ContextType { kNone = 0, @@ -96,6 +99,7 @@ class plGLDevice * Initializes the OpenGL rendering context. */ bool InitDevice(); + void Shutdown(); /** * Set rendering to the specified render target. diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 4cc5a03b7f..f93ca78741 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -121,6 +121,11 @@ plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3 fPlateMgr = new plGLPlateManager(this); } +plGLPipeline::~plGLPipeline() +{ + fDevice.Shutdown(); +} + bool plGLPipeline::PreRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index e8a15ef7f6..fed7a562b6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -70,7 +70,7 @@ class plGLPipeline : public pl3DPipeline public: plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode); - virtual ~plGLPipeline() = default; + virtual ~plGLPipeline(); CLASSNAME_REGISTER(plGLPipeline); GETINTERFACE_ANY(plGLPipeline, plPipeline); From 0fed8d9c204f91f2f2cb2b5c363a1980a3d8f6b6 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Mon, 1 Aug 2016 19:08:32 -0700 Subject: [PATCH 28/76] Add initial pass of GL runtime lighting --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 4 + .../FeatureLib/pfGLPipeline/plGLDevice.h | 1 + .../pfGLPipeline/plGLMaterialShaderRef.cpp | 192 +++++++++++++----- .../pfGLPipeline/plGLMaterialShaderRef.h | 9 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 140 ++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 4 + .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 62 +++++- .../FeatureLib/pfGLPipeline/plShaderNode.h | 78 +++++-- 8 files changed, 400 insertions(+), 90 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 5d7562843c..5b9237fd66 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -814,5 +814,9 @@ void plGLDevice::SetWorldToCameraMatrix(const hsMatrix44& src) void plGLDevice::SetLocalToWorldMatrix(const hsMatrix44& src) { + hsMatrix44 inv; + src.GetInverse(&inv); + hsMatrix2GL(src, fMatrixL2W); + hsMatrix2GL(inv, fMatrixW2L); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index 1c94c4b997..dfb31cfacf 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -88,6 +88,7 @@ class plGLDevice size_t fActiveThread; GLuint fCurrentProgram; GLfloat fMatrixL2W[16]; + GLfloat fMatrixW2L[16]; GLfloat fMatrixW2C[16]; GLfloat fMatrixC2W[16]; GLfloat fMatrixProj[16]; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index f877d603dd..5ecdede66d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -253,8 +253,23 @@ void plGLMaterialShaderRef::ISetupShaderContexts() auto argAlpha = std::make_shared("alpha", "float", 0); invAlpha->PushOp(RETURN(SUB(CONSTANT("1.0"), argAlpha))); + fVertexShader->PushFunction(invColor); + fVertexShader->PushFunction(invAlpha); fFragmentShader->PushFunction(invColor); fFragmentShader->PushFunction(invAlpha); + + std::shared_ptr lightSource = std::make_shared("lightSource"); + lightSource->AddField(STRUCTVAR("vec4", "position")); + lightSource->AddField(STRUCTVAR("vec4", "ambient")); + lightSource->AddField(STRUCTVAR("vec4", "diffuse")); + lightSource->AddField(STRUCTVAR("vec4", "specular")); + lightSource->AddField(STRUCTVAR("float", "constAtten")); + lightSource->AddField(STRUCTVAR("float", "linAtten")); + lightSource->AddField(STRUCTVAR("float", "quadAtten")); + lightSource->AddField(STRUCTVAR("float", "scale")); + + fVertexShader->PushStruct(lightSource); + fFragmentShader->PushStruct(lightSource); } @@ -315,6 +330,29 @@ void plGLMaterialShaderRef::ILoopOverLayers() size_t j = 0; size_t pass = 0; + // Build the vertex shader main function to assign to the varying vars + std::shared_ptr vertMain = std::make_shared("main", "void"); + + // Set the vertex transforms now + std::shared_ptr pos = std::make_shared("pos", "vec4"); + std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); + std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); + std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); + std::shared_ptr mW2C = IFindVariable("uMatrixW2C", "mat4"); + std::shared_ptr mProj = IFindVariable("uMatrixProj", "mat4"); + + std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); + std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); + + vertMain->PushOp(ASSIGN(pos, MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))); + vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); + + vertMain->PushOp(ASSIGN(vCamPos, pos)); + vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("0.0")))))); + + vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); + vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); + // Build the fragment shader main function with the right passes std::shared_ptr fragMain = std::make_shared("main", "void"); std::shared_ptr uPass = IFindVariable("uPassNumber", "int"); @@ -323,16 +361,22 @@ void plGLMaterialShaderRef::ILoopOverLayers() { size_t iCurrMat = j; std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "void"); + std::shared_ptr vertPass = std::make_shared(ST::format("pass{}", pass), "void"); - j = IHandleMaterial(iCurrMat, fragPass); + j = IHandleMaterial(iCurrMat, vertPass, fragPass); if (j == -1) break; + fVertexShader->PushFunction(vertPass); fFragmentShader->PushFunction(fragPass); + std::shared_ptr passCond = COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass)))); + passCond->PushOp(CALL(fragPass->name)); + // if (uPassNumber == curpass) { curpass(); } - fragMain->PushOp(COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass))), CALL(fragPass->name))); + fragMain->PushOp(passCond); + vertMain->PushOp(passCond); pass++; fPassIndices.push_back(iCurrMat); @@ -344,54 +388,26 @@ void plGLMaterialShaderRef::ILoopOverLayers() fFragmentShader->PushFunction(fragMain); - - // Build the vertex shader main function to assign to the varying vars - std::shared_ptr vertMain = std::make_shared("main", "void"); for (const auto& pair : fVariables) { if (pair.second->klass == kVarying) { std::shared_ptr vary = std::static_pointer_cast(pair.second); - if (vary->name == "vCamPosition" || vary->name == "vCamNormal") { + if (vary->name == "vVtxColor" || vary->name == "vCamPosition" || vary->name == "vCamNormal") { continue; } ST::string name = ST::format("a{}", vary->name.substr(1)); std::shared_ptr attr = std::make_shared(name, vary->type); - if (name == "aVtxColor") { - // Need to swizzle to color around - vertMain->PushOp(ASSIGN(vary, PROP(attr, "zyxw"))); - } else { - vertMain->PushOp(ASSIGN(vary, attr)); - } + vertMain->PushOp(ASSIGN(vary, attr)); } } - // Set the vertex transforms now - std::shared_ptr pos = std::make_shared("pos", "vec4"); - std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); - std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); - std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); - std::shared_ptr mW2C = IFindVariable("uMatrixW2C", "mat4"); - std::shared_ptr mProj = IFindVariable("uMatrixProj", "mat4"); - - std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); - std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); - - vertMain->PushOp(ASSIGN(pos, MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))); - vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); - - vertMain->PushOp(ASSIGN(vCamPos, pos)); - vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("0.0")))))); - - vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); - vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); - fVertexShader->PushFunction(vertMain); } -uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr fn) +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) return -1; @@ -451,9 +467,20 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< //ISetBumpMatrices(currLay); } + std::shared_ptr vVtxColor = IFindVariable("vVtxColor", "vec4"); + + std::shared_ptr lighting = ICalcLighting(vfn); + std::shared_ptr baseAlpha = IBuildBaseAlpha(currLay, vfn); + + vfn->PushOp(ASSIGN(vVtxColor, CALL("vec4", PROP(lighting, "rgb"), baseAlpha))); + + std::shared_ptr fBaseAlpha = std::make_shared("baseAlpha", "float"); + ffn->PushOp(ASSIGN(fBaseAlpha, PROP(vVtxColor, "a"))); + ShaderBuilder sb; - sb.fFunction = fn; + sb.fFunction = ffn; sb.fIteration = 0; + sb.fPrevAlpha = fBaseAlpha; if (state.fZFlags & hsGMatState::kZIncLayer) { // Set the Z-bias @@ -463,8 +490,6 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), CONSTANT("gl_FragCoord.z"))); } - IBuildBaseAlpha(currLay, &sb); - for (int32_t i = 0; i < currNumLayers; i++) { sb.fIteration = i; sb.fCurrColor.reset(); @@ -493,16 +518,19 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Handle High Alpha Threshold std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); + std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); + alphaTest->PushOp(CONSTANT("discard")); + // if (final.a < alphaThreshold) { discard; } - sb.fFunction->PushOp(COND(IS_LESS(sb.fCurrAlpha, alphaThreshold), CONSTANT("discard"))); + sb.fFunction->PushOp(alphaTest); // Multiply in the vertex color at the end (but alpha is premultiplied!) std::shared_ptr finalColor; if (sb.fCurrColor) { - finalColor = MUL(PROP(sb.fMatValues, "rgb"), sb.fCurrColor, true); + finalColor = MUL(PROP(vVtxColor, "rgb"), sb.fCurrColor, true); } else { - finalColor = PROP(sb.fMatValues, "rgb"); + finalColor = PROP(vVtxColor, "rgb"); } sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragColor"), CALL("vec4", finalColor, sb.fCurrAlpha))); @@ -573,10 +601,14 @@ bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) return true; } - -void plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb) +std::shared_ptr plGLMaterialShaderRef::ICalcLighting(std::shared_ptr fn) { - std::shared_ptr vtxValue = IFindVariable("vVtxColor", "vec4"); + std::shared_ptr acol = IFindVariable("aVtxColor", "vec4"); + std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); + std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); + + std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); + std::shared_ptr mW2L = IFindVariable("uMatrixW2L", "mat4"); std::shared_ptr uGlobalAmb = IFindVariable("uGlobalAmb", "vec4"); std::shared_ptr uAmbientCol = IFindVariable("uAmbientCol", "vec4"); @@ -591,36 +623,88 @@ void plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, ShaderBuild std::shared_ptr uSpecularCol = IFindVariable("uSpecularCol", "vec4"); std::shared_ptr uSpecularSrc = IFindVariable("uSpecularSrc", "float"); + std::shared_ptr uLampSources = IFindVariable("uLampSources", "lightSource", 8); + // Local vars for the 4 material values - std::shared_ptr diffuse = std::make_shared("diffuse", "vec4"); + // Material values + std::shared_ptr MAmbient = std::make_shared("MAmbient", "vec4"); + std::shared_ptr MDiffuse = std::make_shared("MDiffuse", "vec4"); + std::shared_ptr MEmissive = std::make_shared("MEmissive", "vec4"); + std::shared_ptr MSpecular = std::make_shared("MSpecular", "vec4"); + + // Aggregated Lamp values + std::shared_ptr LAmbient = std::make_shared("LAmbient", "vec4"); + std::shared_ptr LDiffuse = std::make_shared("LDiffuse", "vec4"); + + // Final output values std::shared_ptr ambient = std::make_shared("ambient", "vec4"); - std::shared_ptr emissive = std::make_shared("emissive", "vec4"); + std::shared_ptr diffuse = std::make_shared("diffuse", "vec4"); std::shared_ptr specular = std::make_shared("specular", "vec4"); - sb->fFunction->PushOp(ASSIGN(ambient, MUL(uGlobalAmb, CALL("mix", vtxValue, uAmbientCol, uAmbientSrc)))); - sb->fFunction->PushOp(ASSIGN(diffuse, CALL("mix", vtxValue, uDiffuseCol, uDiffuseSrc))); - sb->fFunction->PushOp(ASSIGN(emissive, CALL("mix", vtxValue, uEmissiveCol, uEmissiveSrc))); - sb->fFunction->PushOp(ASSIGN(specular, CALL("mix", vtxValue, uSpecularCol, uSpecularSrc))); + fn->PushOp(ASSIGN(MAmbient, CALL("mix", PROP(acol, "zyxw"), uAmbientCol, uAmbientSrc))); + fn->PushOp(ASSIGN(MDiffuse, CALL("mix", PROP(acol, "zyxw"), uDiffuseCol, uDiffuseSrc))); + fn->PushOp(ASSIGN(MEmissive, CALL("mix", PROP(acol, "zyxw"), uEmissiveCol, uEmissiveSrc))); + fn->PushOp(ASSIGN(MSpecular, CALL("mix", PROP(acol, "zyxw"), uSpecularCol, uSpecularSrc))); + + std::shared_ptr attenuation = std::make_shared("attenuation", "float"); + std::shared_ptr v2l = std::make_shared("v2l", "vec3"); + std::shared_ptr distance = std::make_shared("distance", "float"); + std::shared_ptr direction = std::make_shared("direction", "vec3"); + std::shared_ptr Ndirection = std::make_shared("Ndirection", "vec3"); + + fn->PushOp(ASSIGN(LAmbient, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); + fn->PushOp(ASSIGN(LDiffuse, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); + + fn->PushOp(ASSIGN(Ndirection, CALL("normalize", CALL("vec3", MUL(mW2L, CALL("vec4", anor, CONSTANT("1.0"))))))); + + for (size_t i = 0; i < 8; i++) { + auto lamp = SUBVAL(uLampSources, ST::format("{}", i)); + + fn->PushOp(ASSIGN(v2l, CALL("vec3", SUB(PROP(lamp, "position"), MUL(mL2W, MUL(CALL("vec4", apos, CONSTANT("1.0")), PROP(PROP(lamp, "position"), "w"))))))); + fn->PushOp(ASSIGN(distance, CALL("length", v2l))); + fn->PushOp(ASSIGN(direction, CALL("normalize", v2l))); + + fn->PushOp(ASSIGN(attenuation, CALL("mix", + // attenuation = 1.0 + CONSTANT("1.0"), + // attenuation = 1.0 / (constA + linA * dist + quadA * dist * dist) + DIV(CONSTANT("1.0"), ADD(PROP(lamp, "constAtten"), ADD(MUL(PROP(lamp, "linAtten"), distance), MUL(PROP(lamp, "quadAtten"), MUL(distance, distance))), true)), + PROP(PROP(lamp, "position"), "w")))); + + // LAmbient = LAmbient + (Atten * Spot * La) + fn->PushOp(ASSIGN(LAmbient, ADD(LAmbient, MUL(attenuation, MUL(PROP(lamp, "ambient"), PROP(lamp, "scale"), true))))); + + // LDiffuse = LDiffuse + (Cd * Ld * (N . Ldir) * Atten * Spot) + fn->PushOp(ASSIGN(LDiffuse, ADD(LDiffuse, MUL(MDiffuse, MUL(MUL(PROP(lamp, "diffuse"), PROP(lamp, "scale"), true), MUL(CALL("max", CONSTANT("0.0"), CALL("dot", Ndirection, direction)), attenuation)))))); + } + + // ambient = ambient * (global amb + ambientL) [clamped 0.0 - 1.0] + fn->PushOp(ASSIGN(ambient, CALL("clamp", MUL(MAmbient, ADD(uGlobalAmb, LAmbient, true)), CONSTANT("0.0"), CONSTANT("1.0")))); + fn->PushOp(ASSIGN(diffuse, CALL("clamp", LDiffuse, CONSTANT("0.0"), CONSTANT("1.0")))); std::shared_ptr matValues = std::make_shared("material", "vec4"); + fn->PushOp(ASSIGN(matValues, CALL("clamp", ADD(ambient, ADD(diffuse, MEmissive)), CONSTANT("0.0"), CONSTANT("1.0")))); + return matValues; +} - //sb->fFunction->PushOp(ASSIGN(matValues, CALL("clamp", ADD(emissive, ADD(ambient, diffuse)), CONSTANT("0.0"), CONSTANT("1.0")))); - sb->fFunction->PushOp(ASSIGN(matValues, CALL("clamp", ADD(emissive, ambient), CONSTANT("0.0"), CONSTANT("1.0")))); - sb->fMatValues = matValues; +std::shared_ptr plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, std::shared_ptr fn) +{ + // This will have been declared by ICalcLighting + std::shared_ptr diffuse = CONSTANT("MDiffuse"); // Local variable to store the starting alpha value std::shared_ptr base = std::make_shared("baseAlpha", "float"); if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { // base = 1.0 - vVtxColor.a - sb->fFunction->PushOp(ASSIGN(base, CALL("invAlpha", PROP(diffuse, "a")))); + fn->PushOp(ASSIGN(base, CALL("invAlpha", PROP(diffuse, "a")))); } else { // base = vVtxColor.a - sb->fFunction->PushOp(ASSIGN(base, PROP(diffuse, "a"))); + fn->PushOp(ASSIGN(base, PROP(diffuse, "a"))); } - sb->fPrevAlpha = base; + return base; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 36ee648f2e..1c653b35c2 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -131,11 +131,11 @@ class plGLMaterialShaderRef : public plGLDeviceRef void ICleanupShaderContexts(); template - std::shared_ptr IFindVariable(const ST::string& name, const ST::string& type) + std::shared_ptr IFindVariable(const ST::string& name, const ST::string& type, size_t n = 1) { auto it = fVariables.find(name); if (it == fVariables.end()) { - std::shared_ptr var = std::make_shared(name, type); + std::shared_ptr var = std::make_shared(name, type, n); fVariables[name] = var; return var; } else { @@ -144,10 +144,11 @@ class plGLMaterialShaderRef : public plGLDeviceRef } void ILoopOverLayers(); - uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr fn); + uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); - void IBuildBaseAlpha(plLayerInterface* layer, ShaderBuilder* sb); + std::shared_ptr ICalcLighting(std::shared_ptr fn); + std::shared_ptr IBuildBaseAlpha(plLayerInterface* layer, std::shared_ptr fn); void IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); void IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); void IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index f93ca78741..031d29551c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -58,6 +58,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPipeDebugFlags.h" #include "plProfile.h" +#include "plGLight/plLightInfo.h" #include "plPipeline/hsWinRef.h" #include "plStatusLog/plStatusLog.h" @@ -459,9 +460,6 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& ISetupTransforms(ice, tempIce, lastL2W); plProfile_EndTiming(SpanTransforms); - // Turn on this spans lights and turn off the rest. - //IEnableLights( &tempIce ); - // Check that the underlying buffers are ready to go. //plProfile_BeginTiming(CheckDyn); //ICheckDynBuffers(drawable, drawable->GetBufferGroup(tempIce.fGroupIdx), &tempIce); @@ -535,6 +533,11 @@ void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& spa uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2L"); + if (uniform != -1) { + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2L); + } } } @@ -596,6 +599,9 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plProfile_EndTiming(RenderBuff); + // Turn on this spans lights and turn off the rest. + ISelectLights(&span); + for (size_t pass = 0; pass < mRef->GetNumPasses(); pass++) { // Set uniform to pass if (mRef->uPassNumber != -1) @@ -879,3 +885,131 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter } } } + +void plGLPipeline::ISelectLights(const plSpan* span, bool proj) +{ + const size_t numLights = 8; + size_t i = 0; + int32_t startScale; + float threshhold; + float overHold = 0.3; + float scale; + + if (!IsDebugFlagSet(plPipeDbg::kFlagNoRuntimeLights) && + !(IsDebugFlagSet(plPipeDbg::kFlagNoApplyProjLights) && proj) && + !(IsDebugFlagSet(plPipeDbg::kFlagOnlyApplyProjLights) && !proj)) + { + std::vector& spanLights = span->GetLightList(proj); + + for (i = 0; i < spanLights.size() && i < numLights; i++) { + IEnableLight(i, spanLights[i]); + } + startScale = i; + + /// Attempt #2: Take some of the n strongest lights (below a given threshhold) and + /// fade them out to nothing as they get closer to the bottom. This way, they fade + /// out of existence instead of pop out. + + if (i < spanLights.size() - 1 && i > 0) { + threshhold = span->GetLightStrength(i, proj); + i--; + overHold = threshhold * 1.5f; + + if (overHold > span->GetLightStrength(0, proj)) { + overHold = span->GetLightStrength(0, proj); + } + + for (; i > 0 && span->GetLightStrength(i, proj) < overHold; i--) { + scale = (overHold - span->GetLightStrength(i, proj)) / (overHold - threshhold); + + IScaleLight(i, (1 - scale) * span->GetLightScale(i, proj)); + } + startScale = i + 1; + } + + + /// Make sure those lights that aren't scaled....aren't + for (i = 0; i < startScale; i++) { + IScaleLight(i, span->GetLightScale(i, proj)); + } + } + + for (; i < numLights; i++) { + IDisableLight(i); + } +} + +void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) +{ + GLuint position = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].position", i).c_str()); + GLuint ambient = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].ambient", i).c_str()); + GLuint diffuse = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].diffuse", i).c_str()); + GLuint specular = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].specular", i).c_str()); + GLuint constAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].constAtten", i).c_str()); + GLuint linAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].linAtten", i).c_str()); + GLuint quadAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].quadAtten", i).c_str()); + GLuint scale = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); + + hsColorRGBA amb = light->GetAmbient(); + glUniform4f(ambient, amb.r, amb.g, amb.b, amb.a); + + hsColorRGBA diff = light->GetDiffuse(); + glUniform4f(diffuse, diff.r, diff.g, diff.b, diff.a); + + hsColorRGBA spec = light->GetSpecular(); + glUniform4f(specular, spec.r, spec.g, spec.b, spec.a); + + plDirectionalLightInfo* dirLight = nullptr; + plOmniLightInfo* omniLight = nullptr; + + if ((dirLight = plDirectionalLightInfo::ConvertNoRef(light)) != nullptr) + { + hsVector3 direction = dirLight->GetWorldDirection(); + glUniform4f(position, direction.fX, direction.fY, direction.fZ, 0.0); + + glUniform1f(constAtten, 1.0f); + glUniform1f(linAtten, 0.0f); + glUniform1f(quadAtten, 0.0f); + } + else if ((omniLight = plOmniLightInfo::ConvertNoRef(light)) != nullptr) + { + hsPoint3 pos = omniLight->GetWorldPosition(); + glUniform4f(position, pos.fX, pos.fY, pos.fZ, 1.0); + + // TODO: Maximum Range + + glUniform1f(constAtten, omniLight->GetConstantAttenuation()); + glUniform1f(linAtten, omniLight->GetLinearAttenuation()); + glUniform1f(quadAtten, omniLight->GetQuadraticAttenuation()); + } + else { + IDisableLight(i); + } +} + +void plGLPipeline::IDisableLight(size_t i) +{ + GLuint position = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].position", i).c_str()); + GLuint ambient = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].ambient", i).c_str()); + GLuint diffuse = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].diffuse", i).c_str()); + GLuint specular = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].specular", i).c_str()); + GLuint constAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].constAtten", i).c_str()); + GLuint linAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].linAtten", i).c_str()); + GLuint quadAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].quadAtten", i).c_str()); + GLuint scale = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); + + if (position != -1) glUniform4f(position, 0.0f, 0.0f, 0.0f, 0.0f); + if (ambient != -1) glUniform4f(ambient, 0.0f, 0.0f, 0.0f, 0.0f); + if (diffuse != -1) glUniform4f(diffuse, 0.0f, 0.0f, 0.0f, 0.0f); + if (specular != -1) glUniform4f(specular, 0.0f, 0.0f, 0.0f, 0.0f); + if (constAtten != -1) glUniform1f(constAtten, 1.0f); + if (linAtten != -1) glUniform1f(linAtten, 0.0f); + if (quadAtten != -1) glUniform1f(quadAtten, 0.0f); + if (scale != -1) glUniform1f(scale, 0.0f); +} + +void plGLPipeline::IScaleLight(size_t i, float scale) +{ + GLuint uniform = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); + if (uniform != -1) glUniform1f(uniform, scale); +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index fed7a562b6..2efad020f7 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -113,6 +113,10 @@ class plGLPipeline : public pl3DPipeline void IHandleZMode(hsGMatState flags); void IHandleBlendMode(hsGMatState flags); void ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); + void ISelectLights(const plSpan* span, bool proj = false); + void IEnableLight(size_t i, plLightInfo* light); + void IDisableLight(size_t i); + void IScaleLight(size_t i, float scale); private: static plGLEnumerate enumerator; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp index 10a66031f5..57f8bd340e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -181,7 +181,22 @@ ST::string plShaderContext::RenderNode(std::shared_ptr node, std:: { std::shared_ptr cond = static_pointer_cast(node); - return ST::format("if ({}) {{ {}; }", this->RenderNode(cond->condition, fn), this->RenderNode(cond->body, fn)); + ST::string_stream out; + out << ST::format("if ({}) {{", this->RenderNode(cond->condition, fn)); + + if (cond->nodes.size() == 1) { + out << ST::format(" {}; }", this->RenderNode(cond->nodes[0], fn)); + } else { + out << "\n"; + + for (size_t i = 0; i < cond->nodes.size(); i++) { + out << "\t" << this->RenderNode(cond->nodes[i], fn) << ";\n"; + } + + out << "}"; + } + + return out.to_string(); } break; @@ -208,14 +223,39 @@ ST::string plShaderContext::Render() if (this->type == kFragment) out << "precision mediump float;\n"; - for (std::shared_ptr node : this->attributes) - out << ST::format("attribute {} {};\n", node->type, node->name); + for (std::shared_ptr st : this->structs) { + out << ST::format("struct {} {{\n", st->name); - for (std::shared_ptr node : this->uniforms) - out << ST::format("uniform {} {};\n", node->type, node->name); + for (std::shared_ptr var : st->fields) { + if (var->count > 1) + out << "\t" << ST::format("{} {}[{}];\n", var->type, var->name, var->count); + else + out << "\t" << ST::format("{} {};\n", var->type, var->name); + } - for (std::shared_ptr node : this->varyings) - out << ST::format("varying {} {};\n", node->type, node->name); + out << "};\n"; + } + + for (std::shared_ptr node : this->attributes) { + if (node->count > 1) + out << ST::format("attribute {} {}[{}];\n", node->type, node->name, node->count); + else + out << ST::format("attribute {} {};\n", node->type, node->name); + } + + for (std::shared_ptr node : this->uniforms) { + if (node->count > 1) + out << ST::format("uniform {} {}[{}];\n", node->type, node->name, node->count); + else + out << ST::format("uniform {} {};\n", node->type, node->name); + } + + for (std::shared_ptr node : this->varyings) { + if (node->count > 1) + out << ST::format("varying {} {}[{}];\n", node->type, node->name, node->count); + else + out << ST::format("varying {} {};\n", node->type, node->name); + } for (std::shared_ptr fn : this->funcs) { @@ -233,8 +273,12 @@ ST::string plShaderContext::Render() out << ") {\n"; - for (std::shared_ptr node : fn->temps) - out << "\t" << ST::format("{} {};\n", node->type, node->name); + for (std::shared_ptr node : fn->temps) { + if (node->count > 1) + out << "\t" << ST::format("{} {}[{}];\n", node->type, node->name, node->count); + else + out << "\t" << ST::format("{} {};\n", node->type, node->name); + } if (fn->temps.size()) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index 8149e84b91..682730da20 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -63,7 +63,9 @@ enum NodeType { kTempVar, kArgument, kFnCall, - kConditional + kBlock, + kConditional, + kLoop }; @@ -101,45 +103,47 @@ class plVariableNode : public plShaderNode { public: ST::string name; ST::string type; + size_t count; - plVariableNode(NodeType klass, ST::string name, ST::string type) + plVariableNode(NodeType klass, ST::string name, ST::string type, size_t n = 1) : plShaderNode(klass), name(name), - type(type) { } + type(type), + count(n){ } }; // ABSTRACT class plGlobalVariableNode : public plVariableNode { public: - plGlobalVariableNode(NodeType klass, ST::string name, ST::string type) - : plVariableNode(klass, name, type) { } + plGlobalVariableNode(NodeType klass, ST::string name, ST::string type, size_t n = 1) + : plVariableNode(klass, name, type, n) { } }; class plAttributeNode : public plGlobalVariableNode { public: - plAttributeNode(ST::string name, ST::string type) - : plGlobalVariableNode(kAttribute, name, type) { } + plAttributeNode(ST::string name, ST::string type, size_t n = 1) + : plGlobalVariableNode(kAttribute, name, type, n) { } }; class plUniformNode : public plGlobalVariableNode { public: - plUniformNode(ST::string name, ST::string type) - : plGlobalVariableNode(kUniform, name, type) { } + plUniformNode(ST::string name, ST::string type, size_t n = 1) + : plGlobalVariableNode(kUniform, name, type, n) { } }; class plVaryingNode : public plGlobalVariableNode { public: - plVaryingNode(ST::string name, ST::string type) - : plGlobalVariableNode(kVarying, name, type) { } + plVaryingNode(ST::string name, ST::string type, size_t n = 1) + : plGlobalVariableNode(kVarying, name, type, n) { } }; class plTempVariableNode : public plVariableNode { public: - plTempVariableNode(ST::string name, ST::string type) - : plVariableNode(kTempVar, name, type) { } + plTempVariableNode(ST::string name, ST::string type, size_t n = 1) + : plVariableNode(kTempVar, name, type, n) { } }; class plArgumentNode : public plVariableNode { @@ -206,15 +210,25 @@ class plCallNode : public plShaderNode { }; -class plConditionNode : public plShaderNode { +class plBlockNode : public plShaderNode { +public: + std::vector> nodes; + + plBlockNode(NodeType klass = kBlock) : plShaderNode(klass) { } + + void PushOp(std::shared_ptr op) { + nodes.push_back(op); + } +}; + + +class plConditionNode : public plBlockNode { public: std::shared_ptr condition; - std::shared_ptr body; - plConditionNode(std::shared_ptr condition, std::shared_ptr body) - : plShaderNode(kConditional), - condition(condition), - body(body) { } + plConditionNode(std::shared_ptr condition) + : plBlockNode(kConditional), + condition(condition) { } }; @@ -222,7 +236,6 @@ bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr class plShaderFunction : public std::enable_shared_from_this { - friend class plShaderContext; std::vector> nodes; @@ -246,6 +259,24 @@ class plShaderFunction : public std::enable_shared_from_this }; +class plShaderStruct : public std::enable_shared_from_this +{ + friend class plShaderContext; + + std::vector> fields; + +public: + ST::string name; + + plShaderStruct(ST::string name) + : name(name) { } + + void AddField(std::shared_ptr var) { + fields.push_back(var); + } +}; + + enum CtxType { @@ -256,6 +287,7 @@ enum CtxType { class plShaderContext : public std::enable_shared_from_this { std::vector> funcs; + std::vector> structs; CtxType type; int32_t version; @@ -270,6 +302,10 @@ class plShaderContext : public std::enable_shared_from_this funcs.push_back(fn); } + void PushStruct(std::shared_ptr st) { + structs.push_back(st); + } + ST::string Render(); private: @@ -292,6 +328,8 @@ class plShaderContext : public std::enable_shared_from_this #define RETURN(n) std::make_shared(n) #define COND(...) std::make_shared(__VA_ARGS__) +#define STRUCTVAR(t, n) std::make_shared(n, t) + // This one is a bit special because of the initializer_list #define CALL(fn, ...) std::shared_ptr(new plCallNode(fn, { __VA_ARGS__ })) From 1ca82bdb636306be73f410c495293a2483f93cee Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 25 Sep 2016 16:06:20 -0700 Subject: [PATCH 29/76] Try to fix depth offsets --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 1 + .../pfGLPipeline/plGLMaterialShaderRef.cpp | 7 +++- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 32 ++++++++++++++----- .../FeatureLib/pfGLPipeline/plShaderNode.h | 1 + 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 5b9237fd66..11ae9ac0a8 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -381,6 +381,7 @@ bool plGLDevice::InitDevice() glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); glFrontFace(GL_CCW); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 5ecdede66d..b92c3d0fd6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -353,6 +353,9 @@ void plGLMaterialShaderRef::ILoopOverLayers() vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); + vertMain->PushOp(ASSIGN(PROP(OUTPUT("gl_Position"), "z"), + SUB(MUL(PROP(OUTPUT("gl_Position"), "z"), CONSTANT("2.0")), PROP(OUTPUT("gl_Position"), "w")))); + // Build the fragment shader main function with the right passes std::shared_ptr fragMain = std::make_shared("main", "void"); std::shared_ptr uPass = IFindVariable("uPassNumber", "int"); @@ -482,6 +485,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< sb.fIteration = 0; sb.fPrevAlpha = fBaseAlpha; +#if 0 if (state.fZFlags & hsGMatState::kZIncLayer) { // Set the Z-bias sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), ADD(CONSTANT("gl_FragCoord.z"), CONSTANT("-0.0001")))); @@ -489,6 +493,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Clear any Z-bias sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), CONSTANT("gl_FragCoord.z"))); } +#endif for (int32_t i = 0; i < currNumLayers; i++) { sb.fIteration = i; @@ -518,7 +523,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Handle High Alpha Threshold std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); - std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); + std::shared_ptr alphaTest = COND(IS_LEQ(sb.fCurrAlpha, alphaThreshold)); alphaTest->PushOp(CONSTANT("discard")); // if (final.a < alphaThreshold) { discard; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 031d29551c..fd606c4679 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -615,15 +615,22 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, IHandleZMode(s); IHandleBlendMode(s); - // AlphaTestHigh is used for reducing sort artifacts on textures that - // are mostly opaque or transparent, but have regions of translucency - // in transition. Like a texture for a bush billboard. It lets there be - // some transparency falloff, but quit drawing before it gets so - // transparent that draw order problems (halos) become apparent. - if (lay->GetBlendFlags() & hsGMatState::kBlendAlphaTestHigh) { - glUniform1f(mRef->uAlphaThreshold, 0.25); + if (lay->GetBlendFlags() & (hsGMatState::kBlendTest | + hsGMatState::kBlendAlpha | + hsGMatState::kBlendAddColorTimesAlpha) + && !(lay->GetBlendFlags() & hsGMatState::kBlendAlphaAlways)) + { + // AlphaTestHigh is used for reducing sort artifacts on textures that + // are mostly opaque or transparent, but have regions of translucency + // in transition. Like a texture for a bush billboard. It lets there be + // some transparency falloff, but quit drawing before it gets so + // transparent that draw order problems (halos) become apparent. + if (lay->GetBlendFlags() & hsGMatState::kBlendAlphaTestHigh) + glUniform1f(mRef->uAlphaThreshold, 40.f/255.f); + else + glUniform1f(mRef->uAlphaThreshold, 1.f/255.f); } else { - glUniform1f(mRef->uAlphaThreshold, 0.0); + glUniform1f(mRef->uAlphaThreshold, 0.f); } if (lay->GetMiscFlags() & hsGMatState::kMiscTwoSided) { @@ -672,6 +679,15 @@ void plGLPipeline::IHandleZMode(hsGMatState flags) hsAssert(false, "Illegal combination of Z Buffer modes (Clear but don't write)"); break; } + + if (flags.fZFlags & hsGMatState::kZIncLayer) { + int32_t int_value = 8; + float value = *(float*)(&int_value); + + glPolygonOffset(0.f, value); + } else { + glPolygonOffset(0.f, 0.f); + } } void plGLPipeline::IHandleBlendMode(hsGMatState flags) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index 682730da20..6cb9dedff1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -324,6 +324,7 @@ class plShaderContext : public std::enable_shared_from_this #define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) #define SUBVAL(n, p) std::make_shared("[", n, CONSTANT(p)) #define IS_EQ(...) std::make_shared("==", __VA_ARGS__) +#define IS_LEQ(...) std::make_shared("<=", __VA_ARGS__) #define IS_LESS(...) std::make_shared("<", __VA_ARGS__) #define RETURN(n) std::make_shared(n) #define COND(...) std::make_shared(__VA_ARGS__) From ce55c96e41547c471d94367b442a26fd88c4a583 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Thu, 21 May 2020 00:07:03 -0700 Subject: [PATCH 30/76] Initial work on GL Plate rendering --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 6 +- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 93 ++++++---- .../pfGLPipeline/plGLMaterialShaderRef.h | 26 +++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 162 +++++++++++++++--- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 2 + .../pfGLPipeline/plGLPlateManager.cpp | 112 +++++++++++- .../pfGLPipeline/plGLPlateManager.h | 23 +++ .../pfMetalPipeline/plMetalPipeline.cpp | 6 +- .../PubUtilLib/plPipeline/pl3DPipeline.cpp | 3 + 9 files changed, 366 insertions(+), 67 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 3eba65eb65..83df33915b 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -303,9 +303,9 @@ plProfile_Extern(CheckDyn); plProfile_Extern(CheckStat); plProfile_Extern(RenderBuff); plProfile_Extern(RenderPrim); -plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); -plProfile_CreateTimer("DebugText", "PipeT", DebugText); -plProfile_CreateTimer("Reset", "PipeT", Reset); +plProfile_Extern(PlateMgr); +plProfile_Extern(DebugText); +plProfile_Extern(Reset); plProfile_CreateMemCounter("DefMem", "PipeC", DefaultMem); plProfile_CreateMemCounter("ManMem", "PipeC", ManagedMem); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index b92c3d0fd6..122d75ff28 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsBitVector.h" +#include "hsGMatState.inl" #include "plPipeline.h" #include "plPipeDebugFlags.h" @@ -225,16 +226,18 @@ void plGLMaterialShaderRef::ICompile() #endif fRef = glCreateProgram(); - LOG_GL_ERROR_CHECK("Create Program failed") + LOG_GL_ERROR_CHECK("Create Program failed"); + + if (epoxy_gl_version() >= 43) { + const char* name = ST::format("hsGMaterial::{}", fMaterial->GetKeyName()).c_str(); + glObjectLabel(GL_PROGRAM, fRef, strlen(name), name); + } glAttachShader(fRef, fVertShaderRef); LOG_GL_ERROR_CHECK("Attach Vertex Shader failed") glAttachShader(fRef, fFragShaderRef); LOG_GL_ERROR_CHECK("Attach Fragment Shader failed") - - glLinkProgram(fRef); - LOG_GL_ERROR_CHECK("Link Program failed") } @@ -275,10 +278,27 @@ void plGLMaterialShaderRef::ISetupShaderContexts() void plGLMaterialShaderRef::ISetShaderVariableLocs() { - // Store the attribute locations for later - aVtxPosition = glGetAttribLocation(fRef, "aVtxPosition"); - aVtxNormal = glGetAttribLocation(fRef, "aVtxNormal"); - aVtxColor = glGetAttribLocation(fRef, "aVtxColor"); + // Assign and bind the attribute locations for later + glBindAttribLocation(fRef, kVtxPosition, "aVtxPosition"); + glBindAttribLocation(fRef, kVtxNormal, "aVtxNormal"); + glBindAttribLocation(fRef, kVtxColor, "aVtxColor"); + + glBindAttribLocation(fRef, kVtxUVWSrc0, "aVtxUVWSrc0"); + glBindAttribLocation(fRef, kVtxUVWSrc1, "aVtxUVWSrc1"); + glBindAttribLocation(fRef, kVtxUVWSrc2, "aVtxUVWSrc2"); + glBindAttribLocation(fRef, kVtxUVWSrc3, "aVtxUVWSrc3"); + glBindAttribLocation(fRef, kVtxUVWSrc4, "aVtxUVWSrc4"); + glBindAttribLocation(fRef, kVtxUVWSrc5, "aVtxUVWSrc5"); + glBindAttribLocation(fRef, kVtxUVWSrc6, "aVtxUVWSrc6"); + glBindAttribLocation(fRef, kVtxUVWSrc7, "aVtxUVWSrc7"); + glBindAttribLocation(fRef, kVtxUVWSrc8, "aVtxUVWSrc8"); + glBindAttribLocation(fRef, kVtxUVWSrc9, "aVtxUVWSrc9"); + glBindAttribLocation(fRef, kVtxUVWSrc10, "aVtxUVWSrc10"); + glBindAttribLocation(fRef, kVtxUVWSrc11, "aVtxUVWSrc11"); + glBindAttribLocation(fRef, kVtxUVWSrc12, "aVtxUVWSrc12"); + + glLinkProgram(fRef); + LOG_GL_ERROR_CHECK("Program Link failed"); uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); uAlphaThreshold = glGetUniformLocation(fRef, "uAlphaThreshold"); @@ -294,12 +314,6 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() uMatSpecularCol = glGetUniformLocation(fRef, "uSpecularCol"); uMatSpecularSrc = glGetUniformLocation(fRef, "uSpecularSrc"); - aVtxUVWSrc.assign(16, -1); - for (size_t i = 0; i < 16; i++) { - ST::string name = ST::format("aVtxUVWSrc{}", i); - aVtxUVWSrc[i] = glGetAttribLocation(fRef, name.c_str()); - } - size_t layerCount = fMaterial->GetNumLayers(); uLayerMat.assign(layerCount, -1); @@ -410,6 +424,14 @@ void plGLMaterialShaderRef::ILoopOverLayers() } +const hsGMatState plGLMaterialShaderRef::ICompositeLayerState(plLayerInterface* layer) +{ + hsGMatState state; + state.Composite(layer->GetState(), fPipeline->GetMaterialOverride(true), fPipeline->GetMaterialOverride(false)); + return state; +} + + uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) @@ -432,7 +454,9 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< //currLay = IPushOverAllLayer(currLay); - hsGMatState state = currLay->GetState(); + hsGMatState state = ICompositeLayerState(currLay); + + // Stuff about ZInc if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagDisableSpecular)) state.fShadeFlags &= ~hsGMatState::kShadeSpecular; @@ -695,13 +719,15 @@ std::shared_ptr plGLMaterialShaderRef::ICalcLighting(std::sh std::shared_ptr plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, std::shared_ptr fn) { + hsGMatState state = ICompositeLayerState(layer); + // This will have been declared by ICalcLighting std::shared_ptr diffuse = CONSTANT("MDiffuse"); // Local variable to store the starting alpha value std::shared_ptr base = std::make_shared("baseAlpha", "float"); - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { + if (state.fBlendFlags & hsGMatState::kBlendInvertVtxAlpha) { // base = 1.0 - vVtxColor.a fn->PushOp(ASSIGN(base, CALL("invAlpha", PROP(diffuse, "a")))); } else { @@ -716,8 +742,9 @@ std::shared_ptr plGLMaterialShaderRef::IBuildBaseAlpha(plLay void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) { std::shared_ptr matrix; + hsGMatState state = ICompositeLayerState(layer); - if (layer->GetMiscFlags() & (hsGMatState::kMiscUseReflectionXform | hsGMatState::kMiscUseRefractionXform)) { + if (state.fMiscFlags & (hsGMatState::kMiscUseReflectionXform | hsGMatState::kMiscUseRefractionXform)) { std::shared_ptr mC2W = IFindVariable("uMatrixC2W", "mat4"); ST::string matName = ST::format("LayerMat{}", idx); @@ -752,7 +779,7 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "2"), SUBVAL(SUBVAL(matrix, "2"), "2"))); sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), temp)); - if (layer->GetMiscFlags() & hsGMatState::kMiscUseRefractionXform) { + if (state.fMiscFlags & hsGMatState::kMiscUseRefractionXform) { // Same as reflection, but then matrix = matrix * scaleMatNegateZ. // mat[0][2] = -mat[0][2]; @@ -766,11 +793,11 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* } #if 0 - } else if (layer->GetMiscFlags() & hsGMatState::kMiscCam2Screen) { - } else if (layer->GetMiscFlags() & hsGMatState::kMiscProjection) { + } else if (state.fMiscFlags & hsGMatState::kMiscCam2Screen) { + } else if (state.fMiscFlags & hsGMatState::kMiscProjection) { ST::string matName = ST::format("uLayerMat{}", idx); std::shared_ptr layMat = IFindVariable(matName, "mat4"); - } else if (layer->GetMiscFlags() & hsGMatState::kMiscBumpChans) { + } else if (state.fMiscFlags & hsGMatState::kMiscBumpChans) { #endif } else { ST::string matName = ST::format("uLayerMat{}", idx); @@ -856,6 +883,8 @@ void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* l void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb) { + hsGMatState state = ICompositeLayerState(layer); + if (!sb->fCurrImage) { hsStatusMessage("Got a layer with no image"); sb->fCurrColor = sb->fPrevColor; @@ -872,7 +901,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil std::shared_ptr alpha = std::make_shared(alphaName, "float"); std::shared_ptr texCol; - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertColor) { + if (state.fBlendFlags & hsGMatState::kBlendInvertColor) { // color = 1.0 - texture.rgb texCol = CALL("invColor", PROP(sb->fCurrImage, "rgb")); } else { @@ -883,7 +912,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil if (sb->fIteration == 0) { // Leave fCurrColor null if we are blending without texture color - if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { + if (state.fBlendFlags & hsGMatState::kBlendNoTexColor) { sb->fCurrColor = sb->fPrevColor; } else { sb->fFunction->PushOp(ASSIGN(col, texCol)); @@ -891,7 +920,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil } std::shared_ptr alphaVal; - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { // 1.0 - texture.a alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); } else { @@ -900,12 +929,12 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil } - if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha || !sb->fPrevAlpha) { + if (state.fBlendFlags & hsGMatState::kBlendNoVtxAlpha || !sb->fPrevAlpha) { // Only use texture alpha sb->fFunction->PushOp(ASSIGN(alpha, alphaVal)); sb->fCurrAlpha = alpha; - } else if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) { + } else if (state.fBlendFlags & hsGMatState::kBlendNoTexAlpha) { // Only use vertex alpha (prev alpha) sb->fCurrAlpha = sb->fPrevAlpha; } else { @@ -914,7 +943,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil sb->fCurrAlpha = alpha; } } else { - switch (layer->GetBlendFlags() & hsGMatState::kBlendMask) + switch (state.fBlendFlags & hsGMatState::kBlendMask) { case hsGMatState::kBlendAddColorTimesAlpha: @@ -923,11 +952,11 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil case hsGMatState::kBlendAlpha: { - if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { + if (state.fBlendFlags & hsGMatState::kBlendNoTexColor) { // color = prev sb->fCurrColor = sb->fPrevColor; } else { - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { // color = texture.rgb + (texture.a * prev) sb->fFunction->PushOp(ASSIGN(col, ADD(texCol, MUL(PROP(sb->fCurrImage, "a"), sb->fPrevColor, true)))); sb->fCurrColor = col; @@ -940,7 +969,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil std::shared_ptr alphaVal; - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { + if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { // 1.0 - texture.a alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); } else { @@ -948,11 +977,11 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil alphaVal = PROP(sb->fCurrImage, "a"); } - if (layer->GetBlendFlags() & hsGMatState::kBlendAlphaAdd) { + if (state.fBlendFlags & hsGMatState::kBlendAlphaAdd) { // alpha = alphaVal + prev sb->fFunction->PushOp(ASSIGN(alpha, ADD(alphaVal, sb->fPrevAlpha))); sb->fCurrAlpha = alpha; - } else if (layer->GetBlendFlags() & hsGMatState::kBlendAlphaMult) { + } else if (state.fBlendFlags & hsGMatState::kBlendAlphaMult) { // alpha = alphaVal * prev sb->fFunction->PushOp(ASSIGN(alpha, MUL(alphaVal, sb->fPrevAlpha))); sb->fCurrAlpha = alpha; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 1c653b35c2..fe1d7b73b8 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -55,6 +55,26 @@ class hsGMaterial; class plPipeline; class plLayerInterface; +enum plGLShaderConstants : GLuint { + kVtxPosition = 0, + kVtxNormal = 1, + kVtxColor = 2, + + kVtxUVWSrc0, + kVtxUVWSrc1, + kVtxUVWSrc2, + kVtxUVWSrc3, + kVtxUVWSrc4, + kVtxUVWSrc5, + kVtxUVWSrc6, + kVtxUVWSrc7, + kVtxUVWSrc8, + kVtxUVWSrc9, + kVtxUVWSrc10, + kVtxUVWSrc11, + kVtxUVWSrc12 +}; + class plGLMaterialShaderRef : public plGLDeviceRef { typedef std::map> plShaderVarLookup; @@ -144,6 +164,12 @@ class plGLMaterialShaderRef : public plGLDeviceRef } void ILoopOverLayers(); + + // Set the current Plasma state based on the input layer state and the material overrides. + // fMatOverOn overrides to set a state bit whether it is set in the layer or not. + // fMatOverOff overrides to clear a state bit whether it is set in the layer or not. + const hsGMatState ICompositeLayerState(plLayerInterface* layer); + uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index fd606c4679..41aad84b30 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -56,10 +56,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLPipeline.h" #include "plGLPlateManager.h" +#include "hsGMatState.inl" #include "plPipeDebugFlags.h" #include "plProfile.h" #include "plGLight/plLightInfo.h" #include "plPipeline/hsWinRef.h" +#include "plPipeline/plDebugText.h" #include "plStatusLog/plStatusLog.h" #ifdef HS_SIMD_INCLUDE @@ -85,6 +87,9 @@ plProfile_Extern(CheckDyn); plProfile_Extern(CheckStat); plProfile_Extern(RenderBuff); plProfile_Extern(RenderPrim); +plProfile_Extern(PlateMgr); +plProfile_Extern(DebugText); +plProfile_Extern(Reset); // Adding a nil RenderPrim for turning off drawing static plRenderNilFunc sRenderNil; @@ -124,6 +129,9 @@ plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3 plGLPipeline::~plGLPipeline() { + if (plGLPlateManager* pm = static_cast(fPlateMgr)) + pm->IReleaseGeometry(); + fDevice.Shutdown(); } @@ -334,7 +342,39 @@ bool plGLPipeline::EndRender() } void plGLPipeline::RenderScreenElements() -{} +{ + bool reset = false; + + if (fView.HasCullProxy()) + Draw(fView.GetCullProxy()); + + hsGMatState tHack = PushMaterialOverride(hsGMatState::kMisc, hsGMatState::kMiscWireFrame, false); + hsGMatState ambHack = PushMaterialOverride(hsGMatState::kShade, hsGMatState::kShadeWhite, true); + + plProfile_BeginTiming(PlateMgr); + // Plates + if (fPlateMgr) { + fPlateMgr->DrawToDevice(this); + reset = true; + } + plProfile_EndTiming(PlateMgr); + + PopMaterialOverride(ambHack, true); + PopMaterialOverride(tHack, false); + + plProfile_BeginTiming(DebugText); + /// Debug text + if (fDebugTextMgr && plDebugText::Instance().IsEnabled()) { + fDebugTextMgr->DrawToDevice(this); + reset = true; + } + plProfile_EndTiming(DebugText); + + plProfile_BeginTiming(Reset); + if (reset) + fView.fXformResetFlags = fView.kResetAll; // Text destroys view transforms + plProfile_EndTiming(Reset); +} bool plGLPipeline::IsFullScreen() const { @@ -345,7 +385,12 @@ void plGLPipeline::Resize(uint32_t width, uint32_t height) {} void plGLPipeline::LoadResources() -{} +{ + if (plGLPlateManager* pm = static_cast(fPlateMgr)) { + pm->IReleaseGeometry(); + pm->ICreateGeometry(); + } +} bool plGLPipeline::SetGamma(float eR, float eG, float eB) { @@ -567,27 +612,19 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, /* Vertex Buffer stuff */ glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); - if (mRef->aVtxPosition != -1) { - glEnableVertexAttribArray(mRef->aVtxPosition); - glVertexAttribPointer(mRef->aVtxPosition, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); - } + glEnableVertexAttribArray(kVtxPosition); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); - if (mRef->aVtxNormal != -1) { - glEnableVertexAttribArray(mRef->aVtxNormal); - glVertexAttribPointer(mRef->aVtxNormal, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); - } + glEnableVertexAttribArray(kVtxNormal); + glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); - if (mRef->aVtxColor != -1) { - glEnableVertexAttribArray(mRef->aVtxColor); - glVertexAttribPointer(mRef->aVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); - } + glEnableVertexAttribArray(kVtxColor); + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); int numUVs = vRef->fOwner->GetNumUVs(); for (int i = 0; i < numUVs; i++) { - if (mRef->aVtxUVWSrc[i] != -1) { - glEnableVertexAttribArray(mRef->aVtxUVWSrc[i]); - glVertexAttribPointer(mRef->aVtxUVWSrc[i], 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); - } + glEnableVertexAttribArray(kVtxUVWSrc0 + i); + glVertexAttribPointer(kVtxUVWSrc0 + i, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); } LOG_GL_ERROR_CHECK("Vertex Attributes failed") @@ -611,21 +648,21 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, ICalcLighting(mRef, lay, &span); - hsGMatState s = lay->GetState(); + hsGMatState s; + s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); + IHandleZMode(s); IHandleBlendMode(s); - if (lay->GetBlendFlags() & (hsGMatState::kBlendTest | - hsGMatState::kBlendAlpha | - hsGMatState::kBlendAddColorTimesAlpha) - && !(lay->GetBlendFlags() & hsGMatState::kBlendAlphaAlways)) + if (s.fBlendFlags & (hsGMatState::kBlendTest | hsGMatState::kBlendAlpha | hsGMatState::kBlendAddColorTimesAlpha) && + !(s.fBlendFlags & hsGMatState::kBlendAlphaAlways)) { // AlphaTestHigh is used for reducing sort artifacts on textures that // are mostly opaque or transparent, but have regions of translucency // in transition. Like a texture for a bush billboard. It lets there be // some transparency falloff, but quit drawing before it gets so // transparent that draw order problems (halos) become apparent. - if (lay->GetBlendFlags() & hsGMatState::kBlendAlphaTestHigh) + if (s.fBlendFlags & hsGMatState::kBlendAlphaTestHigh) glUniform1f(mRef->uAlphaThreshold, 40.f/255.f); else glUniform1f(mRef->uAlphaThreshold, 1.f/255.f); @@ -633,7 +670,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, glUniform1f(mRef->uAlphaThreshold, 0.f); } - if (lay->GetMiscFlags() & hsGMatState::kMiscTwoSided) { + if (s.fMiscFlags & hsGMatState::kMiscTwoSided) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); @@ -798,7 +835,9 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter return; } - hsGMatState state = currLayer->GetState(); + hsGMatState state; + state.Composite(currLayer->GetState(), fMatOverOn, fMatOverOff); + uint32_t mode = (currSpan != nullptr) ? (currSpan->fProps & plSpan::kLiteMask) : plSpan::kLiteMaterial; if (state.fMiscFlags & hsGMatState::kMiscBumpChans) { @@ -1029,3 +1068,74 @@ void plGLPipeline::IScaleLight(size_t i, float scale) GLuint uniform = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); if (uniform != -1) glUniform1f(uniform, scale); } + +void plGLPipeline::IDrawPlate(plPlate* plate) +{ + hsGMaterial* material = plate->GetMaterial(); + + // To override the transform done by the z-bias + static float projMat[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, -2.0f, + 0.0f, 0.0f, 1.0f, 0.0f + }; + + /// Set up the transform directly + fDevice.SetLocalToWorldMatrix(plate->GetTransform()); + + //IPushPiggyBacks(material); + + // First, do we have a device ref at this index? + plGLMaterialShaderRef* mRef = (plGLMaterialShaderRef*)material->GetDeviceRef(); + + if (mRef == nullptr) { + mRef = new plGLMaterialShaderRef(material, this); + material->SetDeviceRef(mRef); + } + + if (!mRef->IsLinked()) + mRef->Link(&fMatRefList); + + glUseProgram(mRef->fRef); + fDevice.fCurrentProgram = mRef->fRef; + + mRef->SetupTextureRefs(); + + /* Push the matrices into the GLSL shader now */ + GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixProj"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, projMat); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2C"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixC2W"); + if (uniform != -1) + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixC2W); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); + + uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2L"); + if (uniform != -1) + glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2L); + + glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); + + glUniform4f(mRef->uMatAmbientCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatDiffuseCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatEmissiveCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatSpecularCol, 1.0, 1.0, 1.0, 1.0); + + glUniform1f(mRef->uMatAmbientSrc, 1.0); + glUniform1f(mRef->uMatDiffuseSrc, 1.0); + glUniform1f(mRef->uMatEmissiveSrc, 1.0); + glUniform1f(mRef->uMatSpecularSrc, 1.0); + + // And this to override cullmode set based on material 2-sidedness. + //glDisable(GL_CULL_FACE); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * 0)); + + //IPopPiggyBacks(); +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 2efad020f7..28f198bcc1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -48,6 +48,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com class plIcicle; class plGLMaterialShaderRef; +class plPlate; class plGLEnumerate { @@ -117,6 +118,7 @@ class plGLPipeline : public pl3DPipeline void IEnableLight(size_t i, plLightInfo* light); void IDisableLight(size_t i); void IScaleLight(size_t i, float scale); + void IDrawPlate(plPlate* plate); private: static plGLEnumerate enumerator; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index 58d68cd765..de9da14760 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -40,16 +40,122 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ +#include "plGLMaterialShaderRef.h" #include "plGLPlateManager.h" #include "plGLPipeline.h" plGLPlateManager::plGLPlateManager(plGLPipeline* pipe) - : plPlateManager(pipe) + : plPlateManager(pipe), fBuffers { 0, 0, 0 } {} plGLPlateManager::~plGLPlateManager() -{} +{ + IReleaseGeometry(); +} + +void plGLPlateManager::ICreateGeometry() +{ + plPlateVertex verts[4]; + + verts[0].fPoint.Set(-0.5f, -0.5f, 0.0f); + verts[0].fNormal.Set(0.0f, 0.0f, 1.0f); + verts[0].fColor = 0xffffffff; + verts[0].fUV.Set(0.0f, 0.0f, 0.0f); + + verts[1].fPoint.Set(-0.5f, 0.5f, 0.0f); + verts[1].fNormal.Set(0.0f, 0.0f, 1.0f); + verts[1].fColor = 0xffffffff; + verts[1].fUV.Set(0.0f, 1.0f, 0.0f); + + verts[2].fPoint.Set(0.5f, -0.5f, 0.0f); + verts[2].fNormal.Set(0.0f, 0.0f, 1.0f); + verts[2].fColor = 0xffffffff; + verts[2].fUV.Set(1.0f, 0.0f, 0.0f); + + verts[3].fPoint.Set(0.5f, 0.5f, 0.0f); + verts[3].fNormal.Set(0.0f, 0.0f, 1.0f); + verts[3].fColor = 0xffffffff; + verts[3].fUV.Set(1.0f, 1.0f, 0.0f); + + uint16_t indices[6] = {0, 1, 2, 1, 2, 3}; + + + GLuint vbo, ibo, vao; + + glCreateBuffers(1, &vbo); + glObjectLabel(GL_BUFFER, vbo, -1, "plPlate/VBO"); + glNamedBufferStorage(vbo, sizeof(verts), verts, 0); + + glCreateBuffers(1, &ibo); + glObjectLabel(GL_BUFFER, ibo, -1, "plPlate/IBO"); + glNamedBufferStorage(ibo, sizeof(indices), indices, 0); + + glCreateVertexArrays(1, &vao); + glObjectLabel(GL_VERTEX_ARRAY, vao, -1, "plPlate/VAO"); + + glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(plPlateVertex)); + glVertexArrayElementBuffer(vao, ibo); + + glEnableVertexArrayAttrib(vao, kVtxPosition); + glEnableVertexArrayAttrib(vao, kVtxNormal); + glEnableVertexArrayAttrib(vao, kVtxColor); + glEnableVertexArrayAttrib(vao, kVtxUVWSrc0); + + glVertexArrayAttribFormat(vao, kVtxPosition, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fPoint)); + glVertexArrayAttribFormat(vao, kVtxNormal, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fNormal)); + glVertexArrayAttribFormat(vao, kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(plPlateVertex, fColor)); + glVertexArrayAttribFormat(vao, kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fUV)); + + glVertexArrayAttribBinding(vao, kVtxPosition, 0); + glVertexArrayAttribBinding(vao, kVtxNormal, 0); + glVertexArrayAttribBinding(vao, kVtxColor, 0); + glVertexArrayAttribBinding(vao, kVtxUVWSrc0, 0); + + fBuffers = {vbo, ibo, vao }; +} + +void plGLPlateManager::IReleaseGeometry() +{ + if (fBuffers.ARef) { + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxPosition); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxNormal); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxColor); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxUVWSrc0); + + glDeleteVertexArrays(1, &fBuffers.ARef); + fBuffers.ARef = 0; + } + + if (fBuffers.VRef) { + glDeleteBuffers(1, &fBuffers.VRef); + fBuffers.VRef = 0; + } + + if (fBuffers.IRef) { + glDeleteBuffers(1, &fBuffers.IRef); + fBuffers.IRef = 0; + } +} void plGLPlateManager::IDrawToDevice(plPipeline* pipe) -{} +{ + plGLPipeline* glPipe = static_cast(pipe); + uint32_t scrnWidthDiv2 = fOwner->Width() >> 1; + uint32_t scrnHeightDiv2 = fOwner->Height() >> 1; + plPlate* plate = nullptr; + + if (fBuffers.VRef == 0 || fBuffers.IRef == 0 || fBuffers.ARef == 0) + return; + + glBindVertexArray(fBuffers.ARef); + + hsMatrix44 c2w; + hsVector3 screenspace(-0.5f/scrnWidthDiv2, -0.5f/scrnHeightDiv2, 0.0f); + c2w.MakeTranslateMat(&screenspace); + glPipe->fDevice.SetWorldToCameraMatrix(c2w); + for (plate = fPlates; plate != nullptr; plate = plate->GetNext()) { + if (plate->IsVisible()) + glPipe->IDrawPlate(plate); + } +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.h index f5e024e39d..5ce5779b42 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.h @@ -43,6 +43,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef _plGLPlateManager_inc_ #define _plGLPlateManager_inc_ +#include "plGLDeviceRef.h" + +#include "hsGeometry3.h" #include "plPipeline/plPlates.h" class plGLPipeline; @@ -56,8 +59,28 @@ class plGLPlateManager : public plPlateManager virtual ~plGLPlateManager(); protected: + struct plPlateVertex + { + hsPoint3 fPoint; + hsVector3 fNormal; + uint32_t fColor; + hsPoint3 fUV; + }; + + struct plPlateBuffers + { + GLuint VRef; + GLuint IRef; + GLuint ARef; + }; + + plPlateBuffers fBuffers; + plGLPlateManager(plGLPipeline* pipe); + void ICreateGeometry(); + void IReleaseGeometry(); + void IDrawToDevice(plPipeline* pipe) override; }; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index c6c4295853..7bc5fc7b03 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -107,9 +107,9 @@ plProfile_Extern(CheckDyn); plProfile_Extern(CheckStat); plProfile_Extern(RenderBuff); plProfile_Extern(RenderPrim); -plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); -plProfile_CreateTimer("DebugText", "PipeT", DebugText); -plProfile_CreateTimer("Reset", "PipeT", Reset); +plProfile_Extern(PlateMgr); +plProfile_Extern(DebugText); +plProfile_Extern(Reset); plProfile_CreateCounterNoReset("Reload", "PipeC", PipeReload); plProfile_CreateCounter("AvRTPoolUsed", "PipeC", AvRTPoolUsed); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index 4966a9033c..5c1fbea8ad 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -45,6 +45,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com plProfile_CreateTimer("RenderScene", "PipeT", RenderScene); plProfile_CreateTimer("VisEval", "PipeT", VisEval); plProfile_CreateTimer("VisSelect", "PipeT", VisSelect); +plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); +plProfile_CreateTimer("DebugText", "PipeT", DebugText); +plProfile_CreateTimer("Reset", "PipeT", Reset); plProfile_CreateTimer("RenderSpan", "PipeT", RenderSpan); plProfile_CreateTimer(" MergeCheck", "PipeT", MergeCheck); From cbd6fb8618e45f0d330091da2ebad706a492b0e9 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 7 Jul 2020 22:26:46 -0700 Subject: [PATCH 31/76] All the fun GL compat stuff for plates... --- .../pfGLPipeline/plGLPlateManager.cpp | 133 ++++++++++++------ 1 file changed, 92 insertions(+), 41 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index de9da14760..e676270be7 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -80,47 +80,80 @@ void plGLPlateManager::ICreateGeometry() uint16_t indices[6] = {0, 1, 2, 1, 2, 3}; - GLuint vbo, ibo, vao; - - glCreateBuffers(1, &vbo); - glObjectLabel(GL_BUFFER, vbo, -1, "plPlate/VBO"); - glNamedBufferStorage(vbo, sizeof(verts), verts, 0); - - glCreateBuffers(1, &ibo); - glObjectLabel(GL_BUFFER, ibo, -1, "plPlate/IBO"); - glNamedBufferStorage(ibo, sizeof(indices), indices, 0); - - glCreateVertexArrays(1, &vao); - glObjectLabel(GL_VERTEX_ARRAY, vao, -1, "plPlate/VAO"); - - glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(plPlateVertex)); - glVertexArrayElementBuffer(vao, ibo); - - glEnableVertexArrayAttrib(vao, kVtxPosition); - glEnableVertexArrayAttrib(vao, kVtxNormal); - glEnableVertexArrayAttrib(vao, kVtxColor); - glEnableVertexArrayAttrib(vao, kVtxUVWSrc0); - - glVertexArrayAttribFormat(vao, kVtxPosition, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fPoint)); - glVertexArrayAttribFormat(vao, kVtxNormal, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fNormal)); - glVertexArrayAttribFormat(vao, kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(plPlateVertex, fColor)); - glVertexArrayAttribFormat(vao, kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fUV)); - - glVertexArrayAttribBinding(vao, kVtxPosition, 0); - glVertexArrayAttribBinding(vao, kVtxNormal, 0); - glVertexArrayAttribBinding(vao, kVtxColor, 0); - glVertexArrayAttribBinding(vao, kVtxUVWSrc0, 0); + GLuint vbo, ibo, vao = 0; + + if (epoxy_gl_version() >= 45) { + glCreateBuffers(1, &vbo); + glObjectLabel(GL_BUFFER, vbo, -1, "plPlate/VBO"); + glNamedBufferStorage(vbo, sizeof(verts), verts, 0); + + glCreateBuffers(1, &ibo); + glObjectLabel(GL_BUFFER, ibo, -1, "plPlate/IBO"); + glNamedBufferStorage(ibo, sizeof(indices), indices, 0); + + glCreateVertexArrays(1, &vao); + glObjectLabel(GL_VERTEX_ARRAY, vao, -1, "plPlate/VAO"); + + glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(plPlateVertex)); + glVertexArrayElementBuffer(vao, ibo); + + glEnableVertexArrayAttrib(vao, kVtxPosition); + glEnableVertexArrayAttrib(vao, kVtxNormal); + glEnableVertexArrayAttrib(vao, kVtxColor); + glEnableVertexArrayAttrib(vao, kVtxUVWSrc0); + + glVertexArrayAttribFormat(vao, kVtxPosition, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fPoint)); + glVertexArrayAttribFormat(vao, kVtxNormal, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fNormal)); + glVertexArrayAttribFormat(vao, kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(plPlateVertex, fColor)); + glVertexArrayAttribFormat(vao, kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fUV)); + + glVertexArrayAttribBinding(vao, kVtxPosition, 0); + glVertexArrayAttribBinding(vao, kVtxNormal, 0); + glVertexArrayAttribBinding(vao, kVtxColor, 0); + glVertexArrayAttribBinding(vao, kVtxUVWSrc0, 0); + } else { + if (epoxy_gl_version() >= 30) { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + } + + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + + glGenBuffers(1, &ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + if (epoxy_gl_version() >= 30) { + glEnableVertexAttribArray(kVtxPosition); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), 0); + + glEnableVertexAttribArray(kVtxNormal); + glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3)); + + glEnableVertexAttribArray(kVtxColor); + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3 * 2)); + + glEnableVertexAttribArray(kVtxUVWSrc0); + glVertexAttribPointer(kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); + + glBindVertexArray(0); + } + } fBuffers = {vbo, ibo, vao }; } void plGLPlateManager::IReleaseGeometry() { - if (fBuffers.ARef) { - glDisableVertexArrayAttrib(fBuffers.ARef, kVtxPosition); - glDisableVertexArrayAttrib(fBuffers.ARef, kVtxNormal); - glDisableVertexArrayAttrib(fBuffers.ARef, kVtxColor); - glDisableVertexArrayAttrib(fBuffers.ARef, kVtxUVWSrc0); + if (epoxy_gl_version() >= 30 && fBuffers.ARef) { + if (epoxy_gl_version() >= 45) { + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxPosition); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxNormal); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxColor); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxUVWSrc0); + } glDeleteVertexArrays(1, &fBuffers.ARef); fBuffers.ARef = 0; @@ -144,15 +177,33 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) uint32_t scrnHeightDiv2 = fOwner->Height() >> 1; plPlate* plate = nullptr; - if (fBuffers.VRef == 0 || fBuffers.IRef == 0 || fBuffers.ARef == 0) + if (fBuffers.VRef == 0 || fBuffers.IRef == 0) return; - glBindVertexArray(fBuffers.ARef); + if (epoxy_gl_version() >= 30) { + if (fBuffers.ARef == 0) + return; + + glBindVertexArray(fBuffers.ARef); + } else { + glBindBuffer(GL_ARRAY_BUFFER, fBuffers.VRef); + + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), 0); + glEnableVertexAttribArray(kVtxPosition); + + glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3)); + glEnableVertexAttribArray(kVtxNormal); + + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3 * 2)); + glEnableVertexAttribArray(kVtxColor); + + glVertexAttribPointer(kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); + glEnableVertexAttribArray(kVtxUVWSrc0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBuffers.IRef); + } - hsMatrix44 c2w; - hsVector3 screenspace(-0.5f/scrnWidthDiv2, -0.5f/scrnHeightDiv2, 0.0f); - c2w.MakeTranslateMat(&screenspace); - glPipe->fDevice.SetWorldToCameraMatrix(c2w); + glPipe->fDevice.SetWorldToCameraMatrix(hsMatrix44::IdentityMatrix()); for (plate = fPlates; plate != nullptr; plate = plate->GetNext()) { if (plate->IsVisible()) From 8aa4bb21e0cf483868e3a7424a0cc53e3ec2939a Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Thu, 9 Jun 2022 23:33:02 -0700 Subject: [PATCH 32/76] Fix crashes due to plate init before GL context --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 1 - .../Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 41aad84b30..cd7037caa9 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -388,7 +388,6 @@ void plGLPipeline::LoadResources() { if (plGLPlateManager* pm = static_cast(fPlateMgr)) { pm->IReleaseGeometry(); - pm->ICreateGeometry(); } } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index e676270be7..b6b7e86fbe 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -177,8 +177,12 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) uint32_t scrnHeightDiv2 = fOwner->Height() >> 1; plPlate* plate = nullptr; - if (fBuffers.VRef == 0 || fBuffers.IRef == 0) - return; + if (fBuffers.VRef == 0 || fBuffers.IRef == 0) { + ICreateGeometry(); + + if (fBuffers.VRef == 0 || fBuffers.IRef == 0) + return; + } if (epoxy_gl_version() >= 30) { if (fBuffers.ARef == 0) From 26401637f563be545b9908f789b3df6782033fc5 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Thu, 21 May 2020 07:45:48 -0700 Subject: [PATCH 33/76] Check textures for refresh every frame --- .../Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 122d75ff28..ba1c0d3979 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -118,6 +118,8 @@ void plGLMaterialShaderRef::SetupTextureRefs() if (!texRef->fRef) continue; + fPipeline->CheckTextureRef(layer); + LOG_GL_ERROR_CHECK("PRE-Active Texture failed") glActiveTexture(GL_TEXTURE0 + numTextures); From b3e56d71c9128a63bc260f28a8519bdb71402ad0 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 3 Jul 2020 20:30:04 -0700 Subject: [PATCH 34/76] Fix some rendering issues in plGLPipeline --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 4 ++++ Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 7 +------ .../Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp | 7 +++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 11ae9ac0a8..e9bd7367fb 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -759,6 +759,8 @@ void plGLDevice::MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMip glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } + tRef->SetDirty(false); + LOG_GL_ERROR_CHECK(ST::format("Mipmap Texture \"{}\" failed", img->GetKeyName())); } @@ -796,6 +798,8 @@ void plGLDevice::MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, glTexParameteri(tRef->fMapping, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } + tRef->SetDirty(false); + LOG_GL_ERROR_CHECK(ST::format("Cubic Environ Texture \"{}\" failed", img->GetKeyName())); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index cd7037caa9..fadec53458 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -1131,10 +1131,5 @@ void plGLPipeline::IDrawPlate(plPlate* plate) glUniform1f(mRef->uMatEmissiveSrc, 1.0); glUniform1f(mRef->uMatSpecularSrc, 1.0); - // And this to override cullmode set based on material 2-sidedness. - //glDisable(GL_CULL_FACE); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * 0)); - - //IPopPiggyBacks(); + glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * 0)); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index b6b7e86fbe..985241ed0e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -209,8 +209,15 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) glPipe->fDevice.SetWorldToCameraMatrix(hsMatrix44::IdentityMatrix()); + GLboolean cull = glIsEnabled(GL_CULL_FACE); + if (cull) + glDisable(GL_CULL_FACE); + for (plate = fPlates; plate != nullptr; plate = plate->GetNext()) { if (plate->IsVisible()) glPipe->IDrawPlate(plate); } + + if (cull) + glEnable(GL_CULL_FACE); } From 35ed3b1088eed1fbba81149823b95c81c52bc5c9 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Thu, 24 Dec 2020 15:44:02 -0800 Subject: [PATCH 35/76] Fix for leaking VAOs A new VAO is being created every time a span is rendered, need to be deleted --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index fadec53458..b4c396e95d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -522,6 +522,8 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& material, tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range tempIce.fIPackedIdx, tempIce.fILength ); + + glDeleteVertexArrays(1, &vao); } // Restart our search... From fc88ee54b96b0a777a7d0776b9d505632f2f7689 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 10 Jun 2022 00:19:53 -0700 Subject: [PATCH 36/76] Version check VAO usage Although we're not realistically trying to target lower than GL 3.3 initially. --- .../Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index b4c396e95d..d147f9e966 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -493,10 +493,12 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& fDevice.fCurrentProgram = mRef->fRef; LOG_GL_ERROR_CHECK(ST::format("Use Program with material \"{}\" failed", material->GetKeyName())); - // TODO: Figure out how to use VAOs properly :( - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + GLuint vao = 0; + if (epoxy_gl_version() >= 30) { + // TODO: Figure out how to use VAOs properly :( + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + } // What do we change? @@ -523,7 +525,8 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range tempIce.fIPackedIdx, tempIce.fILength ); - glDeleteVertexArrays(1, &vao); + if (epoxy_gl_version() >= 30) + glDeleteVertexArrays(1, &vao); } // Restart our search... From ad384ccc4916db40f5a6c72c1bcf5a2147a8ff4a Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Wed, 23 Dec 2020 03:44:41 -0800 Subject: [PATCH 37/76] Fix some rendering glitches --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index d147f9e966..b3bcb981e8 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -275,8 +275,9 @@ void plGLPipeline::ClearRenderTarget(const hsColorRGBA* col, const float* depth) if (fView.fRenderState & kRenderClearDepth) masks |= GL_DEPTH_BUFFER_BIT; + glDepthMask(GL_TRUE); glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClearDepth(clearDepth); + glClearDepth(1.0); glClear(masks); } @@ -301,8 +302,7 @@ bool plGLPipeline::BeginRender() hsColorRGBA clearColor = GetClearColor(); glDepthMask(GL_TRUE); - //glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClearColor(0.f, 0.f, 0.5f, 1.f); + glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } From 6a77293de831dd44a3719ec87cd3dd7da064ab4d Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Wed, 23 Dec 2020 03:46:44 -0800 Subject: [PATCH 38/76] Some initial stabs at rewriting the shaders --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 198 +++++++++++++++--- .../pfGLPipeline/plGLMaterialShaderRef.h | 19 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 58 ++++- .../pfGLPipeline/plGLPlateManager.cpp | 16 +- .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 3 +- 5 files changed, 242 insertions(+), 52 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index ba1c0d3979..4672c538ec 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -60,9 +60,153 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" +#define USE_NEW_SHADERS 1 + // From plGLDevice.cpp extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); +const char* VERTEX_SHADER_STRING = R"(#version 300 es +precision lowp int; + +struct lightSource { + vec4 position; + vec4 ambient; + vec4 diffuse; + vec4 specular; + float constAtten; + float linAtten; + float quadAtten; + float scale; +}; + + +// Input Attributes +layout(location = 0) in vec3 aVtxPosition; +layout(location = 1) in vec3 aVtxNormal; +layout(location = 2) in vec4 aVtxColor; +layout(location = 3) in vec3 aVtxUVWSrc[8]; + +uniform mat4 uMatrixL2W; +uniform mat4 uMatrixW2L; +uniform mat4 uMatrixW2C; +uniform mat4 uMatrixProj; + +uniform vec4 uGlobalAmb; +uniform vec4 uAmbientCol; +uniform float uAmbientSrc; +uniform vec4 uDiffuseCol; +uniform float uDiffuseSrc; +uniform vec4 uEmissiveCol; +uniform float uEmissiveSrc; +uniform vec4 uSpecularCol; +uniform float uSpecularSrc; + +uniform float uInvertVtxAlpha; // Effectively boolean, 0.0 or 1.0 + +uniform lightSource uLampSources[8]; + +// Varying outputs +out vec4 vCamPosition; +out vec4 vCamNormal; +out vec4 vVtxColor; +out vec3 vVtxUVWSrc[8]; + +void main() { + vec4 MAmbient = mix(aVtxColor.bgra, uAmbientCol, uAmbientSrc); + vec4 MDiffuse = mix(aVtxColor.bgra, uDiffuseCol, uDiffuseSrc); + vec4 MEmissive = mix(aVtxColor.bgra, uEmissiveCol, uEmissiveSrc); + vec4 MSpecular = mix(aVtxColor.bgra, uSpecularCol, uSpecularSrc); + + vec4 LAmbient = vec4(0.0, 0.0, 0.0, 0.0); + vec4 LDiffuse = vec4(0.0, 0.0, 0.0, 0.0); + + vec3 Ndirection = normalize(mat3(uMatrixW2L) * aVtxNormal); + + for (int i = 0; i < 8; i++) { + vVtxUVWSrc[i] = aVtxUVWSrc[i]; + + vec3 v2l = vec3(uLampSources[i].position - (uMatrixL2W * vec4(aVtxPosition, 1.0)) * uLampSources[i].position.w); + float distance = length(v2l); + vec3 direction = normalize(v2l); + + float attenuation = mix(1.0, 1.0 / (uLampSources[i].constAtten + uLampSources[i].linAtten * distance + uLampSources[i].quadAtten * distance * distance), uLampSources[i].position.w); + + LAmbient.rgb = LAmbient.rgb + attenuation * (uLampSources[i].ambient.rgb * uLampSources[i].scale); + LDiffuse.rgb = LDiffuse.rgb + MDiffuse.rgb * (uLampSources[i].diffuse.rgb * uLampSources[i].scale) * max(0.0, dot(Ndirection, direction)) * attenuation; + } + + vec4 ambient = clamp(MAmbient * (uGlobalAmb + LAmbient), 0.0, 1.0); + vec4 diffuse = clamp(LDiffuse, 0.0, 1.0); + vec4 material = clamp(ambient + diffuse + MEmissive, 0.0, 1.0); + + vVtxColor = vec4(material.rgb, abs(uInvertVtxAlpha - MDiffuse.a)); + + vCamPosition = uMatrixW2C * (uMatrixL2W * vec4(aVtxPosition, 1.0)); + vCamNormal = uMatrixW2C * (uMatrixL2W * vec4(aVtxNormal, 0.0)); + + gl_Position = uMatrixProj * vCamPosition; +})"; + + +const char* FRAGMENT_SHADER_STRING = R"(#version 300 es +precision mediump float; +precision lowp int; + +uniform mat4 uLayerMat0; + +uniform mat4 uLayerMat[8]; +uniform int uLayerUVWSrc[8]; +uniform int uStartingLayer; +uniform int uLayersAtOnce; + +uniform sampler2D uTexture0; + +uniform float uAlphaThreshold; +uniform int uFogExponential; +uniform vec2 uFogValues; +uniform vec3 uFogColor; + +// Varying inputs +in vec4 vCamPosition; +in vec4 vCamNormal; +in vec4 vVtxColor; +in highp vec3 vVtxUVWSrc[8]; + +// Rendered outputs +out vec4 fragColor; + +void main() { + float baseAlpha; + vec4 coords0; + vec4 image0; + float currAlpha; + vec3 currColor; + + baseAlpha = vVtxColor.a; + coords0 = uLayerMat0 * vec4(vVtxUVWSrc[0], 1.0); + image0 = texture(uTexture0, coords0.xy); + currColor = image0.rgb; + currAlpha = image0.a * baseAlpha; + currColor = vVtxColor.rgb * currColor; + + if (currAlpha < uAlphaThreshold) { discard; }; + + float fogFactor = 1.0; + if (uFogExponential > 0) { + fogFactor = exp(-pow(uFogValues.y * length(vCamPosition.xyz), uFogValues.x)); + } else { + if (uFogValues.y > 0.0) { + float start = uFogValues.x; + float end = uFogValues.y; + fogFactor = (end - length(vCamPosition.xyz)) / (end - start); + } + } + + currColor = mix(currColor, uFogColor, 1.0 - clamp(fogFactor, 0.0, 1.0)); + + fragColor = vec4(currColor, currAlpha); +})"; + plGLMaterialShaderRef::plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe) : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(0), fFragShaderRef(0) { @@ -179,11 +323,16 @@ void plGLMaterialShaderRef::ICompile() LOG_GL_ERROR_CHECK(ST::format("Check Texture Ref on layer \"{}\" failed", layer->GetKeyName())); } +#ifndef USE_NEW_SHADERS ST::string vtx = fVertexShader->Render(); ST::string frg = fFragmentShader->Render(); const char* vs_code = vtx.c_str(); const char* fs_code = frg.c_str(); +#else + const char* vs_code = VERTEX_SHADER_STRING; + const char* fs_code = FRAGMENT_SHADER_STRING; +#endif fVertShaderRef = glCreateShader(GL_VERTEX_SHADER); glShaderSource(fVertShaderRef, 1, &vs_code, nullptr); @@ -248,6 +397,7 @@ void plGLMaterialShaderRef::ISetupShaderContexts() fVertexShader = std::make_shared(kVertex, kShaderVersion); fFragmentShader = std::make_shared(kFragment, kShaderVersion); +#ifndef USE_NEW_SHADERS // Helper function to invert colour auto invColor = std::make_shared("invColor", "vec3"); auto argColor = std::make_shared("color", "vec3", 0); @@ -275,35 +425,26 @@ void plGLMaterialShaderRef::ISetupShaderContexts() fVertexShader->PushStruct(lightSource); fFragmentShader->PushStruct(lightSource); +#endif } void plGLMaterialShaderRef::ISetShaderVariableLocs() { +#ifndef USE_NEW_SHADERS // Assign and bind the attribute locations for later glBindAttribLocation(fRef, kVtxPosition, "aVtxPosition"); glBindAttribLocation(fRef, kVtxNormal, "aVtxNormal"); glBindAttribLocation(fRef, kVtxColor, "aVtxColor"); - - glBindAttribLocation(fRef, kVtxUVWSrc0, "aVtxUVWSrc0"); - glBindAttribLocation(fRef, kVtxUVWSrc1, "aVtxUVWSrc1"); - glBindAttribLocation(fRef, kVtxUVWSrc2, "aVtxUVWSrc2"); - glBindAttribLocation(fRef, kVtxUVWSrc3, "aVtxUVWSrc3"); - glBindAttribLocation(fRef, kVtxUVWSrc4, "aVtxUVWSrc4"); - glBindAttribLocation(fRef, kVtxUVWSrc5, "aVtxUVWSrc5"); - glBindAttribLocation(fRef, kVtxUVWSrc6, "aVtxUVWSrc6"); - glBindAttribLocation(fRef, kVtxUVWSrc7, "aVtxUVWSrc7"); - glBindAttribLocation(fRef, kVtxUVWSrc8, "aVtxUVWSrc8"); - glBindAttribLocation(fRef, kVtxUVWSrc9, "aVtxUVWSrc9"); - glBindAttribLocation(fRef, kVtxUVWSrc10, "aVtxUVWSrc10"); - glBindAttribLocation(fRef, kVtxUVWSrc11, "aVtxUVWSrc11"); - glBindAttribLocation(fRef, kVtxUVWSrc12, "aVtxUVWSrc12"); + glBindAttribLocation(fRef, kVtxUVWSrc, "aVtxUVWSrc"); +#endif glLinkProgram(fRef); LOG_GL_ERROR_CHECK("Program Link failed"); uPassNumber = glGetUniformLocation(fRef, "uPassNumber"); uAlphaThreshold = glGetUniformLocation(fRef, "uAlphaThreshold"); + uInvertVtxAlpha = glGetUniformLocation(fRef, "uInvertVtxAlpha"); // Material inputs uGlobalAmbient = glGetUniformLocation(fRef, "uGlobalAmb"); @@ -316,6 +457,11 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() uMatSpecularCol = glGetUniformLocation(fRef, "uSpecularCol"); uMatSpecularSrc = glGetUniformLocation(fRef, "uSpecularSrc"); + // Fog inputs + uFogExponential = glGetUniformLocation(fRef, "uFogExponential"); + uFogValues = glGetUniformLocation(fRef, "uFogValues"); + uFogColor = glGetUniformLocation(fRef, "uFogColor"); + size_t layerCount = fMaterial->GetNumLayers(); uLayerMat.assign(layerCount, -1); @@ -364,7 +510,7 @@ void plGLMaterialShaderRef::ILoopOverLayers() vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); vertMain->PushOp(ASSIGN(vCamPos, pos)); - vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("0.0")))))); + vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("1.0")))))); vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); @@ -549,7 +695,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Handle High Alpha Threshold std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); - std::shared_ptr alphaTest = COND(IS_LEQ(sb.fCurrAlpha, alphaThreshold)); + std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); alphaTest->PushOp(CONSTANT("discard")); // if (final.a < alphaThreshold) { discard; } @@ -686,7 +832,8 @@ std::shared_ptr plGLMaterialShaderRef::ICalcLighting(std::sh fn->PushOp(ASSIGN(LAmbient, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); fn->PushOp(ASSIGN(LDiffuse, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); - fn->PushOp(ASSIGN(Ndirection, CALL("normalize", CALL("vec3", MUL(mW2L, CALL("vec4", anor, CONSTANT("1.0"))))))); + //fn->PushOp(ASSIGN(Ndirection, CALL("normalize", CALL("vec3", MUL(mW2L, CALL("vec4", anor, CONSTANT("1.0"))))))); + fn->PushOp(ASSIGN(Ndirection, CALL("normalize", MUL(CALL("mat3", mW2L), anor)))); for (size_t i = 0; i < 8; i++) { auto lamp = SUBVAL(uLampSources, ST::format("{}", i)); @@ -839,7 +986,7 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* uvwSrc &= plGBufferGroup::kUVCountMask; ST::string uvwName = ST::format("vVtxUVWSrc{}", uvwSrc); - std::shared_ptr layUVW = IFindVariable(uvwName, "vec3"); + std::shared_ptr layUVW = IFindVariable(uvwName, "highp vec3"); sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", layUVW, CONSTANT("1.0"))))); } @@ -868,16 +1015,16 @@ void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* l ST::string samplerName = ST::format("uTexture{}", idx); std::shared_ptr sampler = IFindVariable(samplerName, "sampler2D"); - // image = texture2D(sampler, coords.xy) - sb->fFunction->PushOp(ASSIGN(img, CALL("texture2D", sampler, PROP(sb->fCurrCoord, "xy")))); + // image = texture(sampler, coords.xy) + sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xy")))); } if ((cube = plCubicEnvironmap::ConvertNoRef(texture)) != nullptr) { ST::string samplerName = ST::format("uTexture{}", idx); std::shared_ptr sampler = IFindVariable(samplerName, "samplerCube"); - // image = texture3D(sampler, coords.xyz) - sb->fFunction->PushOp(ASSIGN(img, CALL("textureCube", sampler, PROP(sb->fCurrCoord, "xyz")))); + // image = texture(sampler, coords.xyz) + sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xyz")))); } } } @@ -1018,8 +1165,9 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil case hsGMatState::kBlendDot3: { - hsStatusMessage("Blend DOT3"); // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) + sb->fFunction->PushOp(ASSIGN(PROP(col, "r"), ASSIGN(PROP(col, "g"), ASSIGN(PROP(col, "b"), CALL("dot", PROP(col, "rgb"), PROP(sb->fPrevColor, "rgb")))))); + sb->fCurrColor = col; // alpha = prev sb->fCurrAlpha = sb->fPrevAlpha; @@ -1039,8 +1187,10 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil case hsGMatState::kBlendAddSigned2X: { - hsStatusMessage("Blend AddSigned2X"); // color = (color + prev - 0.5) << 1 + // Note: using CALL here for multiplication to ensure parentheses + sb->fFunction->PushOp(ASSIGN(col, CALL("2 *", SUB(ADD(texCol, sb->fPrevColor), CONSTANT("0.5"))))); + sb->fCurrColor = col; // alpha = prev sb->fCurrAlpha = sb->fPrevAlpha; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index fe1d7b73b8..4d4bde9bf4 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -59,20 +59,7 @@ enum plGLShaderConstants : GLuint { kVtxPosition = 0, kVtxNormal = 1, kVtxColor = 2, - - kVtxUVWSrc0, - kVtxUVWSrc1, - kVtxUVWSrc2, - kVtxUVWSrc3, - kVtxUVWSrc4, - kVtxUVWSrc5, - kVtxUVWSrc6, - kVtxUVWSrc7, - kVtxUVWSrc8, - kVtxUVWSrc9, - kVtxUVWSrc10, - kVtxUVWSrc11, - kVtxUVWSrc12 + kVtxUVWSrc = 3 }; class plGLMaterialShaderRef : public plGLDeviceRef @@ -129,6 +116,10 @@ class plGLMaterialShaderRef : public plGLDeviceRef GLuint uMatSpecularSrc; GLuint uPassNumber; GLuint uAlphaThreshold; + GLuint uInvertVtxAlpha; + GLuint uFogExponential; + GLuint uFogValues; + GLuint uFogColor; void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index b3bcb981e8..ab51ec4d95 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -627,8 +627,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, int numUVs = vRef->fOwner->GetNumUVs(); for (int i = 0; i < numUVs; i++) { - glEnableVertexAttribArray(kVtxUVWSrc0 + i); - glVertexAttribPointer(kVtxUVWSrc0 + i, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); + glEnableVertexAttribArray(kVtxUVWSrc + i); + glVertexAttribPointer(kVtxUVWSrc + i, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); } LOG_GL_ERROR_CHECK("Vertex Attributes failed") @@ -648,6 +648,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, if (mRef->uPassNumber != -1) glUniform1i(mRef->uPassNumber, pass); + glUniform1f(mRef->uInvertVtxAlpha, 0.f); + plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); ICalcLighting(mRef, lay, &span); @@ -667,9 +669,9 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, // some transparency falloff, but quit drawing before it gets so // transparent that draw order problems (halos) become apparent. if (s.fBlendFlags & hsGMatState::kBlendAlphaTestHigh) - glUniform1f(mRef->uAlphaThreshold, 40.f/255.f); + glUniform1f(mRef->uAlphaThreshold, 64.f/255.f); else - glUniform1f(mRef->uAlphaThreshold, 1.f/255.f); + glUniform1f(mRef->uAlphaThreshold, 0.f); } else { glUniform1f(mRef->uAlphaThreshold, 0.f); } @@ -725,9 +727,11 @@ void plGLPipeline::IHandleZMode(hsGMatState flags) int32_t int_value = 8; float value = *(float*)(&int_value); - glPolygonOffset(0.f, value); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.f, 1.f); } else { glPolygonOffset(0.f, 0.f); + glDisable(GL_POLYGON_OFFSET_FILL); } } @@ -943,6 +947,50 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter break; } } + + // Piggy-back some temporary fog stuff on the lighting... + const plFogEnvironment* fog = (currSpan ? (currSpan->fFogEnvironment ? currSpan->fFogEnvironment : &fView.GetDefaultFog()) : nullptr); + uint8_t type = fog ? fog->GetType() : plFogEnvironment::kNoFog; + hsColorRGBA color; + + switch (type) { + case plFogEnvironment::kLinearFog: + { + float start, end; + fog->GetPipelineParams(&start, &end, &color); + + if (mRef->uFogExponential != -1) + glUniform1i(mRef->uFogExponential, 0); + if (mRef->uFogValues != -1) + glUniform2f(mRef->uFogValues, start, end); + if (mRef->uFogColor != -1) + glUniform3f(mRef->uFogColor, color.r, color.g, color.b); + break; + } + case plFogEnvironment::kExpFog: + case plFogEnvironment::kExp2Fog: + { + float density; + float power = (type == plFogEnvironment::kExp2Fog) ? 2.0f : 1.0f; + fog->GetPipelineParams(&density, &color); + + if (mRef->uFogExponential != -1) + glUniform1i(mRef->uFogExponential, 1); + if (mRef->uFogValues != -1) + glUniform2f(mRef->uFogValues, power, density); + if (mRef->uFogColor != -1) + glUniform3f(mRef->uFogColor, color.r, color.g, color.b); + break; + } + default: + if (mRef->uFogExponential != -1) + glUniform1i(mRef->uFogExponential, 0); + if (mRef->uFogValues != -1) + glUniform2f(mRef->uFogValues, 0.0, 0.0); + if (mRef->uFogColor != -1) + glUniform3f(mRef->uFogColor, 0.0, 0.0, 0.0); + break; + } } void plGLPipeline::ISelectLights(const plSpan* span, bool proj) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index 985241ed0e..6fd21c85f5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -100,17 +100,17 @@ void plGLPlateManager::ICreateGeometry() glEnableVertexArrayAttrib(vao, kVtxPosition); glEnableVertexArrayAttrib(vao, kVtxNormal); glEnableVertexArrayAttrib(vao, kVtxColor); - glEnableVertexArrayAttrib(vao, kVtxUVWSrc0); + glEnableVertexArrayAttrib(vao, kVtxUVWSrc); glVertexArrayAttribFormat(vao, kVtxPosition, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fPoint)); glVertexArrayAttribFormat(vao, kVtxNormal, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fNormal)); glVertexArrayAttribFormat(vao, kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(plPlateVertex, fColor)); - glVertexArrayAttribFormat(vao, kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fUV)); + glVertexArrayAttribFormat(vao, kVtxUVWSrc, 3, GL_FLOAT, GL_FALSE, offsetof(plPlateVertex, fUV)); glVertexArrayAttribBinding(vao, kVtxPosition, 0); glVertexArrayAttribBinding(vao, kVtxNormal, 0); glVertexArrayAttribBinding(vao, kVtxColor, 0); - glVertexArrayAttribBinding(vao, kVtxUVWSrc0, 0); + glVertexArrayAttribBinding(vao, kVtxUVWSrc, 0); } else { if (epoxy_gl_version() >= 30) { glGenVertexArrays(1, &vao); @@ -135,8 +135,8 @@ void plGLPlateManager::ICreateGeometry() glEnableVertexAttribArray(kVtxColor); glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3 * 2)); - glEnableVertexAttribArray(kVtxUVWSrc0); - glVertexAttribPointer(kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); + glEnableVertexAttribArray(kVtxUVWSrc); + glVertexAttribPointer(kVtxUVWSrc, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); glBindVertexArray(0); } @@ -152,7 +152,7 @@ void plGLPlateManager::IReleaseGeometry() glDisableVertexArrayAttrib(fBuffers.ARef, kVtxPosition); glDisableVertexArrayAttrib(fBuffers.ARef, kVtxNormal); glDisableVertexArrayAttrib(fBuffers.ARef, kVtxColor); - glDisableVertexArrayAttrib(fBuffers.ARef, kVtxUVWSrc0); + glDisableVertexArrayAttrib(fBuffers.ARef, kVtxUVWSrc); } glDeleteVertexArrays(1, &fBuffers.ARef); @@ -201,8 +201,8 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3 * 2)); glEnableVertexAttribArray(kVtxColor); - glVertexAttribPointer(kVtxUVWSrc0, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); - glEnableVertexAttribArray(kVtxUVWSrc0); + glVertexAttribPointer(kVtxUVWSrc, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)((sizeof(float) * 3 * 2) + sizeof(uint32_t))); + glEnableVertexAttribArray(kVtxUVWSrc); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBuffers.IRef); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp index 57f8bd340e..7e8f4f1ec5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -218,7 +218,8 @@ ST::string plShaderContext::Render() ST::string_stream out; - out << ST::format("#version {}\n", this->version); + //out << ST::format("#version {}\n", this->version); + out << "#version 300 es\n"; if (this->type == kFragment) out << "precision mediump float;\n"; From 726c12cf4364f90f372b7cc6cf52117c616c3f7e Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 27 Dec 2020 01:38:03 -0800 Subject: [PATCH 39/76] Fix up some GL issues with skinned meshes --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 33 +++++++++++++++++-- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 29 ++++++++++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index e9bd7367fb..873fc20488 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -480,12 +480,11 @@ void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, Verte // will have indices, but we strip them out for the D3D buffer. if (format & plGBufferGroup::kSkinIndices) { hsStatusMessage("Have to deal with skinning :("); -#if 0 + format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... vRef->SetSkinned(true); vRef->SetVolatile(true); -#endif } @@ -599,7 +598,35 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* void plGLDevice::FillVolatileVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* group, uint32_t idx) { - hsStatusMessage("Trying to fill volatile vertex buffer ref!"); + uint8_t* dst = ref->fData; + uint8_t* src = group->GetVertBufferData(idx); + + size_t uvChanSize = plGBufferGroup::CalcNumUVs(group->GetVertexFormat()) * sizeof(float) * 3; + uint8_t numWeights = (group->GetVertexFormat() & plGBufferGroup::kSkinWeightMask) >> 4; + + for (uint32_t i = 0; i < ref->fCount; ++i) { + memcpy(dst, src, sizeof(hsPoint3)); // pre-pos + dst += sizeof(hsPoint3); + src += sizeof(hsPoint3); + + src += numWeights * sizeof(float); // weights + + if (group->GetVertexFormat() & plGBufferGroup::kSkinIndices) + src += sizeof(uint32_t); // indices + + memcpy(dst, src, sizeof(hsVector3)); // pre-normal + dst += sizeof(hsVector3); + src += sizeof(hsVector3); + + memcpy(dst, src, sizeof(uint32_t) * 2); // diffuse & specular + dst += sizeof(uint32_t) * 2; + src += sizeof(uint32_t) * 2; + + // UVWs + memcpy(dst, src, uvChanSize); + src += uvChanSize; + dst += uvChanSize; + } } void plGLDevice::SetupIndexBufferRef(plGBufferGroup* owner, uint32_t idx, IndexBufferRef* iRef) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index ab51ec4d95..476aaf83e3 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -619,16 +619,39 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, glEnableVertexAttribArray(kVtxPosition); glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, 0); + size_t weight_offset = 0; + switch (vRef->fFormat & plGBufferGroup::kSkinWeightMask) + { + case plGBufferGroup::kSkinNoWeights: + break; + case plGBufferGroup::kSkin1Weight: + weight_offset += sizeof(float); + break; + case plGBufferGroup::kSkin2Weights: + weight_offset += sizeof(float) * 2; + break; + case plGBufferGroup::kSkin3Weights: + weight_offset += sizeof(float) * 3; + break; + default: + hsAssert( false, "Bad skin weight value in GBufferGroup" ); + } + + if (vRef->fFormat & plGBufferGroup::kSkinIndices) { + hsAssert(false, "Indexed skinning not supported"); + weight_offset += sizeof(uint32_t); + } + glEnableVertexAttribArray(kVtxNormal); - glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)(sizeof(float) * 3)); + glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3) + weight_offset)); glEnableVertexAttribArray(kVtxColor); - glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)(sizeof(float) * 3 * 2)); + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + weight_offset)); int numUVs = vRef->fOwner->GetNumUVs(); for (int i = 0; i < numUVs; i++) { glEnableVertexAttribArray(kVtxUVWSrc + i); - glVertexAttribPointer(kVtxUVWSrc + i, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i))); + glVertexAttribPointer(kVtxUVWSrc + i, 3, GL_FLOAT, GL_FALSE, vRef->fVertexSize, (void*)((sizeof(float) * 3 * 2) + (sizeof(uint32_t) * 2) + (sizeof(float) * 3 * i) + weight_offset)); } LOG_GL_ERROR_CHECK("Vertex Attributes failed") From 4d53e46e48f2e3a2284dff3d08c6b7f248fcdcc8 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 27 Dec 2020 16:54:30 -0800 Subject: [PATCH 40/76] Working spot lights --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 46 ++++++++++++++----- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 23 +++++++++- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 4672c538ec..100eb15cb5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -73,6 +73,8 @@ struct lightSource { vec4 ambient; vec4 diffuse; vec4 specular; + vec3 direction; + vec3 spotProps; // (falloff, theta, phi) float constAtten; float linAtten; float quadAtten; @@ -125,11 +127,31 @@ void main() { for (int i = 0; i < 8; i++) { vVtxUVWSrc[i] = aVtxUVWSrc[i]; - vec3 v2l = vec3(uLampSources[i].position - (uMatrixL2W * vec4(aVtxPosition, 1.0)) * uLampSources[i].position.w); - float distance = length(v2l); - vec3 direction = normalize(v2l); + float attenuation; + vec3 direction; - float attenuation = mix(1.0, 1.0 / (uLampSources[i].constAtten + uLampSources[i].linAtten * distance + uLampSources[i].quadAtten * distance * distance), uLampSources[i].position.w); + if (uLampSources[i].position.w == 0.0) { + // Directional Light with no attenuation + direction = normalize(uLampSources[i].direction); + attenuation = 1.0; + } else { + // Omni Light in all directions + vec3 v2l = uLampSources[i].position.xyz - vec3(uMatrixL2W * vec4(aVtxPosition, 1.0)); + float distance = length(v2l); + direction = normalize(v2l); + + attenuation = 1.0 / (uLampSources[i].constAtten + uLampSources[i].linAtten * distance + uLampSources[i].quadAtten * pow(distance, 2.0)); + + if (uLampSources[i].spotProps.x > 0.0) { + // Spot Light with cone falloff + float a = dot(direction, normalize(-uLampSources[i].direction)); + float theta = uLampSources[i].spotProps.y; + float phi = uLampSources[i].spotProps.z; + float i = pow((a - phi) / (theta - phi), uLampSources[i].spotProps.x); + + attenuation *= clamp(i, 0.0, 1.0); + } + } LAmbient.rgb = LAmbient.rgb + attenuation * (uLampSources[i].ambient.rgb * uLampSources[i].scale); LDiffuse.rgb = LDiffuse.rgb + MDiffuse.rgb * (uLampSources[i].diffuse.rgb * uLampSources[i].scale) * max(0.0, dot(Ndirection, direction)) * attenuation; @@ -163,12 +185,12 @@ uniform sampler2D uTexture0; uniform float uAlphaThreshold; uniform int uFogExponential; -uniform vec2 uFogValues; +uniform highp vec2 uFogValues; uniform vec3 uFogColor; // Varying inputs -in vec4 vCamPosition; -in vec4 vCamNormal; +in highp vec4 vCamPosition; +in highp vec4 vCamNormal; in vec4 vVtxColor; in highp vec3 vVtxUVWSrc[8]; @@ -191,13 +213,13 @@ void main() { if (currAlpha < uAlphaThreshold) { discard; }; - float fogFactor = 1.0; + highp float fogFactor = 1.0; if (uFogExponential > 0) { fogFactor = exp(-pow(uFogValues.y * length(vCamPosition.xyz), uFogValues.x)); } else { if (uFogValues.y > 0.0) { - float start = uFogValues.x; - float end = uFogValues.y; + highp float start = uFogValues.x; + highp float end = uFogValues.y; fogFactor = (end - length(vCamPosition.xyz)) / (end - start); } } @@ -418,6 +440,8 @@ void plGLMaterialShaderRef::ISetupShaderContexts() lightSource->AddField(STRUCTVAR("vec4", "ambient")); lightSource->AddField(STRUCTVAR("vec4", "diffuse")); lightSource->AddField(STRUCTVAR("vec4", "specular")); + lightSource->AddField(STRUCTVAR("vec3", "direction")); + lightSource->AddField(STRUCTVAR("vec3", "spotProps")); lightSource->AddField(STRUCTVAR("float", "constAtten")); lightSource->AddField(STRUCTVAR("float", "linAtten")); lightSource->AddField(STRUCTVAR("float", "quadAtten")); @@ -838,7 +862,7 @@ std::shared_ptr plGLMaterialShaderRef::ICalcLighting(std::sh for (size_t i = 0; i < 8; i++) { auto lamp = SUBVAL(uLampSources, ST::format("{}", i)); - fn->PushOp(ASSIGN(v2l, CALL("vec3", SUB(PROP(lamp, "position"), MUL(mL2W, MUL(CALL("vec4", apos, CONSTANT("1.0")), PROP(PROP(lamp, "position"), "w"))))))); + fn->PushOp(ASSIGN(v2l, SUB(CALL("vec3", PROP(lamp, "position")), CALL("vec3", MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))))); fn->PushOp(ASSIGN(distance, CALL("length", v2l))); fn->PushOp(ASSIGN(direction, CALL("normalize", v2l))); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 476aaf83e3..eeafec89fd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -1075,6 +1075,8 @@ void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) GLuint ambient = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].ambient", i).c_str()); GLuint diffuse = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].diffuse", i).c_str()); GLuint specular = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].specular", i).c_str()); + GLuint direction = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].direction", i).c_str()); + GLuint spotProps = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].spotProps", i).c_str()); GLuint constAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].constAtten", i).c_str()); GLuint linAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].linAtten", i).c_str()); GLuint quadAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].quadAtten", i).c_str()); @@ -1091,11 +1093,13 @@ void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) plDirectionalLightInfo* dirLight = nullptr; plOmniLightInfo* omniLight = nullptr; + plSpotLightInfo* spotLight = nullptr; if ((dirLight = plDirectionalLightInfo::ConvertNoRef(light)) != nullptr) { - hsVector3 direction = dirLight->GetWorldDirection(); - glUniform4f(position, direction.fX, direction.fY, direction.fZ, 0.0); + hsVector3 lightDir = dirLight->GetWorldDirection(); + glUniform4f(position, lightDir.fX, lightDir.fY, lightDir.fZ, 0.0); + glUniform3f(direction, lightDir.fX, lightDir.fY, lightDir.fZ); glUniform1f(constAtten, 1.0f); glUniform1f(linAtten, 0.0f); @@ -1111,6 +1115,19 @@ void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) glUniform1f(constAtten, omniLight->GetConstantAttenuation()); glUniform1f(linAtten, omniLight->GetLinearAttenuation()); glUniform1f(quadAtten, omniLight->GetQuadraticAttenuation()); + + if (!omniLight->GetProjection() && (spotLight = plSpotLightInfo::ConvertNoRef(omniLight)) != nullptr) { + hsVector3 lightDir = spotLight->GetWorldDirection(); + glUniform3f(direction, lightDir.fX, lightDir.fY, lightDir.fZ); + + float falloff = spotLight->GetFalloff(); + float theta = cosf(spotLight->GetSpotInner()); + float phi = cosf(spotLight->GetProjection() ? hsConstants::half_pi : spotLight->GetSpotOuter()); + + glUniform3f(spotProps, falloff, theta, phi); + } else { + glUniform3f(spotProps, 0.0, 0.0, 0.0); + } } else { IDisableLight(i); @@ -1140,6 +1157,8 @@ void plGLPipeline::IDisableLight(size_t i) void plGLPipeline::IScaleLight(size_t i, float scale) { + scale = int(scale * 1.e1f) * 1.e-1f; + GLuint uniform = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); if (uniform != -1) glUniform1f(uniform, scale); } From 67450131feb9cc9e9b38a4a15b8173c28849ac69 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 27 Dec 2020 16:55:15 -0800 Subject: [PATCH 41/76] Mostly working dynamic vertex buffers --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 - .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 67 ++++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 15 +++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 873fc20488..ca014cc2e1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -479,8 +479,6 @@ void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, Verte // All indexed skinning is currently done on CPU, so the source data // will have indices, but we strip them out for the D3D buffer. if (format & plGBufferGroup::kSkinIndices) { - hsStatusMessage("Have to deal with skinning :("); - format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... vRef->SetSkinned(true); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index eeafec89fd..9629210b41 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -299,6 +299,8 @@ bool plGLPipeline::BeginRender() if (fInSceneDepth++ == 0) { fDevice.BeginRender(); + fVtxRefTime++; + hsColorRGBA clearColor = GetClearColor(); glDepthMask(GL_TRUE); @@ -507,9 +509,9 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& plProfile_EndTiming(SpanTransforms); // Check that the underlying buffers are ready to go. - //plProfile_BeginTiming(CheckDyn); - //ICheckDynBuffers(drawable, drawable->GetBufferGroup(tempIce.fGroupIdx), &tempIce); - //plProfile_EndTiming(CheckDyn); + plProfile_BeginTiming(CheckDyn); + ICheckDynBuffers(ice, ice->GetBufferGroup(tempIce.fGroupIdx), &tempIce); + plProfile_EndTiming(CheckDyn); plProfile_BeginTiming(CheckStat); plGBufferGroup* grp = ice->GetBufferGroup(tempIce.fGroupIdx); @@ -712,6 +714,65 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, LOG_GL_ERROR_CHECK("Render failed") } +bool plGLPipeline::ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* group, const plSpan* spanBase) +{ + if (!(spanBase->fTypeMask & plSpan::kVertexSpan)) + return false; + + // If we arent' an trilist, we're toast. + if (!(spanBase->fTypeMask & plSpan::kIcicleSpan)) + return false; + + plIcicle* span = (plIcicle*)spanBase; + + DeviceType::VertexBufferRef* vRef = (DeviceType::VertexBufferRef*)group->GetVertexBufferRef(span->fVBufferIdx); + if (!vRef) + return true; + + DeviceType::IndexBufferRef* iRef = (DeviceType::IndexBufferRef*)group->GetIndexBufferRef(span->fIBufferIdx); + if (!iRef) + return true; + + // If our vertex buffer ref is volatile and the timestamp is off + // then it needs to be refilled + if (vRef->Expired(fVtxRefTime)) + IRefreshDynVertices(group, vRef); + + if (iRef->IsDirty()) { + fDevice.FillIndexBufferRef(iRef, group, span->fIBufferIdx); + iRef->SetRebuiltSinceUsed(true); + } + + return false; // No error +} + +bool plGLPipeline::IRefreshDynVertices(plGBufferGroup* group, plGLVertexBufferRef* vRef) +{ + ptrdiff_t size = (group->GetVertBufferEnd(vRef->fIndex) - group->GetVertBufferStart(vRef->fIndex)) * vRef->fVertexSize; + if (!size) + return false; // No error, just nothing to do. + + hsAssert(size > 0, "Bad start and end counts in a group"); + + if (!vRef->fRef) + glGenBuffers(1, &vRef->fRef); + + glBindBuffer(GL_ARRAY_BUFFER, vRef->fRef); + + uint8_t* vData; + if (vRef->fData) + vData = vRef->fData; + else + vData = group->GetVertBufferData(vRef->fIndex) + group->GetVertBufferStart(vRef->fIndex) * vRef->fVertexSize; + + glBufferData(GL_ARRAY_BUFFER, size, vData, GL_DYNAMIC_DRAW); + + vRef->fRefTime = fVtxRefTime; + vRef->SetDirty(false); + + return false; +} + void plGLPipeline::IHandleZMode(hsGMatState flags) { switch (flags.fZFlags & hsGMatState::kZMask) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 28f198bcc1..e4d287ea85 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -48,6 +48,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com class plIcicle; class plGLMaterialShaderRef; +class plGLVertexBufferRef; class plPlate; class plGLEnumerate @@ -111,6 +112,20 @@ class plGLPipeline : public pl3DPipeline protected: void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, hsGDeviceRef* ib, hsGMaterial* material, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength); + + /** + * Only software skinned objects, dynamic decals, and particle systems + * currently use the dynamic vertex buffer. + */ + bool IRefreshDynVertices(plGBufferGroup* group, plGLVertexBufferRef* vRef); + + /** + * Make sure the buffers underlying this span are ready to be rendered. + * Meaning that the underlying GL buffers are in sync with the plasma + * buffers. + */ + bool ICheckDynBuffers(plDrawableSpans* drawable, plGBufferGroup* group, const plSpan* span); + void IHandleZMode(hsGMatState flags); void IHandleBlendMode(hsGMatState flags); void ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); From 4f54731ff33e55a0651b641080da5c33d4efb46c Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 27 Dec 2020 22:00:16 -0800 Subject: [PATCH 42/76] Always use the new vertex shader --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 100eb15cb5..7784cc30b4 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -60,7 +60,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" -#define USE_NEW_SHADERS 1 +//#define USE_NEW_SHADERS 1 // From plGLDevice.cpp extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); @@ -345,14 +345,15 @@ void plGLMaterialShaderRef::ICompile() LOG_GL_ERROR_CHECK(ST::format("Check Texture Ref on layer \"{}\" failed", layer->GetKeyName())); } + const char* vs_code = VERTEX_SHADER_STRING; + #ifndef USE_NEW_SHADERS - ST::string vtx = fVertexShader->Render(); + //ST::string vtx = fVertexShader->Render(); ST::string frg = fFragmentShader->Render(); - const char* vs_code = vtx.c_str(); + //const char* vs_code = vtx.c_str(); const char* fs_code = frg.c_str(); #else - const char* vs_code = VERTEX_SHADER_STRING; const char* fs_code = FRAGMENT_SHADER_STRING; #endif @@ -448,7 +449,6 @@ void plGLMaterialShaderRef::ISetupShaderContexts() lightSource->AddField(STRUCTVAR("float", "scale")); fVertexShader->PushStruct(lightSource); - fFragmentShader->PushStruct(lightSource); #endif } @@ -1009,10 +1009,8 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* { uvwSrc &= plGBufferGroup::kUVCountMask; - ST::string uvwName = ST::format("vVtxUVWSrc{}", uvwSrc); - std::shared_ptr layUVW = IFindVariable(uvwName, "highp vec3"); - - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", layUVW, CONSTANT("1.0"))))); + std::shared_ptr layUVW = IFindVariable("vVtxUVWSrc", "highp vec3", 8); + sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", SUBVAL(layUVW, ST::format("{}", uvwSrc)), CONSTANT("1.0"))))); } break; } From de5ff06d5baeca67721d254bb34bda95c3484dee Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Mon, 28 Dec 2020 09:26:40 -0800 Subject: [PATCH 43/76] Initial set of changes to get desktop OpenGL working --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 12 +++--- .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 37 ++++++++++++++++--- .../FeatureLib/pfGLPipeline/plShaderNode.h | 7 ++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 7784cc30b4..35446f3e8e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -65,7 +65,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com // From plGLDevice.cpp extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); -const char* VERTEX_SHADER_STRING = R"(#version 300 es +const char* VERTEX_SHADER_STRING = R"(#version 330 precision lowp int; struct lightSource { @@ -170,7 +170,7 @@ void main() { })"; -const char* FRAGMENT_SHADER_STRING = R"(#version 300 es +const char* FRAGMENT_SHADER_STRING = R"(#version 330 precision mediump float; precision lowp int; @@ -549,7 +549,7 @@ void plGLMaterialShaderRef::ILoopOverLayers() for (j = 0; j < fMaterial->GetNumLayers(); ) { size_t iCurrMat = j; - std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "void"); + std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "vec4"); std::shared_ptr vertPass = std::make_shared(ST::format("pass{}", pass), "void"); j = IHandleMaterial(iCurrMat, vertPass, fragPass); @@ -561,7 +561,9 @@ void plGLMaterialShaderRef::ILoopOverLayers() fFragmentShader->PushFunction(fragPass); std::shared_ptr passCond = COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass)))); - passCond->PushOp(CALL(fragPass->name)); + + std::shared_ptr output = IFindVariable("fragColor", "vec4"); + passCond->PushOp(ASSIGN(output, CALL(fragPass->name))); // if (uPassNumber == curpass) { curpass(); } fragMain->PushOp(passCond); @@ -734,7 +736,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< finalColor = PROP(vVtxColor, "rgb"); } - sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragColor"), CALL("vec4", finalColor, sb.fCurrAlpha))); + sb.fFunction->PushOp(RETURN(CALL("vec4", finalColor, sb.fCurrAlpha))); return layer + currNumLayers; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp index 7e8f4f1ec5..ac776768f0 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp @@ -92,6 +92,16 @@ ST::string plShaderContext::RenderNode(std::shared_ptr node, std:: } break; + case kOutputVariable: + { + std::shared_ptr var = static_pointer_cast(node); + + this->outputVariables.insert(var); + + return var->name; + } + break; + case kTempVar: { std::shared_ptr tmp = static_pointer_cast(node); @@ -219,7 +229,7 @@ ST::string plShaderContext::Render() ST::string_stream out; //out << ST::format("#version {}\n", this->version); - out << "#version 300 es\n"; + out << "#version 330\n"; if (this->type == kFragment) out << "precision mediump float;\n"; @@ -252,10 +262,27 @@ ST::string plShaderContext::Render() } for (std::shared_ptr node : this->varyings) { - if (node->count > 1) - out << ST::format("varying {} {}[{}];\n", node->type, node->name, node->count); - else - out << ST::format("varying {} {};\n", node->type, node->name); + if (node->count > 1) { + if (this->type == kVertex) { + out << ST::format("out {} {}[{}];\n", node->type, node->name, node->count); + } else { + out << ST::format("in {} {}[{}];\n", node->type, node->name, node->count); + } + } else { + if (this->type == kVertex) { + out << ST::format("out {} {};\n", node->type, node->name); + } else { + out << ST::format("in {} {};\n", node->type, node->name); + } + } + } + + for (std::shared_ptr node : this->outputVariables) { + if (node->count > 1) { + out << ST::format("out {} {}[{}];\n", node->type, node->name, node->count); + } else { + out << ST::format("out {} {};\n", node->type, node->name); + } } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h index 6cb9dedff1..1544748a70 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h @@ -60,6 +60,7 @@ enum NodeType { kAttribute, kVarying, kUniform, + kOutputVariable, kTempVar, kArgument, kFnCall, @@ -139,6 +140,11 @@ class plVaryingNode : public plGlobalVariableNode { : plGlobalVariableNode(kVarying, name, type, n) { } }; +class plOutputVariableNode : public plGlobalVariableNode { +public: + plOutputVariableNode(ST::string name, ST::string type, size_t n = 1) + : plGlobalVariableNode(kOutputVariable, name, type, n) { } +}; class plTempVariableNode : public plVariableNode { public: @@ -294,6 +300,7 @@ class plShaderContext : public std::enable_shared_from_this std::set> attributes; std::set> uniforms; std::set> varyings; + std::set> outputVariables; public: plShaderContext(CtxType type, int32_t version) : type(type), version(version) { } From 571e90626fe3d393be4e90830ca3859efcfa9211 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 2 Jan 2021 00:30:13 -0800 Subject: [PATCH 44/76] Cache the matrix locations from the shader --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 7 +++ .../pfGLPipeline/plGLMaterialShaderRef.h | 5 ++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 50 ++++++------------- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 2 +- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 35446f3e8e..68d1fb1053 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -470,6 +470,13 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() uAlphaThreshold = glGetUniformLocation(fRef, "uAlphaThreshold"); uInvertVtxAlpha = glGetUniformLocation(fRef, "uInvertVtxAlpha"); + // Matrix inputs + uMatrixProj = glGetUniformLocation(fRef, "uMatrixProj"); + uMatrixC2W = glGetUniformLocation(fRef, "uMatrixC2W"); + uMatrixW2C = glGetUniformLocation(fRef, "uMatrixW2C"); + uMatrixL2W = glGetUniformLocation(fRef, "uMatrixL2W"); + uMatrixW2L = glGetUniformLocation(fRef, "uMatrixW2L"); + // Material inputs uGlobalAmbient = glGetUniformLocation(fRef, "uGlobalAmb"); uMatAmbientCol = glGetUniformLocation(fRef, "uAmbientCol"); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 4d4bde9bf4..22a7767142 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -105,6 +105,11 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::vector aVtxUVWSrc; // These are indexed by UV chan std::vector uLayerMat; // These are indexed by layer std::vector uTexture; // These are indexed by layer + GLuint uMatrixProj; + GLuint uMatrixC2W; + GLuint uMatrixW2C; + GLuint uMatrixL2W; + GLuint uMatrixW2L; GLuint uGlobalAmbient; GLuint uMatAmbientCol; GLuint uMatAmbientSrc; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 9629210b41..759a6ad27c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -505,7 +505,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& // What do we change? plProfile_BeginTiming(SpanTransforms); - ISetupTransforms(ice, tempIce, lastL2W); + ISetupTransforms(ice, tempIce, mRef, lastL2W); plProfile_EndTiming(SpanTransforms); // Check that the underlying buffers are ready to go. @@ -540,7 +540,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& } -void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W) +void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, plGLMaterialShaderRef* mRef, hsMatrix44& lastL2W) { if (span.fNumMatrices) { if (span.fNumMatrices <= 2) { @@ -569,26 +569,15 @@ void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& spa } #endif - if (fDevice.fCurrentProgram) { + if (mRef) { /* Push the matrices into the GLSL shader now */ - GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixProj"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixProj); + glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, fDevice.fMatrixProj); + glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.fMatrixW2C); + glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.fMatrixL2W); + glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.fMatrixW2L); - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2C"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixC2W"); - if (uniform != -1) { - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixC2W); - } - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2L"); - if (uniform != -1) { - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2L); - } + if (mRef->uMatrixC2W != -1) + glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.fMatrixC2W); } } @@ -1258,22 +1247,13 @@ void plGLPipeline::IDrawPlate(plPlate* plate) mRef->SetupTextureRefs(); /* Push the matrices into the GLSL shader now */ - GLint uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixProj"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, projMat); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2C"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2C); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixC2W"); - if (uniform != -1) - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixC2W); - - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixL2W"); - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixL2W); + glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, projMat); + glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.fMatrixW2C); + glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.fMatrixC2W); + glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.fMatrixL2W); - uniform = glGetUniformLocation(fDevice.fCurrentProgram, "uMatrixW2L"); - if (uniform != -1) - glUniformMatrix4fv(uniform, 1, GL_TRUE, fDevice.fMatrixW2L); + if (mRef->uMatrixW2L != -1) + glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.fMatrixW2L); glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index e4d287ea85..3b7265c9f5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -110,7 +110,7 @@ class plGLPipeline : public pl3DPipeline void RenderSpans(plDrawableSpans* ice, const std::vector& visList) override; protected: - void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); + void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, plGLMaterialShaderRef* mRef, hsMatrix44& lastL2W); void IRenderBufferSpan(const plIcicle& span, hsGDeviceRef* vb, hsGDeviceRef* ib, hsGMaterial* material, uint32_t vStart, uint32_t vLength, uint32_t iStart, uint32_t iLength); /** From e636d2713d2ff24a26ebd3c5ccb62ebfe07e9565 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 2 Jan 2021 02:19:38 -0800 Subject: [PATCH 45/76] Cache the lamp uniforms too --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 14 +++ .../pfGLPipeline/plGLMaterialShaderRef.h | 14 +++ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 90 +++++++------------ .../FeatureLib/pfGLPipeline/plGLPipeline.h | 8 +- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 68d1fb1053..4f3f1c3f5f 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -493,6 +493,20 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() uFogValues = glGetUniformLocation(fRef, "uFogValues"); uFogColor = glGetUniformLocation(fRef, "uFogColor"); + // Lamp inputs + for (size_t i = 0; i < 8; i++) { + uLampSources[i].position = glGetUniformLocation(fRef, ST::format("uLampSources[{}].position", i).c_str()); + uLampSources[i].ambient = glGetUniformLocation(fRef, ST::format("uLampSources[{}].ambient", i).c_str()); + uLampSources[i].diffuse = glGetUniformLocation(fRef, ST::format("uLampSources[{}].diffuse", i).c_str()); + uLampSources[i].specular = glGetUniformLocation(fRef, ST::format("uLampSources[{}].specular", i).c_str()); + uLampSources[i].direction = glGetUniformLocation(fRef, ST::format("uLampSources[{}].direction", i).c_str()); + uLampSources[i].spotProps = glGetUniformLocation(fRef, ST::format("uLampSources[{}].spotProps", i).c_str()); + uLampSources[i].constAtten = glGetUniformLocation(fRef, ST::format("uLampSources[{}].constAtten", i).c_str()); + uLampSources[i].linAtten = glGetUniformLocation(fRef, ST::format("uLampSources[{}].linAtten", i).c_str()); + uLampSources[i].quadAtten = glGetUniformLocation(fRef, ST::format("uLampSources[{}].quadAtten", i).c_str()); + uLampSources[i].scale = glGetUniformLocation(fRef, ST::format("uLampSources[{}].scale", i).c_str()); + } + size_t layerCount = fMaterial->GetNumLayers(); uLayerMat.assign(layerCount, -1); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 22a7767142..210f75fa37 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -85,6 +85,19 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::shared_ptr fCurrImage; }; + struct uniformLightSource { + GLuint position; + GLuint ambient; + GLuint diffuse; + GLuint specular; + GLuint direction; + GLuint spotProps; + GLuint constAtten; + GLuint linAtten; + GLuint quadAtten; + GLuint scale; + }; + protected: hsGMaterial* fMaterial; plPipeline* fPipeline; @@ -125,6 +138,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef GLuint uFogExponential; GLuint uFogValues; GLuint uFogColor; + uniformLightSource uLampSources[8]; void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 759a6ad27c..be2b75b84d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -655,7 +655,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plProfile_EndTiming(RenderBuff); // Turn on this spans lights and turn off the rest. - ISelectLights(&span); + ISelectLights(&span, mRef); for (size_t pass = 0; pass < mRef->GetNumPasses(); pass++) { // Set uniform to pass @@ -1066,7 +1066,7 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter } } -void plGLPipeline::ISelectLights(const plSpan* span, bool proj) +void plGLPipeline::ISelectLights(const plSpan* span, plGLMaterialShaderRef* mRef, bool proj) { const size_t numLights = 8; size_t i = 0; @@ -1082,7 +1082,7 @@ void plGLPipeline::ISelectLights(const plSpan* span, bool proj) std::vector& spanLights = span->GetLightList(proj); for (i = 0; i < spanLights.size() && i < numLights; i++) { - IEnableLight(i, spanLights[i]); + IEnableLight(mRef, i, spanLights[i]); } startScale = i; @@ -1102,7 +1102,7 @@ void plGLPipeline::ISelectLights(const plSpan* span, bool proj) for (; i > 0 && span->GetLightStrength(i, proj) < overHold; i--) { scale = (overHold - span->GetLightStrength(i, proj)) / (overHold - threshhold); - IScaleLight(i, (1 - scale) * span->GetLightScale(i, proj)); + IScaleLight(mRef, i, (1 - scale) * span->GetLightScale(i, proj)); } startScale = i + 1; } @@ -1110,36 +1110,25 @@ void plGLPipeline::ISelectLights(const plSpan* span, bool proj) /// Make sure those lights that aren't scaled....aren't for (i = 0; i < startScale; i++) { - IScaleLight(i, span->GetLightScale(i, proj)); + IScaleLight(mRef, i, span->GetLightScale(i, proj)); } } for (; i < numLights; i++) { - IDisableLight(i); + IDisableLight(mRef, i); } } -void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) +void plGLPipeline::IEnableLight(plGLMaterialShaderRef* mRef, size_t i, plLightInfo* light) { - GLuint position = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].position", i).c_str()); - GLuint ambient = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].ambient", i).c_str()); - GLuint diffuse = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].diffuse", i).c_str()); - GLuint specular = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].specular", i).c_str()); - GLuint direction = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].direction", i).c_str()); - GLuint spotProps = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].spotProps", i).c_str()); - GLuint constAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].constAtten", i).c_str()); - GLuint linAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].linAtten", i).c_str()); - GLuint quadAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].quadAtten", i).c_str()); - GLuint scale = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); - hsColorRGBA amb = light->GetAmbient(); - glUniform4f(ambient, amb.r, amb.g, amb.b, amb.a); + glUniform4f(mRef->uLampSources[i].ambient, amb.r, amb.g, amb.b, amb.a); hsColorRGBA diff = light->GetDiffuse(); - glUniform4f(diffuse, diff.r, diff.g, diff.b, diff.a); + glUniform4f(mRef->uLampSources[i].diffuse, diff.r, diff.g, diff.b, diff.a); hsColorRGBA spec = light->GetSpecular(); - glUniform4f(specular, spec.r, spec.g, spec.b, spec.a); + glUniform4f(mRef->uLampSources[i].specular, spec.r, spec.g, spec.b, spec.a); plDirectionalLightInfo* dirLight = nullptr; plOmniLightInfo* omniLight = nullptr; @@ -1148,69 +1137,58 @@ void plGLPipeline::IEnableLight(size_t i, plLightInfo* light) if ((dirLight = plDirectionalLightInfo::ConvertNoRef(light)) != nullptr) { hsVector3 lightDir = dirLight->GetWorldDirection(); - glUniform4f(position, lightDir.fX, lightDir.fY, lightDir.fZ, 0.0); - glUniform3f(direction, lightDir.fX, lightDir.fY, lightDir.fZ); + glUniform4f(mRef->uLampSources[i].position, lightDir.fX, lightDir.fY, lightDir.fZ, 0.0); + glUniform3f(mRef->uLampSources[i].direction, lightDir.fX, lightDir.fY, lightDir.fZ); - glUniform1f(constAtten, 1.0f); - glUniform1f(linAtten, 0.0f); - glUniform1f(quadAtten, 0.0f); + glUniform1f(mRef->uLampSources[i].constAtten, 1.0f); + glUniform1f(mRef->uLampSources[i].linAtten, 0.0f); + glUniform1f(mRef->uLampSources[i].quadAtten, 0.0f); } else if ((omniLight = plOmniLightInfo::ConvertNoRef(light)) != nullptr) { hsPoint3 pos = omniLight->GetWorldPosition(); - glUniform4f(position, pos.fX, pos.fY, pos.fZ, 1.0); + glUniform4f(mRef->uLampSources[i].position, pos.fX, pos.fY, pos.fZ, 1.0); // TODO: Maximum Range - glUniform1f(constAtten, omniLight->GetConstantAttenuation()); - glUniform1f(linAtten, omniLight->GetLinearAttenuation()); - glUniform1f(quadAtten, omniLight->GetQuadraticAttenuation()); + glUniform1f(mRef->uLampSources[i].constAtten, omniLight->GetConstantAttenuation()); + glUniform1f(mRef->uLampSources[i].linAtten, omniLight->GetLinearAttenuation()); + glUniform1f(mRef->uLampSources[i].quadAtten, omniLight->GetQuadraticAttenuation()); if (!omniLight->GetProjection() && (spotLight = plSpotLightInfo::ConvertNoRef(omniLight)) != nullptr) { hsVector3 lightDir = spotLight->GetWorldDirection(); - glUniform3f(direction, lightDir.fX, lightDir.fY, lightDir.fZ); + glUniform3f(mRef->uLampSources[i].direction, lightDir.fX, lightDir.fY, lightDir.fZ); float falloff = spotLight->GetFalloff(); float theta = cosf(spotLight->GetSpotInner()); float phi = cosf(spotLight->GetProjection() ? hsConstants::half_pi : spotLight->GetSpotOuter()); - glUniform3f(spotProps, falloff, theta, phi); + glUniform3f(mRef->uLampSources[i].spotProps, falloff, theta, phi); } else { - glUniform3f(spotProps, 0.0, 0.0, 0.0); + glUniform3f(mRef->uLampSources[i].spotProps, 0.0, 0.0, 0.0); } } else { - IDisableLight(i); + IDisableLight(mRef, i); } } -void plGLPipeline::IDisableLight(size_t i) +void plGLPipeline::IDisableLight(plGLMaterialShaderRef* mRef, size_t i) { - GLuint position = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].position", i).c_str()); - GLuint ambient = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].ambient", i).c_str()); - GLuint diffuse = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].diffuse", i).c_str()); - GLuint specular = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].specular", i).c_str()); - GLuint constAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].constAtten", i).c_str()); - GLuint linAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].linAtten", i).c_str()); - GLuint quadAtten = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].quadAtten", i).c_str()); - GLuint scale = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); - - if (position != -1) glUniform4f(position, 0.0f, 0.0f, 0.0f, 0.0f); - if (ambient != -1) glUniform4f(ambient, 0.0f, 0.0f, 0.0f, 0.0f); - if (diffuse != -1) glUniform4f(diffuse, 0.0f, 0.0f, 0.0f, 0.0f); - if (specular != -1) glUniform4f(specular, 0.0f, 0.0f, 0.0f, 0.0f); - if (constAtten != -1) glUniform1f(constAtten, 1.0f); - if (linAtten != -1) glUniform1f(linAtten, 0.0f); - if (quadAtten != -1) glUniform1f(quadAtten, 0.0f); - if (scale != -1) glUniform1f(scale, 0.0f); + glUniform4f(mRef->uLampSources[i].position, 0.0f, 0.0f, 0.0f, 0.0f); + glUniform4f(mRef->uLampSources[i].ambient, 0.0f, 0.0f, 0.0f, 0.0f); + glUniform4f(mRef->uLampSources[i].diffuse, 0.0f, 0.0f, 0.0f, 0.0f); + glUniform4f(mRef->uLampSources[i].specular, 0.0f, 0.0f, 0.0f, 0.0f); + glUniform1f(mRef->uLampSources[i].constAtten, 1.0f); + glUniform1f(mRef->uLampSources[i].linAtten, 0.0f); + glUniform1f(mRef->uLampSources[i].quadAtten, 0.0f); + glUniform1f(mRef->uLampSources[i].scale, 0.0f); } -void plGLPipeline::IScaleLight(size_t i, float scale) +void plGLPipeline::IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale) { scale = int(scale * 1.e1f) * 1.e-1f; - - GLuint uniform = glGetUniformLocation(fDevice.fCurrentProgram, ST::format("uLampSources[{}].scale", i).c_str()); - if (uniform != -1) glUniform1f(uniform, scale); + glUniform1f(mRef->uLampSources[i].scale, scale); } void plGLPipeline::IDrawPlate(plPlate* plate) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 3b7265c9f5..e37cb74025 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -129,10 +129,10 @@ class plGLPipeline : public pl3DPipeline void IHandleZMode(hsGMatState flags); void IHandleBlendMode(hsGMatState flags); void ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); - void ISelectLights(const plSpan* span, bool proj = false); - void IEnableLight(size_t i, plLightInfo* light); - void IDisableLight(size_t i); - void IScaleLight(size_t i, float scale); + void ISelectLights(const plSpan* span, plGLMaterialShaderRef* mRef, bool proj = false); + void IEnableLight(plGLMaterialShaderRef* mRef, size_t i, plLightInfo* light); + void IDisableLight(plGLMaterialShaderRef* mRef, size_t i); + void IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale); void IDrawPlate(plPlate* plate); private: From 4f1bd85b1b17bff1f47d215fd9890ac846c7bbec Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jan 2021 23:18:56 -0800 Subject: [PATCH 46/76] Don't force skinned meshes to be dynamic buffers --- .../Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 13 +++---------- .../Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index ca014cc2e1..b1d3d53c6e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -476,16 +476,6 @@ void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, Verte { uint8_t format = owner->GetVertexFormat(); - // All indexed skinning is currently done on CPU, so the source data - // will have indices, but we strip them out for the D3D buffer. - if (format & plGBufferGroup::kSkinIndices) { - format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); - format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... - vRef->SetSkinned(true); - vRef->SetVolatile(true); - } - - uint32_t vertSize = owner->GetVertexSize(); //IGetBufferFormatSize(format); // vertex stride uint32_t numVerts = owner->GetVertBufferCount(idx); @@ -499,6 +489,9 @@ void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, Verte vRef->SetRebuiltSinceUsed(true); vRef->fData = nullptr; + if (format & plGBufferGroup::kSkinIndices) + vRef->SetSkinned(true); + vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); vRef->fIndex = idx; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index be2b75b84d..d000c283c6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -629,7 +629,6 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, } if (vRef->fFormat & plGBufferGroup::kSkinIndices) { - hsAssert(false, "Indexed skinning not supported"); weight_offset += sizeof(uint32_t); } From 77c6cd3f2f08af76023951af76b7d7cbbbf23af6 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jan 2021 23:25:43 -0800 Subject: [PATCH 47/76] Set up GL render targets with framebuffers --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 17 +++ .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 21 ++- .../pfGLPipeline/plGLDeviceRefs.cpp | 17 +++ .../pfGLPipeline/plGLMaterialShaderRef.cpp | 24 ++-- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 133 +++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 3 +- 6 files changed, 197 insertions(+), 18 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index b1d3d53c6e..a934f32a22 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plDrawable/plGBufferGroup.h" #include "plGImage/plMipmap.h" #include "plGImage/plCubicEnvironmap.h" +#include "plPipeline/plRenderTarget.h" #include "plStatusLog/plStatusLog.h" #pragma region EGL_Init @@ -410,6 +411,22 @@ void plGLDevice::Shutdown() void plGLDevice::SetRenderTarget(plRenderTarget* target) { + plGLRenderTargetRef* ref = nullptr; + + if (target != nullptr) { + ref = static_cast(target->GetDeviceRef()); + + if (ref == nullptr || ref->IsDirty()) + ref = static_cast(fPipeline->MakeRenderTargetRef(target)); + } + + if (ref == nullptr) + /// Set to main screen + glBindFramebuffer(GL_FRAMEBUFFER, 0); + else + /// Set to this target + glBindFramebuffer(GL_FRAMEBUFFER, ref->fFrameBuffer); + SetViewport(); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index e6944a335d..5e944ecebc 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -61,8 +61,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com # define LOG_GL_ERROR_CHECK(message) #endif -class plGBufferGroup; class plBitmap; +class plGBufferGroup; +class plRenderTarget; class plGLDeviceRef : public hsGDeviceRef { @@ -196,5 +197,23 @@ class plGLTextureRef : public plGLDeviceRef }; +class plGLRenderTargetRef: public plGLTextureRef +{ +public: + // fRef is the texture ref, so we can keep using this like a normal texture + GLuint fFrameBuffer; + GLuint fDepthBuffer; + + void Link(plGLRenderTargetRef**back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } + plGLRenderTargetRef* GetNext() { return (plGLRenderTargetRef*)fNext; } + + virtual ~plGLRenderTargetRef(); + + void Release(); + + virtual void SetOwner(plRenderTarget* targ) { fOwner = (plBitmap*)targ; } +}; + + #endif // _plGLDeviceRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index 65cc1bc185..0adce49552 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -144,4 +144,21 @@ void plGLTextureRef::Release() glDeleteTextures(1, &fRef); fRef = 0; } + SetDirty(true); +} + + +/***************************************************************************** + ** FrameBuffer cleanup Functions ** + *****************************************************************************/ + +plGLRenderTargetRef::~plGLRenderTargetRef() +{ + Release(); +} + +void plGLRenderTargetRef::Release() +{ + plGLTextureRef::Release(); + SetDirty(true); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 4f3f1c3f5f..23b8305570 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -57,6 +57,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plDrawable/plGBufferGroup.h" #include "plGImage/plCubicEnvironmap.h" #include "plGImage/plMipmap.h" +#include "plPipeline/plCubicRenderTarget.h" +#include "plPipeline/plRenderTarget.h" +#include "plStatusLog/plStatusLog.h" #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" @@ -1047,29 +1050,24 @@ void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* l plBitmap* texture = layer->GetTexture(); if (texture != nullptr && sb->fCurrCoord) { - plMipmap* mip; - plCubicEnvironmap* cube; - // Local variable to store the mesh uvw * layer matrix ST::string imgName = ST::format("image{}", idx); std::shared_ptr img = std::make_shared(imgName, "vec4"); sb->fCurrImage = img; - if ((mip = plMipmap::ConvertNoRef(texture)) != nullptr) { - ST::string samplerName = ST::format("uTexture{}", idx); - std::shared_ptr sampler = IFindVariable(samplerName, "sampler2D"); - - // image = texture(sampler, coords.xy) - sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xy")))); - } - - if ((cube = plCubicEnvironmap::ConvertNoRef(texture)) != nullptr) { + if (plCubicEnvironmap::ConvertNoRef(texture) != nullptr || plCubicRenderTarget::ConvertNoRef(texture) != nullptr) { ST::string samplerName = ST::format("uTexture{}", idx); std::shared_ptr sampler = IFindVariable(samplerName, "samplerCube"); // image = texture(sampler, coords.xyz) sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xyz")))); + } else if (plMipmap::ConvertNoRef(texture) != nullptr || plRenderTarget::ConvertNoRef(texture) != nullptr) { + ST::string samplerName = ST::format("uTexture{}", idx); + std::shared_ptr sampler = IFindVariable(samplerName, "sampler2D"); + + // image = texture(sampler, coords.xy) + sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xy")))); } } } @@ -1080,7 +1078,7 @@ void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuil hsGMatState state = ICompositeLayerState(layer); if (!sb->fCurrImage) { - hsStatusMessage("Got a layer with no image"); + plStatusLog::AddLineSF("pipeline.log", "Got a layer with no image: {}", layer->GetKeyName()); sb->fCurrColor = sb->fPrevColor; sb->fCurrAlpha = sb->fPrevAlpha; return; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index d000c283c6..a3cd53632e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -58,11 +58,16 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsGMatState.inl" #include "plPipeDebugFlags.h" +#include "plPipeResReq.h" #include "plProfile.h" +#include "pnMessage/plPipeResMakeMsg.h" #include "plGLight/plLightInfo.h" #include "plPipeline/hsWinRef.h" +#include "plPipeline/plCubicRenderTarget.h" #include "plPipeline/plDebugText.h" +#include "plPipeline/plDynamicEnvMap.h" #include "plStatusLog/plStatusLog.h" +#include "plSurface/plLayer.h" #ifdef HS_SIMD_INCLUDE # include HS_SIMD_INCLUDE @@ -115,7 +120,7 @@ class plGLRenderTriListFunc : public plRenderTriListFunc plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) - : pl3DPipeline(devMode), fMatRefList() + : pl3DPipeline(devMode), fMatRefList(), fRenderTargetRefList() { plStatusLog::AddLineS("pipeline.log", "Constructing plGLPipeline"); plStatusLog::AddLineSF("pipeline.log", "Driver vendor: {}", devMode->GetDevice()->GetDriverDesc()); @@ -261,7 +266,14 @@ void plGLPipeline::PopRenderRequest(plRenderRequest* req) } void plGLPipeline::ClearRenderTarget(plDrawable* d) -{} +{ + plDrawableSpans* src = plDrawableSpans::ConvertNoRef(d); + + ClearRenderTarget(); + + if (!src) + return; +} void plGLPipeline::ClearRenderTarget(const hsColorRGBA* col, const float* depth) { @@ -285,7 +297,122 @@ void plGLPipeline::ClearRenderTarget(const hsColorRGBA* col, const float* depth) hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) { - return nullptr; + plGLRenderTargetRef* ref = nullptr; + GLuint depthBuffer = -1; + + // If we have Shader Model 3 and support non-POT textures, let's make reflections the pipe size +#if 1 + if (plDynamicCamMap* camMap = plDynamicCamMap::ConvertNoRef(owner)) { + //if ((plQuality::GetCapability() > plQuality::kPS_2) && fSettings.fD3DCaps & kCapsNpotTextures) + camMap->ResizeViewport(IGetViewTransform()); + } +#endif + + /// Check--is this renderTarget really a child of a cubicRenderTarget? + if (owner->GetParent()) { + /// This'll create the deviceRefs for all of its children as well + MakeRenderTargetRef(owner->GetParent()); + return owner->GetDeviceRef(); + } + + // If we already have a rendertargetref, we just need it filled out with D3D resources. + if (owner->GetDeviceRef()) + ref = (plGLRenderTargetRef*)owner->GetDeviceRef(); + + /// Create the render target now + // Start with the depth surface. + // Note that we only ever give a cubic rendertarget a single shared depth buffer, + // since we only render one face at a time. If we were rendering part of face X, then part + // of face Y, then more of face X, then they would all need their own depth buffers. + if (owner->GetZDepth() && (owner->GetFlags() & (plRenderTarget::kIsTexture | plRenderTarget::kIsOffscreen))) { + if (epoxy_gl_version() >= 45) { + glCreateRenderbuffers(1, &depthBuffer); + glNamedRenderbufferStorage(depthBuffer, GL_DEPTH24_STENCIL8, owner->GetWidth(), owner->GetHeight()); + } else { + glGenRenderbuffers(1, &depthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, owner->GetWidth(), owner->GetHeight()); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + } + + // See if it's a cubic render target. + // Primary consumer here is the vertex/pixel shader water. + if (plCubicRenderTarget* cubicRT = plCubicRenderTarget::ConvertNoRef(owner)) { + /// And create the ref (it'll know how to set all the flags) + //if (ref) + // ref->Set(surfFormat, 0, owner); + //else + // ref = new plGLRenderTargetRef(surfFormat, 0, owner); + + // TODO: The rest + } + + // Not a cubic, is it a texture render target? These are currently used + // primarily for shadow map generation. + else if (owner->GetFlags() & plRenderTarget::kIsTexture) { + /// Create a normal texture + if (!ref) + ref = new plGLRenderTargetRef(); + + ref->fOwner = owner; + ref->fDepthBuffer = depthBuffer; + ref->fMapping = GL_TEXTURE_2D; + + if (epoxy_gl_version() >= 45) { + glCreateTextures(GL_TEXTURE_2D, 1, &ref->fRef); + glTextureStorage2D(ref->fRef, 1, GL_RGBA8, owner->GetWidth(), owner->GetHeight()); + glTextureParameteri(ref->fRef, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(ref->fRef, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glCreateFramebuffers(1, &ref->fFrameBuffer); + glNamedFramebufferTexture(ref->fFrameBuffer, GL_COLOR_ATTACHMENT0, ref->fRef, 0); + if (ref->fDepthBuffer != -1) + glNamedFramebufferRenderbuffer(ref->fFrameBuffer, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, ref->fDepthBuffer); + } else { + glGenTextures(1, &ref->fRef); + glBindTexture(GL_TEXTURE_2D, ref->fRef); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, owner->GetWidth(), owner->GetHeight()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &ref->fFrameBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, ref->fFrameBuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ref->fRef, 0); + if (ref->fDepthBuffer != -1) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, ref->fDepthBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + } + + // Not a texture either, must be a plain offscreen. + // Offscreen isn't currently used for anything. + else if (owner->GetFlags() & plRenderTarget::kIsOffscreen) { + /// Create a blank surface + //if (ref) + // ref->Set(surfFormat, 0, owner); + //else + // ref = new plGLRenderTargetRef(surfFormat, 0, owner); + } + + // Keep it in a linked list for ready destruction. + if (owner->GetDeviceRef() != ref) { + owner->SetDeviceRef(ref); + // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) + hsRefCnt_SafeUnRef(ref); + if (ref != nullptr && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); + } else { + if (ref != nullptr && !ref->IsLinked()) + ref->Link(&fRenderTargetRefList); + } + + // Mark as not dirty so it doesn't get re-created + if (ref != nullptr) + ref->SetDirty(false); + + return ref; } bool plGLPipeline::BeginRender() diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index e37cb74025..ffb13e2192 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -68,7 +68,8 @@ class plGLPipeline : public pl3DPipeline friend class plGLDevice; protected: - plGLMaterialShaderRef* fMatRefList; + plGLMaterialShaderRef* fMatRefList; + plGLRenderTargetRef* fRenderTargetRefList; public: plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode); From af32aecbc37ecd8f02d0bc4bab7299f56c50a3f4 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jan 2021 23:29:26 -0800 Subject: [PATCH 48/76] GL pipeline cleanups --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 35 +++++++++++++++---- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 31 ++-------------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index a934f32a22..40dc196959 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -522,7 +522,11 @@ void plGLDevice::CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); if (!vRef->fRef) { - glGenBuffers(1, &vRef->fRef); + if (epoxy_gl_version() >= 45) { + glCreateBuffers(1, &vRef->fRef); + } else { + glGenBuffers(1, &vRef->fRef); + } // Fill in the vertex data. FillStaticVertexBufferRef(vRef, owner, idx); @@ -545,10 +549,14 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* if (!size) return; - glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); if (ref->fData) { - glBufferData(GL_ARRAY_BUFFER, size, ref->fData + vertStart, GL_STATIC_DRAW); + if (epoxy_gl_version() >= 45) { + glNamedBufferData(ref->fRef, size, ref->fData + vertStart, GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); + glBufferData(GL_ARRAY_BUFFER, size, ref->fData + vertStart, GL_STATIC_DRAW); + } } else { hsAssert(0 == vertStart, "Offsets on non-interleaved data not supported"); hsAssert(group->GetVertBufferCount(idx) * vertSize == size, "Trailing dead space on non-interleaved data not supported"); @@ -594,7 +602,12 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* } hsAssert((ptr - buffer) == size, "Didn't fill the buffer?"); - glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW); + if (epoxy_gl_version() >= 45) { + glNamedBufferData(ref->fRef, size, buffer, GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); + glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW); + } delete[] buffer; } @@ -659,7 +672,11 @@ void plGLDevice::CheckIndexBuffer(IndexBufferRef* iRef) if (!iRef->fRef && iRef->fCount) { iRef->SetVolatile(false); - glGenBuffers(1, &iRef->fRef); + if (epoxy_gl_version() >= 45) { + glCreateBuffers(1, &iRef->fRef); + } else { + glGenBuffers(1, &iRef->fRef); + } iRef->SetDirty(true); iRef->SetRebuiltSinceUsed(true); @@ -674,8 +691,12 @@ void plGLDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, if (!size) return; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, owner->GetIndexBufferData(idx) + startIdx, GL_STATIC_DRAW); + if (epoxy_gl_version() >= 45) { + glNamedBufferData(iRef->fRef, size, owner->GetIndexBufferData(idx) + startIdx, GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, owner->GetIndexBufferData(idx) + startIdx, GL_STATIC_DRAW); + } iRef->SetDirty(false); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index a3cd53632e..0ca4665e96 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -218,19 +218,6 @@ void plGLPipeline::PushRenderRequest(plRenderRequest* req) float depth = req->GetClearDepth(); fView.SetClear(&req->GetClearColor(), &depth); -#if 0 - if (req->GetFogStart() < 0) - { - fView.SetDefaultFog(defFog); - } - else - { - defFog.Set(req->GetYon() * (1.f - req->GetFogStart()), req->GetYon(), 1.f, &req->GetClearColor()); - fView.SetDefaultFog(defFog); - fCurrFog.fEnvPtr = nullptr; - } -#endif - if (req->GetOverrideMat()) PushOverrideMaterial(req->GetOverrideMat()); @@ -255,12 +242,6 @@ void plGLPipeline::PopRenderRequest(plRenderRequest* req) fView = fViewStack.top(); fViewStack.pop(); -#if 0 - // Force the next thing drawn to update the fog settings. - fD3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); - fCurrFog.fEnvPtr = nullptr; -#endif - PopRenderTarget(); fView.fXformResetFlags = fView.kResetProjection | fView.kResetCamera; } @@ -999,20 +980,14 @@ void plGLPipeline::IHandleBlendMode(hsGMatState flags) { hsAssert(false, "Too many blend modes specified in material"); -#if 0 plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); - if( lay ) - { - if( lay->GetBlendFlags() & hsGMatState::kBlendAlpha ) - { + if (lay) { + if (lay->GetBlendFlags() & hsGMatState::kBlendAlpha) { lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAlpha); - } - else - { + } else { lay->SetBlendFlags((lay->GetBlendFlags() & ~hsGMatState::kBlendMask) | hsGMatState::kBlendAdd); } } -#endif } break; } From 2dfd6330dab79bbe6d56bed73ef009b5edc8e956 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jan 2021 23:30:03 -0800 Subject: [PATCH 49/76] Try to get DynamicCamMaps working --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 42 ++++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 5 +-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 23b8305570..9663c21e44 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -990,9 +990,44 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* // mat[2][2] = -mat[2][2]; sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "2"), "2")))); } + } else if (state.fMiscFlags & hsGMatState::kMiscCam2Screen) { + // cam2Screen will also have the kMiscPerspProjection flag set, so this + // needs to go before the regular kMiscProjection check. + std::shared_ptr mNDC = IFindVariable("uMatrixProj", "mat4"); + + ST::string matName = ST::format("LayerMat{}", idx); + matrix = std::make_shared(matName, "mat4"); + // mat.Reset(); + sb->fFunction->PushOp(ASSIGN(matrix, CALL("mat4", CONSTANT("1.0")))); + + // mat.MakeScaleMat(hsVector3 camScale(0.5f, -0.5f, 1.f)); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "0"), CONSTANT("0.5"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "1"), CONSTANT("-0.5"))); + + // hsVector3 camTrans(0.5f, 0.5f, 0.f); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "3"), CONSTANT("0.5"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "3"), CONSTANT("0.5"))); + + // The scale and trans move us from NDC to Screen space. We need to swap + // the Z and W coordinates so that the texture projection will divide by W + // and give us projected 2D coordinates. + ST::string tempName = ST::format("t{}", idx); + std::shared_ptr temp = std::make_shared(tempName, "float"); + + // swap mat[2][2] and mat[3][2] + sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "2"), "2"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), SUBVAL(SUBVAL(matrix, "3"), "2"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "3"), "2"), temp)); + + // swap mat[2][3] and mat[3][3] + sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "2"), "3"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "3"), SUBVAL(SUBVAL(matrix, "3"), "3"))); + sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "3"), "3"), temp)); + + // Multiply by the projection matrix + sb->fFunction->PushOp(ASSIGN(matrix, MUL(matrix, mNDC))); #if 0 - } else if (state.fMiscFlags & hsGMatState::kMiscCam2Screen) { } else if (state.fMiscFlags & hsGMatState::kMiscProjection) { ST::string matName = ST::format("uLayerMat{}", idx); std::shared_ptr layMat = IFindVariable(matName, "mat4"); @@ -1041,6 +1076,11 @@ void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* break; } + if (state.fMiscFlags & hsGMatState::kMiscPerspProjection) { + sb->fFunction->PushOp(ASSIGN(PROP(coords, "x"), DIV(PROP(coords, "x"), PROP(coords, "z")))); + sb->fFunction->PushOp(ASSIGN(PROP(coords, "y"), DIV(PROP(coords, "y"), PROP(coords, "z")))); + } + sb->fCurrCoord = coords; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 0ca4665e96..4bd93f82f1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -51,6 +51,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsWindows.h" +#include "plQuality.h" #include "plGLMaterialShaderRef.h" #include "plGLPipeline.h" @@ -282,12 +283,10 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) GLuint depthBuffer = -1; // If we have Shader Model 3 and support non-POT textures, let's make reflections the pipe size -#if 1 if (plDynamicCamMap* camMap = plDynamicCamMap::ConvertNoRef(owner)) { - //if ((plQuality::GetCapability() > plQuality::kPS_2) && fSettings.fD3DCaps & kCapsNpotTextures) + if (plQuality::GetCapability() > plQuality::kPS_2) camMap->ResizeViewport(IGetViewTransform()); } -#endif /// Check--is this renderTarget really a child of a cubicRenderTarget? if (owner->GetParent()) { From bb3f93a60dfba5cefdcf1be0328c0447da9501df Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jan 2021 23:30:29 -0800 Subject: [PATCH 50/76] Fixes for plate GL state being wrong --- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 15 +++++++++++---- .../FeatureLib/pfGLPipeline/plGLPlateManager.cpp | 3 +++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 4bd93f82f1..60ce010ad6 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -903,11 +903,8 @@ void plGLPipeline::IHandleZMode(hsGMatState flags) } if (flags.fZFlags & hsGMatState::kZIncLayer) { - int32_t int_value = 8; - float value = *(float*)(&int_value); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f, 1.f); + glPolygonOffset(-1.f, -1.f); } else { glPolygonOffset(0.f, 0.f); glDisable(GL_POLYGON_OFFSET_FILL); @@ -1324,6 +1321,13 @@ void plGLPipeline::IDrawPlate(plPlate* plate) mRef->SetupTextureRefs(); + plLayerInterface* lay = material->GetLayer(0); + hsGMatState s; + s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); + + IHandleZMode(s); + IHandleBlendMode(s); + /* Push the matrices into the GLSL shader now */ glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, projMat); glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.fMatrixW2C); @@ -1333,6 +1337,9 @@ void plGLPipeline::IDrawPlate(plPlate* plate) if (mRef->uMatrixW2L != -1) glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.fMatrixW2L); + glUniform1f(mRef->uInvertVtxAlpha, 0.f); + glUniform1f(mRef->uAlphaThreshold, 0.f); + glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); glUniform4f(mRef->uMatAmbientCol, 1.0, 1.0, 1.0, 1.0); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index 6fd21c85f5..67b8e90f0f 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -220,4 +220,7 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) if (cull) glEnable(GL_CULL_FACE); + + if (epoxy_gl_version() >= 30) + glBindVertexArray(0); } From dd6856030e56073882fafb1cd55a45c05496c0cb Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 2 Jan 2021 02:54:34 -0800 Subject: [PATCH 51/76] Remove (unused) dynamic vertex shader generation --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 219 ++---------------- .../pfGLPipeline/plGLMaterialShaderRef.h | 5 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 7 +- 3 files changed, 27 insertions(+), 204 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 9663c21e44..cd3b4e3c70 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -351,35 +351,36 @@ void plGLMaterialShaderRef::ICompile() const char* vs_code = VERTEX_SHADER_STRING; #ifndef USE_NEW_SHADERS - //ST::string vtx = fVertexShader->Render(); ST::string frg = fFragmentShader->Render(); - - //const char* vs_code = vtx.c_str(); const char* fs_code = frg.c_str(); #else const char* fs_code = FRAGMENT_SHADER_STRING; #endif - fVertShaderRef = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(fVertShaderRef, 1, &vs_code, nullptr); - glCompileShader(fVertShaderRef); - LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); + static GLuint vshader = 0; + if (!vshader) { + vshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vshader, 1, &vs_code, nullptr); + glCompileShader(vshader); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); #ifdef HS_DEBUGGING - { - GLint compiled = 0; - glGetShaderiv(fVertShaderRef, GL_COMPILE_STATUS, &compiled); - if (compiled == 0) { - GLint length = 0; - glGetShaderiv(fVertShaderRef, GL_INFO_LOG_LENGTH, &length); - if (length) { - char* log = new char[length]; - glGetShaderInfoLog(fVertShaderRef, length, &length, log); - hsStatusMessage(log); + { + GLint compiled = 0; + glGetShaderiv(vshader, GL_COMPILE_STATUS, &compiled); + if (compiled == 0) { + GLint length = 0; + glGetShaderiv(vshader, GL_INFO_LOG_LENGTH, &length); + if (length) { + char* log = new char[length]; + glGetShaderInfoLog(vshader, length, &length, log); + hsStatusMessage(log); + } } } - } #endif + } + fVertShaderRef = vshader; fFragShaderRef = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fFragShaderRef, 1, &fs_code, nullptr); @@ -420,7 +421,6 @@ void plGLMaterialShaderRef::ICompile() void plGLMaterialShaderRef::ISetupShaderContexts() { - fVertexShader = std::make_shared(kVertex, kShaderVersion); fFragmentShader = std::make_shared(kFragment, kShaderVersion); #ifndef USE_NEW_SHADERS @@ -434,24 +434,8 @@ void plGLMaterialShaderRef::ISetupShaderContexts() auto argAlpha = std::make_shared("alpha", "float", 0); invAlpha->PushOp(RETURN(SUB(CONSTANT("1.0"), argAlpha))); - fVertexShader->PushFunction(invColor); - fVertexShader->PushFunction(invAlpha); fFragmentShader->PushFunction(invColor); fFragmentShader->PushFunction(invAlpha); - - std::shared_ptr lightSource = std::make_shared("lightSource"); - lightSource->AddField(STRUCTVAR("vec4", "position")); - lightSource->AddField(STRUCTVAR("vec4", "ambient")); - lightSource->AddField(STRUCTVAR("vec4", "diffuse")); - lightSource->AddField(STRUCTVAR("vec4", "specular")); - lightSource->AddField(STRUCTVAR("vec3", "direction")); - lightSource->AddField(STRUCTVAR("vec3", "spotProps")); - lightSource->AddField(STRUCTVAR("float", "constAtten")); - lightSource->AddField(STRUCTVAR("float", "linAtten")); - lightSource->AddField(STRUCTVAR("float", "quadAtten")); - lightSource->AddField(STRUCTVAR("float", "scale")); - - fVertexShader->PushStruct(lightSource); #endif } @@ -530,7 +514,6 @@ void plGLMaterialShaderRef::ICleanupShaderContexts() { fVariables.clear(); - fVertexShader.reset(); fFragmentShader.reset(); } @@ -540,32 +523,6 @@ void plGLMaterialShaderRef::ILoopOverLayers() size_t j = 0; size_t pass = 0; - // Build the vertex shader main function to assign to the varying vars - std::shared_ptr vertMain = std::make_shared("main", "void"); - - // Set the vertex transforms now - std::shared_ptr pos = std::make_shared("pos", "vec4"); - std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); - std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); - std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); - std::shared_ptr mW2C = IFindVariable("uMatrixW2C", "mat4"); - std::shared_ptr mProj = IFindVariable("uMatrixProj", "mat4"); - - std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); - std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); - - vertMain->PushOp(ASSIGN(pos, MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))); - vertMain->PushOp(ASSIGN(pos, MUL(mW2C, pos))); - - vertMain->PushOp(ASSIGN(vCamPos, pos)); - vertMain->PushOp(ASSIGN(vCamNor, MUL(mW2C, MUL(mL2W, CALL("vec4", anor, CONSTANT("1.0")))))); - - vertMain->PushOp(ASSIGN(pos, MUL(mProj, pos))); - vertMain->PushOp(ASSIGN(OUTPUT("gl_Position"), pos)); - - vertMain->PushOp(ASSIGN(PROP(OUTPUT("gl_Position"), "z"), - SUB(MUL(PROP(OUTPUT("gl_Position"), "z"), CONSTANT("2.0")), PROP(OUTPUT("gl_Position"), "w")))); - // Build the fragment shader main function with the right passes std::shared_ptr fragMain = std::make_shared("main", "void"); std::shared_ptr uPass = IFindVariable("uPassNumber", "int"); @@ -574,14 +531,12 @@ void plGLMaterialShaderRef::ILoopOverLayers() { size_t iCurrMat = j; std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "vec4"); - std::shared_ptr vertPass = std::make_shared(ST::format("pass{}", pass), "void"); - j = IHandleMaterial(iCurrMat, vertPass, fragPass); + j = IHandleMaterial(iCurrMat, fragPass); if (j == -1) break; - fVertexShader->PushFunction(vertPass); fFragmentShader->PushFunction(fragPass); std::shared_ptr passCond = COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass)))); @@ -591,7 +546,6 @@ void plGLMaterialShaderRef::ILoopOverLayers() // if (uPassNumber == curpass) { curpass(); } fragMain->PushOp(passCond); - vertMain->PushOp(passCond); pass++; fPassIndices.push_back(iCurrMat); @@ -602,23 +556,6 @@ void plGLMaterialShaderRef::ILoopOverLayers() } fFragmentShader->PushFunction(fragMain); - - for (const auto& pair : fVariables) { - if (pair.second->klass == kVarying) { - std::shared_ptr vary = std::static_pointer_cast(pair.second); - - if (vary->name == "vVtxColor" || vary->name == "vCamPosition" || vary->name == "vCamNormal") { - continue; - } - - ST::string name = ST::format("a{}", vary->name.substr(1)); - std::shared_ptr attr = std::make_shared(name, vary->type); - - vertMain->PushOp(ASSIGN(vary, attr)); - } - } - - fVertexShader->PushFunction(vertMain); } @@ -630,7 +567,7 @@ const hsGMatState plGLMaterialShaderRef::ICompositeLayerState(plLayerInterface* } -uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn) +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr ffn) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) return -1; @@ -694,11 +631,6 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< std::shared_ptr vVtxColor = IFindVariable("vVtxColor", "vec4"); - std::shared_ptr lighting = ICalcLighting(vfn); - std::shared_ptr baseAlpha = IBuildBaseAlpha(currLay, vfn); - - vfn->PushOp(ASSIGN(vVtxColor, CALL("vec4", PROP(lighting, "rgb"), baseAlpha))); - std::shared_ptr fBaseAlpha = std::make_shared("baseAlpha", "float"); ffn->PushOp(ASSIGN(fBaseAlpha, PROP(vVtxColor, "a"))); @@ -828,115 +760,6 @@ bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) return true; } -std::shared_ptr plGLMaterialShaderRef::ICalcLighting(std::shared_ptr fn) -{ - std::shared_ptr acol = IFindVariable("aVtxColor", "vec4"); - std::shared_ptr apos = IFindVariable("aVtxPosition", "vec3"); - std::shared_ptr anor = IFindVariable("aVtxNormal", "vec3"); - - std::shared_ptr mL2W = IFindVariable("uMatrixL2W", "mat4"); - std::shared_ptr mW2L = IFindVariable("uMatrixW2L", "mat4"); - - std::shared_ptr uGlobalAmb = IFindVariable("uGlobalAmb", "vec4"); - std::shared_ptr uAmbientCol = IFindVariable("uAmbientCol", "vec4"); - std::shared_ptr uAmbientSrc = IFindVariable("uAmbientSrc", "float"); - - std::shared_ptr uDiffuseCol = IFindVariable("uDiffuseCol", "vec4"); - std::shared_ptr uDiffuseSrc = IFindVariable("uDiffuseSrc", "float"); - - std::shared_ptr uEmissiveCol = IFindVariable("uEmissiveCol", "vec4"); - std::shared_ptr uEmissiveSrc = IFindVariable("uEmissiveSrc", "float"); - - std::shared_ptr uSpecularCol = IFindVariable("uSpecularCol", "vec4"); - std::shared_ptr uSpecularSrc = IFindVariable("uSpecularSrc", "float"); - - std::shared_ptr uLampSources = IFindVariable("uLampSources", "lightSource", 8); - - // Local vars for the 4 material values - // Material values - std::shared_ptr MAmbient = std::make_shared("MAmbient", "vec4"); - std::shared_ptr MDiffuse = std::make_shared("MDiffuse", "vec4"); - std::shared_ptr MEmissive = std::make_shared("MEmissive", "vec4"); - std::shared_ptr MSpecular = std::make_shared("MSpecular", "vec4"); - - // Aggregated Lamp values - std::shared_ptr LAmbient = std::make_shared("LAmbient", "vec4"); - std::shared_ptr LDiffuse = std::make_shared("LDiffuse", "vec4"); - - // Final output values - std::shared_ptr ambient = std::make_shared("ambient", "vec4"); - std::shared_ptr diffuse = std::make_shared("diffuse", "vec4"); - std::shared_ptr specular = std::make_shared("specular", "vec4"); - - fn->PushOp(ASSIGN(MAmbient, CALL("mix", PROP(acol, "zyxw"), uAmbientCol, uAmbientSrc))); - fn->PushOp(ASSIGN(MDiffuse, CALL("mix", PROP(acol, "zyxw"), uDiffuseCol, uDiffuseSrc))); - fn->PushOp(ASSIGN(MEmissive, CALL("mix", PROP(acol, "zyxw"), uEmissiveCol, uEmissiveSrc))); - fn->PushOp(ASSIGN(MSpecular, CALL("mix", PROP(acol, "zyxw"), uSpecularCol, uSpecularSrc))); - - std::shared_ptr attenuation = std::make_shared("attenuation", "float"); - std::shared_ptr v2l = std::make_shared("v2l", "vec3"); - std::shared_ptr distance = std::make_shared("distance", "float"); - std::shared_ptr direction = std::make_shared("direction", "vec3"); - std::shared_ptr Ndirection = std::make_shared("Ndirection", "vec3"); - - fn->PushOp(ASSIGN(LAmbient, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); - fn->PushOp(ASSIGN(LDiffuse, CONSTANT("vec4(0.0, 0.0, 0.0, 0.0)"))); - - //fn->PushOp(ASSIGN(Ndirection, CALL("normalize", CALL("vec3", MUL(mW2L, CALL("vec4", anor, CONSTANT("1.0"))))))); - fn->PushOp(ASSIGN(Ndirection, CALL("normalize", MUL(CALL("mat3", mW2L), anor)))); - - for (size_t i = 0; i < 8; i++) { - auto lamp = SUBVAL(uLampSources, ST::format("{}", i)); - - fn->PushOp(ASSIGN(v2l, SUB(CALL("vec3", PROP(lamp, "position")), CALL("vec3", MUL(mL2W, CALL("vec4", apos, CONSTANT("1.0"))))))); - fn->PushOp(ASSIGN(distance, CALL("length", v2l))); - fn->PushOp(ASSIGN(direction, CALL("normalize", v2l))); - - fn->PushOp(ASSIGN(attenuation, CALL("mix", - // attenuation = 1.0 - CONSTANT("1.0"), - // attenuation = 1.0 / (constA + linA * dist + quadA * dist * dist) - DIV(CONSTANT("1.0"), ADD(PROP(lamp, "constAtten"), ADD(MUL(PROP(lamp, "linAtten"), distance), MUL(PROP(lamp, "quadAtten"), MUL(distance, distance))), true)), - PROP(PROP(lamp, "position"), "w")))); - - // LAmbient = LAmbient + (Atten * Spot * La) - fn->PushOp(ASSIGN(LAmbient, ADD(LAmbient, MUL(attenuation, MUL(PROP(lamp, "ambient"), PROP(lamp, "scale"), true))))); - - // LDiffuse = LDiffuse + (Cd * Ld * (N . Ldir) * Atten * Spot) - fn->PushOp(ASSIGN(LDiffuse, ADD(LDiffuse, MUL(MDiffuse, MUL(MUL(PROP(lamp, "diffuse"), PROP(lamp, "scale"), true), MUL(CALL("max", CONSTANT("0.0"), CALL("dot", Ndirection, direction)), attenuation)))))); - } - - // ambient = ambient * (global amb + ambientL) [clamped 0.0 - 1.0] - fn->PushOp(ASSIGN(ambient, CALL("clamp", MUL(MAmbient, ADD(uGlobalAmb, LAmbient, true)), CONSTANT("0.0"), CONSTANT("1.0")))); - fn->PushOp(ASSIGN(diffuse, CALL("clamp", LDiffuse, CONSTANT("0.0"), CONSTANT("1.0")))); - - std::shared_ptr matValues = std::make_shared("material", "vec4"); - fn->PushOp(ASSIGN(matValues, CALL("clamp", ADD(ambient, ADD(diffuse, MEmissive)), CONSTANT("0.0"), CONSTANT("1.0")))); - return matValues; -} - - -std::shared_ptr plGLMaterialShaderRef::IBuildBaseAlpha(plLayerInterface* layer, std::shared_ptr fn) -{ - hsGMatState state = ICompositeLayerState(layer); - - // This will have been declared by ICalcLighting - std::shared_ptr diffuse = CONSTANT("MDiffuse"); - - // Local variable to store the starting alpha value - std::shared_ptr base = std::make_shared("baseAlpha", "float"); - - if (state.fBlendFlags & hsGMatState::kBlendInvertVtxAlpha) { - // base = 1.0 - vVtxColor.a - fn->PushOp(ASSIGN(base, CALL("invAlpha", PROP(diffuse, "a")))); - } else { - // base = vVtxColor.a - fn->PushOp(ASSIGN(base, PROP(diffuse, "a"))); - } - - return base; -} - void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 210f75fa37..21e640bce1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -106,7 +106,6 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::vector fPassIndices; - std::shared_ptr fVertexShader; std::shared_ptr fFragmentShader; plShaderVarLookup fVariables; @@ -180,11 +179,9 @@ class plGLMaterialShaderRef : public plGLDeviceRef // fMatOverOff overrides to clear a state bit whether it is set in the layer or not. const hsGMatState ICompositeLayerState(plLayerInterface* layer); - uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr vfn, std::shared_ptr ffn); + uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr ffn); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); - std::shared_ptr ICalcLighting(std::shared_ptr fn); - std::shared_ptr IBuildBaseAlpha(plLayerInterface* layer, std::shared_ptr fn); void IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); void IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); void IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 60ce010ad6..a1bfeee6b4 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -768,8 +768,6 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, if (mRef->uPassNumber != -1) glUniform1i(mRef->uPassNumber, pass); - glUniform1f(mRef->uInvertVtxAlpha, 0.f); - plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); ICalcLighting(mRef, lay, &span); @@ -780,6 +778,11 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, IHandleZMode(s); IHandleBlendMode(s); + if (s.fBlendFlags & hsGMatState::kBlendInvertVtxAlpha) + glUniform1f(mRef->uInvertVtxAlpha, 1.f); + else + glUniform1f(mRef->uInvertVtxAlpha, 0.f); + if (s.fBlendFlags & (hsGMatState::kBlendTest | hsGMatState::kBlendAlpha | hsGMatState::kBlendAddColorTimesAlpha) && !(s.fBlendFlags & hsGMatState::kBlendAlphaAlways)) { From 267251077bc5f4d70ccbd9cda46bf3a6cf504784 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Wed, 1 Dec 2021 22:11:07 -0800 Subject: [PATCH 52/76] Fixes for cull mode in GL Adding support for both front face and back face culling. Plasma mixes both. --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 16 +--------------- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 1 - .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 10 ++++++++++ .../FeatureLib/pfGLPipeline/plGLPipeline.h | 8 ++++++++ .../pfMetalPipeline/plMetalPipeline.cpp | 15 +-------------- .../FeatureLib/pfMetalPipeline/plMetalPipeline.h | 1 - .../plPipeline/plPipelineViewSettings.h | 1 + 7 files changed, 21 insertions(+), 31 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index 83df33915b..b129e4fa40 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -7972,20 +7972,6 @@ void plDXPipeline::IFormatTextureData( uint32_t formatType, uint32_t numPix, } -/////////////////////////////////////////////////////////////////////////////// -//// View Stuff /////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -//// IIsViewLeftHanded //////////////////////////////////////////////////////// -// Returns true if the combination of the local2world and world2camera -// matrices is left-handed. - -bool plDXPipeline::IIsViewLeftHanded() -{ - return fView.GetViewTransform().GetOrthogonal() ^ ( fView.fLocalToWorldLeftHanded ^ fView.fWorldToCamLeftHanded ) ? true : false; -} - - /////////////////////////////////////////////////////////////////////////////// //// Transforms /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -8031,7 +8017,7 @@ void plDXPipeline::ISetCullMode(bool flip) D3DCULL newCull = D3DCULL_NONE; if( !(fLayerState[0].fMiscFlags & hsGMatState::kMiscTwoSided) ) - newCull = !IIsViewLeftHanded() ^ !flip ? D3DCULL_CW : D3DCULL_CCW; + newCull = !fView.IsViewLeftHanded() ^ !flip ? D3DCULL_CW : D3DCULL_CCW; if( newCull != fDevice.fCurrCullMode ) { diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index 538e3e0c86..07047a3f54 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -438,7 +438,6 @@ class plDXPipeline : public pl3DPipeline // Transforms D3DMATRIX& IMatrix44ToD3DMatrix( D3DMATRIX& dst, const hsMatrix44& src ); void ISetCullMode(bool flip=false); - bool inline IIsViewLeftHanded(); bool IGetClearViewPort(D3DRECT& r); void ISetupTransforms(plDrawableSpans* drawable, const plSpan& span, hsMatrix44& lastL2W); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index a1bfeee6b4..f334c9ce32 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -803,6 +803,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); + ISetCullMode(); } // TEMP @@ -994,6 +995,15 @@ void plGLPipeline::IHandleBlendMode(hsGMatState flags) } +void plGLPipeline::ISetCullMode() +{ + if (fView.IsViewLeftHanded()) + glCullFace(GL_BACK); + else + glCullFace(GL_FRONT); +} + + void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan) { //plProfile_Inc(MatLightState); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index ffb13e2192..8bf631de6a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -129,6 +129,14 @@ class plGLPipeline : public pl3DPipeline void IHandleZMode(hsGMatState flags); void IHandleBlendMode(hsGMatState flags); + + /** + * Tests and sets the current winding order cull mode (CW, CCW, or none). + * Will reverse the cull mode as necessary for left handed camera or local + * to world transforms. + */ + void ISetCullMode(); + void ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan); void ISelectLights(const plSpan* span, plGLMaterialShaderRef* mRef, bool proj = false); void IEnableLight(plGLMaterialShaderRef* mRef, size_t i, plLightInfo* light); diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 7bc5fc7b03..41e933a788 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -3931,26 +3931,13 @@ void plMetalPipeline::ISetupShadowSlaveTextures(plShadowSlave* slave) fCurrentRenderPassUniforms->uvTransforms[1].transform = tXfm; } -/////////////////////////////////////////////////////////////////////////////// -//// View Stuff /////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -//// IIsViewLeftHanded //////////////////////////////////////////////////////// -// Returns true if the combination of the local2world and world2camera -// matrices is left-handed. - -bool plMetalPipeline::IIsViewLeftHanded() -{ - return fView.GetViewTransform().GetOrthogonal() ^ (fView.fLocalToWorldLeftHanded ^ fView.fWorldToCamLeftHanded) ? true : false; -} - //// ISetCullMode ///////////////////////////////////////////////////////////// // Tests and sets the current winding order cull mode (CW, CCW, or none). // Will reverse the cull mode as necessary for left handed camera or local to world // transforms. void plMetalPipeline::ISetCullMode(bool flip) { - MTL::CullMode newCullMode = !IIsViewLeftHanded() ^ !flip ? MTL::CullModeFront : MTL::CullModeBack; + MTL::CullMode newCullMode = !fView.IsViewLeftHanded() ^ !flip ? MTL::CullModeFront : MTL::CullModeBack; if (fState.fCurrentCullMode != newCullMode) { fDevice.CurrentRenderCommandEncoder()->setCullMode(newCullMode); fState.fCurrentCullMode = newCullMode; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 484a182d9e..04e2f84095 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -176,7 +176,6 @@ class plMetalPipeline : public pl3DPipeline void IReleaseDynamicBuffers(); void IReleaseDeviceObjects(); - bool IIsViewLeftHanded(); void ISetCullMode(bool flip = false); plLayerInterface* IPushOverBaseLayer(plLayerInterface* li); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/plPipelineViewSettings.h b/Sources/Plasma/PubUtilLib/plPipeline/plPipelineViewSettings.h index 57df71ecf8..b8ec99bb1f 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/plPipelineViewSettings.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/plPipelineViewSettings.h @@ -151,6 +151,7 @@ class plPipelineViewSettings uint32_t GetSubDrawableTypeMask() const { return fSubDrawableTypeMask; } void SetSubDrawableTypeMask(uint32_t mask) { fSubDrawableTypeMask = mask; } + bool IsViewLeftHanded() const { return (GetConstViewTransform().GetOrthogonal() ^ (fLocalToWorldLeftHanded ^ fWorldToCamLeftHanded)) != 0; } /** Initialize the ViewSettings to default (normal/neutral) values. */ void Reset(plPipeline* pipeline); From d6d882e8ea945a41db0ae59bcbe1a58d6eeb50a2 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Sat, 11 Dec 2021 15:19:32 -0800 Subject: [PATCH 53/76] Fix for z-fighting with physics bodies This should fix things like the fire marbles in Neighborhood. Those objects contain physics bodies that render as transparent, but were still contributing to the Z buffer and sometimes blocking other textures. This borrows from the DX renderer, where transparent bodies are not rendered. That also keeps them from contributing to the Z-buffer. --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index f334c9ce32..de840dabf8 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -770,6 +770,14 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); + // If the layer opacity is 0, don't draw it. This prevents it from + // contributing to the Z buffer. This can happen with some models like + // the fire marbles in the neighborhood that have some models for + // physics only, and then can block other rendering in the Z buffer. DX + // pipeline does this in ILoopOverLayers. + if (lay->GetOpacity() <= 0) + continue; + ICalcLighting(mRef, lay, &span); hsGMatState s; From adb67649aa3cf9b08fb2f596c85b19488c4addc7 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Sat, 11 Dec 2021 15:24:23 -0800 Subject: [PATCH 54/76] Fix for alpha testing in fragment shader This should solve z-fighting in transparent textures. I haven't compared against DX so it's a bit of a guess, but fragments that are completely transparent should probably be discarded. This was causing z-fighting to occur with transparent materials that were overlapped on each other. Commonly seen in the "HeekD'nji" material in "Neighborhood." --- .../Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index cd3b4e3c70..364fc7d06b 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -677,7 +677,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Handle High Alpha Threshold std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); - std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); + std::shared_ptr alphaTest = COND(IS_LEQ(sb.fCurrAlpha, alphaThreshold)); alphaTest->PushOp(CONSTANT("discard")); // if (final.a < alphaThreshold) { discard; } From 96066fa3f72db8e945900c3379ee09fa05070fc9 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Sun, 12 Dec 2021 21:50:48 -0800 Subject: [PATCH 55/76] Opacity based culling fixes The GetOpacity based culling needed some more conditions, it was doing things like not rendering the fountain in Eder Kemo. That should be resolved now, and the fire marbles are still fixed. The alpha threshold change caused unresolvable issues in Eder Kemo. Undoing for now. I'll have to figure out a better way to fix that hologram. --- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 2 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 364fc7d06b..cd3b4e3c70 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -677,7 +677,7 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Handle High Alpha Threshold std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); - std::shared_ptr alphaTest = COND(IS_LEQ(sb.fCurrAlpha, alphaThreshold)); + std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); alphaTest->PushOp(CONSTANT("discard")); // if (final.a < alphaThreshold) { discard; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index de840dabf8..d13082c829 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -770,19 +770,19 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); + ICalcLighting(mRef, lay, &span); + + hsGMatState s; + s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); + // If the layer opacity is 0, don't draw it. This prevents it from // contributing to the Z buffer. This can happen with some models like // the fire marbles in the neighborhood that have some models for // physics only, and then can block other rendering in the Z buffer. DX // pipeline does this in ILoopOverLayers. - if (lay->GetOpacity() <= 0) + if ((s.fBlendFlags & hsGMatState::kBlendAlpha) && lay->GetOpacity() <= 0 && fCurrLightingMethod != plSpan::kLiteVtxPreshaded) continue; - ICalcLighting(mRef, lay, &span); - - hsGMatState s; - s.Composite(lay->GetState(), fMatOverOn, fMatOverOff); - IHandleZMode(s); IHandleBlendMode(s); @@ -1087,6 +1087,7 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter glUniform1f(mRef->uMatAmbientSrc, 0.0); } + fCurrLightingMethod = plSpan::kLiteMaterial; break; } @@ -1106,6 +1107,8 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter glUniform1f(mRef->uMatEmissiveSrc, 0.0); else glUniform1f(mRef->uMatEmissiveSrc, 1.0); + + fCurrLightingMethod = plSpan::kLiteVtxPreshaded; break; } @@ -1135,6 +1138,8 @@ void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInter glUniform1f(mRef->uMatDiffuseSrc, 0.0); glUniform1f(mRef->uMatEmissiveSrc, 1.0); glUniform1f(mRef->uMatSpecularSrc, 1.0); + + fCurrLightingMethod = plSpan::kLiteVtxNonPreshaded; break; } } From c2632899b2a833cf60d8f41c2f23c8fabff77e1e Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Sun, 12 Dec 2021 22:34:33 -0800 Subject: [PATCH 56/76] Better fix for Z-fighting with hologram MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DX version sets a really low threshold, but doesn’t actually set it to zero for when blending is enabled. Actual line from the DirectX is: fD3DDevice->SetRenderState(D3DRS_ALPHAREF, 0x00000001); This should fix things like the hologram in the neighborhood, and doesn’t break other things like blending in Eder Kemo. --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index d13082c829..0671b08389 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -802,7 +802,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, if (s.fBlendFlags & hsGMatState::kBlendAlphaTestHigh) glUniform1f(mRef->uAlphaThreshold, 64.f/255.f); else - glUniform1f(mRef->uAlphaThreshold, 0.f); + glUniform1f(mRef->uAlphaThreshold, 0.00000000001f); } else { glUniform1f(mRef->uAlphaThreshold, 0.f); } From d8ab6a3eec32a5df51ea1534ffd9c3a1f213b283 Mon Sep 17 00:00:00 2001 From: Colin Cornaby Date: Sat, 1 Jan 2022 23:14:56 -0800 Subject: [PATCH 57/76] Fix for directional lighting Directional lights in plasma are a global light vector. The lighting algorithm expects the vector to the light, so the global light vector needs to be reversed for accurate lighting. --- .../Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index cd3b4e3c70..88f2facb1f 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -135,7 +135,7 @@ void main() { if (uLampSources[i].position.w == 0.0) { // Directional Light with no attenuation - direction = normalize(uLampSources[i].direction); + direction = -uLampSources[i].direction; attenuation = 1.0; } else { // Omni Light in all directions From cd36224c4f557e5c1ac023c8a623643c1c43e47c Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 2 Jan 2022 03:49:49 -0800 Subject: [PATCH 58/76] Hack in the same CPU skinning from DX for now --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 12 +- .../FeatureLib/pfGLPipeline/CMakeLists.txt | 1 + .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 32 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 348 +++++++++++++++++- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 25 ++ .../pfMetalPipeline/plMetalPipeline.cpp | 8 +- .../PubUtilLib/plPipeline/pl3DPipeline.cpp | 6 + 7 files changed, 413 insertions(+), 19 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index b129e4fa40..de01b1169f 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -284,14 +284,15 @@ plProfile_Extern(TotalTexSize); plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); +plProfile_Extern(NumSkin); plProfile_CreateCounterNoReset("Reload", "PipeC", PipeReload); -plProfile_CreateTimer("PrepShadows", "PipeT", PrepShadows); -plProfile_CreateTimer("PrepDrawable", "PipeT", PrepDrawable); -plProfile_CreateTimer(" Skin", "PipeT", Skin); -plProfile_CreateTimer(" AvSort", "PipeT", AvatarSort); -plProfile_CreateTimer(" ClearLights", "PipeT", ClearLights); +plProfile_Extern(PrepShadows); +plProfile_Extern(PrepDrawable); +plProfile_Extern(Skin); +plProfile_Extern(AvatarSort); +plProfile_Extern(ClearLights); plProfile_Extern(RenderSpan); plProfile_Extern(MergeCheck); plProfile_Extern(MergeSpan); @@ -318,7 +319,6 @@ plProfile_CreateMemCounterReset("fVtxManaged", "PipeC", fVtxManaged); plProfile_CreateCounter("Merge", "PipeC", SpanMerge); plProfile_CreateCounter("TexNum", "PipeC", NumTex); plProfile_CreateCounter("LiState", "PipeC", MatLightState); -plProfile_CreateCounter("NumSkin", "PipeC", NumSkin); plProfile_CreateCounter("AvatarFaces", "PipeC", AvatarFaces); plProfile_CreateCounter("VertexChange", "PipeC", VertexChange); plProfile_CreateCounter("IndexChange", "PipeC", IndexChange); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index 92934cbf75..a60674a698 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -19,6 +19,7 @@ set(pfGLPipeline_HEADERS ) plasma_library(pfGLPipeline SOURCES ${pfGLPipeline_SOURCES} ${pfGLPipeline_HEADERS}) +plasma_target_simd_sources(pfGLPipeline SSE3 SSE41 plGLPipeline.cpp) target_link_libraries(pfGLPipeline PUBLIC CoreLib diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 40dc196959..9a2fd4432d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -489,11 +489,38 @@ bool plGLDevice::EndRender() return false; } +static uint32_t IGetBufferFormatSize(uint8_t format) +{ + uint32_t size = sizeof( float ) * 6 + sizeof( uint32_t ) * 2; // Position and normal, and two packed colors + + switch (format & plGBufferGroup::kSkinWeightMask) + { + case plGBufferGroup::kSkinNoWeights: + break; + case plGBufferGroup::kSkin1Weight: + size += sizeof(float); + break; + default: + hsAssert( false, "Invalid skin weight value in IGetBufferFormatSize()" ); + } + + size += sizeof( float ) * 3 * plGBufferGroup::CalcNumUVs(format); + + return size; +} + void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, VertexBufferRef* vRef) { uint8_t format = owner->GetVertexFormat(); - uint32_t vertSize = owner->GetVertexSize(); //IGetBufferFormatSize(format); // vertex stride + if (format & plGBufferGroup::kSkinIndices) { + format &= ~(plGBufferGroup::kSkinWeightMask | plGBufferGroup::kSkinIndices); + format |= plGBufferGroup::kSkinNoWeights; // Should do nothing, but just in case... + vRef->SetSkinned(true); + vRef->SetVolatile(true); + } + + uint32_t vertSize = IGetBufferFormatSize(format); // vertex stride uint32_t numVerts = owner->GetVertBufferCount(idx); vRef->fOwner = owner; @@ -506,9 +533,6 @@ void plGLDevice::SetupVertexBufferRef(plGBufferGroup* owner, uint32_t idx, Verte vRef->SetRebuiltSinceUsed(true); vRef->fData = nullptr; - if (format & plGBufferGroup::kSkinIndices) - vRef->SetSkinned(true); - vRef->SetVolatile(vRef->Volatile() || owner->AreVertsVolatile()); vRef->fIndex = idx; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 0671b08389..94f31d1279 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include #include "HeadSpin.h" +#include "hsSIMD.h" #include "hsWindows.h" #include "plQuality.h" @@ -70,10 +71,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plStatusLog/plStatusLog.h" #include "plSurface/plLayer.h" -#ifdef HS_SIMD_INCLUDE -# include HS_SIMD_INCLUDE -#endif - typedef plGLDevice DeviceType; plProfile_Extern(DrawFeedTriangles); @@ -82,6 +79,8 @@ plProfile_Extern(TotalTexSize); plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); +plProfile_Extern(PrepDrawable); +plProfile_Extern(Skin); plProfile_Extern(RenderSpan); plProfile_Extern(MergeCheck); plProfile_Extern(MergeSpan); @@ -96,6 +95,7 @@ plProfile_Extern(RenderPrim); plProfile_Extern(PlateMgr); plProfile_Extern(DebugText); plProfile_Extern(Reset); +plProfile_Extern(NumSkin); // Adding a nil RenderPrim for turning off drawing static plRenderNilFunc sRenderNil; @@ -118,6 +118,63 @@ class plGLRenderTriListFunc : public plRenderTriListFunc }; +template +static inline void inlCopy(uint8_t*& src, uint8_t*& dst) +{ + T* src_ptr = reinterpret_cast(src); + T* dst_ptr = reinterpret_cast(dst); + *dst_ptr = *src_ptr; + src += sizeof(T); + dst += sizeof(T); +} + +template +static inline const uint8_t* inlExtract(const uint8_t* src, T* val) +{ + const T* ptr = reinterpret_cast(src); + *val = *ptr++; + return reinterpret_cast(ptr); +} + +template<> +inline const uint8_t* inlExtract(const uint8_t* src, hsPoint3* val) +{ + const float* src_ptr = reinterpret_cast(src); + float* dst_ptr = reinterpret_cast(val); + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = *src_ptr++; + *dst_ptr = 1.f; + return reinterpret_cast(src_ptr); +} + +template<> +inline const uint8_t* inlExtract(const uint8_t* src, hsVector3* val) +{ + const float* src_ptr = reinterpret_cast(src); + float* dst_ptr = reinterpret_cast(val); + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = *src_ptr++; + *dst_ptr = 0.f; + return reinterpret_cast(src_ptr); +} + +template +static inline void inlSkip(uint8_t*& src) +{ + src += sizeof(T) * N; +} + +template +static inline uint8_t* inlStuff(uint8_t* dst, const T* val) +{ + T* ptr = reinterpret_cast(dst); + *ptr++ = *val; + return reinterpret_cast(ptr); +} + + plGLEnumerate plGLPipeline::enumerator; plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3DDeviceModeRecord *devMode) @@ -159,9 +216,13 @@ bool plGLPipeline::PreRender(plDrawable* drawable, std::vector& visList bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& visList, plVisMgr* visMgr) { + plProfile_BeginTiming(PrepDrawable); + plDrawableSpans* ice = plDrawableSpans::ConvertNoRef(drawable); - if (!ice) + if (!ice) { + plProfile_EndTiming(PrepDrawable); return false; + } // Find our lights ICheckLighting(ice, visList, visMgr); @@ -175,8 +236,16 @@ bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& vis // generating particle tri lists. ice->PrepForRender(this); + // Any skinning necessary + if (!ISoftwareVertexBlend(ice, visList)) { + plProfile_EndTiming(PrepDrawable); + return false; + } + // Other stuff that we're ignoring for now... + plProfile_EndTiming(PrepDrawable); + return true; } @@ -1380,3 +1449,272 @@ void plGLPipeline::IDrawPlate(plPlate* plate) glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * 0)); } + + +bool plGLPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector& visList) +{ + if (IsDebugFlagSet(plPipeDbg::kFlagNoSkinning)) + return true; + + if (drawable->GetSkinTime() == fRenderCnt) + return true; + + const hsBitVector& blendBits = drawable->GetBlendingSpanVector(); + + if (drawable->GetBlendingSpanVector().Empty()) { + // This sucker doesn't have any skinning spans anyway. Just return + drawable->SetSkinTime(fRenderCnt); + return true; + } + + plProfile_BeginTiming(Skin); + + // lock the data buffer + + // First, figure out which buffers we need to blend. + constexpr size_t kMaxBufferGroups = 20; + constexpr size_t kMaxVertexBuffers = 20; + static char blendBuffers[kMaxBufferGroups][kMaxVertexBuffers]; + memset(blendBuffers, 0, kMaxBufferGroups * kMaxVertexBuffers * sizeof(**blendBuffers)); + + hsAssert(kMaxBufferGroups >= drawable->GetNumBufferGroups(), "Bigger than we counted on num groups skin."); + + const std::vector& spans = drawable->GetSpanArray(); + for (int16_t idx : visList) { + if (blendBits.IsBitSet(idx)) { + const plVertexSpan &vSpan = *(plVertexSpan *)spans[idx]; + hsAssert(kMaxVertexBuffers > vSpan.fVBufferIdx, "Bigger than we counted on num buffers skin."); + + blendBuffers[vSpan.fGroupIdx][vSpan.fVBufferIdx] = 1; + drawable->SetBlendingSpanVectorBit(idx, false); + } + } + + // Now go through each of the group/buffer (= a real vertex buffer) pairs we found, + // and blend into it. We'll lock the buffer once, and then for each span that + // uses it, set the matrix palette and and then do the blend for that span. + // When we've done all the spans for a group/buffer, we unlock it and move on. + for (size_t i = 0; i < kMaxBufferGroups; i++) { + for (size_t j = 0; j < kMaxVertexBuffers; j++) { + if (blendBuffers[i][j]) { + // Found one. Do the lock. + plGLVertexBufferRef* vRef = static_cast(drawable->GetVertexRef(i, j)); + + hsAssert(vRef->fData, "Going into skinning with no place to put results!"); + + uint8_t* destPtr = vRef->fData; + + for (int16_t idx : visList) { + const plIcicle& span = *(plIcicle*)spans[idx]; + if ((span.fGroupIdx == i) && (span.fVBufferIdx == j)) { + plProfile_Inc(NumSkin); + + hsMatrix44* matrixPalette = drawable->GetMatrixPalette(span.fBaseMatrix); + matrixPalette[0] = span.fLocalToWorld; + + uint8_t* ptr = vRef->fOwner->GetVertBufferData(vRef->fIndex); + ptr += span.fVStartIdx * vRef->fOwner->GetVertexSize(); + IBlendVertsIntoBuffer((plSpan*)&span, + matrixPalette, span.fNumMatrices, + ptr, + vRef->fOwner->GetVertexFormat(), + vRef->fOwner->GetVertexSize(), + destPtr + span.fVStartIdx * vRef->fVertexSize, + vRef->fVertexSize, + span.fVLength, + span.fLocalUVWChans); + vRef->SetDirty(true); + } + } + // Unlock and move on. + } + } + } + + plProfile_EndTiming(Skin); + + if (drawable->GetBlendingSpanVector().Empty()) { + // Only do this if we've blended ALL of the spans. Thus, this becomes a trivial + // rejection for all the skinning flags being cleared + drawable->SetSkinTime(fRenderCnt); + } + + return true; +} + +static inline void ISkinVertexFPU(const hsMatrix44& xfm, float wgt, + const float* pt_src, float* pt_dst, + const float* vec_src, float* vec_dst) +{ + const float& m00 = xfm.fMap[0][0]; + const float& m01 = xfm.fMap[0][1]; + const float& m02 = xfm.fMap[0][2]; + const float& m03 = xfm.fMap[0][3]; + const float& m10 = xfm.fMap[1][0]; + const float& m11 = xfm.fMap[1][1]; + const float& m12 = xfm.fMap[1][2]; + const float& m13 = xfm.fMap[1][3]; + const float& m20 = xfm.fMap[2][0]; + const float& m21 = xfm.fMap[2][1]; + const float& m22 = xfm.fMap[2][2]; + const float& m23 = xfm.fMap[2][3]; + + // position + { + const float& srcX = pt_src[0]; + const float& srcY = pt_src[1]; + const float& srcZ = pt_src[2]; + + pt_dst[0] += (srcX * m00 + srcY * m01 + srcZ * m02 + m03) * wgt; + pt_dst[1] += (srcX * m10 + srcY * m11 + srcZ * m12 + m13) * wgt; + pt_dst[2] += (srcX * m20 + srcY * m21 + srcZ * m22 + m23) * wgt; + } + + // normal + { + const float& srcX = vec_src[0]; + const float& srcY = vec_src[1]; + const float& srcZ = vec_src[2]; + + vec_dst[0] += (srcX * m00 + srcY * m01 + srcZ * m02) * wgt; + vec_dst[1] += (srcX * m10 + srcY * m11 + srcZ * m12) * wgt; + vec_dst[2] += (srcX * m20 + srcY * m21 + srcZ * m22) * wgt; + } +} + +#ifdef HAVE_SSE3 +static inline void ISkinDpSSE3(const float* src, float* dst, const __m128& mc0, + const __m128& mc1, const __m128& mc2, const __m128& mwt) +{ + __m128 msr = _mm_load_ps(src); + __m128 _x = _mm_mul_ps(_mm_mul_ps(mc0, msr), mwt); + __m128 _y = _mm_mul_ps(_mm_mul_ps(mc1, msr), mwt); + __m128 _z = _mm_mul_ps(_mm_mul_ps(mc2, msr), mwt); + + __m128 hbuf1 = _mm_hadd_ps(_x, _y); + __m128 hbuf2 = _mm_hadd_ps(_z, _z); + hbuf1 = _mm_hadd_ps(hbuf1, hbuf2); + __m128 _dst = _mm_load_ps(dst); + _dst = _mm_add_ps(_dst, hbuf1); + _mm_store_ps(dst, _dst); +} +#endif // HAVE_SSE3 + +static inline void ISkinVertexSSE3(const hsMatrix44& xfm, float wgt, + const float* pt_src, float* pt_dst, + const float* vec_src, float* vec_dst) +{ +#ifdef HAVE_SSE3 + __m128 mc0 = _mm_load_ps(xfm.fMap[0]); + __m128 mc1 = _mm_load_ps(xfm.fMap[1]); + __m128 mc2 = _mm_load_ps(xfm.fMap[2]); + __m128 mwt = _mm_set_ps1(wgt); + + ISkinDpSSE3(pt_src, pt_dst, mc0, mc1, mc2, mwt); + ISkinDpSSE3(vec_src, vec_dst, mc0, mc1, mc2, mwt); +#endif // HAVE_SSE3 +} + +#ifdef HAVE_SSE41 +static inline void ISkinDpSSE41(const float* src, float* dst, const __m128& mc0, + const __m128& mc1, const __m128& mc2, const __m128& mwt) +{ + enum { DP_F4_X = 0xF1, DP_F4_Y = 0xF2, DP_F4_Z = 0xF4 }; + + __m128 msr = _mm_load_ps(src); + __m128 _r = _mm_dp_ps(msr, mc0, DP_F4_X); + _r = _mm_or_ps(_r, _mm_dp_ps(msr, mc1, DP_F4_Y)); + _r = _mm_or_ps(_r, _mm_dp_ps(msr, mc2, DP_F4_Z)); + + __m128 _dst = _mm_load_ps(dst); + _dst = _mm_add_ps(_dst, _mm_mul_ps(_r, mwt)); + _mm_store_ps(dst, _dst); +} +#endif // HAVE_SSE41 + +static inline void ISkinVertexSSE41(const hsMatrix44& xfm, float wgt, + const float* pt_src, float* pt_dst, + const float* vec_src, float* vec_dst) +{ +#ifdef HAVE_SSE41 + __m128 mc0 = _mm_load_ps(xfm.fMap[0]); + __m128 mc1 = _mm_load_ps(xfm.fMap[1]); + __m128 mc2 = _mm_load_ps(xfm.fMap[2]); + __m128 mwt = _mm_set_ps1(wgt); + + ISkinDpSSE41(pt_src, pt_dst, mc0, mc1, mc2, mwt); + ISkinDpSSE41(vec_src, vec_dst, mc0, mc1, mc2, mwt); +#endif // HAVE_SSE41 +} + +typedef void(*skin_vert_ptr)(const hsMatrix44&, float, const float*, float*, const float*, float*); + +template +static void IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, int numMatrices, + const uint8_t* src, uint8_t format, uint32_t srcStride, + uint8_t* dest, uint32_t destStride, uint32_t count, + uint16_t localUVWChans) +{ + alignas(16) float pt_buf[] = { 0.f, 0.f, 0.f, 1.f }; + alignas(16) float vec_buf[] = { 0.f, 0.f, 0.f, 0.f }; + hsPoint3* pt = reinterpret_cast(pt_buf); + hsVector3* vec = reinterpret_cast(vec_buf); + + uint32_t indices; + float weights[4]; + + // Dropped support for localUVWChans at templatization of code + hsAssert(localUVWChans == 0, "support for skinned UVWs dropped. reimplement me?"); + const size_t uvChanSize = plGBufferGroup::CalcNumUVs(format) * sizeof(float) * 3; + uint8_t numWeights = (format & plGBufferGroup::kSkinWeightMask) >> 4; + + for (uint32_t i = 0; i < count; ++i) { + // Extract data + src = inlExtract(src, pt); + + float weightSum = 0.f; + for (uint8_t j = 0; j < numWeights; ++j) { + src = inlExtract(src, &weights[j]); + weightSum += weights[j]; + } + weights[numWeights] = 1.f - weightSum; + + if (format & plGBufferGroup::kSkinIndices) + src = inlExtract(src, &indices); + else + indices = 1 << 8; + src = inlExtract(src, vec); + + // Destination buffers (float4 for SSE alignment) + alignas(16) float destNorm_buf[] = { 0.f, 0.f, 0.f, 0.f }; + alignas(16) float destPt_buf[] = { 0.f, 0.f, 0.f, 1.f }; + + // Blend + for (uint32_t j = 0; j < numWeights + 1; ++j) { + if (weights[j]) + T(matrixPalette[indices & 0xFF], weights[j], pt_buf, destPt_buf, vec_buf, destNorm_buf); + indices >>= 8; + } + // Probably don't really need to renormalize this. There errors are + // going to be subtle and "smooth". + /* hsFastMath::NormalizeAppr(destNorm); */ + + // Slam data into position now + dest = inlStuff(dest, reinterpret_cast(destPt_buf)); + dest = inlStuff(dest, reinterpret_cast(destNorm_buf)); + + // Jump past colors and UVws + dest += sizeof(uint32_t) * 2 + uvChanSize; + src += sizeof(uint32_t) * 2 + uvChanSize; + } +} + +// CPU-optimized functions requiring dispatch +hsCpuFunctionDispatcher plGLPipeline::blend_vert_buffer { + &IBlendVertBuffer, + nullptr, // SSE1 + nullptr, // SSE2 + &IBlendVertBuffer, + nullptr, // SSSE3 + &IBlendVertBuffer +}; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 8bf631de6a..751681ba2d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -68,6 +68,9 @@ class plGLPipeline : public pl3DPipeline friend class plGLDevice; protected: + typedef void(*blend_vert_buffer_ptr)(plSpan*, hsMatrix44*, int, const uint8_t*, uint8_t , uint32_t, uint8_t*, uint32_t, uint32_t, uint16_t); + static hsCpuFunctionDispatcher blend_vert_buffer; + plGLMaterialShaderRef* fMatRefList; plGLRenderTargetRef* fRenderTargetRefList; @@ -144,6 +147,28 @@ class plGLPipeline : public pl3DPipeline void IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale); void IDrawPlate(plPlate* plate); + /** + * Emulate matrix palette operations in software. + * + * The big difference between the hardware and software versions is we only + * want to lock the vertex buffer once and blend all the verts we're going + * to in software, so the vertex blend happens once for an entire drawable. + * In hardware, we want the opposite, to break it into managable chunks, + * manageable meaning few enough matrices to fit into hardware registers. + * So for hardware version, we set up our palette, draw a span or few, + * setup our matrix palette with new matrices, draw, repeat. + */ + bool ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector& visList); + + /** + * Given a pointer into a buffer of verts that have blending data in the + * plVertCoder format, blends them into the destination buffer given + * without the blending info. + */ + void IBlendVertsIntoBuffer(plSpan* span, hsMatrix44* matrixPalette, int numMatrices, const uint8_t* src, uint8_t format, uint32_t srcStride, uint8_t* dest, uint32_t destStride, uint32_t count, uint16_t localUVWChans) { + blend_vert_buffer.call(span, matrixPalette, numMatrices, src, format, srcStride, dest, destStride, count, localUVWChans); + }; + private: static plGLEnumerate enumerator; }; diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 41e933a788..bac426967b 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -92,10 +92,11 @@ plProfile_Extern(TotalTexSize); plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); +plProfile_Extern(NumSkin); -plProfile_CreateTimer("PrepShadows", "PipeT", PrepShadows); -plProfile_CreateTimer("PrepDrawable", "PipeT", PrepDrawable); -plProfile_CreateTimer(" Skin", "PipeT", Skin); +plProfile_Extern(PrepShadows); +plProfile_Extern(PrepDrawable); +plProfile_Extern(Skin); plProfile_Extern(RenderSpan); plProfile_Extern(MergeCheck); plProfile_Extern(MergeSpan); @@ -116,7 +117,6 @@ plProfile_CreateCounter("AvRTPoolUsed", "PipeC", AvRTPoolUsed); plProfile_CreateCounter("AvRTPoolCount", "PipeC", AvRTPoolCount); plProfile_CreateCounter("AvRTPoolRes", "PipeC", AvRTPoolRes); plProfile_CreateCounter("AvRTShrinkTime", "PipeC", AvRTShrinkTime); -plProfile_CreateCounter("NumSkin", "PipeC", NumSkin); plMetalEnumerate plMetalPipeline::enumerator; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index 5c1fbea8ad..14d4297969 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -48,6 +48,11 @@ plProfile_CreateTimer("VisSelect", "PipeT", VisSelect); plProfile_CreateTimer("PlateMgr", "PipeT", PlateMgr); plProfile_CreateTimer("DebugText", "PipeT", DebugText); plProfile_CreateTimer("Reset", "PipeT", Reset); +plProfile_CreateTimer("PrepShadows", "PipeT", PrepShadows); +plProfile_CreateTimer("PrepDrawable", "PipeT", PrepDrawable); +plProfile_CreateTimer(" Skin", "PipeT", Skin); +plProfile_CreateTimer(" AvSort", "PipeT", AvatarSort); +plProfile_CreateTimer(" ClearLights", "PipeT", ClearLights); plProfile_CreateTimer("RenderSpan", "PipeT", RenderSpan); plProfile_CreateTimer(" MergeCheck", "PipeT", MergeCheck); @@ -77,6 +82,7 @@ plProfile_CreateCounter("LightChar", "PipeC", LightChar); plProfile_CreateCounter("LightActive", "PipeC", LightActive); plProfile_CreateCounter("Lights Found", "PipeC", FindLightsFound); plProfile_CreateCounter("Perms Found", "PipeC", FindLightsPerm); +plProfile_CreateCounter("NumSkin", "PipeC", NumSkin); plProfile_CreateCounter("Polys", "General", DrawTriangles); plProfile_CreateCounter("Material Change", "Draw", MatChange); From 25d3e2fa6df7c4aabcc89f2a90be687bc8431cb7 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 1 Jul 2022 20:02:51 -0700 Subject: [PATCH 59/76] Move Push/Pop Layer stuff to pl3DPipeline This is what calls `Eval()` to make layer animations work, so that's now hooked up for plGLPipeline. I don't love this approach because it feels weird doing it in the shader class, and I suspect we need to know about layer overrides when the shader is being generated, but... for now it sorta works. --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 82 -------------- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 5 - .../pfGLPipeline/plGLMaterialShaderRef.cpp | 22 +++- .../pfGLPipeline/plGLMaterialShaderRef.h | 6 +- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 + .../pfMetalPipeline/plMetalPipeline.cpp | 81 ------------- .../pfMetalPipeline/plMetalPipeline.h | 5 - .../PubUtilLib/plPipeline/pl3DPipeline.h | 106 +++++++++++++++++- 8 files changed, 125 insertions(+), 183 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index de01b1169f..ff5d97aa81 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -5299,88 +5299,6 @@ void plDXPipeline::IBottomLayer() // Special effects ///////////////////////////////////////////////////////////// -// IPushOverBaseLayer ///////////////////////////////////////////////////////// -// Sets fOverBaseLayer (if any) as a wrapper on top of input layer. -// This allows the OverBaseLayer to intercept and modify queries of -// the real current layer's properties (e.g. color or state). -// fOverBaseLayer is set to only get applied to the base layer during -// multitexturing. -// Must be matched with call to IPopOverBaseLayer. -plLayerInterface* plDXPipeline::IPushOverBaseLayer(plLayerInterface* li) -{ - if( !li ) - return nullptr; - - fOverLayerStack.push_back(li); - - if( !fOverBaseLayer ) - return fOverBaseLayer = li; - - fForceMatHandle = true; - fOverBaseLayer = fOverBaseLayer->Attach(li); - fOverBaseLayer->Eval(fTime, fFrame, 0); - return fOverBaseLayer; -} - -// IPopOverBaseLayer ///////////////////////////////////////////////////////// -// Removes fOverBaseLayer as wrapper on top of input layer. -// Should match calls to IPushOverBaseLayer. -plLayerInterface* plDXPipeline::IPopOverBaseLayer(plLayerInterface* li) -{ - if( !li ) - return nullptr; - - fForceMatHandle = true; - - plLayerInterface* pop = fOverLayerStack.back(); - fOverLayerStack.pop_back(); - fOverBaseLayer = fOverBaseLayer->Detach(pop); - - return pop; -} - -// IPushOverAllLayer /////////////////////////////////////////////////// -// Push fOverAllLayer (if any) as wrapper around the input layer. -// fOverAllLayer is set to be applied to each layer during multitexturing. -// Must be matched by call to IPopOverAllLayer -plLayerInterface* plDXPipeline::IPushOverAllLayer(plLayerInterface* li) -{ - if( !li ) - return nullptr; - - fOverLayerStack.push_back(li); - - if( !fOverAllLayer ) - { - fOverAllLayer = li; - fOverAllLayer->Eval(fTime, fFrame, 0); - return fOverAllLayer; - } - - fForceMatHandle = true; - fOverAllLayer = fOverAllLayer->Attach(li); - fOverAllLayer->Eval(fTime, fFrame, 0); - - return fOverAllLayer; -} - -// IPopOverAllLayer ////////////////////////////////////////////////// -// Remove fOverAllLayer as wrapper on top of input layer. -// Should match calls to IPushOverAllLayer. -plLayerInterface* plDXPipeline::IPopOverAllLayer(plLayerInterface* li) -{ - if( !li ) - return nullptr; - - fForceMatHandle = true; - - plLayerInterface* pop = fOverLayerStack.back(); - fOverLayerStack.pop_back(); - fOverAllLayer = fOverAllLayer->Detach(pop); - - return pop; -} - // PiggyBacks - used in techniques like projective lighting. // PiggyBacks are layers appended to each drawprimitive pass. // For example, if a material has 3 layers which will be drawn diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index 07047a3f54..fe9d10dffc 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -341,11 +341,6 @@ class plDXPipeline : public pl3DPipeline void IBottomLayer(); // Push special effects - plLayerInterface* IPushOverBaseLayer(plLayerInterface* li); - plLayerInterface* IPopOverBaseLayer(plLayerInterface* li); - plLayerInterface* IPushOverAllLayer(plLayerInterface* li); - plLayerInterface* IPopOverAllLayer(plLayerInterface* li); - int ISetNumActivePiggyBacks(); void IPushPiggyBacks(hsGMaterial* mat); void IPopPiggyBacks(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 88f2facb1f..d91cd9c30b 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -42,6 +42,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLMaterialShaderRef.h" #include "plGLDevice.h" +#include "plGLPipeline.h" #include #include @@ -51,7 +52,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsBitVector.h" #include "hsGMatState.inl" -#include "plPipeline.h" #include "plPipeDebugFlags.h" #include "plDrawable/plGBufferGroup.h" @@ -232,7 +232,7 @@ void main() { fragColor = vec4(currColor, currAlpha); })"; -plGLMaterialShaderRef::plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe) +plGLMaterialShaderRef::plGLMaterialShaderRef(hsGMaterial* mat, plGLPipeline* pipe) : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(0), fFragShaderRef(0) { ISetupShaderContexts(); @@ -276,16 +276,22 @@ void plGLMaterialShaderRef::SetupTextureRefs() if (!layer) continue; + layer = fPipeline->IPushOverAllLayer(layer); + // Load the image plBitmap* img = plBitmap::ConvertNoRef(layer->GetTexture()); - if (!img) + if (!img) { + layer = fPipeline->IPopOverAllLayer(layer); continue; + } plGLTextureRef* texRef = static_cast(img->GetDeviceRef()); - if (!texRef->fRef) + if (!texRef->fRef) { + layer = fPipeline->IPopOverAllLayer(layer); continue; + } fPipeline->CheckTextureRef(layer); @@ -327,6 +333,7 @@ void plGLMaterialShaderRef::SetupTextureRefs() glUniform1i(this->uTexture[i], numTextures); LOG_GL_ERROR_CHECK("Uniform Texture failed") + layer = fPipeline->IPopOverAllLayer(layer); numTextures++; } } @@ -582,12 +589,12 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< // Ignoring the bit about self-rendering cube maps - plLayerInterface* currLay = /*IPushOverBaseLayer*/ fMaterial->GetLayer(layer); + plLayerInterface* currLay = fPipeline->IPushOverBaseLayer(fMaterial->GetLayer(layer)); if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagBumpW) && (currLay->GetMiscFlags() & hsGMatState::kMiscBumpDu)) currLay = fMaterial->GetLayer(++layer); - //currLay = IPushOverAllLayer(currLay); + currLay = fPipeline->IPushOverAllLayer(currLay); hsGMatState state = ICompositeLayerState(currLay); @@ -629,6 +636,9 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< //ISetBumpMatrices(currLay); } + currLay = fPipeline->IPopOverAllLayer(currLay); + currLay = fPipeline->IPopOverBaseLayer(currLay); + std::shared_ptr vVtxColor = IFindVariable("vVtxColor", "vec4"); std::shared_ptr fBaseAlpha = std::make_shared("baseAlpha", "float"); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 21e640bce1..03674e3d69 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -52,7 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsGMatState.h" class hsGMaterial; -class plPipeline; +class plGLPipeline; class plLayerInterface; enum plGLShaderConstants : GLuint { @@ -100,7 +100,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef protected: hsGMaterial* fMaterial; - plPipeline* fPipeline; + plGLPipeline* fPipeline; GLuint fVertShaderRef; GLuint fFragShaderRef; @@ -142,7 +142,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef void Link(plGLMaterialShaderRef** back) { plGLDeviceRef::Link((plGLDeviceRef**)back); } plGLMaterialShaderRef* GetNext() { return (plGLMaterialShaderRef*)fNext; } - plGLMaterialShaderRef(hsGMaterial* mat, plPipeline* pipe); + plGLMaterialShaderRef(hsGMaterial* mat, plGLPipeline* pipe); virtual ~plGLMaterialShaderRef(); void Release(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 751681ba2d..10caa3803c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -66,6 +66,7 @@ class plGLPipeline : public pl3DPipeline { friend class plGLPlateManager; friend class plGLDevice; + friend class plGLMaterialShaderRef; protected: typedef void(*blend_vert_buffer_ptr)(plSpan*, hsMatrix44*, int, const uint8_t*, uint8_t , uint32_t, uint8_t*, uint32_t, uint32_t, uint16_t); diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index bac426967b..9ac4b70fec 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -2516,87 +2516,6 @@ void plMetalPipeline::PopCurrentLightSources() // Special effects ///////////////////////////////////////////////////////////// -// IPushOverBaseLayer ///////////////////////////////////////////////////////// -// Sets fOverBaseLayer (if any) as a wrapper on top of input layer. -// This allows the OverBaseLayer to intercept and modify queries of -// the real current layer's properties (e.g. color or state). -// fOverBaseLayer is set to only get applied to the base layer during -// multitexturing. -// Must be matched with call to IPopOverBaseLayer. -plLayerInterface* plMetalPipeline::IPushOverBaseLayer(plLayerInterface* li) -{ - if (!li) - return nullptr; - - fOverLayerStack.emplace_back(li); - - if (!fOverBaseLayer) - return fOverBaseLayer = li; - - fForceMatHandle = true; - fOverBaseLayer = fOverBaseLayer->Attach(li); - fOverBaseLayer->Eval(fTime, fFrame, 0); - return fOverBaseLayer; -} - -// IPopOverBaseLayer ///////////////////////////////////////////////////////// -// Removes fOverBaseLayer as wrapper on top of input layer. -// Should match calls to IPushOverBaseLayer. -plLayerInterface* plMetalPipeline::IPopOverBaseLayer(plLayerInterface* li) -{ - if (!li) - return nullptr; - - fForceMatHandle = true; - - plLayerInterface* pop = fOverLayerStack.back(); - fOverLayerStack.pop_back(); - fOverBaseLayer = fOverBaseLayer->Detach(pop); - - return pop; -} - -// IPushOverAllLayer /////////////////////////////////////////////////// -// Push fOverAllLayer (if any) as wrapper around the input layer. -// fOverAllLayer is set to be applied to each layer during multitexturing. -// Must be matched by call to IPopOverAllLayer -plLayerInterface* plMetalPipeline::IPushOverAllLayer(plLayerInterface* li) -{ - if (!li) - return nullptr; - - fOverLayerStack.push_back(li); - - if (!fOverAllLayer) { - fOverAllLayer = li; - fOverAllLayer->Eval(fTime, fFrame, 0); - return fOverAllLayer; - } - - fForceMatHandle = true; - fOverAllLayer = fOverAllLayer->Attach(li); - fOverAllLayer->Eval(fTime, fFrame, 0); - - return fOverAllLayer; -} - -// IPopOverAllLayer ////////////////////////////////////////////////// -// Remove fOverAllLayer as wrapper on top of input layer. -// Should match calls to IPushOverAllLayer. -plLayerInterface* plMetalPipeline::IPopOverAllLayer(plLayerInterface* li) -{ - if (!li) - return nullptr; - - fForceMatHandle = true; - - plLayerInterface* pop = fOverLayerStack.back(); - fOverLayerStack.pop_back(); - fOverAllLayer = fOverAllLayer->Detach(pop); - - return pop; -} - // IPushProjPiggyBack ////////////////////////////////////////////////// // Push a projected texture on as a piggy back. void plMetalPipeline::IPushProjPiggyBack(plLayerInterface* li) diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 04e2f84095..2c0335f7aa 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -178,11 +178,6 @@ class plMetalPipeline : public pl3DPipeline void ISetCullMode(bool flip = false); - plLayerInterface* IPushOverBaseLayer(plLayerInterface* li); - plLayerInterface* IPopOverBaseLayer(plLayerInterface* li); - plLayerInterface* IPushOverAllLayer(plLayerInterface* li); - plLayerInterface* IPopOverAllLayer(plLayerInterface* li); - void IPushPiggyBacks(hsGMaterial* mat); void IPopPiggyBacks(); void IPushProjPiggyBack(plLayerInterface* li); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 6fb5783f50..1f5e7208fb 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -681,7 +681,6 @@ class pl3DPipeline : public plPipeline /** Removes a layer wrapper installed by AppendLayerInterface. */ plLayerInterface* RemoveLayerInterface(plLayerInterface* li, bool onAllLayers = false) override; - /** * Return the current bits set to be always on for the given category * (e.g. ZFlags). @@ -853,6 +852,39 @@ class pl3DPipeline : public plPipeline plRenderTarget* IGetNextAvRT(); void IFreeAvRT(plRenderTarget* tex); + /** + * Sets fOverBaseLayer (if any) as a wrapper on top of input layer. + * This allows the OverBaseLayer to intercept and modify queries of + * the real current layer's properties (e.g. color or state). + * fOverBaseLayer is set to only get applied to the base layer during + * multitexturing. + * + * Must be matched with call to IPopOverBaseLayer. + */ + plLayerInterface* IPushOverBaseLayer(plLayerInterface* li); + + /** + * Removes fOverBaseLayer as wrapper on top of input layer. + * + * Should match calls to IPushOverBaseLayer. + */ + plLayerInterface* IPopOverBaseLayer(plLayerInterface* li); + + /** + * Push fOverAllLayer (if any) as wrapper around the input layer. + * + * fOverAllLayer is set to be applied to each layer during multitexturing. + * + * Must be matched by call to IPopOverAllLayer + */ + plLayerInterface* IPushOverAllLayer(plLayerInterface* li); + + /** + * Remove fOverAllLayer as wrapper on top of input layer. + * + * Should match calls to IPushOverAllLayer. + */ + plLayerInterface* IPopOverAllLayer(plLayerInterface* li); /** * For every span in the list of visible span indices, find the list of @@ -1747,6 +1779,78 @@ void pl3DPipeline::IFreeAvRT(plRenderTarget* tex) } +template +plLayerInterface* pl3DPipeline::IPushOverBaseLayer(plLayerInterface* li) +{ + if (!li) + return nullptr; + + fOverLayerStack.push_back(li); + + if (!fOverBaseLayer) + return fOverBaseLayer = li; + + fForceMatHandle = true; + fOverBaseLayer = fOverBaseLayer->Attach(li); + fOverBaseLayer->Eval(fTime, fFrame, 0); + return fOverBaseLayer; +} + + +template +plLayerInterface* pl3DPipeline::IPopOverBaseLayer(plLayerInterface* li) +{ + if (!li) + return nullptr; + + fForceMatHandle = true; + + plLayerInterface* pop = fOverLayerStack.back(); + fOverLayerStack.pop_back(); + fOverBaseLayer = fOverBaseLayer->Detach(pop); + + return pop; +} + + +template +plLayerInterface* pl3DPipeline::IPushOverAllLayer(plLayerInterface* li) +{ + if (!li) + return nullptr; + + fOverLayerStack.push_back(li); + + if (!fOverAllLayer) { + fOverAllLayer = li; + fOverAllLayer->Eval(fTime, fFrame, 0); + return fOverAllLayer; + } + + fForceMatHandle = true; + fOverAllLayer = fOverAllLayer->Attach(li); + fOverAllLayer->Eval(fTime, fFrame, 0); + + return fOverAllLayer; +} + + +template +plLayerInterface* pl3DPipeline::IPopOverAllLayer(plLayerInterface* li) +{ + if (!li) + return nullptr; + + fForceMatHandle = true; + + plLayerInterface* pop = fOverLayerStack.back(); + fOverLayerStack.pop_back(); + fOverAllLayer = fOverAllLayer->Detach(pop); + + return pop; +} + + template void pl3DPipeline::ICheckLighting(plDrawableSpans* drawable, std::vector& visList, plVisMgr* visMgr) { From fed4c616b16c85e172ff322021fab39fba1370f6 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 30 Dec 2022 12:59:58 -0800 Subject: [PATCH 60/76] Fix GL pipeline crash opening the KI --- .../Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index d91cd9c30b..013f9478d0 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -286,6 +286,8 @@ void plGLMaterialShaderRef::SetupTextureRefs() continue; } + fPipeline->CheckTextureRef(layer); + plGLTextureRef* texRef = static_cast(img->GetDeviceRef()); if (!texRef->fRef) { @@ -293,8 +295,6 @@ void plGLMaterialShaderRef::SetupTextureRefs() continue; } - fPipeline->CheckTextureRef(layer); - LOG_GL_ERROR_CHECK("PRE-Active Texture failed") glActiveTexture(GL_TEXTURE0 + numTextures); From 8256d82b13385a45eb6bd26c445fd2218601f561 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 30 Dec 2022 13:00:36 -0800 Subject: [PATCH 61/76] Fix GL "too many blend modes" crash --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 94f31d1279..5ab89f1d4b 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -778,6 +778,7 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, LOG_GL_ERROR_CHECK("PRE Render failed"); + hsRefCnt_SafeAssign(fCurrMaterial, material); mRef->SetupTextureRefs(); /* Vertex Buffer stuff */ @@ -837,7 +838,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, if (mRef->uPassNumber != -1) glUniform1i(mRef->uPassNumber, pass); - plLayerInterface* lay = material->GetLayer(mRef->GetPassIndex(pass)); + fCurrLayerIdx = mRef->GetPassIndex(pass); + plLayerInterface* lay = material->GetLayer(fCurrLayerIdx); ICalcLighting(mRef, lay, &span); @@ -1055,7 +1057,7 @@ void plGLPipeline::IHandleBlendMode(hsGMatState flags) default: { - hsAssert(false, "Too many blend modes specified in material"); + hsAssert(false, ST::format("Too many blend modes specified in material {}", fCurrMaterial->GetKeyName()).c_str()); plLayer* lay = plLayer::ConvertNoRef(fCurrMaterial->GetLayer(fCurrLayerIdx)->BottomOfStack()); if (lay) { From 34818b1f207c754c9e04d78a1c5335935e7a7e85 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 8 Jan 2023 22:33:03 -0800 Subject: [PATCH 62/76] Add plGLVersion helper function for testing --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 16 ++++++++-------- .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 13 +++++++++++++ .../pfGLPipeline/plGLMaterialShaderRef.cpp | 2 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 8 ++++---- .../pfGLPipeline/plGLPlateManager.cpp | 18 +++++++++--------- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 9a2fd4432d..e71cd86b1b 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -370,7 +370,7 @@ bool plGLDevice::InitDevice() plStatusLog::AddLineSF("pipeline.log", "Initialized with OpenGL {}", reinterpret_cast(glGetString(GL_VERSION))); #ifdef HS_DEBUGGING - if (epoxy_gl_version() >= 43) { + if (plGLVersion() >= 43) { glEnable(GL_DEBUG_OUTPUT); // Turn off low-severity messages @@ -546,7 +546,7 @@ void plGLDevice::CheckStaticVertexBuffer(VertexBufferRef* vRef, plGBufferGroup* hsAssert(!vRef->Volatile(), "Creating a managed vertex buffer for a volatile buffer ref"); if (!vRef->fRef) { - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glCreateBuffers(1, &vRef->fRef); } else { glGenBuffers(1, &vRef->fRef); @@ -575,7 +575,7 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* if (ref->fData) { - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glNamedBufferData(ref->fRef, size, ref->fData + vertStart, GL_STATIC_DRAW); } else { glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); @@ -626,7 +626,7 @@ void plGLDevice::FillStaticVertexBufferRef(VertexBufferRef* ref, plGBufferGroup* } hsAssert((ptr - buffer) == size, "Didn't fill the buffer?"); - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glNamedBufferData(ref->fRef, size, buffer, GL_STATIC_DRAW); } else { glBindBuffer(GL_ARRAY_BUFFER, ref->fRef); @@ -696,7 +696,7 @@ void plGLDevice::CheckIndexBuffer(IndexBufferRef* iRef) if (!iRef->fRef && iRef->fCount) { iRef->SetVolatile(false); - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glCreateBuffers(1, &iRef->fRef); } else { glGenBuffers(1, &iRef->fRef); @@ -715,7 +715,7 @@ void plGLDevice::FillIndexBufferRef(IndexBufferRef* iRef, plGBufferGroup* owner, if (!size) return; - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glNamedBufferData(iRef->fRef, size, owner->GetIndexBufferData(idx) + startIdx, GL_STATIC_DRAW); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iRef->fRef); @@ -826,7 +826,7 @@ void plGLDevice::MakeTextureRef(TextureRef* tRef, plLayerInterface* layer, plMip glBindTexture(tRef->fMapping, tRef->fRef); BindTexture(tRef, img, tRef->fMapping); - if (epoxy_gl_version() >= 43) { + if (plGLVersion() >= 43) { glObjectLabel(GL_TEXTURE, tRef->fRef, -1, img->GetKeyName().c_str()); } @@ -862,7 +862,7 @@ void plGLDevice::MakeCubicTextureRef(TextureRef* tRef, plLayerInterface* layer, BindTexture(tRef, img->GetFace(i), kFaceMapping[i]); } - if (epoxy_gl_version() >= 43) { + if (plGLVersion() >= 43) { glObjectLabel(GL_TEXTURE, tRef->fRef, -1, img->GetKeyName().c_str()); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index 5e944ecebc..8936e70a20 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -47,6 +47,19 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include +inline int plGLVersion() +{ + // This exists for testing purposes to force the pipeline to behave as if a + // specific version of OpenGL were present, mainly for ensuring + // compatibility with older GL API versions on machines where newer + // versions are available by default. To pretend to be limited to a + // specific version, just return the GL version with the decimal removed as + // an integer: + + // return 42; // Pretend we only support OpenGL 4.2 + return epoxy_gl_version(); +} + // Helper macro for logging GL Errors #ifdef HS_DEBUGGING # include "plStatusLog/plStatusLog.h" diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 013f9478d0..ca97aa3b73 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -413,7 +413,7 @@ void plGLMaterialShaderRef::ICompile() fRef = glCreateProgram(); LOG_GL_ERROR_CHECK("Create Program failed"); - if (epoxy_gl_version() >= 43) { + if (plGLVersion() >= 43) { const char* name = ST::format("hsGMaterial::{}", fMaterial->GetKeyName()).c_str(); glObjectLabel(GL_PROGRAM, fRef, strlen(name), name); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 5ab89f1d4b..5f34d385fb 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -374,7 +374,7 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) // since we only render one face at a time. If we were rendering part of face X, then part // of face Y, then more of face X, then they would all need their own depth buffers. if (owner->GetZDepth() && (owner->GetFlags() & (plRenderTarget::kIsTexture | plRenderTarget::kIsOffscreen))) { - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glCreateRenderbuffers(1, &depthBuffer); glNamedRenderbufferStorage(depthBuffer, GL_DEPTH24_STENCIL8, owner->GetWidth(), owner->GetHeight()); } else { @@ -408,7 +408,7 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) ref->fDepthBuffer = depthBuffer; ref->fMapping = GL_TEXTURE_2D; - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glCreateTextures(GL_TEXTURE_2D, 1, &ref->fRef); glTextureStorage2D(ref->fRef, 1, GL_RGBA8, owner->GetWidth(), owner->GetHeight()); glTextureParameteri(ref->fRef, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -672,7 +672,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& LOG_GL_ERROR_CHECK(ST::format("Use Program with material \"{}\" failed", material->GetKeyName())); GLuint vao = 0; - if (epoxy_gl_version() >= 30) { + if (plGLVersion() >= 30) { // TODO: Figure out how to use VAOs properly :( glGenVertexArrays(1, &vao); glBindVertexArray(vao); @@ -703,7 +703,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& tempIce.fVStartIdx, tempIce.fVLength, // These are used as our accumulated range tempIce.fIPackedIdx, tempIce.fILength ); - if (epoxy_gl_version() >= 30) + if (plGLVersion() >= 30) glDeleteVertexArrays(1, &vao); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp index 67b8e90f0f..8c96bb91ab 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPlateManager.cpp @@ -82,7 +82,7 @@ void plGLPlateManager::ICreateGeometry() GLuint vbo, ibo, vao = 0; - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 45) { glCreateBuffers(1, &vbo); glObjectLabel(GL_BUFFER, vbo, -1, "plPlate/VBO"); glNamedBufferStorage(vbo, sizeof(verts), verts, 0); @@ -112,7 +112,7 @@ void plGLPlateManager::ICreateGeometry() glVertexArrayAttribBinding(vao, kVtxColor, 0); glVertexArrayAttribBinding(vao, kVtxUVWSrc, 0); } else { - if (epoxy_gl_version() >= 30) { + if (plGLVersion() >= 30) { glGenVertexArrays(1, &vao); glBindVertexArray(vao); } @@ -125,9 +125,9 @@ void plGLPlateManager::ICreateGeometry() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - if (epoxy_gl_version() >= 30) { + if (plGLVersion() >= 30) { glEnableVertexAttribArray(kVtxPosition); - glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), 0); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 0)); glEnableVertexAttribArray(kVtxNormal); glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3)); @@ -147,8 +147,8 @@ void plGLPlateManager::ICreateGeometry() void plGLPlateManager::IReleaseGeometry() { - if (epoxy_gl_version() >= 30 && fBuffers.ARef) { - if (epoxy_gl_version() >= 45) { + if (plGLVersion() >= 30 && fBuffers.ARef) { + if (plGLVersion() >= 45) { glDisableVertexArrayAttrib(fBuffers.ARef, kVtxPosition); glDisableVertexArrayAttrib(fBuffers.ARef, kVtxNormal); glDisableVertexArrayAttrib(fBuffers.ARef, kVtxColor); @@ -184,7 +184,7 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) return; } - if (epoxy_gl_version() >= 30) { + if (plGLVersion() >= 30) { if (fBuffers.ARef == 0) return; @@ -192,7 +192,7 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) } else { glBindBuffer(GL_ARRAY_BUFFER, fBuffers.VRef); - glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), 0); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 0)); glEnableVertexAttribArray(kVtxPosition); glVertexAttribPointer(kVtxNormal, 3, GL_FLOAT, GL_FALSE, sizeof(plPlateVertex), (void*)(sizeof(float) * 3)); @@ -221,6 +221,6 @@ void plGLPlateManager::IDrawToDevice(plPipeline* pipe) if (cull) glEnable(GL_CULL_FACE); - if (epoxy_gl_version() >= 30) + if (plGLVersion() >= 30) glBindVertexArray(0); } From f35843f0691fbe50a3e1d3aab3bcce3b374dec7d Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sun, 19 Feb 2023 13:30:19 -0800 Subject: [PATCH 63/76] Initial pass of avatar rendering (with no textures) --- .../FeatureLib/pfDXPipeline/plDXPipeline.cpp | 167 +----------------- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 1 - .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 15 +- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 161 +++++++++++++++-- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 + .../pfMetalPipeline/plMetalPipeline.cpp | 11 +- .../PubUtilLib/plPipeline/pl3DPipeline.cpp | 10 ++ .../PubUtilLib/plPipeline/pl3DPipeline.h | 161 +++++++++++++++++ 8 files changed, 344 insertions(+), 183 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp index ff5d97aa81..02fa842066 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.cpp @@ -285,13 +285,10 @@ plProfile_Extern(LayChange); plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); plProfile_Extern(NumSkin); - -plProfile_CreateCounterNoReset("Reload", "PipeC", PipeReload); - +plProfile_Extern(PipeReload); plProfile_Extern(PrepShadows); plProfile_Extern(PrepDrawable); plProfile_Extern(Skin); -plProfile_Extern(AvatarSort); plProfile_Extern(ClearLights); plProfile_Extern(RenderSpan); plProfile_Extern(MergeCheck); @@ -307,6 +304,13 @@ plProfile_Extern(RenderPrim); plProfile_Extern(PlateMgr); plProfile_Extern(DebugText); plProfile_Extern(Reset); +plProfile_Extern(AvRTPoolUsed); +plProfile_Extern(AvRTPoolCount); +plProfile_Extern(AvRTPoolRes); +plProfile_Extern(AvRTShrinkTime); +plProfile_Extern(SpanMerge); +plProfile_Extern(MatLightState); +plProfile_Extern(EmptyList); plProfile_CreateMemCounter("DefMem", "PipeC", DefaultMem); plProfile_CreateMemCounter("ManMem", "PipeC", ManagedMem); @@ -316,18 +320,10 @@ plProfile_CreateMemCounterReset("fTexUsed", "PipeC", fTexUsed); plProfile_CreateMemCounterReset("fTexManaged", "PipeC", fTexManaged); plProfile_CreateMemCounterReset("fVtxUsed", "PipeC", fVtxUsed); plProfile_CreateMemCounterReset("fVtxManaged", "PipeC", fVtxManaged); -plProfile_CreateCounter("Merge", "PipeC", SpanMerge); plProfile_CreateCounter("TexNum", "PipeC", NumTex); -plProfile_CreateCounter("LiState", "PipeC", MatLightState); -plProfile_CreateCounter("AvatarFaces", "PipeC", AvatarFaces); plProfile_CreateCounter("VertexChange", "PipeC", VertexChange); plProfile_CreateCounter("IndexChange", "PipeC", IndexChange); plProfile_CreateCounter("DynVBuffs", "PipeC", DynVBuffs); -plProfile_CreateCounter("EmptyList", "PipeC", EmptyList); -plProfile_CreateCounter("AvRTPoolUsed", "PipeC", AvRTPoolUsed); -plProfile_CreateCounter("AvRTPoolCount", "PipeC", AvRTPoolCount); -plProfile_CreateCounter("AvRTPoolRes", "PipeC", AvRTPoolRes); -plProfile_CreateCounter("AvRTShrinkTime", "PipeC", AvRTShrinkTime); #ifndef PLASMA_EXTERNAL_RELEASE /// Fun inlines for keeping track of surface creation/deletion memory @@ -2331,153 +2327,6 @@ bool plDXPipeline::PreRender(plDrawable* drawable, std::vector& visLis return !visList.empty(); } -struct plSortFace -{ - uint16_t fIdx[3]; - float fDist; -}; - -struct plCompSortFace -{ - bool operator()( const plSortFace& lhs, const plSortFace& rhs) const - { - return lhs.fDist > rhs.fDist; - } -}; - -// IAvatarSort ///////////////////////////////////////////////////////////////////////// -// We handle avatar sort differently from the rest of the face sort. The reason is that -// within the single avatar index buffer, we want to only sort the faces of spans requesting -// a sort, and sort them in place. -// Contrast that with the normal scene translucency sort. There, we sort all the spans in a drawble, -// then we sort all the faces in that drawable, then for each span in the sorted span list, we extract -// the faces for that span appending onto the index buffer. This gives great efficiency because -// only the visible faces are sorted and they wind up packed into the front of the index buffer, which -// permits more batching. See plDrawableSpans::SortVisibleSpans. -// For the avatar, it's generally the case that all the avatar is visible or not, and there is only -// one material, so neither of those efficiencies is helpful. Moreover, for the avatar the faces we -// want sorted are a tiny subset of the avatar's faces. Moreover, and most importantly, for the avatar, we -// want to preserve the order that spans are drawn, so, for example, the opaque base head will always be -// drawn before the translucent hair fringe, which will always be drawn before the pink clear plastic baseball cap. -bool plDXPipeline::IAvatarSort(plDrawableSpans* d, const std::vector& visList) -{ - plProfile_BeginTiming(AvatarSort); - for (int16_t visIdx : visList) - { - hsAssert(d->GetSpan(visIdx)->fTypeMask & plSpan::kIcicleSpan, "Unknown type for sorting faces"); - - plIcicle* span = (plIcicle*)d->GetSpan(visIdx); - - if( span->fProps & plSpan::kPartialSort ) - { - hsAssert(d->GetBufferGroup(span->fGroupIdx)->AreIdxVolatile(), "Badly setup buffer group - set PartialSort too late?"); - - const hsPoint3 viewPos = GetViewPositionWorld(); - - plGBufferGroup* group = d->GetBufferGroup(span->fGroupIdx); - - plDXVertexBufferRef* vRef = (plDXVertexBufferRef*)group->GetVertexBufferRef(span->fVBufferIdx); - - const uint8_t* vdata = vRef->fData; - const uint32_t stride = vRef->fVertexSize; - - const int numTris = span->fILength/3; - - static std::vector sortScratch; - sortScratch.resize(numTris); - - plProfile_IncCount(AvatarFaces, numTris); - - // - // Have three very similar sorts here, differing only on where the "position" of - // each triangle is defined, either as the center of the triangle, the nearest - // point on the triangle, or the farthest point on the triangle. - // Having tried all three on the avatar (the only thing this sort is used on), - // the best results surprisingly came from using the center of the triangle. - uint16_t* indices = group->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx; - int j; - for( j = 0; j < numTris; j++ ) - { -#if 1 // TRICENTER - uint16_t idx = *indices++; - sortScratch[j].fIdx[0] = idx; - hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); - - idx = *indices++; - sortScratch[j].fIdx[1] = idx; - pos += *(hsPoint3*)(vdata + idx * stride); - - idx = *indices++; - sortScratch[j].fIdx[2] = idx; - pos += *(hsPoint3*)(vdata + idx * stride); - - pos *= 0.3333f; - - sortScratch[j].fDist = hsVector3(&pos, &viewPos).MagnitudeSquared(); -#elif 0 // NEAREST - uint16_t idx = *indices++; - sortScratch[j].fIdx[0] = idx; - hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); - float dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - float minDist = dist; - - idx = *indices++; - sortScratch[j].fIdx[1] = idx; - pos = *(hsPoint3*)(vdata + idx * stride); - dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - if( dist < minDist ) - minDist = dist; - - idx = *indices++; - sortScratch[j].fIdx[2] = idx; - pos = *(hsPoint3*)(vdata + idx * stride); - dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - if( dist < minDist ) - minDist = dist; - - sortScratch[j].fDist = minDist; -#elif 1 // FURTHEST - uint16_t idx = *indices++; - sortScratch[j].fIdx[0] = idx; - hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); - float dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - float maxDist = dist; - - idx = *indices++; - sortScratch[j].fIdx[1] = idx; - pos = *(hsPoint3*)(vdata + idx * stride); - dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - if( dist > maxDist ) - maxDist = dist; - - idx = *indices++; - sortScratch[j].fIdx[2] = idx; - pos = *(hsPoint3*)(vdata + idx * stride); - dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); - if( dist > maxDist ) - maxDist = dist; - - sortScratch[j].fDist = maxDist; -#endif // SORTTYPES - } - - std::sort(sortScratch.begin(), sortScratch.end(), plCompSortFace()); - - indices = group->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx; - for (const plSortFace& iter : sortScratch) - { - *indices++ = iter.fIdx[0]; - *indices++ = iter.fIdx[1]; - *indices++ = iter.fIdx[2]; - } - - group->DirtyIndexBuffer(span->fIBufferIdx); - } - } - plProfile_EndTiming(AvatarSort); - return true; -} - // PrepForRender ////////////////////////////////////////////////////////////////// // Make sure the given drawable and each of the spans to be drawn (as noted in the // indices in visList) is ready to be rendered. diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index fe9d10dffc..de3d3f0b72 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -374,7 +374,6 @@ class plDXPipeline : public pl3DPipeline // Visualization of active occluders void IMakeOcclusionSnap(); - bool IAvatarSort(plDrawableSpans* d, const std::vector& visList); void IBlendVertsIntoBuffer( plSpan* span, hsMatrix44* matrixPalette, int numMatrices, const uint8_t *src, uint8_t format, uint32_t srcStride, diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index e71cd86b1b..b8f2dd337d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -348,7 +348,7 @@ bool plGLDevice::InitDevice() // ANGLE. // // On Linux, this should be true with mesa or nvidia drivers. - if (epoxy_has_egl()) + if (epoxy_has_egl() && fContextType == kNone) InitEGLDevice(this); #endif @@ -458,6 +458,19 @@ bool plGLDevice::BeginRender() return false; } +#ifdef USE_EGL + if (fContextType == kEGL) { + EGLDisplay display = static_cast(fDisplay); + EGLContext context = static_cast(fContext); + EGLSurface surface = static_cast(fSurface); + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + fErrorMsg = "Failed to attach EGL context to surface"; + return false; + } + } //else +#endif + return true; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 5f34d385fb..79b5ed431e 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -62,7 +62,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPipeDebugFlags.h" #include "plPipeResReq.h" #include "plProfile.h" +#include "pnNetCommon/plNetApp.h" // for dbg logging #include "pnMessage/plPipeResMakeMsg.h" +#include "plAvatar/plAvatarClothing.h" +#include "plGImage/plMipmap.h" #include "plGLight/plLightInfo.h" #include "plPipeline/hsWinRef.h" #include "plPipeline/plCubicRenderTarget.h" @@ -96,6 +99,14 @@ plProfile_Extern(PlateMgr); plProfile_Extern(DebugText); plProfile_Extern(Reset); plProfile_Extern(NumSkin); +plProfile_Extern(PipeReload); +plProfile_Extern(AvRTPoolUsed); +plProfile_Extern(AvRTPoolCount); +plProfile_Extern(AvRTPoolRes); +plProfile_Extern(AvRTShrinkTime); +plProfile_Extern(SpanMerge); +plProfile_Extern(MatLightState); +plProfile_Extern(EmptyList); // Adding a nil RenderPrim for turning off drawing static plRenderNilFunc sRenderNil; @@ -242,7 +253,9 @@ bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& vis return false; } - // Other stuff that we're ignoring for now... + // Avatar face sorting happens after the software skin. + if (ice->GetNativeProperty(plDrawable::kPropPartialSort)) + IAvatarSort(ice, visList); plProfile_EndTiming(PrepDrawable); @@ -353,7 +366,7 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) // If we have Shader Model 3 and support non-POT textures, let's make reflections the pipe size if (plDynamicCamMap* camMap = plDynamicCamMap::ConvertNoRef(owner)) { - if (plQuality::GetCapability() > plQuality::kPS_2) + if (camMap->IsReflection() && plQuality::GetCapability() > plQuality::kPS_2) camMap->ResizeViewport(IGetViewTransform()); } @@ -388,13 +401,23 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) // See if it's a cubic render target. // Primary consumer here is the vertex/pixel shader water. if (plCubicRenderTarget* cubicRT = plCubicRenderTarget::ConvertNoRef(owner)) { - /// And create the ref (it'll know how to set all the flags) - //if (ref) - // ref->Set(surfFormat, 0, owner); - //else - // ref = new plGLRenderTargetRef(surfFormat, 0, owner); +#if 0 + if (!ref) + ref = new plGLRenderTargetRef(); + + ref->fOwner = owner; + ref->fDepthBuffer = depthBuffer; + ref->fMapping = GL_TEXTURE_CUBE_MAP; - // TODO: The rest + if (plGLVersion() >= 45) { + glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &ref->fRef); + // TODO: The rest + } else { + glGenTextures(1, &ref->fRef); + glBindTexture(GL_TEXTURE_CUBE_MAP, ref->fRef); + // TODO: The rest + } +#endif } // Not a cubic, is it a texture render target? These are currently used @@ -448,6 +471,7 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) // Keep it in a linked list for ready destruction. if (owner->GetDeviceRef() != ref) { owner->SetDeviceRef(ref); + // Unref now, since for now ONLY the RT owns the ref, not us (not until we use it, at least) hsRefCnt_SafeUnRef(ref); if (ref != nullptr && !ref->IsLinked()) @@ -460,14 +484,16 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) // Mark as not dirty so it doesn't get re-created if (ref != nullptr) ref->SetDirty(false); + else { + hsStatusMessage("Got an unfilled render target!"); + ref->SetDirty(false); + } return ref; } bool plGLPipeline::BeginRender() { - // TODO: Device Init/Reset stuff here - // offset transform RefreshScreenMatrices(); @@ -477,6 +503,8 @@ bool plGLPipeline::BeginRender() fVtxRefTime++; + IPreprocessAvatarTextures(); + hsColorRGBA clearColor = GetClearColor(); glDepthMask(GL_TRUE); @@ -564,9 +592,46 @@ void plGLPipeline::Resize(uint32_t width, uint32_t height) void plGLPipeline::LoadResources() { - if (plGLPlateManager* pm = static_cast(fPlateMgr)) { + hsStatusMessageF("Begin Device Reload t=%f",hsTimer::GetSeconds()); + plNetClientApp::StaticDebugMsg("Begin Device Reload"); + + if (plGLPlateManager* pm = static_cast(fPlateMgr)) pm->IReleaseGeometry(); + + IReleaseAvRTPool(); + + if (fDevice.fContextType == plGLDevice::kNone) { + // We can't create anything if the OpenGL context isn't initialized + plProfile_IncCount(PipeReload, 1); + + hsStatusMessageF("End Device Reload (but no GL Context) t=%f",hsTimer::GetSeconds()); + plNetClientApp::StaticDebugMsg("End Device Reload (but no GL Context)"); + return; } + + // Create all RenderTargets + plPipeRTMakeMsg* rtMake = new plPipeRTMakeMsg(this); + rtMake->Send(); + + if (plGLPlateManager* pm = static_cast(fPlateMgr)) + pm->ICreateGeometry(); + + plPipeGeoMakeMsg* defMake = new plPipeGeoMakeMsg(this, true); + defMake->Send(); + + IFillAvRTPool(); + + // Force a create of all our static vertex buffers. + plPipeGeoMakeMsg* manMake = new plPipeGeoMakeMsg(this, false); + manMake->Send(); + + // Okay, we've done it, clear the request. + plPipeResReq::Clear(); + + plProfile_IncCount(PipeReload, 1); + + hsStatusMessageF("End Device Reload t=%f",hsTimer::GetSeconds()); + plNetClientApp::StaticDebugMsg("End Device Reload"); } bool plGLPipeline::SetGamma(float eR, float eG, float eB) @@ -613,7 +678,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& hsGMaterial* material; const std::vector& spans = ice->GetSpanArray(); - //plProfile_IncCount(EmptyList, visList.empty()); + plProfile_IncCount(EmptyList, visList.empty()); /// Set this (*before* we do our TestVisibleWorld stuff...) lastL2W.Reset(); @@ -646,7 +711,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& break; } plProfile_EndTiming(MergeCheck); - //plProfile_Inc(SpanMerge); + plProfile_Inc(SpanMerge); plProfile_BeginTiming(MergeSpan); spans[visList[j]]->MergeInto(&tempIce); @@ -849,8 +914,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, // If the layer opacity is 0, don't draw it. This prevents it from // contributing to the Z buffer. This can happen with some models like // the fire marbles in the neighborhood that have some models for - // physics only, and then can block other rendering in the Z buffer. DX - // pipeline does this in ILoopOverLayers. + // physics only, and then can block other rendering in the Z buffer. + // DX pipeline does this in ILoopOverLayers. if ((s.fBlendFlags & hsGMatState::kBlendAlpha) && lay->GetOpacity() <= 0 && fCurrLightingMethod != plSpan::kLiteVtxPreshaded) continue; @@ -1085,7 +1150,7 @@ void plGLPipeline::ISetCullMode() void plGLPipeline::ICalcLighting(plGLMaterialShaderRef* mRef, const plLayerInterface* currLayer, const plSpan* currSpan) { - //plProfile_Inc(MatLightState); + plProfile_Inc(MatLightState); GLint e; @@ -1452,6 +1517,70 @@ void plGLPipeline::IDrawPlate(plPlate* plate) glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(uint16_t) * 0)); } +struct plAVTexVert +{ + float fPos[3]; + float fUv[2]; +}; + +void plGLPipeline::IPreprocessAvatarTextures() +{ + plProfile_Set(AvRTPoolUsed, fClothingOutfits.size()); + plProfile_Set(AvRTPoolCount, fAvRTPool.size()); + plProfile_Set(AvRTPoolRes, fAvRTWidth); + plProfile_Set(AvRTShrinkTime, uint32_t(hsTimer::GetSysSeconds() - fAvRTShrinkValidSince)); + + // Frees anyone used last frame that we don't need this frame + IClearClothingOutfits(&fPrevClothingOutfits); + + if (fClothingOutfits.empty()) + return; + + static float kIdentityMatrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + //glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, kIdentityMatrix); + //glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, kIdentityMatrix); + //glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, kIdentityMatrix); + //glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, kIdentityMatrix); + + for (size_t oIdx = 0; oIdx < fClothingOutfits.size(); oIdx++) { + plClothingOutfit* co = fClothingOutfits[oIdx]; + if (co->fBase == nullptr || co->fBase->fBaseTexture == nullptr) + continue; + +#if 0 + plRenderTarget* rt = plRenderTarget::ConvertNoRef(co->fTargetLayer->GetTexture()); + if (rt != nullptr && co->fDirtyItems.Empty()) + // we've still got our valid RT from last frame and we have nothing to do. + continue; + + if (rt == nullptr) { + rt = IGetNextAvRT(); + co->fTargetLayer->SetTexture(rt); + } +#endif + + //PushRenderTarget(rt); + + // HACK HACK HACK + co->fTargetLayer->SetTexture(co->fBase->fBaseTexture); + + // TODO: Actually render to the render target + + //PopRenderTarget(); + //co->fDirtyItems.Clear(); + } + + fView.fXformResetFlags = fView.kResetAll; + + fClothingOutfits.swap(fPrevClothingOutfits); +} + bool plGLPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector& visList) { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 10caa3803c..1f5f137815 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -147,6 +147,7 @@ class plGLPipeline : public pl3DPipeline void IDisableLight(plGLMaterialShaderRef* mRef, size_t i); void IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale); void IDrawPlate(plPlate* plate); + void IPreprocessAvatarTextures(); /** * Emulate matrix palette operations in software. diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 9ac4b70fec..50ff2e1803 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -94,6 +94,7 @@ plProfile_Extern(DrawTriangles); plProfile_Extern(MatChange); plProfile_Extern(NumSkin); +plProfile_Extern(PipeReload); plProfile_Extern(PrepShadows); plProfile_Extern(PrepDrawable); plProfile_Extern(Skin); @@ -111,12 +112,10 @@ plProfile_Extern(RenderPrim); plProfile_Extern(PlateMgr); plProfile_Extern(DebugText); plProfile_Extern(Reset); - -plProfile_CreateCounterNoReset("Reload", "PipeC", PipeReload); -plProfile_CreateCounter("AvRTPoolUsed", "PipeC", AvRTPoolUsed); -plProfile_CreateCounter("AvRTPoolCount", "PipeC", AvRTPoolCount); -plProfile_CreateCounter("AvRTPoolRes", "PipeC", AvRTPoolRes); -plProfile_CreateCounter("AvRTShrinkTime", "PipeC", AvRTShrinkTime); +plProfile_Extern(AvRTPoolUsed); +plProfile_Extern(AvRTPoolCount); +plProfile_Extern(AvRTPoolRes); +plProfile_Extern(AvRTShrinkTime); plMetalEnumerate plMetalPipeline::enumerator; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp index 14d4297969..dc7372b41e 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.cpp @@ -83,6 +83,16 @@ plProfile_CreateCounter("LightActive", "PipeC", LightActive); plProfile_CreateCounter("Lights Found", "PipeC", FindLightsFound); plProfile_CreateCounter("Perms Found", "PipeC", FindLightsPerm); plProfile_CreateCounter("NumSkin", "PipeC", NumSkin); +plProfile_CreateCounter("AvRTPoolUsed", "PipeC", AvRTPoolUsed); +plProfile_CreateCounter("AvRTPoolCount", "PipeC", AvRTPoolCount); +plProfile_CreateCounter("AvRTPoolRes", "PipeC", AvRTPoolRes); +plProfile_CreateCounter("AvRTShrinkTime", "PipeC", AvRTShrinkTime); +plProfile_CreateCounter("AvatarFaces", "PipeC", AvatarFaces); +plProfile_CreateCounter("Merge", "PipeC", SpanMerge); +plProfile_CreateCounter("LiState", "PipeC", MatLightState); +plProfile_CreateCounter("EmptyList", "PipeC", EmptyList); + +plProfile_CreateCounterNoReset("Reload", "PipeC", PipeReload); plProfile_CreateCounter("Polys", "General", DrawTriangles); plProfile_CreateCounter("Material Change", "Draw", MatChange); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 1f5e7208fb..b366a28c69 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -100,6 +100,8 @@ plProfile_Extern(LightChar); plProfile_Extern(LightActive); plProfile_Extern(FindLightsFound); plProfile_Extern(FindLightsPerm); +plProfile_Extern(AvatarSort); +plProfile_Extern(AvatarFaces); static const float kPerspLayerScale = 0.00001f; static const float kPerspLayerScaleW = 0.001f; @@ -940,6 +942,32 @@ class pl3DPipeline : public plPipeline /** pass the current local to world tranform on to the device. */ void ILocalToWorldToDevice(); + + /** + * Sorts the avatar geometry for display. + * + * We handle avatar sort differently from the rest of the face sort. The + * reason is that within the single avatar index buffer, we want to only + * sort the faces of spans requesting a sort, and sort them in place. + * + * Contrast that with the normal scene translucency sort. There, we sort + * all the spans in a drawble, then we sort all the faces in that drawable, + * then for each span in the sorted span list, we extract the faces for + * that span appending onto the index buffer. This gives great efficiency + * because only the visible faces are sorted and they wind up packed into + * the front of the index buffer, which permits more batching. See + * plDrawableSpans::SortVisibleSpans. + * + * For the avatar, it's generally the case that all the avatar is visible + * or not, and there is only one material, so neither of those efficiencies + * is helpful. Moreover, for the avatar the faces we want sorted are a tiny + * subset of the avatar's faces. Moreover, and most importantly, for the + * avatar, we want to preserve the order that spans are drawn, so, for + * example, the opaque base head will always be drawn before the + * translucent hair fringe, which will always be drawn before the pink + * clear plastic baseball cap. + */ + bool IAvatarSort(plDrawableSpans* d, const std::vector& visList); }; @@ -1027,6 +1055,7 @@ pl3DPipeline::~pl3DPipeline() while (fActiveLights) UnRegisterLight(fActiveLights); + IReleaseAvRTPool(); IClearClothingOutfits(&fClothingOutfits); IClearClothingOutfits(&fPrevClothingOutfits); } @@ -2173,4 +2202,136 @@ void pl3DPipeline::ILocalToWorldToDevice() fView.fXformResetFlags &= ~fView.kResetL2W; } +struct plSortFace +{ + uint16_t fIdx[3]; + float fDist; +}; + +struct plCompSortFace +{ + bool operator()( const plSortFace& lhs, const plSortFace& rhs) const + { + return lhs.fDist > rhs.fDist; + } +}; + +template +bool pl3DPipeline::IAvatarSort(plDrawableSpans* d, const std::vector& visList) +{ + plProfile_BeginTiming(AvatarSort); + for (int16_t visIdx : visList) + { + hsAssert(d->GetSpan(visIdx)->fTypeMask & plSpan::kIcicleSpan, "Unknown type for sorting faces"); + + plIcicle* span = (plIcicle*)d->GetSpan(visIdx); + + if (span->fProps & plSpan::kPartialSort) { + hsAssert(d->GetBufferGroup(span->fGroupIdx)->AreIdxVolatile(), "Badly setup buffer group - set PartialSort too late?"); + + const hsPoint3 viewPos = GetViewPositionWorld(); + + plGBufferGroup* group = d->GetBufferGroup(span->fGroupIdx); + + typename DeviceType::VertexBufferRef* vRef = static_cast(group->GetVertexBufferRef(span->fVBufferIdx)); + + const uint8_t* vdata = vRef->fData; + const uint32_t stride = vRef->fVertexSize; + + const int numTris = span->fILength/3; + + static std::vector sortScratch; + sortScratch.resize(numTris); + + plProfile_IncCount(AvatarFaces, numTris); + + // Have three very similar sorts here, differing only on where the "position" of + // each triangle is defined, either as the center of the triangle, the nearest + // point on the triangle, or the farthest point on the triangle. + // Having tried all three on the avatar (the only thing this sort is used on), + // the best results surprisingly came from using the center of the triangle. + uint16_t* indices = group->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx; + int j; + for( j = 0; j < numTris; j++ ) + { +#if 1 // TRICENTER + uint16_t idx = *indices++; + sortScratch[j].fIdx[0] = idx; + hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); + + idx = *indices++; + sortScratch[j].fIdx[1] = idx; + pos += *(hsPoint3*)(vdata + idx * stride); + + idx = *indices++; + sortScratch[j].fIdx[2] = idx; + pos += *(hsPoint3*)(vdata + idx * stride); + + pos *= 0.3333f; + + sortScratch[j].fDist = hsVector3(&pos, &viewPos).MagnitudeSquared(); +#elif 0 // NEAREST + uint16_t idx = *indices++; + sortScratch[j].fIdx[0] = idx; + hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); + float dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + float minDist = dist; + + idx = *indices++; + sortScratch[j].fIdx[1] = idx; + pos = *(hsPoint3*)(vdata + idx * stride); + dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + if( dist < minDist ) + minDist = dist; + + idx = *indices++; + sortScratch[j].fIdx[2] = idx; + pos = *(hsPoint3*)(vdata + idx * stride); + dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + if( dist < minDist ) + minDist = dist; + + sortScratch[j].fDist = minDist; +#elif 1 // FURTHEST + uint16_t idx = *indices++; + sortScratch[j].fIdx[0] = idx; + hsPoint3 pos = *(hsPoint3*)(vdata + idx * stride); + float dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + float maxDist = dist; + + idx = *indices++; + sortScratch[j].fIdx[1] = idx; + pos = *(hsPoint3*)(vdata + idx * stride); + dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + if( dist > maxDist ) + maxDist = dist; + + idx = *indices++; + sortScratch[j].fIdx[2] = idx; + pos = *(hsPoint3*)(vdata + idx * stride); + dist = hsVector3(&pos, &viewPos).MagnitudeSquared(); + if( dist > maxDist ) + maxDist = dist; + + sortScratch[j].fDist = maxDist; +#endif // SORTTYPES + } + + std::sort(sortScratch.begin(), sortScratch.end(), plCompSortFace()); + + indices = group->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx; + for (const plSortFace& iter : sortScratch) + { + *indices++ = iter.fIdx[0]; + *indices++ = iter.fIdx[1]; + *indices++ = iter.fIdx[2]; + } + + group->DirtyIndexBuffer(span->fIBufferIdx); + } + } + plProfile_EndTiming(AvatarSort); + return true; +} + #endif //_pl3DPipeline_inc_ From 4cdc8ca37c4499e6a86b0e5bfb73ed09c4de1b27 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Mon, 20 Feb 2023 20:57:53 -0800 Subject: [PATCH 64/76] OpenGL avatar clothing texture rendering --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 16 +- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 2 + .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 216 ++++++++++++++++-- .../FeatureLib/pfGLPipeline/plGLPipeline.h | 1 + .../pfMetalPipeline/plMetalPipeline.cpp | 40 ---- .../pfMetalPipeline/plMetalPipeline.h | 3 - .../PubUtilLib/plAvatar/plAvatarClothing.h | 2 + .../PubUtilLib/plPipeline/pl3DPipeline.h | 36 ++- 8 files changed, 251 insertions(+), 65 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index b8f2dd337d..3559086654 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -388,6 +388,9 @@ bool plGLDevice::InitDevice() glFrontFace(GL_CCW); glCullFace(GL_BACK); + if (plGLVersion() >= 46) + glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); + return true; } @@ -420,13 +423,22 @@ void plGLDevice::SetRenderTarget(plRenderTarget* target) ref = static_cast(fPipeline->MakeRenderTargetRef(target)); } - if (ref == nullptr) + if (ref == nullptr) { /// Set to main screen glBindFramebuffer(GL_FRAMEBUFFER, 0); - else + + if (plGLVersion() >= 46) + glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); + } else { /// Set to this target glBindFramebuffer(GL_FRAMEBUFFER, ref->fFrameBuffer); + // We need to flip the Y axis :( + if (plGLVersion() >= 46) + glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE); + // else... find a way to do this with the projection matrix? + } + SetViewport(); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index ca97aa3b73..9f9757f4fd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -382,6 +382,7 @@ void plGLMaterialShaderRef::ICompile() char* log = new char[length]; glGetShaderInfoLog(vshader, length, &length, log); hsStatusMessage(log); + delete[] log; } } } @@ -405,6 +406,7 @@ void plGLMaterialShaderRef::ICompile() char* log = new char[length]; glGetShaderInfoLog(fFragShaderRef, length, &length, log); hsStatusMessage(log); + delete[] log; } } } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 79b5ed431e..10b62228c3 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -1519,12 +1519,41 @@ void plGLPipeline::IDrawPlate(plPlate* plate) struct plAVTexVert { - float fPos[3]; + float fPos[2]; float fUv[2]; }; +static const char* AVATAR_VERTEX_SHADER_STRING = R"(#version 430 + +layout(location = 0) in vec2 aVtxPosition; +layout(location = 1) in vec2 aVtxUV; + +out vec2 vVtxUV; + +void main() { + vVtxUV = aVtxUV; + gl_Position = vec4(aVtxPosition, 0.0, 1.0); +})"; + +static const char* AVATAR_FRAGMENT_SHADER_STRING = R"(#version 430 +precision mediump float; + +layout(location = 0) uniform sampler2D uTex; +layout(location = 1) uniform vec4 uColor; + +in highp vec2 vVtxUV; +out vec4 fragColor; + +void main() { + fragColor = texture(uTex, vVtxUV.xy) * uColor; +})"; + void plGLPipeline::IPreprocessAvatarTextures() { + static GLuint sVertShader = 0; + static GLuint sFragShader = 0; + static GLuint sProgram = 0; + plProfile_Set(AvRTPoolUsed, fClothingOutfits.size()); plProfile_Set(AvRTPoolCount, fAvRTPool.size()); plProfile_Set(AvRTPoolRes, fAvRTWidth); @@ -1536,24 +1565,66 @@ void plGLPipeline::IPreprocessAvatarTextures() if (fClothingOutfits.empty()) return; - static float kIdentityMatrix[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; + // Set up the shaders the first time to go through here + if (!sVertShader) { + GLuint vshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vshader, 1, &AVATAR_VERTEX_SHADER_STRING, nullptr); + glCompileShader(vshader); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); + + sVertShader = vshader; + } + + if (!sFragShader) { + GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fshader, 1, &AVATAR_FRAGMENT_SHADER_STRING, nullptr); + glCompileShader(fshader); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); - //glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, kIdentityMatrix); - //glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, kIdentityMatrix); - //glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, kIdentityMatrix); - //glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, kIdentityMatrix); + sFragShader = fshader; + } + + if (!sProgram) { + GLuint program = glCreateProgram(); + LOG_GL_ERROR_CHECK("Create Program failed"); + + if (plGLVersion() >= 43) { + const char* name = "AvatarClothing"; + glObjectLabel(GL_PROGRAM, program, strlen(name), name); + } + + glAttachShader(program, sVertShader); + LOG_GL_ERROR_CHECK("Attach Vertex Shader failed"); + + glAttachShader(program, sFragShader); + LOG_GL_ERROR_CHECK("Attach Fragment Shader failed"); + + glLinkProgram(program); + LOG_GL_ERROR_CHECK("Program Link failed"); + + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) + { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + char* log = new char[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, log); + + hsStatusMessage(log); + delete[] log; + } + + sProgram = program; + } for (size_t oIdx = 0; oIdx < fClothingOutfits.size(); oIdx++) { plClothingOutfit* co = fClothingOutfits[oIdx]; if (co->fBase == nullptr || co->fBase->fBaseTexture == nullptr) continue; -#if 0 plRenderTarget* rt = plRenderTarget::ConvertNoRef(co->fTargetLayer->GetTexture()); if (rt != nullptr && co->fDirtyItems.Empty()) // we've still got our valid RT from last frame and we have nothing to do. @@ -1561,19 +1632,64 @@ void plGLPipeline::IPreprocessAvatarTextures() if (rt == nullptr) { rt = IGetNextAvRT(); + + plGLMaterialShaderRef* mRef = static_cast(co->fMaterial->GetDeviceRef()); + if (mRef) + mRef->SetDirty(true); + co->fTargetLayer->SetTexture(rt); } -#endif - //PushRenderTarget(rt); + PushRenderTarget(rt); + glViewport(0, 0, rt->GetWidth(), rt->GetHeight()); + glDepthRange(0.0, 1.0); - // HACK HACK HACK - co->fTargetLayer->SetTexture(co->fBase->fBaseTexture); + glUseProgram(sProgram); + LOG_GL_ERROR_CHECK("Use Program failed"); + fDevice.fCurrentProgram = sProgram; + + glUniform1i(0, 0); + glUniform4f(1, 1.f, 1.f, 1.f, 1.f); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_TRUE); - // TODO: Actually render to the render target + float uOff = 0.5f / rt->GetWidth(); + float vOff = 0.5f / rt->GetHeight(); - //PopRenderTarget(); - //co->fDirtyItems.Clear(); + IDrawClothingQuad(-1.f, -1.f, 2.f, 2.f, uOff, vOff, co->fBase->fBaseTexture); + plClothingLayout *layout = plClothingMgr::GetClothingMgr()->GetLayout(co->fBase->fLayoutName); + + for (plClothingItem *item : co->fItems) { + for (size_t j = 0; j < item->fElements.size(); j++) { + for (int k = 0; k < plClothingElement::kLayerMax; k++) { + if (item->fTextures[j][k] == nullptr) + continue; + + plMipmap* itemBufferTex = item->fTextures[j][k]; + hsColorRGBA tint = co->GetItemTint(item, k); + if (k >= plClothingElement::kLayerSkinBlend1 && k <= plClothingElement::kLayerSkinLast) + tint.a = co->fSkinBlends[k - plClothingElement::kLayerSkinBlend1]; + + if (k == plClothingElement::kLayerBase) { + glBlendFunc(GL_ONE, GL_ZERO); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + glUniform4f(1, tint.r, tint.g, tint.b, tint.a); + + float screenW = (float)item->fElements[j]->fWidth / layout->fOrigWidth * 2.f; + float screenH = (float)item->fElements[j]->fHeight / layout->fOrigWidth * 2.f; + float screenX = (float)item->fElements[j]->fXPos / layout->fOrigWidth * 2.f - 1.f; + float screenY = (1.f - (float)item->fElements[j]->fYPos / layout->fOrigWidth) * 2.f - 1.f - screenH; + + IDrawClothingQuad(screenX, screenY, screenW, screenH, uOff, vOff, itemBufferTex); + } + } + } + + PopRenderTarget(); + co->fDirtyItems.Clear(); } fView.fXformResetFlags = fView.kResetAll; @@ -1581,6 +1697,68 @@ void plGLPipeline::IPreprocessAvatarTextures() fClothingOutfits.swap(fPrevClothingOutfits); } +void plGLPipeline::IDrawClothingQuad(float x, float y, float w, float h, float uOff, float vOff, plMipmap *tex) +{ + const uint32_t kVSize = sizeof(plAVTexVert); + + plGLTextureRef* ref = static_cast(tex->GetDeviceRef()); + if (!ref || ref->IsDirty()) + { + CheckTextureRef(tex); + ref = (plGLTextureRef*)tex->GetDeviceRef(); + } + + glActiveTexture(GL_TEXTURE0); + LOG_GL_ERROR_CHECK("Active Texture failed") + + glBindTexture(GL_TEXTURE_2D, ref->fRef); + LOG_GL_ERROR_CHECK("Bind Texture failed"); + + plAVTexVert ptr[4]; + plAVTexVert vert; + vert.fPos[0] = x; + vert.fPos[1] = y; + vert.fUv[0] = uOff; + vert.fUv[1] = 1.f + vOff; + + // P0 + ptr[2] = vert; + + // P1 + ptr[0] = vert; + ptr[0].fPos[0] += w; + ptr[0].fUv[0] += 1.f; + + // P2 + ptr[1] = vert; + ptr[1].fPos[0] += w; + ptr[1].fUv[0] += 1.f; + ptr[1].fPos[1] += h; + ptr[1].fUv[1] -= 1.f; + + // P3 + ptr[3] = vert; + ptr[3].fPos[1] += h; + ptr[3].fUv[1] -= 1.f; + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(ptr), ptr, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, kVSize, (void*)(sizeof(float) * 0)); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, kVSize, (void*)(sizeof(float) * 2)); + glEnableVertexAttribArray(1); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 6); + + LOG_GL_ERROR_CHECK("Render failed") + + glDeleteBuffers(1, &vbo); +} + bool plGLPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector& visList) { diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h index 1f5f137815..b5eb6312dc 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h @@ -148,6 +148,7 @@ class plGLPipeline : public pl3DPipeline void IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale); void IDrawPlate(plPlate* plate); void IPreprocessAvatarTextures(); + void IDrawClothingQuad(float x, float y, float w, float h, float uOff, float vOff, plMipmap *tex); /** * Emulate matrix palette operations in software. diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp index 50ff2e1803..4cddac0438 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp @@ -4099,46 +4099,6 @@ void plMetalPipeline::IBlendVertBuffer(plSpan* span, hsMatrix44* matrixPalette, } } -// Resource checking - -void plMetalPipeline::CheckTextureRef(plBitmap* bitmap) -{ - plMetalTextureRef* tRef = static_cast(bitmap->GetDeviceRef()); - - if (!tRef) { - tRef = static_cast(MakeTextureRef(bitmap)); - } - - // If it's dirty, refill it. - if (tRef->IsDirty()) { - IReloadTexture(bitmap, tRef); - } -} - -hsGDeviceRef* plMetalPipeline::MakeTextureRef(plBitmap* bitmap) -{ - plMetalTextureRef* tRef = static_cast(bitmap->GetDeviceRef()); - - if (!tRef) { - tRef = new plMetalTextureRef(); - - fDevice.SetupTextureRef(nullptr, bitmap, tRef); - } - - if (!tRef->IsLinked()) { - tRef->Link(&fTextureRefList); - } - - // Make sure it has all resources created. - fDevice.CheckTexture(tRef); - - // If it's dirty, refill it. - if (tRef->IsDirty()) { - IReloadTexture(bitmap, tRef); - } - return tRef; -} - void plMetalPipeline::IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref) { plMipmap* mip = plMipmap::ConvertNoRef(bitmap); diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 2c0335f7aa..516ced27ff 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -140,9 +140,6 @@ class plMetalPipeline : public pl3DPipeline bool IHandleMaterialPass(hsGMaterial* material, uint32_t pass, const plSpan* currSpan, const plMetalVertexBufferRef* vRef, const bool allowShaders = true); plMetalDevice* GetMetalDevice() const; - // Create and/or Refresh geometry buffers - void CheckTextureRef(plBitmap* bitmap); - hsGDeviceRef* MakeTextureRef(plBitmap* bitmap); void IReloadTexture(plBitmap* bitmap, plMetalTextureRef* ref); plRenderTarget* PopRenderTarget() override; diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h index e5599bd0f5..b4bfc98980 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h +++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h @@ -65,6 +65,7 @@ class plSharedMesh; class plStateDataRecord; class plDXPipeline; class plMetalPipeline; +class plGLPipeline; struct plClothingItemOptions { @@ -165,6 +166,7 @@ class plClothingOutfit : public plSynchedObject { friend class plDXPipeline; friend class plMetalPipeline; + friend class plGLPipeline; public: plArmatureMod *fAvatar; diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index b366a28c69..68f0006bd1 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -317,6 +317,8 @@ class pl3DPipeline : public plPipeline void CheckTextureRef(plLayerInterface* lay) override; + void CheckTextureRef(plBitmap* bmp); + void SetDefaultFogEnviron(plFogEnvironment* fog) override { fView.SetDefaultFog(*fog); } @@ -1192,6 +1194,38 @@ void pl3DPipeline::CheckTextureRef(plLayerInterface* layer) } } +template +void pl3DPipeline::CheckTextureRef(plBitmap* bitmap) +{ + typename DeviceType::TextureRef* tRef = static_cast(bitmap->GetDeviceRef()); + + if (!tRef) { + tRef = new typename DeviceType::TextureRef(); + fDevice.SetupTextureRef(nullptr, bitmap, tRef); + } + + if (!tRef->IsLinked()) + tRef->Link(&fTextureRefList); + + // Make sure it has all resources created. + fDevice.CheckTexture(tRef); + + // If it's dirty, refill it. + if (tRef->IsDirty()) { + plMipmap* mip = plMipmap::ConvertNoRef(bitmap); + if (mip) { + fDevice.MakeTextureRef(tRef, nullptr, mip); + return; + } + + plCubicEnvironmap* cubic = plCubicEnvironmap::ConvertNoRef(bitmap); + if (cubic) { + fDevice.MakeCubicTextureRef(tRef, nullptr, cubic); + return; + } + } +} + template void pl3DPipeline::RegisterLight(plLightInfo* liInfo) @@ -2216,7 +2250,7 @@ struct plCompSortFace } }; -template +template bool pl3DPipeline::IAvatarSort(plDrawableSpans* d, const std::vector& visList) { plProfile_BeginTiming(AvatarSort); From ce89be2b99612e6f48ddaa0e83f63e5d235c4435 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Mon, 10 Apr 2023 21:28:54 -0700 Subject: [PATCH 65/76] Fix EGL enumeration with mesa/nouveau --- .../FeatureLib/pfGLPipeline/plGLEnumerate.cpp | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp index cb02496d83..3ef6e1900d 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp @@ -100,12 +100,18 @@ void plEGLEnumerate(std::vector& records) if (!eglBindAPI(EGL_OPENGL_API)) break; - GLint numConfigs = 0; - if (!eglGetConfigs(display, nullptr, 0, &numConfigs) || numConfigs == 0) - break; + /* Set up the config attributes for EGL */ + EGLConfig config; + EGLint config_count; + EGLint config_attrs[] = { + EGL_BUFFER_SIZE, 24, + EGL_DEPTH_SIZE, 24, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; - std::vector configs(numConfigs); - if (!eglGetConfigs(display, configs.data(), configs.size(), &numConfigs)) + if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) break; EGLint ctx_attrs[] = { @@ -114,11 +120,17 @@ void plEGLEnumerate(std::vector& records) EGL_NONE }; - context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, ctx_attrs); + context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); if (context == EGL_NO_CONTEXT) break; - surface = eglCreatePbufferSurface(display, configs[0], nullptr); + EGLint pbuf_attrs[] = { + EGL_WIDTH, 800, + EGL_HEIGHT, 600, + EGL_NONE + }; + + surface = eglCreatePbufferSurface(display, config, pbuf_attrs); if (surface == EGL_NO_SURFACE) break; From e47a4588d748047bc3db474fb96820379642895b Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Thu, 4 May 2023 22:23:02 -0700 Subject: [PATCH 66/76] plTextFont rendering for GL Pipeline This enables the loading bars and console. --- .../FeatureLib/pfDXPipeline/plDXPipeline.h | 1 - .../FeatureLib/pfGLPipeline/CMakeLists.txt | 2 + .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 14 +- .../FeatureLib/pfGLPipeline/plGLTextFont.cpp | 299 ++++++++++++++++++ .../FeatureLib/pfGLPipeline/plGLTextFont.h | 75 +++++ .../pfMetalPipeline/plMetalPipeline.h | 2 - .../PubUtilLib/plPipeline/pl3DPipeline.h | 2 + 7 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.h diff --git a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h index de3d3f0b72..31a45649ab 100644 --- a/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h +++ b/Sources/Plasma/FeatureLib/pfDXPipeline/plDXPipeline.h @@ -218,7 +218,6 @@ class plDXPipeline : public pl3DPipeline bool fDevWasLost; plDXTextureRef* fTextureRefList; - plTextFont* fTextFontRefList; plDXRenderTargetRef* fRenderTargetRefList; plDXVertexShader* fVShaderRefList; plDXPixelShader* fPShaderRefList; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index a60674a698..d1d08de4bb 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -5,6 +5,7 @@ set(pfGLPipeline_SOURCES plGLMaterialShaderRef.cpp plGLPipeline.cpp plGLPlateManager.cpp + plGLTextFont.cpp plShaderNode.cpp ) @@ -15,6 +16,7 @@ set(pfGLPipeline_HEADERS plGLPipeline.h pfGLPipelineCreatable.h plGLPlateManager.h + plGLTextFont.h plShaderNode.h ) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 10b62228c3..c5bbe22cc1 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -57,6 +57,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLMaterialShaderRef.h" #include "plGLPipeline.h" #include "plGLPlateManager.h" +#include "plGLTextFont.h" #include "hsGMatState.inl" #include "plPipeDebugFlags.h" @@ -206,6 +207,9 @@ plGLPipeline::~plGLPipeline() if (plGLPlateManager* pm = static_cast(fPlateMgr)) pm->IReleaseGeometry(); + while (fTextFontRefList) + delete fTextFontRefList; + fDevice.Shutdown(); } @@ -264,7 +268,13 @@ bool plGLPipeline::PrepForRender(plDrawable* drawable, std::vector& vis plTextFont* plGLPipeline::MakeTextFont(ST::string face, uint16_t size) { - return nullptr; + plTextFont* font = new plGLTextFont(this, nullptr); + if (!font) + return nullptr; + + font->Create(face, size); + font->Link(&fTextFontRefList); + return font; } bool plGLPipeline::OpenAccess(plAccessSpan& dst, plDrawableSpans* d, const plVertexSpan* span, bool readOnly) @@ -609,6 +619,8 @@ void plGLPipeline::LoadResources() return; } + fDebugTextMgr = new plDebugTextManager(); + // Create all RenderTargets plPipeRTMakeMsg* rtMake = new plPipeRTMakeMsg(this); rtMake->Send(); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp new file mode 100644 index 0000000000..5395d2d4ee --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp @@ -0,0 +1,299 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plGLTextFont.h" + +#include "HeadSpin.h" + +#include "plGLPipeline.h" + +// Following number needs to be at least: 64 chars max in plTextFont drawn at any one time +// * 4 primitives per char max (for bold text) +// * 3 verts per primitive + +//const uint32_t kNumVertsInBuffer(32768); +const uint32_t kNumVertsInBuffer(4608); + +enum plGLTextFontShaderConstants : GLuint { + kVtxPosition = 0, + kVtxColor = 1, + kVtxUVWSrc = 2 +}; + +plGLTextFont::plGLTextFont(plPipeline* pipe, plGLDevice* device) + : plTextFont(pipe), fTexture(), fBuffer(), fState(), fShader(), fBufferCursor() +{ +} + +plGLTextFont::~plGLTextFont() +{ + DestroyObjects(); +} + +void plGLTextFont::ICreateTexture(uint16_t* data) +{ + if (fTexture) + glDeleteTextures(1, &fTexture); + + glGenTextures(1, &fTexture); + glBindTexture(GL_TEXTURE_2D, fTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fTextureWidth, fTextureHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (plGLVersion() >= 43) { + glObjectLabel(GL_TEXTURE, fTexture, -1, fFace.c_str()); + } +} + +static const char* TEXTFONT_VERTEX_SHADER_STRING = R"(#version 430 + +layout(location = 0) in vec3 aVtxPosition; +layout(location = 1) in vec4 aVtxColor; +layout(location = 2) in highp vec3 aVtxUV; + +layout(location = 1) uniform vec2 uPipeSize; + +out vec4 vVtxColor; +out vec3 vVtxUV; + +void main() { + mat4 projMatrix = mat4(1.0); + projMatrix[0][0] = 2.0 / uPipeSize.x; + projMatrix[1][1] = -2.0 / uPipeSize.y; + projMatrix[3][0] = -1.0; + projMatrix[3][1] = 1.0; + + vVtxColor = aVtxColor.bgra; + vVtxUV = aVtxUV; + + gl_Position = projMatrix * vec4(aVtxPosition, 1.0); +})"; + +static const char* TEXTFONT_FRAGMENT_SHADER_STRING = R"(#version 430 +precision mediump float; + +layout(location = 0) uniform sampler2D uTex; + +in vec4 vVtxColor; +in highp vec3 vVtxUV; +out vec4 fragColor; + +void main() { + fragColor = texture(uTex, vec2(vVtxUV.x, vVtxUV.y)) * vVtxColor; +})"; + +void plGLTextFont::IInitStateBlocks() +{ + GLuint vshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vshader, 1, &TEXTFONT_VERTEX_SHADER_STRING, nullptr); + glCompileShader(vshader); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); + + GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fshader, 1, &TEXTFONT_FRAGMENT_SHADER_STRING, nullptr); + glCompileShader(fshader); + LOG_GL_ERROR_CHECK("Vertex Shader compile failed"); + + GLuint program = glCreateProgram(); + LOG_GL_ERROR_CHECK("Create Program failed"); + + if (plGLVersion() >= 43) { + const char* name = "TextFont"; + glObjectLabel(GL_PROGRAM, program, strlen(name), name); + } + + glAttachShader(program, vshader); + LOG_GL_ERROR_CHECK("Attach Vertex Shader failed"); + + glAttachShader(program, fshader); + LOG_GL_ERROR_CHECK("Attach Fragment Shader failed"); + + glLinkProgram(program); + LOG_GL_ERROR_CHECK("Program Link failed"); + + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) + { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + char* log = new char[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, log); + + LOG_GL_ERROR_CHECK(log); + delete[] log; + } + + fShader = program; + + if (plGLVersion() >= 30) { + glGenVertexArrays(1, &fState); + //glBindVertexArray(fState); + } + + /* + glGenBuffers(1, &fBuffer); + glBindBuffer(GL_ARRAY_BUFFER, fBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(plFontVertex) * kNumVertsInBuffer, nullptr, GL_STATIC_DRAW); + + if (plGLVersion() >= 30) { + glEnableVertexAttribArray(kVtxPosition); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plFontVertex), (void*)(sizeof(float) * 0)); + + glEnableVertexAttribArray(kVtxColor); + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plFontVertex), (void*)(sizeof(float) * 3)); + + glEnableVertexAttribArray(kVtxUVWSrc); + glVertexAttribPointer(kVtxUVWSrc, 3, GL_FLOAT, GL_FALSE, sizeof(plFontVertex), (void*)((sizeof(float) * 3) + sizeof(uint32_t))); + + glBindVertexArray(0); + } + */ +} + +void plGLTextFont::IDrawPrimitive(uint32_t count, plFontVertex* array) +{ + if (count == 0 || array == nullptr) + return; + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(plFontVertex) * 3 * count, array, GL_STATIC_DRAW); + + glEnableVertexAttribArray(kVtxPosition); + glVertexAttribPointer(kVtxPosition, 3, GL_FLOAT, GL_FALSE, sizeof(plFontVertex), (void*)(sizeof(float) * 0)); + + glEnableVertexAttribArray(kVtxColor); + glVertexAttribPointer(kVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(plFontVertex), (void*)(sizeof(float) * 3)); + + glEnableVertexAttribArray(kVtxUVWSrc); + glVertexAttribPointer(kVtxUVWSrc, 3, GL_FLOAT, GL_FALSE, sizeof(plFontVertex), (void*)(sizeof(float) * 3 + sizeof(uint32_t))); + + glDrawArrays(GL_TRIANGLES, 0, count * 3); + + LOG_GL_ERROR_CHECK("Render failed") + + glDeleteBuffers(1, &vbo); +} + +void plGLTextFont::IDrawLines(uint32_t count, plFontVertex* array) +{ + if (count == 0 || array == nullptr) + return; + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(plFontVertex) * 3 * count, array, GL_STATIC_DRAW); + + glDrawArrays(GL_LINES, 0, count * 3); + + LOG_GL_ERROR_CHECK("Render failed") + + glDeleteBuffers(1, &vbo); +} + +void plGLTextFont::FlushDraws() +{ +} + +void plGLTextFont::SaveStates() +{ + if (!fInitialized) + IInitObjects(); + + if (plGLVersion() >= 30 && fState) + glBindVertexArray(fState); + + glActiveTexture(GL_TEXTURE0); + LOG_GL_ERROR_CHECK("Active Texture failed") + + glBindTexture(GL_TEXTURE_2D, fTexture); + LOG_GL_ERROR_CHECK("Bind Texture failed"); + + glViewport(0, 0, fPipe->Width(), fPipe->Height()); + glDepthRange(0.0, 1.0); + + glUseProgram(fShader); + LOG_GL_ERROR_CHECK("Use Program failed"); + + glUniform1i(0, 0); + glUniform2f(1, float(fPipe->Width()), float(fPipe->Height())); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + glDisable(GL_CULL_FACE); +} + +void plGLTextFont::RestoreStates() +{ + if (plGLVersion() >= 30) + glBindVertexArray(0); + + glUseProgram(0); +} + +void plGLTextFont::DestroyObjects() +{ + if (fTexture) + glDeleteTextures(1, &fTexture); + fTexture = 0; + + if (plGLVersion() >= 30 && fState) { + if (plGLVersion() >= 45) { + glDisableVertexArrayAttrib(fState, kVtxPosition); + glDisableVertexArrayAttrib(fState, kVtxColor); + glDisableVertexArrayAttrib(fState, kVtxUVWSrc); + } + + glDeleteVertexArrays(1, &fState); + } + fState = 0; + + if (fBuffer) + glDeleteBuffers(1, &fBuffer); + fBuffer = 0; +} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.h new file mode 100644 index 0000000000..fd90dc322c --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.h @@ -0,0 +1,75 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#ifndef _plGLTextFont_h +#define _plGLTextFont_h + +#include "plGLDeviceRef.h" +#include "plPipeline/plTextFont.h" + +class plPipeline; +class plGLDevice; + +class plGLTextFont : public plTextFont +{ +protected: + GLuint fTexture; + GLuint fBuffer; + GLuint fState; + GLuint fShader; + uint32_t fBufferCursor; + + void ICreateTexture(uint16_t* data) override; + void IInitStateBlocks() override; + void IDrawPrimitive(uint32_t count, plFontVertex* array) override; + void IDrawLines(uint32_t count, plFontVertex* array) override; + +public: + plGLTextFont(plPipeline* pipe, plGLDevice* device); + ~plGLTextFont(); + + void FlushDraws() override; + void SaveStates() override; + void RestoreStates() override; + void DestroyObjects() override; +}; + +#endif // _plGLTextFont_h diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h index 516ced27ff..c150b19b73 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h @@ -241,8 +241,6 @@ class plMetalPipeline : public pl3DPipeline static plMetalEnumerate enumerator; - plTextFont* fTextFontRefList; - NS::AutoreleasePool* fCurrentPool; /// Describes the state for the "fixed function" shader. diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index 68f0006bd1..d18a06d3d6 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -199,6 +199,7 @@ class pl3DPipeline : public plPipeline typename DeviceType::VertexBufferRef* fVtxBuffRefList; typename DeviceType::IndexBufferRef* fIdxBuffRefList; typename DeviceType::TextureRef* fTextureRefList; + plTextFont* fTextFontRefList; hsGDeviceRef* fLayerRef[8]; @@ -986,6 +987,7 @@ pl3DPipeline::pl3DPipeline(const hsG3DDeviceModeRecord* devModeRec) fVtxBuffRefList(), fIdxBuffRefList(), fTextureRefList(), + fTextFontRefList(), fCurrMaterial(), fCurrLay(), fCurrNumLayers(), From 617741a93b69a28d646febbb4747021a19d9ad55 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Fri, 12 May 2023 23:33:14 -0700 Subject: [PATCH 67/76] Fix linking transition opacity animation for GL --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index c5bbe22cc1..9031003bd5 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -1517,7 +1517,7 @@ void plGLPipeline::IDrawPlate(plPlate* plate) glUniform4f(mRef->uGlobalAmbient, 1.0, 1.0, 1.0, 1.0); glUniform4f(mRef->uMatAmbientCol, 1.0, 1.0, 1.0, 1.0); - glUniform4f(mRef->uMatDiffuseCol, 1.0, 1.0, 1.0, 1.0); + glUniform4f(mRef->uMatDiffuseCol, 1.0, 1.0, 1.0, lay->GetOpacity()); glUniform4f(mRef->uMatEmissiveCol, 1.0, 1.0, 1.0, 1.0); glUniform4f(mRef->uMatSpecularCol, 1.0, 1.0, 1.0, 1.0); From 1530abc27fb8d9116d9d43aea0d88fd5016119b8 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 13 May 2023 01:12:02 -0700 Subject: [PATCH 68/76] Fix Relto crash with GL Pipeline Now it just leaks an absurd amount of memory rather than crashing. --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 9031003bd5..31c923e3e0 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -496,7 +496,6 @@ hsGDeviceRef* plGLPipeline::MakeRenderTargetRef(plRenderTarget* owner) ref->SetDirty(false); else { hsStatusMessage("Got an unfilled render target!"); - ref->SetDirty(false); } return ref; From 635cfdd95b7b641560ef9fa6262ae90cc975d8e4 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 13 May 2023 11:11:31 -0700 Subject: [PATCH 69/76] Fix awful font layout on GL pipeline --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp index 5395d2d4ee..1b2225f65c 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLTextFont.cpp @@ -77,8 +77,8 @@ void plGLTextFont::ICreateTexture(uint16_t* data) glGenTextures(1, &fTexture); glBindTexture(GL_TEXTURE_2D, fTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fTextureWidth, fTextureHeight, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (plGLVersion() >= 43) { glObjectLabel(GL_TEXTURE, fTexture, -1, fFace.c_str()); From 790174dafa37c913b568354f0bd5410f5d4d0d1e Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 20 Jun 2023 21:19:33 -0700 Subject: [PATCH 70/76] Disable dynamic shader creation by default --- .../FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 9f9757f4fd..db5cf07081 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -63,7 +63,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" -//#define USE_NEW_SHADERS 1 +//#define USE_DYNAMIC_SHADERS 1 // From plGLDevice.cpp extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); @@ -357,7 +357,7 @@ void plGLMaterialShaderRef::ICompile() const char* vs_code = VERTEX_SHADER_STRING; -#ifndef USE_NEW_SHADERS +#ifdef USE_DYNAMIC_SHADERS ST::string frg = fFragmentShader->Render(); const char* fs_code = frg.c_str(); #else @@ -432,7 +432,7 @@ void plGLMaterialShaderRef::ISetupShaderContexts() { fFragmentShader = std::make_shared(kFragment, kShaderVersion); -#ifndef USE_NEW_SHADERS +#ifdef USE_DYNAMIC_SHADERS // Helper function to invert colour auto invColor = std::make_shared("invColor", "vec3"); auto argColor = std::make_shared("color", "vec3", 0); @@ -451,7 +451,7 @@ void plGLMaterialShaderRef::ISetupShaderContexts() void plGLMaterialShaderRef::ISetShaderVariableLocs() { -#ifndef USE_NEW_SHADERS +#ifdef USE_DYNAMIC_SHADERS // Assign and bind the attribute locations for later glBindAttribLocation(fRef, kVtxPosition, "aVtxPosition"); glBindAttribLocation(fRef, kVtxNormal, "aVtxNormal"); From 50998dea9c7b3851ba04e28bbdcefad4c2e60b10 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 20 Jun 2023 22:30:08 -0700 Subject: [PATCH 71/76] Remove dynamic shader system --- .../FeatureLib/pfGLPipeline/CMakeLists.txt | 2 - .../pfGLPipeline/plGLMaterialShaderRef.cpp | 653 +----------------- .../pfGLPipeline/plGLMaterialShaderRef.h | 43 +- .../FeatureLib/pfGLPipeline/plShaderNode.cpp | 323 --------- .../FeatureLib/pfGLPipeline/plShaderNode.h | 344 --------- 5 files changed, 5 insertions(+), 1360 deletions(-) delete mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp delete mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index d1d08de4bb..daa6d93fb3 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -6,7 +6,6 @@ set(pfGLPipeline_SOURCES plGLPipeline.cpp plGLPlateManager.cpp plGLTextFont.cpp - plShaderNode.cpp ) set(pfGLPipeline_HEADERS @@ -17,7 +16,6 @@ set(pfGLPipeline_HEADERS pfGLPipelineCreatable.h plGLPlateManager.h plGLTextFont.h - plShaderNode.h ) plasma_library(pfGLPipeline SOURCES ${pfGLPipeline_SOURCES} ${pfGLPipeline_HEADERS}) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index db5cf07081..8b6eeff586 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -63,8 +63,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plSurface/hsGMaterial.h" #include "plSurface/plLayerInterface.h" -//#define USE_DYNAMIC_SHADERS 1 - // From plGLDevice.cpp extern GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst); @@ -183,6 +181,7 @@ uniform mat4 uLayerMat[8]; uniform int uLayerUVWSrc[8]; uniform int uStartingLayer; uniform int uLayersAtOnce; +uniform int uPassNumber; uniform sampler2D uTexture0; @@ -235,11 +234,9 @@ void main() { plGLMaterialShaderRef::plGLMaterialShaderRef(hsGMaterial* mat, plGLPipeline* pipe) : plGLDeviceRef(), fMaterial(mat), fPipeline(pipe), fVertShaderRef(0), fFragShaderRef(0) { - ISetupShaderContexts(); ILoopOverLayers(); ICompile(); ISetShaderVariableLocs(); - ICleanupShaderContexts(); } plGLMaterialShaderRef::~plGLMaterialShaderRef() @@ -356,13 +353,7 @@ void plGLMaterialShaderRef::ICompile() } const char* vs_code = VERTEX_SHADER_STRING; - -#ifdef USE_DYNAMIC_SHADERS - ST::string frg = fFragmentShader->Render(); - const char* fs_code = frg.c_str(); -#else const char* fs_code = FRAGMENT_SHADER_STRING; -#endif static GLuint vshader = 0; if (!vshader) { @@ -428,37 +419,8 @@ void plGLMaterialShaderRef::ICompile() } -void plGLMaterialShaderRef::ISetupShaderContexts() -{ - fFragmentShader = std::make_shared(kFragment, kShaderVersion); - -#ifdef USE_DYNAMIC_SHADERS - // Helper function to invert colour - auto invColor = std::make_shared("invColor", "vec3"); - auto argColor = std::make_shared("color", "vec3", 0); - invColor->PushOp(RETURN(SUB(CONSTANT("1.0"), argColor))); - - // Helper function to invert alpha - auto invAlpha = std::make_shared("invAlpha", "float"); - auto argAlpha = std::make_shared("alpha", "float", 0); - invAlpha->PushOp(RETURN(SUB(CONSTANT("1.0"), argAlpha))); - - fFragmentShader->PushFunction(invColor); - fFragmentShader->PushFunction(invAlpha); -#endif -} - - void plGLMaterialShaderRef::ISetShaderVariableLocs() { -#ifdef USE_DYNAMIC_SHADERS - // Assign and bind the attribute locations for later - glBindAttribLocation(fRef, kVtxPosition, "aVtxPosition"); - glBindAttribLocation(fRef, kVtxNormal, "aVtxNormal"); - glBindAttribLocation(fRef, kVtxColor, "aVtxColor"); - glBindAttribLocation(fRef, kVtxUVWSrc, "aVtxUVWSrc"); -#endif - glLinkProgram(fRef); LOG_GL_ERROR_CHECK("Program Link failed"); @@ -519,52 +481,18 @@ void plGLMaterialShaderRef::ISetShaderVariableLocs() } -void plGLMaterialShaderRef::ICleanupShaderContexts() -{ - fVariables.clear(); - - fFragmentShader.reset(); -} - - void plGLMaterialShaderRef::ILoopOverLayers() { - size_t j = 0; - size_t pass = 0; - - // Build the fragment shader main function with the right passes - std::shared_ptr fragMain = std::make_shared("main", "void"); - std::shared_ptr uPass = IFindVariable("uPassNumber", "int"); - - for (j = 0; j < fMaterial->GetNumLayers(); ) - { + for (size_t j = 0; j < fMaterial->GetNumLayers(); ) { size_t iCurrMat = j; - std::shared_ptr fragPass = std::make_shared(ST::format("pass{}", pass), "vec4"); - j = IHandleMaterial(iCurrMat, fragPass); + j = IHandleMaterial(iCurrMat); if (j == -1) break; - fFragmentShader->PushFunction(fragPass); - - std::shared_ptr passCond = COND(IS_EQ(uPass, CONSTANT(ST::format("{}", pass)))); - - std::shared_ptr output = IFindVariable("fragColor", "vec4"); - passCond->PushOp(ASSIGN(output, CALL(fragPass->name))); - - // if (uPassNumber == curpass) { curpass(); } - fragMain->PushOp(passCond); - - pass++; fPassIndices.push_back(iCurrMat); - -#if 0 - ISetFogParameters(fMaterial->GetLayer(iCurrMat)); -#endif } - - fFragmentShader->PushFunction(fragMain); } @@ -576,7 +504,7 @@ const hsGMatState plGLMaterialShaderRef::ICompositeLayerState(plLayerInterface* } -uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr ffn) +uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer) { if (!fMaterial || layer >= fMaterial->GetNumLayers() || !fMaterial->GetLayer(layer)) return -1; @@ -641,71 +569,6 @@ uint32_t plGLMaterialShaderRef::IHandleMaterial(uint32_t layer, std::shared_ptr< currLay = fPipeline->IPopOverAllLayer(currLay); currLay = fPipeline->IPopOverBaseLayer(currLay); - std::shared_ptr vVtxColor = IFindVariable("vVtxColor", "vec4"); - - std::shared_ptr fBaseAlpha = std::make_shared("baseAlpha", "float"); - ffn->PushOp(ASSIGN(fBaseAlpha, PROP(vVtxColor, "a"))); - - ShaderBuilder sb; - sb.fFunction = ffn; - sb.fIteration = 0; - sb.fPrevAlpha = fBaseAlpha; - -#if 0 - if (state.fZFlags & hsGMatState::kZIncLayer) { - // Set the Z-bias - sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), ADD(CONSTANT("gl_FragCoord.z"), CONSTANT("-0.0001")))); - } else { - // Clear any Z-bias - sb.fFunction->PushOp(ASSIGN(OUTPUT("gl_FragDepth"), CONSTANT("gl_FragCoord.z"))); - } -#endif - - for (int32_t i = 0; i < currNumLayers; i++) { - sb.fIteration = i; - sb.fCurrColor.reset(); - sb.fCurrAlpha.reset(); - sb.fCurrCoord.reset(); - sb.fCurrImage.reset(); - - plLayerInterface* layPtr = fMaterial->GetLayer(layer + i); - if (!layPtr) - return -1; - - IBuildLayerTransform(layer + i, layPtr, &sb); - IBuildLayerTexture(layer + i, layPtr, &sb); - IBuildLayerBlend(layPtr, &sb); - - sb.fPrevColor = sb.fCurrColor; - sb.fPrevAlpha = sb.fCurrAlpha; - } - - //IHandleTextureMode(layer); - //IHandleShadeMode(layer); - //IHandleZMode(); - //IHandleMiscMode() - //IHandleTextureStage(0, layer); - - // Handle High Alpha Threshold - std::shared_ptr alphaThreshold = IFindVariable("uAlphaThreshold", "float"); - - std::shared_ptr alphaTest = COND(IS_LESS(sb.fCurrAlpha, alphaThreshold)); - alphaTest->PushOp(CONSTANT("discard")); - - // if (final.a < alphaThreshold) { discard; } - sb.fFunction->PushOp(alphaTest); - - // Multiply in the vertex color at the end (but alpha is premultiplied!) - std::shared_ptr finalColor; - - if (sb.fCurrColor) { - finalColor = MUL(PROP(vVtxColor, "rgb"), sb.fCurrColor, true); - } else { - finalColor = PROP(vVtxColor, "rgb"); - } - - sb.fFunction->PushOp(RETURN(CALL("vec4", finalColor, sb.fCurrAlpha))); - return layer + currNumLayers; } @@ -771,511 +634,3 @@ bool plGLMaterialShaderRef::ICanEatLayer(plLayerInterface* lay) return true; } - - -void plGLMaterialShaderRef::IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) -{ - std::shared_ptr matrix; - hsGMatState state = ICompositeLayerState(layer); - - if (state.fMiscFlags & (hsGMatState::kMiscUseReflectionXform | hsGMatState::kMiscUseRefractionXform)) { - std::shared_ptr mC2W = IFindVariable("uMatrixC2W", "mat4"); - - ST::string matName = ST::format("LayerMat{}", idx); - matrix = std::make_shared(matName, "mat4"); - - ST::string tempName = ST::format("t{}", idx); - std::shared_ptr temp = std::make_shared(tempName, "float"); - - sb->fFunction->PushOp(ASSIGN(matrix, mC2W)); - - // mat[0][3] = mat[1][3] = mat[2][3] = 0 - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "3"), - ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "3"), - ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "3"), - CONSTANT("0.0"))))); - - // This is just a rotation about X of Pi/2 (y = z, z = -y), - // followed by flipping Z to reflect back towards us (z = -z). - - // swap mat[1][0] and mat[2][0] - sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "0"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "0"), SUBVAL(SUBVAL(matrix, "2"), "0"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "0"), temp)); - - // swap mat[1][1] and mat[2][1] - sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "1"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "1"), SUBVAL(SUBVAL(matrix, "2"), "1"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "1"), temp)); - - // swap mat[1][2] and mat[2][2] - sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "1"), "2"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "2"), SUBVAL(SUBVAL(matrix, "2"), "2"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), temp)); - - if (state.fMiscFlags & hsGMatState::kMiscUseRefractionXform) { - // Same as reflection, but then matrix = matrix * scaleMatNegateZ. - - // mat[0][2] = -mat[0][2]; - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "0"), "2")))); - - // mat[1][2] = -mat[1][2]; - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "1"), "2")))); - - // mat[2][2] = -mat[2][2]; - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), SUB(CONSTANT("0.0"), SUBVAL(SUBVAL(matrix, "2"), "2")))); - } - } else if (state.fMiscFlags & hsGMatState::kMiscCam2Screen) { - // cam2Screen will also have the kMiscPerspProjection flag set, so this - // needs to go before the regular kMiscProjection check. - std::shared_ptr mNDC = IFindVariable("uMatrixProj", "mat4"); - - ST::string matName = ST::format("LayerMat{}", idx); - matrix = std::make_shared(matName, "mat4"); - - // mat.Reset(); - sb->fFunction->PushOp(ASSIGN(matrix, CALL("mat4", CONSTANT("1.0")))); - - // mat.MakeScaleMat(hsVector3 camScale(0.5f, -0.5f, 1.f)); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "0"), CONSTANT("0.5"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "1"), CONSTANT("-0.5"))); - - // hsVector3 camTrans(0.5f, 0.5f, 0.f); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "0"), "3"), CONSTANT("0.5"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "1"), "3"), CONSTANT("0.5"))); - - // The scale and trans move us from NDC to Screen space. We need to swap - // the Z and W coordinates so that the texture projection will divide by W - // and give us projected 2D coordinates. - ST::string tempName = ST::format("t{}", idx); - std::shared_ptr temp = std::make_shared(tempName, "float"); - - // swap mat[2][2] and mat[3][2] - sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "2"), "2"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "2"), SUBVAL(SUBVAL(matrix, "3"), "2"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "3"), "2"), temp)); - - // swap mat[2][3] and mat[3][3] - sb->fFunction->PushOp(ASSIGN(temp, SUBVAL(SUBVAL(matrix, "2"), "3"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "2"), "3"), SUBVAL(SUBVAL(matrix, "3"), "3"))); - sb->fFunction->PushOp(ASSIGN(SUBVAL(SUBVAL(matrix, "3"), "3"), temp)); - - // Multiply by the projection matrix - sb->fFunction->PushOp(ASSIGN(matrix, MUL(matrix, mNDC))); -#if 0 - } else if (state.fMiscFlags & hsGMatState::kMiscProjection) { - ST::string matName = ST::format("uLayerMat{}", idx); - std::shared_ptr layMat = IFindVariable(matName, "mat4"); - } else if (state.fMiscFlags & hsGMatState::kMiscBumpChans) { -#endif - } else { - ST::string matName = ST::format("uLayerMat{}", idx); - matrix = IFindVariable(matName, "mat4"); - } - - uint32_t uvwSrc = layer->GetUVWSrc(); - - // Local variable to store the mesh uvw * layer matrix - ST::string coordName = ST::format("coords{}", idx); - std::shared_ptr coords = std::make_shared(coordName, "vec4"); - - switch (uvwSrc) { - case plLayerInterface::kUVWNormal: - { - std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, vCamNor))); - } - break; - case plLayerInterface::kUVWPosition: - { - std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, vCamPos))); - } - break; - case plLayerInterface::kUVWReflect: - { - std::shared_ptr vCamPos = IFindVariable("vCamPosition", "vec4"); - std::shared_ptr vCamNor = IFindVariable("vCamNormal", "vec4"); - std::shared_ptr mC2W = IFindVariable("uMatrixC2W", "mat4"); - - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, MUL(mC2W, CALL("reflect", CALL("normalize", vCamPos), CALL("normalize", vCamNor)))))); - } - break; - default: - { - uvwSrc &= plGBufferGroup::kUVCountMask; - - std::shared_ptr layUVW = IFindVariable("vVtxUVWSrc", "highp vec3", 8); - sb->fFunction->PushOp(ASSIGN(coords, MUL(matrix, CALL("vec4", SUBVAL(layUVW, ST::format("{}", uvwSrc)), CONSTANT("1.0"))))); - } - break; - } - - if (state.fMiscFlags & hsGMatState::kMiscPerspProjection) { - sb->fFunction->PushOp(ASSIGN(PROP(coords, "x"), DIV(PROP(coords, "x"), PROP(coords, "z")))); - sb->fFunction->PushOp(ASSIGN(PROP(coords, "y"), DIV(PROP(coords, "y"), PROP(coords, "z")))); - } - - sb->fCurrCoord = coords; -} - - -void plGLMaterialShaderRef::IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb) -{ - plBitmap* texture = layer->GetTexture(); - - if (texture != nullptr && sb->fCurrCoord) { - // Local variable to store the mesh uvw * layer matrix - ST::string imgName = ST::format("image{}", idx); - std::shared_ptr img = std::make_shared(imgName, "vec4"); - - sb->fCurrImage = img; - - if (plCubicEnvironmap::ConvertNoRef(texture) != nullptr || plCubicRenderTarget::ConvertNoRef(texture) != nullptr) { - ST::string samplerName = ST::format("uTexture{}", idx); - std::shared_ptr sampler = IFindVariable(samplerName, "samplerCube"); - - // image = texture(sampler, coords.xyz) - sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xyz")))); - } else if (plMipmap::ConvertNoRef(texture) != nullptr || plRenderTarget::ConvertNoRef(texture) != nullptr) { - ST::string samplerName = ST::format("uTexture{}", idx); - std::shared_ptr sampler = IFindVariable(samplerName, "sampler2D"); - - // image = texture(sampler, coords.xy) - sb->fFunction->PushOp(ASSIGN(img, CALL("texture", sampler, PROP(sb->fCurrCoord, "xy")))); - } - } -} - - -void plGLMaterialShaderRef::IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb) -{ - hsGMatState state = ICompositeLayerState(layer); - - if (!sb->fCurrImage) { - plStatusLog::AddLineSF("pipeline.log", "Got a layer with no image: {}", layer->GetKeyName()); - sb->fCurrColor = sb->fPrevColor; - sb->fCurrAlpha = sb->fPrevAlpha; - return; - } - - // Local variable to store the color value - ST::string colName = ST::format("color{}", sb->fIteration); - std::shared_ptr col = std::make_shared(colName, "vec3"); - - // Local variable to store the alpha value - ST::string alphaName = ST::format("alpha{}", sb->fIteration); - std::shared_ptr alpha = std::make_shared(alphaName, "float"); - - std::shared_ptr texCol; - if (state.fBlendFlags & hsGMatState::kBlendInvertColor) { - // color = 1.0 - texture.rgb - texCol = CALL("invColor", PROP(sb->fCurrImage, "rgb")); - } else { - // color = texture.rgb - texCol = PROP(sb->fCurrImage, "rgb"); - } - - - if (sb->fIteration == 0) { - // Leave fCurrColor null if we are blending without texture color - if (state.fBlendFlags & hsGMatState::kBlendNoTexColor) { - sb->fCurrColor = sb->fPrevColor; - } else { - sb->fFunction->PushOp(ASSIGN(col, texCol)); - sb->fCurrColor = col; - } - - std::shared_ptr alphaVal; - if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { - // 1.0 - texture.a - alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); - } else { - // texture.a - alphaVal = PROP(sb->fCurrImage, "a"); - } - - - if (state.fBlendFlags & hsGMatState::kBlendNoVtxAlpha || !sb->fPrevAlpha) { - // Only use texture alpha - sb->fFunction->PushOp(ASSIGN(alpha, alphaVal)); - - sb->fCurrAlpha = alpha; - } else if (state.fBlendFlags & hsGMatState::kBlendNoTexAlpha) { - // Only use vertex alpha (prev alpha) - sb->fCurrAlpha = sb->fPrevAlpha; - } else { - // Vertex alpha * base texture alpha - sb->fFunction->PushOp(ASSIGN(alpha, MUL(alphaVal, sb->fPrevAlpha))); - sb->fCurrAlpha = alpha; - } - } else { - switch (state.fBlendFlags & hsGMatState::kBlendMask) - { - - case hsGMatState::kBlendAddColorTimesAlpha: - hsAssert(false, "Blend mode unsupported on upper layers"); - break; - - case hsGMatState::kBlendAlpha: - { - if (state.fBlendFlags & hsGMatState::kBlendNoTexColor) { - // color = prev - sb->fCurrColor = sb->fPrevColor; - } else { - if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { - // color = texture.rgb + (texture.a * prev) - sb->fFunction->PushOp(ASSIGN(col, ADD(texCol, MUL(PROP(sb->fCurrImage, "a"), sb->fPrevColor, true)))); - sb->fCurrColor = col; - } else { - // color = mix(prev, texture.rgb, texture.a) - sb->fFunction->PushOp(ASSIGN(col, CALL("mix", sb->fPrevColor, texCol, PROP(sb->fCurrImage, "a")))); - sb->fCurrColor = col; - } - } - - - std::shared_ptr alphaVal; - if (state.fBlendFlags & hsGMatState::kBlendInvertAlpha) { - // 1.0 - texture.a - alphaVal = CALL("invAlpha", PROP(sb->fCurrImage, "a")); - } else { - // texture.a - alphaVal = PROP(sb->fCurrImage, "a"); - } - - if (state.fBlendFlags & hsGMatState::kBlendAlphaAdd) { - // alpha = alphaVal + prev - sb->fFunction->PushOp(ASSIGN(alpha, ADD(alphaVal, sb->fPrevAlpha))); - sb->fCurrAlpha = alpha; - } else if (state.fBlendFlags & hsGMatState::kBlendAlphaMult) { - // alpha = alphaVal * prev - sb->fFunction->PushOp(ASSIGN(alpha, MUL(alphaVal, sb->fPrevAlpha))); - sb->fCurrAlpha = alpha; - } else { - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - } - break; - } - - case hsGMatState::kBlendAdd: - { - // color = texture.rgb + prev - sb->fFunction->PushOp(ASSIGN(col, ADD(texCol, sb->fPrevColor))); - sb->fCurrColor = col; - - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - break; - } - - case hsGMatState::kBlendMult: - { - // color = color * prev - sb->fFunction->PushOp(ASSIGN(col, MUL(texCol, sb->fPrevColor))); - sb->fCurrColor = col; - - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - break; - } - - case hsGMatState::kBlendDot3: - { - // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) - sb->fFunction->PushOp(ASSIGN(PROP(col, "r"), ASSIGN(PROP(col, "g"), ASSIGN(PROP(col, "b"), CALL("dot", PROP(col, "rgb"), PROP(sb->fPrevColor, "rgb")))))); - sb->fCurrColor = col; - - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - break; - } - - case hsGMatState::kBlendAddSigned: - { - // color = color + prev - 0.5 - sb->fFunction->PushOp(ASSIGN(col, SUB(ADD(texCol, sb->fPrevColor), CONSTANT("0.5")))); - sb->fCurrColor = col; - - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - break; - } - - case hsGMatState::kBlendAddSigned2X: - { - // color = (color + prev - 0.5) << 1 - // Note: using CALL here for multiplication to ensure parentheses - sb->fFunction->PushOp(ASSIGN(col, CALL("2 *", SUB(ADD(texCol, sb->fPrevColor), CONSTANT("0.5"))))); - sb->fCurrColor = col; - - // alpha = prev - sb->fCurrAlpha = sb->fPrevAlpha; - break; - } - - case 0: - { - // color = texture.rgb - sb->fFunction->PushOp(ASSIGN(col, texCol)); - sb->fCurrColor = col; - - // alpha = texture.a - sb->fFunction->PushOp(ASSIGN(alpha, PROP(sb->fCurrImage, "a"))); - sb->fCurrAlpha = alpha; - break; - } - } - } - -} - - -#if 0 -void plGLMaterialShaderRef::IHandleTextureMode(plLayerInterface* layer) -{ - plBitmap* bitmap = layer->GetTexture(); - - if (bitmap) { - // EnvBumpNext is unused in production -- ignoring for now - - - if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexColor) { - // color = null - } else { - if (lay->GetBlendFlags() & hsGMatState::kBlendInvertColor) { - // color = 1.0 - texture.rgb - } else { - // color = texture.rgb - } - } - - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertAlpha) { - // alpha1 = 1.0 - texture.a - } else { - // alpha1 = texture.a - } - - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { - // alpha2 = 1.0 - vVtxColor.a - } else { - // alpha2 = vVtxColor.a - } - - if (layer->GetBlendFlags() & hsGMatState::kBlendNoVtxAlpha) { - // alpha = alpha1 - } else if (layer->GetBlendFlags() & hsGMatState::kBlendNoTexAlpha) { - // alpha = alpha2 - } else { - // alpha = alpha1 * alpha2 - } - } else if (piggybacks) { - // Plasma says it selects the vertex colours, but actually selects an - // undefined arg2. We're going to assume that's wrong and select the - // vertex colours. - - // color = vVtxColor.rgb - // alpha = vVtxColor.a - } else { - // color = vVtxColor.rgb - if (layer->GetBlendFlags() & hsGMatState::kBlendInvertVtxAlpha) { - // alpha = 1.0 - vVtxColor.a - } else { - // alpha = vVtxColor.a - } - } -} - -void plGLMaterialShaderRef::IHandleStageBlend(const hsGMatState& state) -{ - const uint32_t blendFlags = state.fBlendFlags; - - if (blendFlags & hsGMatState::kBlendInvertColor) { - // color = 1.0 - texture.rgb - } else { - // color = texture.rgb - } - - // Ignoring the unused kBlendEnvBumpNext - - switch (blendFlags & hsGMatState::kBlendMask) - { - case hsGMatState::kBlendAlpha: - { - if (blendFlags & hsGMatState::kBlendNoTexColor) { - // if (prev) { color = prev } - } else { - if (blendFlags & hsGMatState::kBlendInvertAlpha) { - // color = color.rgb + (texture.a * prev.rgb) - } else { - // color = mix(prev.rgb, color.rgb, texture.a) - } - } - - if (blendFlags & hsGMatState::kBlendAlphaAdd) { - if (blendFlags & hsGMatState::kBlendInvertAlpha) { - // alpha = (1.0 - texture.a) + prev - } else { - // alpha = texture.a + prev - } - } else if (blendFlags & hsGMatState::kBlendAlphaMult) { - if (blendFlags & hsGMatState::kBlendInvertAlpha) { - // alpha = (1.0 - texture.a) * prev - } else { - // alpha = texture.a * prev - } - } else { - // alpha = prev - } - break; - } - - case hsGMatState::kBlendAdd: - { - // color = color + prev - // alpha = prev - break; - } - - case hsGMatState::kBlendMult: - { - // color = color * prev - // alpha = prev - break; - } - - case hsGMatState::kBlendDot3: - { - // color = (color.r * prev.r + color.g * prev.g + color.b * prev.b) - // alpha = prev - break; - } - - case hsGMatState::kBlendAddSigned: - { - // color = color + prev - 0.5 - // alpha = prev - break; - } - - case hsGMatState::kBlendAddSigned2X: - { - // color = (color + prev - 0.5) << 1 - // alpha = prev - break; - } - - case hsGMatState::kBlendAddColorTimesAlpha: - hsAssert(false, "Blend mode unsupported on upper layers"); - break; - - case 0: - { - // color = color - // alpha = prev - break; - } - } -} -#endif diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h index 03674e3d69..13c1550619 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.h @@ -44,7 +44,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define _plGLMaterialShaderRef_inc_ #include "plGLDeviceRef.h" -#include "plShaderNode.h" #include #include @@ -64,27 +63,10 @@ enum plGLShaderConstants : GLuint { class plGLMaterialShaderRef : public plGLDeviceRef { - typedef std::map> plShaderVarLookup; - enum { kShaderVersion = 100 }; - struct ShaderBuilder { - std::shared_ptr fFunction; - uint32_t fIteration; - - std::shared_ptr fMatValues; - - std::shared_ptr fPrevColor; - std::shared_ptr fPrevAlpha; - - std::shared_ptr fCurrColor; - std::shared_ptr fCurrAlpha; - std::shared_ptr fCurrCoord; - std::shared_ptr fCurrImage; - }; - struct uniformLightSource { GLuint position; GLuint ambient; @@ -106,9 +88,6 @@ class plGLMaterialShaderRef : public plGLDeviceRef std::vector fPassIndices; - std::shared_ptr fFragmentShader; - plShaderVarLookup fVariables; - public: // These are named to match the GLSL variable names and are public vars GLuint aVtxPosition; @@ -155,22 +134,7 @@ class plGLMaterialShaderRef : public plGLDeviceRef protected: void ICompile(); - void ISetupShaderContexts(); void ISetShaderVariableLocs(); - void ICleanupShaderContexts(); - - template - std::shared_ptr IFindVariable(const ST::string& name, const ST::string& type, size_t n = 1) - { - auto it = fVariables.find(name); - if (it == fVariables.end()) { - std::shared_ptr var = std::make_shared(name, type, n); - fVariables[name] = var; - return var; - } else { - return std::static_pointer_cast(it->second); - } - } void ILoopOverLayers(); @@ -179,14 +143,9 @@ class plGLMaterialShaderRef : public plGLDeviceRef // fMatOverOff overrides to clear a state bit whether it is set in the layer or not. const hsGMatState ICompositeLayerState(plLayerInterface* layer); - uint32_t IHandleMaterial(uint32_t layer, std::shared_ptr ffn); + uint32_t IHandleMaterial(uint32_t layer); uint32_t ILayersAtOnce(uint32_t which); bool ICanEatLayer(plLayerInterface* lay); - void IBuildLayerTransform(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); - void IBuildLayerTexture(uint32_t idx, plLayerInterface* layer, ShaderBuilder* sb); - void IBuildLayerBlend(plLayerInterface* layer, ShaderBuilder* sb); - //void IHandleFirstTextureStage(plLayerInterface* layer); - //void IHandleFirstStageBlend(const hsGMatState& layerState); }; #endif // _plGLMaterialShaderRef_inc_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp deleted file mode 100644 index ac776768f0..0000000000 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ - -#include "plShaderNode.h" -#include - -using namespace std; - -bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr b) -{ - return a->pos < b->pos; -} - -ST::string plShaderContext::RenderNode(std::shared_ptr node, std::shared_ptr fn) -{ - switch (node->klass) - { - case kConstant: - { - std::shared_ptr c = static_pointer_cast(node); - - return c->value; - } - break; - - case kAttribute: - { - std::shared_ptr attr = static_pointer_cast(node); - - this->attributes.insert(attr); - - return attr->name; - } - break; - - case kUniform: - { - std::shared_ptr uni = static_pointer_cast(node); - - this->uniforms.insert(uni); - - return uni->name; - } - break; - - case kVarying: - { - std::shared_ptr var = static_pointer_cast(node); - - this->varyings.insert(var); - - return var->name; - } - break; - - case kOutputVariable: - { - std::shared_ptr var = static_pointer_cast(node); - - this->outputVariables.insert(var); - - return var->name; - } - break; - - case kTempVar: - { - std::shared_ptr tmp = static_pointer_cast(node); - - fn->temps.insert(tmp); - - return tmp->name; - } - break; - - case kArgument: - { - std::shared_ptr arg = static_pointer_cast(node); - - fn->args.insert(arg); - - return arg->name; - } - break; - - case kOutput: - { - std::shared_ptr out = static_pointer_cast(node); - - return out->name; - } - break; - - case kOperator: - { - std::shared_ptr op = static_pointer_cast(node); - - if (op->op == ".") { - return ST::format("{}{}{}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); - } else if (op->op == "[") { - return ST::format("{}{}{}]", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); - } else if (op->parens) { - return ST::format("({} {} {})", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); - } else { - return ST::format("{} {} {}", this->RenderNode(op->lhs, fn), op->op, this->RenderNode(op->rhs, fn)); - } - } - break; - - case kAssignment: - { - std::shared_ptr asn = static_pointer_cast(node); - - return ST::format("{} = {}", this->RenderNode(asn->lhs, fn), this->RenderNode(asn->rhs, fn)); - } - break; - - case kReturn: - { - std::shared_ptr ret = static_pointer_cast(node); - - return ST::format("return {}", this->RenderNode(ret->var, fn)); - } - break; - - case kFnCall: - { - std::shared_ptr call = static_pointer_cast(node); - - std::vector params; - - for (std::shared_ptr arg : call->args) { - params.push_back(this->RenderNode(arg, fn)); - } - - ST::string_stream out; - out << call->function << "("; - - for (size_t i = 0; i < call->args.size(); i++) { - if (i > 0) { - out << ", "; - } - out << params[i]; - } - out << ")"; - - return out.to_string(); - } - break; - - case kConditional: - { - std::shared_ptr cond = static_pointer_cast(node); - - ST::string_stream out; - out << ST::format("if ({}) {{", this->RenderNode(cond->condition, fn)); - - if (cond->nodes.size() == 1) { - out << ST::format(" {}; }", this->RenderNode(cond->nodes[0], fn)); - } else { - out << "\n"; - - for (size_t i = 0; i < cond->nodes.size(); i++) { - out << "\t" << this->RenderNode(cond->nodes[i], fn) << ";\n"; - } - - out << "}"; - } - - return out.to_string(); - } - break; - - default: - return ""; - } -} - -ST::string plShaderContext::Render() -{ - std::vector lines; - - for (std::shared_ptr fn : this->funcs) { - for (std::shared_ptr node : fn->nodes) { - fn->output.push_back(this->RenderNode(node, fn)); - } - } - - - ST::string_stream out; - - //out << ST::format("#version {}\n", this->version); - out << "#version 330\n"; - - if (this->type == kFragment) - out << "precision mediump float;\n"; - - for (std::shared_ptr st : this->structs) { - out << ST::format("struct {} {{\n", st->name); - - for (std::shared_ptr var : st->fields) { - if (var->count > 1) - out << "\t" << ST::format("{} {}[{}];\n", var->type, var->name, var->count); - else - out << "\t" << ST::format("{} {};\n", var->type, var->name); - } - - out << "};\n"; - } - - for (std::shared_ptr node : this->attributes) { - if (node->count > 1) - out << ST::format("attribute {} {}[{}];\n", node->type, node->name, node->count); - else - out << ST::format("attribute {} {};\n", node->type, node->name); - } - - for (std::shared_ptr node : this->uniforms) { - if (node->count > 1) - out << ST::format("uniform {} {}[{}];\n", node->type, node->name, node->count); - else - out << ST::format("uniform {} {};\n", node->type, node->name); - } - - for (std::shared_ptr node : this->varyings) { - if (node->count > 1) { - if (this->type == kVertex) { - out << ST::format("out {} {}[{}];\n", node->type, node->name, node->count); - } else { - out << ST::format("in {} {}[{}];\n", node->type, node->name, node->count); - } - } else { - if (this->type == kVertex) { - out << ST::format("out {} {};\n", node->type, node->name); - } else { - out << ST::format("in {} {};\n", node->type, node->name); - } - } - } - - for (std::shared_ptr node : this->outputVariables) { - if (node->count > 1) { - out << ST::format("out {} {}[{}];\n", node->type, node->name, node->count); - } else { - out << ST::format("out {} {};\n", node->type, node->name); - } - } - - - for (std::shared_ptr fn : this->funcs) { - out << ST::format("\n{} {}(", fn->type, fn->name); - - size_t i = 0; - for (std::shared_ptr arg : fn->args) { - if (i > 0) - out << ", "; - - out << ST::format("{} {}", arg->type, arg->name); - i++; - } - - out << ") {\n"; - - - for (std::shared_ptr node : fn->temps) { - if (node->count > 1) - out << "\t" << ST::format("{} {}[{}];\n", node->type, node->name, node->count); - else - out << "\t" << ST::format("{} {};\n", node->type, node->name); - } - - - if (fn->temps.size()) - out << "\n"; - - - for (ST::string ln : fn->output) - out << "\t" << ln << ";\n"; - - out << "}\n"; - } - - return out.to_string(); -} diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h deleted file mode 100644 index 1544748a70..0000000000 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plShaderNode.h +++ /dev/null @@ -1,344 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ - -#ifndef _plShaderNode_h_ -#define _plShaderNode_h_ - -#include -#include -#include -#include -#include - -enum NodeType { - kInvalid, - - kConstant, - kOutput, - kOperator, - kReturn, - kAssignment, - kAttribute, - kVarying, - kUniform, - kOutputVariable, - kTempVar, - kArgument, - kFnCall, - kBlock, - kConditional, - kLoop -}; - - -class plShaderNode : public std::enable_shared_from_this { -public: - NodeType klass; - - plShaderNode(NodeType klass) - : klass(klass) { } -}; - - -class plConstantNode : public plShaderNode { -public: - ST::string value; - - plConstantNode(ST::string value) - : plShaderNode(kConstant), - value(value) { } -}; - - -class plOutputNode : public plShaderNode { -public: - ST::string name; - - plOutputNode(ST::string name) - : plShaderNode(kOutput), - name(name) { } -}; - - -// ABSTRACT -class plVariableNode : public plShaderNode { -public: - ST::string name; - ST::string type; - size_t count; - - plVariableNode(NodeType klass, ST::string name, ST::string type, size_t n = 1) - : plShaderNode(klass), - name(name), - type(type), - count(n){ } -}; - - -// ABSTRACT -class plGlobalVariableNode : public plVariableNode { -public: - plGlobalVariableNode(NodeType klass, ST::string name, ST::string type, size_t n = 1) - : plVariableNode(klass, name, type, n) { } -}; - - -class plAttributeNode : public plGlobalVariableNode { -public: - plAttributeNode(ST::string name, ST::string type, size_t n = 1) - : plGlobalVariableNode(kAttribute, name, type, n) { } -}; - -class plUniformNode : public plGlobalVariableNode { -public: - plUniformNode(ST::string name, ST::string type, size_t n = 1) - : plGlobalVariableNode(kUniform, name, type, n) { } -}; - -class plVaryingNode : public plGlobalVariableNode { -public: - plVaryingNode(ST::string name, ST::string type, size_t n = 1) - : plGlobalVariableNode(kVarying, name, type, n) { } -}; - -class plOutputVariableNode : public plGlobalVariableNode { -public: - plOutputVariableNode(ST::string name, ST::string type, size_t n = 1) - : plGlobalVariableNode(kOutputVariable, name, type, n) { } -}; - -class plTempVariableNode : public plVariableNode { -public: - plTempVariableNode(ST::string name, ST::string type, size_t n = 1) - : plVariableNode(kTempVar, name, type, n) { } -}; - -class plArgumentNode : public plVariableNode { -public: - int pos; - - plArgumentNode(ST::string name, ST::string type, int pos) - : plVariableNode(kArgument, name, type), - pos(pos) { } -}; - - -// ABSTRACT -class plOperationNode : public plShaderNode { -public: - std::shared_ptr lhs; - std::shared_ptr rhs; - - plOperationNode(NodeType klass, std::shared_ptr lhs, std::shared_ptr rhs) - : plShaderNode(klass), - lhs(lhs), - rhs(rhs) { } -}; - - -class plOperatorNode : public plOperationNode { -public: - ST::string op; - bool parens; - - plOperatorNode(ST::string op, std::shared_ptr lhs, std::shared_ptr rhs, bool parens=false) - : plOperationNode(kOperator, lhs, rhs), - op(op), - parens(parens) { } -}; - - -class plAssignmentNode : public plOperationNode { -public: - plAssignmentNode(std::shared_ptr lhs, std::shared_ptr rhs) - : plOperationNode(kAssignment, lhs, rhs) { } -}; - - -class plReturnNode : public plShaderNode { -public: - std::shared_ptr var; - - plReturnNode(std::shared_ptr var) - : plShaderNode(kReturn), - var(var) { } -}; - - -class plCallNode : public plShaderNode { -public: - ST::string function; - std::vector> args; - - plCallNode(ST::string function, std::initializer_list> args) - : plShaderNode(kFnCall), - function(function), - args(args) { } -}; - - -class plBlockNode : public plShaderNode { -public: - std::vector> nodes; - - plBlockNode(NodeType klass = kBlock) : plShaderNode(klass) { } - - void PushOp(std::shared_ptr op) { - nodes.push_back(op); - } -}; - - -class plConditionNode : public plBlockNode { -public: - std::shared_ptr condition; - - plConditionNode(std::shared_ptr condition) - : plBlockNode(kConditional), - condition(condition) { } -}; - - -bool plArgumentNodeSorterFunc(std::shared_ptr a, std::shared_ptr b); - -class plShaderFunction : public std::enable_shared_from_this -{ - friend class plShaderContext; - - std::vector> nodes; - std::set> temps; - std::set, decltype(&plArgumentNodeSorterFunc)> args; - - std::vector output; - -public: - ST::string type; - ST::string name; - - plShaderFunction(ST::string name, ST::string type) - : name(name), - type(type), - args(plArgumentNodeSorterFunc) { } - - void PushOp(std::shared_ptr op) { - nodes.push_back(op); - } -}; - - -class plShaderStruct : public std::enable_shared_from_this -{ - friend class plShaderContext; - - std::vector> fields; - -public: - ST::string name; - - plShaderStruct(ST::string name) - : name(name) { } - - void AddField(std::shared_ptr var) { - fields.push_back(var); - } -}; - - - - -enum CtxType { - kVertex, - kFragment -}; - -class plShaderContext : public std::enable_shared_from_this -{ - std::vector> funcs; - std::vector> structs; - CtxType type; - int32_t version; - - std::set> attributes; - std::set> uniforms; - std::set> varyings; - std::set> outputVariables; - -public: - plShaderContext(CtxType type, int32_t version) : type(type), version(version) { } - - void PushFunction(std::shared_ptr fn) { - funcs.push_back(fn); - } - - void PushStruct(std::shared_ptr st) { - structs.push_back(st); - } - - ST::string Render(); - -private: - ST::string RenderNode(std::shared_ptr node, std::shared_ptr fn); -}; - - -// Helper Macros -#define CONSTANT(v) std::make_shared(v) -#define OUTPUT(n) std::make_shared(n) -#define ASSIGN(l, r) std::make_shared(l, r) -#define ADD(...) std::make_shared("+", __VA_ARGS__) -#define SUB(...) std::make_shared("-", __VA_ARGS__) -#define MUL(...) std::make_shared("*", __VA_ARGS__) -#define DIV(...) std::make_shared("/", __VA_ARGS__) -#define PROP(n, p) std::make_shared(".", n, CONSTANT(p)) -#define SUBVAL(n, p) std::make_shared("[", n, CONSTANT(p)) -#define IS_EQ(...) std::make_shared("==", __VA_ARGS__) -#define IS_LEQ(...) std::make_shared("<=", __VA_ARGS__) -#define IS_LESS(...) std::make_shared("<", __VA_ARGS__) -#define RETURN(n) std::make_shared(n) -#define COND(...) std::make_shared(__VA_ARGS__) - -#define STRUCTVAR(t, n) std::make_shared(n, t) - -// This one is a bit special because of the initializer_list -#define CALL(fn, ...) std::shared_ptr(new plCallNode(fn, { __VA_ARGS__ })) - -#endif From 02b6c5f4651cf9a843e6112d712936a1de841f24 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Sep 2023 02:53:41 -0700 Subject: [PATCH 72/76] Reorganize platform GL context providers --- .../FeatureLib/pfGLPipeline/CMakeLists.txt | 6 + .../FeatureLib/pfGLPipeline/plCGLDevice.cpp | 187 ++++++++++ .../FeatureLib/pfGLPipeline/plCGLDevice.h | 72 ++++ .../FeatureLib/pfGLPipeline/plEGLDevice.cpp | 250 +++++++++++++ .../FeatureLib/pfGLPipeline/plEGLDevice.h | 73 ++++ .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 330 +----------------- .../FeatureLib/pfGLPipeline/plGLDevice.h | 42 +-- .../FeatureLib/pfGLPipeline/plGLEnumerate.cpp | 261 ++------------ .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 2 +- .../FeatureLib/pfGLPipeline/plWGLDevice.cpp | 212 +++++++++++ .../FeatureLib/pfGLPipeline/plWGLDevice.h | 72 ++++ 11 files changed, 933 insertions(+), 574 deletions(-) create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.h create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.h create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.cpp create mode 100644 Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.h diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt index daa6d93fb3..963bb4b2d0 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/CMakeLists.txt @@ -6,6 +6,9 @@ set(pfGLPipeline_SOURCES plGLPipeline.cpp plGLPlateManager.cpp plGLTextFont.cpp + $<$:plCGLDevice.cpp> + plEGLDevice.cpp + $<$:plWGLDevice.cpp> ) set(pfGLPipeline_HEADERS @@ -16,6 +19,9 @@ set(pfGLPipeline_HEADERS pfGLPipelineCreatable.h plGLPlateManager.h plGLTextFont.h + plCGLDevice.h + plEGLDevice.h + plWGLDevice.h ) plasma_library(pfGLPipeline SOURCES ${pfGLPipeline_SOURCES} ${pfGLPipeline_HEADERS}) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.cpp new file mode 100644 index 0000000000..3e27bbde7a --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.cpp @@ -0,0 +1,187 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plCGLDevice.h" + +#ifdef HS_BUILD_FOR_MACOS +#include + +bool plCGLDevice::Enumerate(hsG3DDeviceRecord& record) +{ + bool result = false; + + IGNORE_WARNINGS_BEGIN("deprecated-declarations") + CGLPixelFormatObj pix = nullptr; + CGLContextObj ctx = nullptr; + + do { + CGLPixelFormatAttribute attribs[6] = { + kCGLPFAAccelerated, + kCGLPFANoRecovery, + kCGLPFADoubleBuffer, +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + // OpenGL profiles introduced in 10.7 + kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, +#endif + (CGLPixelFormatAttribute) 0 + }; + + int nPix = 0; + if (CGLChoosePixelFormat(attribs, &pix, &nPix) != kCGLNoError || nPix == 0) + break; + + if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) + break; + + if (CGLSetCurrentContext(ctx) != kCGLNoError) + break; + + if (epoxy_gl_version() < 33) + break; + + record.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); + record.SetDriverName("OpenGL.framework"); + record.SetDeviceDesc(reinterpret_cast(glGetString(GL_RENDERER))); + record.SetDriverDesc(reinterpret_cast(glGetString(GL_VENDOR))); + record.SetDriverVersion(reinterpret_cast(glGetString(GL_VERSION))); + + result = true; + } while (0); + + // Cleanup: + if (ctx) { + CGLSetCurrentContext(nullptr); + CGLReleaseContext(ctx); + } + + if (pix) + CGLReleasePixelFormat(pix); + + IGNORE_WARNINGS_END + + return result; +} + + +plCGLDevice* plCGLDevice::TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error) +{ + IGNORE_WARNINGS_BEGIN("deprecated-declarations") + + CGLPixelFormatObj pix = nullptr; + CGLContextObj ctx = nullptr; + + do { + CGLPixelFormatAttribute attribs[6] = { + kCGLPFAAccelerated, + kCGLPFANoRecovery, + kCGLPFADoubleBuffer, +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + // OpenGL profiles introduced in 10.7 + kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, +#endif + (CGLPixelFormatAttribute) 0 + }; + + int nPix = 0; + if (CGLChoosePixelFormat(attribs, &pix, &nPix) != kCGLNoError || nPix == 0) { + error = ST_LITERAL("Could not choose appropriate config"); + break; + } + + if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) { + error = ST_LITERAL("Unable to create rendering context"); + break; + } + + if (CGLSetCurrentContext(ctx) != kCGLNoError) { + error = ST_LITERAL("Failed to attach CGL context to surface"); + break; + } + + CGLReleasePixelFormat(pix); + + // Successfully initialized + return new plCGLDevice(window, device, ctx); + } while (0); + + // Cleanup for failure case: + if (ctx) { + CGLSetCurrentContext(nullptr); + CGLReleaseContext(ctx); + } + + if (pix) + CGLReleasePixelFormat(pix); + + IGNORE_WARNINGS_END + + return nullptr; +} + + +plCGLDevice::plCGLDevice(hsWindowHndl window, hsWindowHndl device, CGLContextObj context) + : plGLDeviceImpl(window, device), fContext(context) +{ } + +void plCGLDevice::Shutdown() +{ + IGNORE_WARNINGS_BEGIN("deprecated-declarations") + + CGLSetCurrentContext(nullptr); + CGLReleaseContext(fContext); + fContext = nullptr; + + IGNORE_WARNINGS_END +} + +bool plCGLDevice::BeginRender(ST::string& error) +{ + return true; +} + +bool plCGLDevice::EndRender(ST::string& error) +{ + return true; +} + +#endif // HS_BUILD_FOR_MACOS + diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.h new file mode 100644 index 0000000000..da72833ff3 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plCGLDevice.h @@ -0,0 +1,72 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#ifndef _plCGLDevice_h_ +#define _plCGLDevice_h_ + +#include "HeadSpin.h" + +#ifdef HS_BUILD_FOR_MACOS +#include "plGLDevice.h" +#include "plPipeline/hsG3DDeviceSelector.h" +#include + +class plCGLDevice : public plGLDeviceImpl +{ +protected: + CGLContextObj fContext; + + plCGLDevice(hsWindowHndl window, hsWindowHndl device, CGLContextObj context); + +public: + static bool Enumerate(hsG3DDeviceRecord& record); + static plCGLDevice* TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error); + + void Shutdown() override; + bool BeginRender(ST::string& error) override; + bool EndRender(ST::string& error) override; +}; + +#endif // HS_BUILD_FOR_MACOS + +#endif // _plCGLDevice_h_ + + diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.cpp new file mode 100644 index 0000000000..9811b8e16f --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.cpp @@ -0,0 +1,250 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plEGLDevice.h" + +#ifdef USE_EGL + +bool plEGLDevice::Enumerate(hsG3DDeviceRecord& record) +{ + bool result = false; + EGLDisplay display = EGL_NO_DISPLAY; + EGLContext context = EGL_NO_CONTEXT; + EGLSurface surface = EGL_NO_SURFACE; + + do { + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) + break; + + if (!eglInitialize(display, nullptr, nullptr)) + break; + + if (!eglBindAPI(EGL_OPENGL_API)) + break; + + /* Set up the config attributes for EGL */ + EGLConfig config; + EGLint config_count; + EGLint config_attrs[] = { + EGL_BUFFER_SIZE, 24, + EGL_DEPTH_SIZE, 24, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + + if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) + break; + + EGLint ctx_attrs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_NONE + }; + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); + if (context == EGL_NO_CONTEXT) + break; + + EGLint pbuf_attrs[] = { + EGL_WIDTH, 800, + EGL_HEIGHT, 600, + EGL_NONE + }; + + surface = eglCreatePbufferSurface(display, config, pbuf_attrs); + if (surface == EGL_NO_SURFACE) + break; + + if (!eglMakeCurrent(display, surface, surface, context)) + break; + + if (epoxy_gl_version() < 33) + break; + + record.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); + record.SetDriverName("EGL"); + record.SetDeviceDesc(reinterpret_cast(glGetString(GL_RENDERER))); + record.SetDriverDesc(reinterpret_cast(glGetString(GL_VENDOR))); + record.SetDriverVersion(reinterpret_cast(glGetString(GL_VERSION))); + + result = true; + } while (0); + + // Cleanup: + if (surface != EGL_NO_SURFACE) { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + } + + if (context != EGL_NO_CONTEXT) + eglDestroyContext(display, context); + + if (display != EGL_NO_DISPLAY) + eglTerminate(display); + + return result; +} + + +plEGLDevice* plEGLDevice::TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error) +{ + EGLDisplay display = EGL_NO_DISPLAY; + EGLContext context = EGL_NO_CONTEXT; + EGLSurface surface = EGL_NO_SURFACE; + + do { + if (!eglBindAPI(EGL_OPENGL_API)) { + error = ST_LITERAL("Could not bind to OpenGL API"); + break; + } + + /* Set up the display */ + display = eglGetDisplay(device); + if (display == EGL_NO_DISPLAY) { + error = ST_LITERAL("Could not get the display"); + break; + } + + if (!eglInitialize(display, nullptr, nullptr)) { + error = ST_LITERAL("Could not initialize the display"); + break; + } + + /* Set up the config attributes for EGL */ + EGLConfig config; + EGLint config_count; + EGLint config_attrs[] = { + EGL_BUFFER_SIZE, 24, + EGL_DEPTH_SIZE, 24, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; + + if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) { + error = ST_LITERAL("Could not choose appropriate config"); + break; + } + + /* Set up the GL context */ + EGLint ctx_attrs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_NONE + }; + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); + if (context == EGL_NO_CONTEXT) { + error = ST_LITERAL("Unable to create rendering context"); + break; + } + + /* Set up the rendering surface */ + surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)window, nullptr); + if (surface == EGL_NO_SURFACE) { + error = ST_LITERAL("Unable to create rendering surface"); + break; + } + + /* Associate everything */ + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + error = ST_LITERAL("Failed to attach EGL context to surface"); + break; + } + + // Successfully initialized + return new plEGLDevice(window, device, display, context, surface); + } while (0); + + // Cleanup for failure case: + if (surface != EGL_NO_SURFACE) { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + } + + if (context != EGL_NO_CONTEXT) + eglDestroyContext(display, context); + + if (display != EGL_NO_DISPLAY) + eglTerminate(display); + + return nullptr; +} + + +plEGLDevice::plEGLDevice(hsWindowHndl window, hsWindowHndl device, EGLDisplay display, EGLContext context, EGLSurface surface) + : plGLDeviceImpl(window, device), fDisplay(display), fContext(context), fSurface(surface) +{ } + +void plEGLDevice::Shutdown() +{ + eglDestroySurface(fDisplay, fSurface); + fSurface = EGL_NO_SURFACE; + + eglDestroyContext(fDisplay, fContext); + fContext = EGL_NO_CONTEXT; + + eglTerminate(fDisplay); + fDisplay = EGL_NO_DISPLAY; +} + +bool plEGLDevice::BeginRender(ST::string& error) +{ + if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext) == EGL_FALSE) { + error = ST_LITERAL("Failed to attach EGL context to surface"); + return false; + } + + return true; +} + +bool plEGLDevice::EndRender(ST::string& error) +{ + if (eglSwapBuffers(fDisplay, fSurface) == EGL_FALSE) { + error = ST_LITERAL("Failed to swap buffers"); + return false; + } + + return true; +} +#endif // USE_EGL diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.h new file mode 100644 index 0000000000..4879f6db07 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plEGLDevice.h @@ -0,0 +1,73 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#ifndef _plEGLDevice_h_ +#define _plEGLDevice_h_ + +#include "HeadSpin.h" +#include "plGLDevice.h" + +#ifdef USE_EGL +#include + +#include "plPipeline/hsG3DDeviceSelector.h" + +class plEGLDevice : public plGLDeviceImpl +{ +protected: + EGLDisplay fDisplay; + EGLContext fContext; + EGLSurface fSurface; + + plEGLDevice(hsWindowHndl window, hsWindowHndl device, EGLDisplay display, EGLContext context, EGLSurface surface); + +public: + static bool Enumerate(hsG3DDeviceRecord& record); + static plEGLDevice* TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error); + + void Shutdown() override; + bool BeginRender(ST::string& error) override; + bool EndRender(ST::string& error) override; +}; + +#endif // USE_EGL + +#endif // _plEGLDevice_h_ diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 3559086654..c8efbc0d04 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -47,263 +47,16 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plGLDevice.h" #include "plGLPipeline.h" +#include "plCGLDevice.h" +#include "plEGLDevice.h" +#include "plWGLDevice.h" + #include "plDrawable/plGBufferGroup.h" #include "plGImage/plMipmap.h" #include "plGImage/plCubicEnvironmap.h" #include "plPipeline/plRenderTarget.h" #include "plStatusLog/plStatusLog.h" -#pragma region EGL_Init -#ifdef USE_EGL -#include - -void InitEGLDevice(plGLDevice* dev) -{ - EGLNativeDisplayType device = static_cast((void*)dev->fDevice); - EGLDisplay display = EGL_NO_DISPLAY; - EGLContext context = EGL_NO_CONTEXT; - EGLSurface surface = EGL_NO_SURFACE; - - do { - if (!eglBindAPI(EGL_OPENGL_API)) { - dev->fErrorMsg = "Could not bind to OpenGL API"; - break; - } - - /* Set up the display */ - display = eglGetDisplay(device); - if (display == EGL_NO_DISPLAY) { - dev->fErrorMsg = "Could not get the display"; - break; - } - - if (!eglInitialize(display, nullptr, nullptr)) { - dev->fErrorMsg = "Could not initialize the display"; - break; - } - - /* Set up the config attributes for EGL */ - EGLConfig config; - EGLint config_count; - EGLint config_attrs[] = { - EGL_BUFFER_SIZE, 24, - EGL_DEPTH_SIZE, 24, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_NONE - }; - - if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) { - dev->fErrorMsg = "Could not choose appropriate config"; - break; - } - - /* Set up the GL context */ - EGLint ctx_attrs[] = { - EGL_CONTEXT_MAJOR_VERSION, 3, - EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - EGL_NONE - }; - - context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); - if (context == EGL_NO_CONTEXT) { - dev->fErrorMsg = "Unable to create rendering context"; - break; - } - - /* Set up the rendering surface */ - surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)dev->fWindow, nullptr); - if (surface == EGL_NO_SURFACE) { - dev->fErrorMsg = "Unable to create rendering surface"; - break; - } - - /* Associate everything */ - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - dev->fErrorMsg = "Failed to attach EGL context to surface"; - break; - } - - // Successfully initialized: - dev->fDisplay = display; - dev->fContext = context; - dev->fSurface = surface; - dev->fContextType = plGLDevice::kEGL; - return; - } while (0); - - // Cleanup for failure case: - if (surface != EGL_NO_SURFACE) { - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(display, surface); - } - - if (context != EGL_NO_CONTEXT) - eglDestroyContext(display, context); - - if (display != EGL_NO_DISPLAY) - eglTerminate(display); -} - -void FiniEGLDevice(plGLDevice* dev) -{ - EGLSurface surface = static_cast(dev->fSurface); - EGLContext context = static_cast(dev->fContext); - EGLDisplay display = static_cast(dev->fDisplay); - - if (surface != EGL_NO_SURFACE) - eglDestroySurface(display, surface); - - if (context != EGL_NO_CONTEXT) - eglDestroyContext(display, context); - - if (display != EGL_NO_DISPLAY) - eglTerminate(display); -} -#endif // USE_EGL -#pragma endregion EGL_Init - -#pragma region WGL_Init -#ifdef HS_BUILD_FOR_WIN32 -#include "hsWindows.h" -#include - -void InitWGLDevice(plGLDevice* dev) -{ - HDC dc = static_cast((HANDLE)dev->fDevice); - HGLRC ctx = nullptr; - - do { - PIXELFORMATDESCRIPTOR pfd{}; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 24; - pfd.iLayerType = PFD_MAIN_PLANE; - - int format = ChoosePixelFormat(dc, &pfd); - if (!format) { - dev->fErrorMsg = "Could not find appropriate pixel config"; - break; - } - - if (!SetPixelFormat(dc, format, &pfd)) { - dev->fErrorMsg = "Could not set appropriate pixel config"; - break; - } - - ctx = wglCreateContext(dc); - if (!ctx) { - dev->fErrorMsg = "Unable to create rendering context"; - break; - } - - if (!wglMakeCurrent(dc, ctx)) { - dev->fErrorMsg = "Failed to attach WGL context to surface"; - break; - } - - // Successfully initialized: - dev->fContext = ctx; - dev->fContextType = plGLDevice::kWGL; - return; - } while (0); - - // Cleanup for failure case: - if (ctx) { - wglMakeCurrent(nullptr, nullptr); - wglDeleteContext(ctx); - } -} - -void FiniWGLDevice(plGLDevice* dev) -{ - HGLRC ctx = static_cast(dev->fContext); - - if (ctx) { - wglMakeCurrent(nullptr, nullptr); - wglDeleteContext(ctx); - } -} -#endif // HS_BUILD_FOR_WIN32 -#pragma endregion WGL_Init - -#pragma region CGL_Init -#ifdef HS_BUILD_FOR_MACOS -#include -#include -void InitCGLDevice(plGLDevice* dev) -{ - IGNORE_WARNINGS_BEGIN("deprecated-declarations") - - CGLPixelFormatObj pix = nullptr; - CGLContextObj ctx = nullptr; - - do { - CGLPixelFormatAttribute attribs[6] = { - kCGLPFAAccelerated, - kCGLPFANoRecovery, - kCGLPFADoubleBuffer, -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - // OpenGL profiles introduced in 10.7 - kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, -#endif - (CGLPixelFormatAttribute) 0 - }; - - int nPix = 0; - if (CGLChoosePixelFormat(attribs, &pix, &nPix) != kCGLNoError || nPix == 0) { - dev->fErrorMsg = "Could not choose appropriate config"; - break; - } - - if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) { - dev->fErrorMsg = "Unable to create rendering context"; - break; - } - - if (CGLSetCurrentContext(ctx) != kCGLNoError) { - dev->fErrorMsg = "Failed to attach CGL context to surface"; - break; - } - - CGLReleasePixelFormat(pix); - - // Successfully initialized: - dev->fContext = ctx; - dev->fContextType = plGLDevice::kCGL; - return; - } while (0); - - // Cleanup for failure case: - if (ctx) { - CGLSetCurrentContext(nullptr); - CGLReleaseContext(ctx); - } - - if (pix) - CGLReleasePixelFormat(pix); - - IGNORE_WARNINGS_END -} - -void FiniCGLDevice(plGLDevice* dev) -{ - IGNORE_WARNINGS_BEGIN("deprecated-declarations") - - CGLContextObj ctx = static_cast(dev->fContext); - - if (ctx) { - CGLSetCurrentContext(nullptr); - CGLReleaseContext(ctx); - } - - IGNORE_WARNINGS_END -} -#endif // HS_BUILD_FOR_MACOS -#pragma endregion CGL_Init - #ifdef HS_DEBUGGING static void GLAPIENTRY plGLDebugLog(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { @@ -329,8 +82,7 @@ GLfloat* hsMatrix2GL(const hsMatrix44& src, GLfloat* dst) } plGLDevice::plGLDevice() - : fErrorMsg(), fPipeline(), fContextType(kNone), fWindow(), fDevice(), - fDisplay(), fSurface(), fContext(), fActiveThread(), fCurrentProgram() + : fErrorMsg(), fPipeline(), fImpl(), fWindow(), fDevice(), fActiveThread(), fCurrentProgram() { memcpy(fMatrixL2W, kIdentityMatrix, sizeof(GLfloat) * 16); memcpy(fMatrixW2C, kIdentityMatrix, sizeof(GLfloat) * 16); @@ -348,23 +100,23 @@ bool plGLDevice::InitDevice() // ANGLE. // // On Linux, this should be true with mesa or nvidia drivers. - if (epoxy_has_egl() && fContextType == kNone) - InitEGLDevice(this); + if (epoxy_has_egl() && !fImpl) + fImpl = plEGLDevice::TryInit(fWindow, fDevice, fErrorMsg); #endif #ifdef HS_BUILD_FOR_WIN32 - if (fContextType == kNone) - InitWGLDevice(this); + if (!fImpl) + fImpl = plWGLDevice::TryInit(fWindow, fDevice, fErrorMsg); #endif #ifdef HS_BUILD_FOR_MACOS - if (fContextType == kNone) - InitCGLDevice(this); + if (!fImpl) + fImpl = plCGLDevice::TryInit(fWindow, fDevice, fErrorMsg); #endif // If we still don't have a valid context type set by this point, we've // failed to initialize so we need to exit. - if (fContextType == kNone) + if (!fImpl) return false; plStatusLog::AddLineSF("pipeline.log", "Initialized with OpenGL {}", reinterpret_cast(glGetString(GL_VERSION))); @@ -396,20 +148,8 @@ bool plGLDevice::InitDevice() void plGLDevice::Shutdown() { -#ifdef USE_EGL - if (fContextType == kEGL) { - FiniEGLDevice(this); - return; - } -#endif - -#ifdef HS_BUILD_FOR_WIN32 - FiniWGLDevice(this); -#endif - -#ifdef HS_BUILD_FOR_MACOS - FiniCGLDevice(this); -#endif + if (fImpl) + fImpl->Shutdown(); } void plGLDevice::SetRenderTarget(plRenderTarget* target) @@ -452,12 +192,6 @@ void plGLDevice::SetViewport() bool plGLDevice::BeginRender() { -#ifdef HS_BUILD_FOR_WIN32 - // Best practice, apparently, is to get and release the DC every time we need it. - // A DC is only valid on one thread at a time. - fDevice = static_cast((HANDLE)GetDC(fWindow)); -#endif - if (fActiveThread == hsThread::ThisThreadHash()) { return true; } @@ -470,20 +204,10 @@ bool plGLDevice::BeginRender() return false; } -#ifdef USE_EGL - if (fContextType == kEGL) { - EGLDisplay display = static_cast(fDisplay); - EGLContext context = static_cast(fContext); - EGLSurface surface = static_cast(fSurface); - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - fErrorMsg = "Failed to attach EGL context to surface"; - return false; - } - } //else -#endif + if (fImpl) + return fImpl->BeginRender(fErrorMsg); - return true; + return false; } bool plGLDevice::EndRender() @@ -492,24 +216,8 @@ bool plGLDevice::EndRender() return true; } -#ifdef USE_EGL - if (fContextType == kEGL) { - if (eglSwapBuffers(static_cast(fDisplay), static_cast(fSurface)) == EGL_FALSE) { - fErrorMsg = "Failed to swap buffers"; - return false; - } - return true; - } else -#endif - -#ifdef HS_BUILD_FOR_WIN32 - if (fContextType == kWGL) { - SwapBuffers(static_cast((HANDLE)fDevice)); - } - - ReleaseDC(fWindow, static_cast((HANDLE)fDevice)); - fDevice = nullptr; -#endif + if (fImpl) + return fImpl->EndRender(fErrorMsg); return false; } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index dfb31cfacf..c3e9a01fbd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -54,22 +54,24 @@ class plLayerInterface; class plMipmap; class plRenderTarget; +class plGLDeviceImpl +{ +protected: + hsWindowHndl fWindow; + hsWindowHndl fDevice; + + plGLDeviceImpl(hsWindowHndl window, hsWindowHndl device) + : fWindow(window), fDevice(device) {}; + +public: + virtual void Shutdown() = 0; + virtual bool BeginRender(ST::string& error) = 0; + virtual bool EndRender(ST::string& error) = 0; +}; + class plGLDevice { friend class plGLPipeline; - friend void InitEGLDevice(plGLDevice* dev); - friend void FiniEGLDevice(plGLDevice* dev); - friend void InitWGLDevice(plGLDevice* dev); - friend void FiniWGLDevice(plGLDevice* dev); - friend void InitCGLDevice(plGLDevice* dev); - friend void FiniCGLDevice(plGLDevice* dev); - - enum ContextType { - kNone = 0, - kWGL, - kCGL, - kEGL - }; public: typedef plGLVertexBufferRef VertexBufferRef; @@ -79,12 +81,9 @@ class plGLDevice protected: ST::string fErrorMsg; plGLPipeline* fPipeline; - ContextType fContextType; + plGLDeviceImpl* fImpl; hsWindowHndl fWindow; hsWindowHndl fDevice; - void* fDisplay; - void* fSurface; - void* fContext; size_t fActiveThread; GLuint fCurrentProgram; GLfloat fMatrixL2W[16]; @@ -96,10 +95,6 @@ class plGLDevice public: plGLDevice(); - /** - * Initializes the OpenGL rendering context. - */ - bool InitDevice(); void Shutdown(); /** @@ -141,6 +136,11 @@ class plGLDevice ST::string GetErrorString() const { return fErrorMsg; } private: + /** + * Initializes the OpenGL rendering context. + */ + bool InitDevice(); + void BindTexture(TextureRef* tRef, plMipmap* img, GLuint mapping); }; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp index 3ef6e1900d..3d98dfafdd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLEnumerate.cpp @@ -46,21 +46,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include #include "plGLPipeline.h" +#include "plCGLDevice.h" +#include "plEGLDevice.h" +#include "plWGLDevice.h" -bool fillDeviceRecord(hsG3DDeviceRecord& devRec) +static void fillDeviceRecord(hsG3DDeviceRecord& devRec) { - if (epoxy_gl_version() < 33) - return false; - - const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); - devRec.SetDeviceDesc(renderer); - - const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); - devRec.SetDriverDesc(vendor); - - const char* version = reinterpret_cast(glGetString(GL_VERSION)); - devRec.SetDriverVersion(version); - devRec.SetCap(hsG3DDeviceSelector::kCapsMipmap); devRec.SetCap(hsG3DDeviceSelector::kCapsPerspective); devRec.SetCap(hsG3DDeviceSelector::kCapsCompressTextures); @@ -74,232 +65,7 @@ bool fillDeviceRecord(hsG3DDeviceRecord& devRec) devMode.SetHeight(hsG3DDeviceSelector::kDefaultHeight); devMode.SetColorDepth(hsG3DDeviceSelector::kDefaultDepth); devRec.GetModes().emplace_back(devMode); - - return true; -} - - -#pragma region EGL_Enumerate -#ifdef USE_EGL -#include - -void plEGLEnumerate(std::vector& records) -{ - EGLDisplay display = EGL_NO_DISPLAY; - EGLContext context = EGL_NO_CONTEXT; - EGLSurface surface = EGL_NO_SURFACE; - - do { - display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) - break; - - if (!eglInitialize(display, nullptr, nullptr)) - break; - - if (!eglBindAPI(EGL_OPENGL_API)) - break; - - /* Set up the config attributes for EGL */ - EGLConfig config; - EGLint config_count; - EGLint config_attrs[] = { - EGL_BUFFER_SIZE, 24, - EGL_DEPTH_SIZE, 24, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_NONE - }; - - if (!eglChooseConfig(display, config_attrs, &config, 1, &config_count) || config_count != 1) - break; - - EGLint ctx_attrs[] = { - EGL_CONTEXT_MAJOR_VERSION, 3, - EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - EGL_NONE - }; - - context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs); - if (context == EGL_NO_CONTEXT) - break; - - EGLint pbuf_attrs[] = { - EGL_WIDTH, 800, - EGL_HEIGHT, 600, - EGL_NONE - }; - - surface = eglCreatePbufferSurface(display, config, pbuf_attrs); - if (surface == EGL_NO_SURFACE) - break; - - if (!eglMakeCurrent(display, surface, surface, context)) - break; - - hsG3DDeviceRecord devRec; - devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); - devRec.SetDriverName("EGL"); - - if (fillDeviceRecord(devRec)) - records.emplace_back(devRec); - } while (0); - - // Cleanup: - if (surface != EGL_NO_SURFACE) { - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(display, surface); - } - - if (context != EGL_NO_CONTEXT) - eglDestroyContext(display, context); - - if (display != EGL_NO_DISPLAY) - eglTerminate(display); } -#endif // USE_EGL -#pragma endregion EGL_Enumerate - - -#pragma region WGL_Enumerate -#ifdef HS_BUILD_FOR_WIN32 -#include "hsWindows.h" -#include - -void plWGLEnumerate(std::vector& records) -{ - ATOM cls = 0; - HWND wnd = nullptr; - HDC dc = nullptr; - HGLRC ctx = nullptr; - - do { - WNDCLASSW tempClass = {}; - tempClass.lpfnWndProc = DefWindowProc; - tempClass.hInstance = GetModuleHandle(nullptr); - tempClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - tempClass.lpszClassName = L"GLTestClass"; - tempClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - - cls = RegisterClassW(&tempClass); - if (!cls) - break; - - wnd = CreateWindowExW(WS_EX_NOACTIVATE, reinterpret_cast(cls), - L"OpenGL Test Window", - WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - nullptr, nullptr, GetModuleHandle(nullptr), nullptr); - if (!wnd) - break; - - dc = GetDC(wnd); - if (!dc) - break; - - PIXELFORMATDESCRIPTOR pfd = {}; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 24; - pfd.iLayerType = PFD_MAIN_PLANE; - - int format = ChoosePixelFormat(dc, &pfd); - if (!format) - break; - - if (!SetPixelFormat(dc, format, &pfd)) - break; - - ctx = wglCreateContext(dc); - if (!ctx) - break; - - if (!wglMakeCurrent(dc, ctx)) - break; - - hsG3DDeviceRecord devRec; - devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); - devRec.SetDriverName("opengl32.dll"); - - if (fillDeviceRecord(devRec)) - records.emplace_back(devRec); - } while (0); - - // Cleanup: - if (ctx) { - wglMakeCurrent(nullptr, nullptr); - wglDeleteContext(ctx); - } - - if (dc) - ReleaseDC(wnd, dc); - - if (wnd) - DestroyWindow(wnd); - - if (cls) - UnregisterClassW(reinterpret_cast(cls), GetModuleHandle(nullptr)); -} -#endif // HS_BUILD_FOR_WIN32 -#pragma endregion WGL_Enumerate - - -#pragma region CGL_Enumerate -#ifdef HS_BUILD_FOR_MACOS -#include -#include - -void plCGLEnumerate(std::vector& records) -{ - IGNORE_WARNINGS_BEGIN("deprecated-declarations") - CGLPixelFormatObj pix = nullptr; - CGLContextObj ctx = nullptr; - - do { - CGLPixelFormatAttribute attribs[6] = { - kCGLPFAAccelerated, - kCGLPFANoRecovery, - kCGLPFADoubleBuffer, -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - // OpenGL profiles introduced in 10.7 - kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, -#endif - (CGLPixelFormatAttribute) 0 - }; - - int nPix = 0; - if (CGLChoosePixelFormat(attribs, &pix, &nPix) != kCGLNoError || nPix == 0) - break; - - if (CGLCreateContext(pix, nullptr, &ctx) != kCGLNoError) - break; - - if (CGLSetCurrentContext(ctx) != kCGLNoError) - break; - - hsG3DDeviceRecord devRec; - devRec.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); - devRec.SetDriverName("OpenGL.framework"); - - if (fillDeviceRecord(devRec)) - records.emplace_back(devRec); - } while (0); - - // Cleanup: - if (ctx) { - CGLSetCurrentContext(nullptr); - CGLReleaseContext(ctx); - } - - if (pix) - CGLReleasePixelFormat(pix); - IGNORE_WARNINGS_END -} -#endif // HS_BUILD_FOR_MACOS -#pragma endregion CGL_Enumerate void plGLEnumerate::Enumerate(std::vector& records) { @@ -313,15 +79,28 @@ void plGLEnumerate::Enumerate(std::vector& records) // // On Linux, this should be true with mesa or nvidia drivers. if (epoxy_has_egl()) { - plEGLEnumerate(records); + hsG3DDeviceRecord rec; + fillDeviceRecord(rec); + if (plEGLDevice::Enumerate(rec)) + records.emplace_back(rec); } #endif #ifdef HS_BUILD_FOR_WIN32 - plWGLEnumerate(records); + { + hsG3DDeviceRecord rec; + fillDeviceRecord(rec); + if (plWGLDevice::Enumerate(rec)) + records.emplace_back(rec); + } #endif #ifdef HS_BUILD_FOR_MACOS - plCGLEnumerate(records); + { + hsG3DDeviceRecord rec; + fillDeviceRecord(rec); + if (plCGLDevice::Enumerate(rec)) + records.emplace_back(rec); + } #endif } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 31c923e3e0..d9c4b26d13 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -609,7 +609,7 @@ void plGLPipeline::LoadResources() IReleaseAvRTPool(); - if (fDevice.fContextType == plGLDevice::kNone) { + if (!fDevice.fImpl) { // We can't create anything if the OpenGL context isn't initialized plProfile_IncCount(PipeReload, 1); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.cpp new file mode 100644 index 0000000000..702793b354 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.cpp @@ -0,0 +1,212 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plWGLDevice.h" + +#ifdef HS_BUILD_FOR_WIN32 + +bool plWGLDevice::Enumerate(hsG3DDeviceRecord& record) +{ + bool result = false; + ATOM cls = 0; + HWND wnd = nullptr; + HDC dc = nullptr; + HGLRC ctx = nullptr; + + do { + WNDCLASSW tempClass = {}; + tempClass.lpfnWndProc = DefWindowProc; + tempClass.hInstance = GetModuleHandle(nullptr); + tempClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + tempClass.lpszClassName = L"GLTestClass"; + tempClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + + cls = RegisterClassW(&tempClass); + if (!cls) + break; + + wnd = CreateWindowExW(WS_EX_NOACTIVATE, reinterpret_cast(cls), + L"OpenGL Test Window", + WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + nullptr, nullptr, GetModuleHandle(nullptr), nullptr); + if (!wnd) + break; + + dc = GetDC(wnd); + if (!dc) + break; + + PIXELFORMATDESCRIPTOR pfd = {}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 24; + pfd.iLayerType = PFD_MAIN_PLANE; + + int format = ChoosePixelFormat(dc, &pfd); + if (!format) + break; + + if (!SetPixelFormat(dc, format, &pfd)) + break; + + ctx = wglCreateContext(dc); + if (!ctx) + break; + + if (!wglMakeCurrent(dc, ctx)) + break; + + if (epoxy_gl_version() < 33) + break; + + record.SetG3DDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); + record.SetDriverName("opengl32.dll"); + record.SetDeviceDesc(reinterpret_cast(glGetString(GL_RENDERER))); + record.SetDriverDesc(reinterpret_cast(glGetString(GL_VENDOR))); + record.SetDriverVersion(reinterpret_cast(glGetString(GL_VERSION))); + + result = true; + } while (0); + + // Cleanup: + if (ctx) { + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(ctx); + } + + if (dc) + ReleaseDC(wnd, dc); + + if (wnd) + DestroyWindow(wnd); + + if (cls) + UnregisterClassW(reinterpret_cast(cls), GetModuleHandle(nullptr)); + + return result; +} + + +plWGLDevice* plWGLDevice::TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error) +{ + HDC dc = static_cast((HANDLE)device); + HGLRC ctx = nullptr; + + do { + PIXELFORMATDESCRIPTOR pfd{}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_GENERIC_ACCELERATED | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 24; + pfd.iLayerType = PFD_MAIN_PLANE; + + int format = ChoosePixelFormat(dc, &pfd); + if (!format) { + error = ST_LITERAL("Could not find appropriate pixel config"); + break; + } + + if (!SetPixelFormat(dc, format, &pfd)) { + error = ST_LITERAL("Could not set appropriate pixel config"); + break; + } + + ctx = wglCreateContext(dc); + if (!ctx) { + error = ST_LITERAL("Unable to create rendering context"); + break; + } + + if (!wglMakeCurrent(dc, ctx)) { + error = ST_LITERAL("Failed to attach WGL context to surface"); + break; + } + + // Successfully initialized + return new plWGLDevice(window, device, ctx); + } while (0); + + // Cleanup for failure case: + if (ctx) { + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(ctx); + } + return nullptr; +} + + +plWGLDevice::plWGLDevice(hsWindowHndl window, hsWindowHndl device, HGLRC context) + : plGLDeviceImpl(window, device), fContext(context) +{ } + +void plWGLDevice::Shutdown() +{ + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(fContext); + fContext = nullptr; +} + +bool plWGLDevice::BeginRender(ST::string& error) +{ + // Best practice, apparently, is to get and release the DC every time we need it. + // A DC is only valid on one thread at a time. + fDevice = static_cast((HANDLE)GetDC(fWindow)); + + return true; +} + +bool plWGLDevice::EndRender(ST::string& error) +{ + SwapBuffers(static_cast((HANDLE)fDevice)); + + ReleaseDC(fWindow, static_cast((HANDLE)fDevice)); + fDevice = nullptr; + return true; +} + +#endif // HS_BUILD_FOR_WIN32 diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.h new file mode 100644 index 0000000000..fd8cbae427 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plWGLDevice.h @@ -0,0 +1,72 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#ifndef _plWGLDevice_h_ +#define _plWGLDevice_h_ + +#include "HeadSpin.h" +#include "plGLDevice.h" + +#ifdef HS_BUILD_FOR_WIN32 +#include "hsWindows.h" +#include "plPipeline/hsG3DDeviceSelector.h" +#include + +class plWGLDevice : public plGLDeviceImpl +{ +protected: + HGLRC fContext; + + plWGLDevice(hsWindowHndl window, hsWindowHndl device, HGLRC context); + +public: + static bool Enumerate(hsG3DDeviceRecord& record); + static plWGLDevice* TryInit(hsWindowHndl window, hsWindowHndl device, ST::string& error); + + void Shutdown() override; + bool BeginRender(ST::string& error) override; + bool EndRender(ST::string& error) override; +}; + +#endif // HS_BUILD_FOR_WIN32 + +#endif // _plWGLDevice_h_ + From efc7d7d0efeb947b2c0c0b911b9e28fa6fc12bcc Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Sep 2023 02:54:10 -0700 Subject: [PATCH 73/76] Identity-initialize all the GL device matrices --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index c8efbc0d04..bc3c7da097 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -85,7 +85,9 @@ plGLDevice::plGLDevice() : fErrorMsg(), fPipeline(), fImpl(), fWindow(), fDevice(), fActiveThread(), fCurrentProgram() { memcpy(fMatrixL2W, kIdentityMatrix, sizeof(GLfloat) * 16); + memcpy(fMatrixW2L, kIdentityMatrix, sizeof(GLfloat) * 16); memcpy(fMatrixW2C, kIdentityMatrix, sizeof(GLfloat) * 16); + memcpy(fMatrixC2W, kIdentityMatrix, sizeof(GLfloat) * 16); memcpy(fMatrixProj, kIdentityMatrix, sizeof(GLfloat) * 16); } From 26cf71f2d77749eabe2816689432b1c6ebcb89ed Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Sep 2023 13:11:21 -0700 Subject: [PATCH 74/76] Clean up API boundary for plGLDevice --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 7 +++++ .../FeatureLib/pfGLPipeline/plGLDevice.h | 13 ++++++-- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 30 +++++++++---------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index bc3c7da097..558851694a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -91,6 +91,13 @@ plGLDevice::plGLDevice() memcpy(fMatrixProj, kIdentityMatrix, sizeof(GLfloat) * 16); } +void plGLDevice::Setup(plGLPipeline* pipe, hsWindowHndl window, hsWindowHndl device) +{ + fPipeline = pipe; + fWindow = window; + fDevice = device; +} + bool plGLDevice::InitDevice() { #ifdef USE_EGL diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index c3e9a01fbd..e4deb36dfa 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -71,8 +71,6 @@ class plGLDeviceImpl class plGLDevice { - friend class plGLPipeline; - public: typedef plGLVertexBufferRef VertexBufferRef; typedef plGLIndexBufferRef IndexBufferRef; @@ -95,6 +93,7 @@ class plGLDevice public: plGLDevice(); + void Setup(plGLPipeline* pipe, hsWindowHndl window, hsWindowHndl device); void Shutdown(); /** @@ -133,8 +132,18 @@ class plGLDevice void SetWorldToCameraMatrix(const hsMatrix44& src); void SetLocalToWorldMatrix(const hsMatrix44& src); + void SetCurrentProgram(GLuint program) { fCurrentProgram = program; } + ST::string GetErrorString() const { return fErrorMsg; } + bool HasContext() const { return fImpl != nullptr; } + + const GLfloat* GetL2WMatrix() const { return fMatrixL2W; } + const GLfloat* GetW2LMatrix() const { return fMatrixW2L; } + const GLfloat* GetC2WMatrix() const { return fMatrixC2W; } + const GLfloat* GetW2CMatrix() const { return fMatrixW2C; } + const GLfloat* GetProjectionMatrix() const { return fMatrixProj; } + private: /** * Initializes the OpenGL rendering context. diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index d9c4b26d13..94fa22ef68 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -195,9 +195,7 @@ plGLPipeline::plGLPipeline(hsWindowHndl display, hsWindowHndl window, const hsG3 plStatusLog::AddLineS("pipeline.log", "Constructing plGLPipeline"); plStatusLog::AddLineSF("pipeline.log", "Driver vendor: {}", devMode->GetDevice()->GetDriverDesc()); - fDevice.fWindow = window; - fDevice.fDevice = display; - fDevice.fPipeline = this; + fDevice.Setup(this, window, display); fPlateMgr = new plGLPlateManager(this); } @@ -609,7 +607,7 @@ void plGLPipeline::LoadResources() IReleaseAvRTPool(); - if (!fDevice.fImpl) { + if (!fDevice.HasContext()) { // We can't create anything if the OpenGL context isn't initialized plProfile_IncCount(PipeReload, 1); @@ -744,7 +742,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& mRef->Link(&fMatRefList); glUseProgram(mRef->fRef); - fDevice.fCurrentProgram = mRef->fRef; + fDevice.SetCurrentProgram(mRef->fRef); LOG_GL_ERROR_CHECK(ST::format("Use Program with material \"{}\" failed", material->GetKeyName())); GLuint vao = 0; @@ -823,13 +821,13 @@ void plGLPipeline::ISetupTransforms(plDrawableSpans* drawable, const plSpan& spa if (mRef) { /* Push the matrices into the GLSL shader now */ - glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, fDevice.fMatrixProj); - glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.fMatrixW2C); - glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.fMatrixL2W); - glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.fMatrixW2L); + glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, fDevice.GetProjectionMatrix()); + glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.GetW2CMatrix()); + glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.GetL2WMatrix()); + glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.GetW2LMatrix()); if (mRef->uMatrixC2W != -1) - glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.fMatrixC2W); + glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.GetC2WMatrix()); } } @@ -1490,7 +1488,7 @@ void plGLPipeline::IDrawPlate(plPlate* plate) mRef->Link(&fMatRefList); glUseProgram(mRef->fRef); - fDevice.fCurrentProgram = mRef->fRef; + fDevice.SetCurrentProgram(mRef->fRef); mRef->SetupTextureRefs(); @@ -1503,12 +1501,12 @@ void plGLPipeline::IDrawPlate(plPlate* plate) /* Push the matrices into the GLSL shader now */ glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, projMat); - glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.fMatrixW2C); - glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.fMatrixC2W); - glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.fMatrixL2W); + glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, fDevice.GetW2CMatrix()); + glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, fDevice.GetC2WMatrix()); + glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, fDevice.GetL2WMatrix()); if (mRef->uMatrixW2L != -1) - glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.fMatrixW2L); + glUniformMatrix4fv(mRef->uMatrixW2L, 1, GL_TRUE, fDevice.GetW2LMatrix()); glUniform1f(mRef->uInvertVtxAlpha, 0.f); glUniform1f(mRef->uAlphaThreshold, 0.f); @@ -1657,7 +1655,7 @@ void plGLPipeline::IPreprocessAvatarTextures() glUseProgram(sProgram); LOG_GL_ERROR_CHECK("Use Program failed"); - fDevice.fCurrentProgram = sProgram; + fDevice.SetCurrentProgram(sProgram); glUniform1i(0, 0); glUniform4f(1, 1.f, 1.f, 1.f, 1.f); From cbfcf032e945ffaccf9e196e5c61f25379b37b1e Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 9 Sep 2023 13:41:40 -0700 Subject: [PATCH 75/76] Clean up some buffer ref casts --- Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 94fa22ef68..51fa286f2a 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -839,8 +839,8 @@ void plGLPipeline::IRenderBufferSpan(const plIcicle& span, { plProfile_BeginTiming(RenderBuff); - typename DeviceType::VertexBufferRef* vRef = (typename DeviceType::VertexBufferRef*)vb; - typename DeviceType::IndexBufferRef* iRef = (typename DeviceType::IndexBufferRef*)ib; + plGLVertexBufferRef* vRef = static_cast(vb); + plGLIndexBufferRef* iRef = static_cast(ib); plGLMaterialShaderRef* mRef = static_cast(material->GetDeviceRef()); if (!vRef->fRef || !iRef->fRef) { From 2dd8afc86ac5e6a33628d3c00ecc27057d8e8758 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 27 Apr 2024 02:55:00 -0700 Subject: [PATCH 76/76] Resolve some GL Pipeline memory leaks & crashes --- .../FeatureLib/pfGLPipeline/plGLDevice.cpp | 2 ++ .../FeatureLib/pfGLPipeline/plGLDevice.h | 2 ++ .../FeatureLib/pfGLPipeline/plGLDeviceRef.h | 2 +- .../FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp | 7 +++++-- .../pfGLPipeline/plGLMaterialShaderRef.cpp | 4 ++-- .../FeatureLib/pfGLPipeline/plGLPipeline.cpp | 8 ++++++++ .../PubUtilLib/plPipeline/pl3DPipeline.h | 18 ++++++++++++++++++ .../PubUtilLib/plPipeline/plNullPipeline.h | 2 ++ 8 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp index 558851694a..c9475eef14 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp @@ -159,6 +159,8 @@ void plGLDevice::Shutdown() { if (fImpl) fImpl->Shutdown(); + + delete fImpl; } void plGLDevice::SetRenderTarget(plRenderTarget* target) diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h index e4deb36dfa..ff3d553f90 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.h @@ -64,6 +64,8 @@ class plGLDeviceImpl : fWindow(window), fDevice(device) {}; public: + virtual ~plGLDeviceImpl() { }; + virtual void Shutdown() = 0; virtual bool BeginRender(ST::string& error) = 0; virtual bool EndRender(ST::string& error) = 0; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h index 8936e70a20..a404e94bfd 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRef.h @@ -222,7 +222,7 @@ class plGLRenderTargetRef: public plGLTextureRef virtual ~plGLRenderTargetRef(); - void Release(); + void Release() override; virtual void SetOwner(plRenderTarget* targ) { fOwner = (plBitmap*)targ; } }; diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp index 0adce49552..21330c3672 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLDeviceRefs.cpp @@ -39,13 +39,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "plPipeline/hsWinRef.h" #include "plGLPipeline.h" #include "plGLDeviceRef.h" #include "plProfile.h" -#include "plStatusLog/plStatusLog.h" plProfile_Extern(MemVertex); plProfile_Extern(MemIndex); @@ -105,6 +103,11 @@ void plGLVertexBufferRef::Release() glDeleteBuffers(1, &fRef); fRef = 0; } + + if (fData) { + delete[] fData; + } + SetDirty(true); } diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp index 8b6eeff586..452f730b37 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp @@ -407,8 +407,8 @@ void plGLMaterialShaderRef::ICompile() LOG_GL_ERROR_CHECK("Create Program failed"); if (plGLVersion() >= 43) { - const char* name = ST::format("hsGMaterial::{}", fMaterial->GetKeyName()).c_str(); - glObjectLabel(GL_PROGRAM, fRef, strlen(name), name); + ST::string name = ST::format("hsGMaterial::{}", fMaterial->GetKeyName()); + glObjectLabel(GL_PROGRAM, fRef, strlen(name.c_str()), name.c_str()); } glAttachShader(fRef, fVertShaderRef); diff --git a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp index 51fa286f2a..e8d2deb5c9 100644 --- a/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp +++ b/Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp @@ -205,9 +205,15 @@ plGLPipeline::~plGLPipeline() if (plGLPlateManager* pm = static_cast(fPlateMgr)) pm->IReleaseGeometry(); + delete fPlateMgr; + fPlateMgr = nullptr; + while (fTextFontRefList) delete fTextFontRefList; + delete fDebugTextMgr; + fDebugTextMgr = nullptr; + fDevice.Shutdown(); } @@ -736,6 +742,7 @@ void plGLPipeline::RenderSpans(plDrawableSpans* ice, const std::vector& if (mRef == nullptr) { mRef = new plGLMaterialShaderRef(material, this); material->SetDeviceRef(mRef); + hsRefCnt_SafeUnRef(mRef); } if (!mRef->IsLinked()) @@ -1482,6 +1489,7 @@ void plGLPipeline::IDrawPlate(plPlate* plate) if (mRef == nullptr) { mRef = new plGLMaterialShaderRef(material, this); material->SetDeviceRef(mRef); + hsRefCnt_SafeUnRef(mRef); } if (!mRef->IsLinked()) diff --git a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h index d18a06d3d6..f5931a4210 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h @@ -1059,6 +1059,24 @@ pl3DPipeline::~pl3DPipeline() while (fActiveLights) UnRegisterLight(fActiveLights); + while (fVtxBuffRefList) { + typename DeviceType::VertexBufferRef* ref = fVtxBuffRefList; + ref->Release(); + ref->Unlink(); + } + + while (fIdxBuffRefList) { + typename DeviceType::IndexBufferRef* ref = fIdxBuffRefList; + ref->Release(); + ref->Unlink(); + } + + while (fTextureRefList) { + typename DeviceType::TextureRef* ref = fTextureRefList; + ref->Release(); + ref->Unlink(); + } + IReleaseAvRTPool(); IClearClothingOutfits(&fClothingOutfits); IClearClothingOutfits(&fPrevClothingOutfits); diff --git a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h index 846b2e3edb..4ad36caf02 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h +++ b/Sources/Plasma/PubUtilLib/plPipeline/plNullPipeline.h @@ -56,7 +56,9 @@ class plNullPipelineDevice uint32_t fVertexSize; uint32_t fFormat; + void Release() { } void Link(NullDeviceRef** back) { } + void Unlink() { } bool IsLinked() { return true; } bool Volatile() const { return false; } };