From b53458b3b5566b6a90ecb71da4a7f787fd301692 Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Thu, 21 May 2026 16:05:55 -0700 Subject: [PATCH] Fixed a issue were the shim would recompute the batch key unneedingly. --- neo/engine/opengl/gl_d3d12shim.cpp | 214 ++++++++++++++++++++++++++--- 1 file changed, 197 insertions(+), 17 deletions(-) diff --git a/neo/engine/opengl/gl_d3d12shim.cpp b/neo/engine/opengl/gl_d3d12shim.cpp index 090b760f..784197ac 100644 --- a/neo/engine/opengl/gl_d3d12shim.cpp +++ b/neo/engine/opengl/gl_d3d12shim.cpp @@ -1631,6 +1631,9 @@ struct GLState GLuint currentSpecularMapTexture = 0; float currentSpecularMapStrength = 1.0f; ImmediateVertexBuffer immediateVerts; + BatchKey cachedImmediateBatchKey{}; + uint64_t cachedImmediateBatchStamp = 0; + bool cachedImmediateBatchKeyValid = false; GLenum matrixMode = GL_MODELVIEW; std::vector modelStack{ Mat4::Identity() }; @@ -5178,7 +5181,8 @@ static bool QD3D12_PolygonOffsetEnabledForMode(GLenum originalMode) } static BatchKey BuildCurrentBatchKey(GLenum originalMode, const TextureResource* tex0, const TextureResource* tex1, TextureResource* const* allTextures, - TextureResource* selectedNormalMap = nullptr, TextureResource* selectedGlowMap = nullptr, TextureResource* selectedSpecularMap = nullptr, bool selectedMapsValid = false) + TextureResource* selectedNormalMap = nullptr, TextureResource* selectedGlowMap = nullptr, TextureResource* selectedSpecularMap = nullptr, bool selectedMapsValid = false, + bool finalizeHash = true) { const bool tex0IsMaterialMapOnly = QD3D12_TextureIsMaterialMapOnlyForFixedFunctionColor(tex0); const bool tex1IsMaterialMapOnly = QD3D12_TextureIsMaterialMapOnlyForFixedFunctionColor(tex1); @@ -5367,7 +5371,196 @@ static BatchKey BuildCurrentBatchKey(GLenum originalMode, const TextureResource* if (key.useARBPrograms) key.useTessellation = false; g_gl.currObjectMVPs[key.motionObjectId] = key.mvp; - QD3D12_FinalizeBatchKeyHash(key); + if (finalizeHash) + QD3D12_FinalizeBatchKeyHash(key); + return key; +} + +static void QD3D12_MixTextureStamp(uint64_t& h, const TextureResource* tex) +{ + QD3D12_MixHash(h, reinterpret_cast(tex)); + if (!tex) + return; + + QD3D12_MixHash(h, tex->glId); + QD3D12_MixHash(h, tex->srvIndex); + QD3D12_MixHash(h, tex->gpuValid ? 1ull : 0ull); + QD3D12_MixHash(h, tex->isNormalMap ? 1ull : 0ull); + QD3D12_MixHash(h, tex->isGlowMap ? 1ull : 0ull); + QD3D12_MixHash(h, tex->isSpecularMap ? 1ull : 0ull); + QD3D12_MixHash(h, tex->cpuGeneration); + QD3D12_MixHash(h, tex->neuralPOM.gpuValid ? 1ull : 0ull); + QD3D12_MixHash(h, tex->neuralPOM.gpuGeneration); + QD3D12_MixHash(h, tex->neuralPOM.weightsSrvIndex); + QD3D12_MixHash(h, tex->neuralPOM.latentSrvIndex); +} + +static uint64_t QD3D12_CurrentImmediateBatchStateStamp( + GLenum originalMode, + TextureResource* const* allTextures, + TextureResource* selectedNormalMap, + TextureResource* selectedGlowMap, + TextureResource* selectedSpecularMap, + bool tessellationVertexCountOk) +{ + if (QD3D12ARB_IsActive() || !g_currentWindow || g_gl.modelStack.empty() || g_gl.projStack.empty()) + return 0; + + uint64_t h = 1469598103934665603ull; + QD3D12_MixHash(h, originalMode); + QD3D12_MixHash(h, tessellationVertexCountOk ? 1ull : 0ull); + QD3D12_MixHash(h, reinterpret_cast(g_currentWindow)); + QD3D12_MixHashBytes(h, &g_currentWindow->viewport, sizeof(g_currentWindow->viewport)); + QD3D12_MixHashBytes(h, &g_currentWindow->scissor, sizeof(g_currentWindow->scissor)); + QD3D12_MixHash(h, g_currentWindow->renderWidth); + QD3D12_MixHash(h, g_currentWindow->renderHeight); + + for (UINT unit = 0; unit < QD3D12_MaxTextureUnits; ++unit) + { + QD3D12_MixHash(h, g_gl.boundTexture[unit]); + QD3D12_MixHash(h, g_gl.texture2D[unit] ? 1ull : 0ull); + QD3D12_MixTextureStamp(h, allTextures ? allTextures[unit] : nullptr); + } + QD3D12_MixTextureStamp(h, selectedNormalMap); + QD3D12_MixTextureStamp(h, selectedGlowMap); + QD3D12_MixTextureStamp(h, selectedSpecularMap); + + QD3D12_MixHashFloat(h, g_gl.alphaRef); + QD3D12_MixHashFloat(h, g_gl.alphaFuncMapped); + QD3D12_MixHash(h, g_gl.alphaTest ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.blend ? 1ull : 0ull); + QD3D12_MixHash(h, uint32_t(g_gl.blendSrc)); + QD3D12_MixHash(h, uint32_t(g_gl.blendDst)); + QD3D12_MixHash(h, g_gl.depthTest ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.depthWrite ? 1ull : 0ull); + QD3D12_MixHash(h, uint32_t(g_gl.depthFunc)); + QD3D12_MixHash(h, g_gl.cullFace ? 1ull : 0ull); + QD3D12_MixHash(h, uint32_t(g_gl.cullMode)); + QD3D12_MixHash(h, uint32_t(g_gl.frontFace)); + QD3D12_MixHash(h, QD3D12_CurrentColorWriteMask()); + + QD3D12_MixHash(h, g_gl.fog ? 1ull : 0ull); + QD3D12_MixHash(h, uint32_t(g_gl.fogMode)); + QD3D12_MixHashFloat(h, g_gl.fogDensity); + QD3D12_MixHashFloat(h, g_gl.fogStart); + QD3D12_MixHashFloat(h, g_gl.fogEnd); + QD3D12_MixHashBytes(h, g_gl.fogColor, sizeof(g_gl.fogColor)); + QD3D12_MixHashBytes(h, g_gl.curColor, sizeof(g_gl.curColor)); + QD3D12_MixHash(h, g_gl.colorArray.enabled ? 1ull : 0ull); + + QD3D12_MixHash(h, uint32_t(g_gl.texEnvMode[0])); + QD3D12_MixHash(h, uint32_t(g_gl.texEnvMode[1])); + for (UINT unit = 0; unit < 2; ++unit) + { + QD3D12_MixHash(h, uint32_t(g_gl.texCombineRGB[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texCombineAlpha[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texSource0RGB[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texSource1RGB[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texSource0Alpha[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texSource1Alpha[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texOperand0RGB[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texOperand1RGB[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texOperand0Alpha[unit])); + QD3D12_MixHash(h, uint32_t(g_gl.texOperand1Alpha[unit])); + QD3D12_MixHashFloat(h, g_gl.texRGBScale[unit]); + QD3D12_MixHashFloat(h, g_gl.texAlphaScale[unit]); + QD3D12_MixHashBytes(h, g_gl.texEnvColor[unit], sizeof(g_gl.texEnvColor[unit])); + } + + QD3D12_MixHash(h, g_gl.stencilTest ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.stencilFrontMask); + QD3D12_MixHash(h, g_gl.stencilBackMask); + QD3D12_MixHash(h, g_gl.stencilFrontFuncMask); + QD3D12_MixHash(h, g_gl.stencilBackFuncMask); + QD3D12_MixHash(h, uint32_t(g_gl.stencilFrontFunc)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilFrontSFail)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilFrontDPFail)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilFrontDPPass)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilBackFunc)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilBackSFail)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilBackDPFail)); + QD3D12_MixHash(h, uint32_t(g_gl.stencilBackDPPass)); + QD3D12_MixHash(h, g_gl.stencilFrontRef); + QD3D12_MixHash(h, g_gl.stencilBackRef); + QD3D12_MixHash(h, g_gl.depthBoundsTest ? 1ull : 0ull); + QD3D12_MixHashFloat(h, (float)g_gl.depthBoundsMin); + QD3D12_MixHashFloat(h, (float)g_gl.depthBoundsMax); + QD3D12_MixHash(h, g_gl.polygonOffsetPoint ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.polygonOffsetLine ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.polygonOffsetFill ? 1ull : 0ull); + QD3D12_MixHashFloat(h, g_gl.polygonOffsetFactor); + QD3D12_MixHashFloat(h, g_gl.polygonOffsetUnits); + + QD3D12_MixHashBytes(h, g_gl.projStack.back().m, sizeof(g_gl.projStack.back().m)); + QD3D12_MixHashBytes(h, g_gl.modelStack.back().m, sizeof(g_gl.modelStack.back().m)); + QD3D12_MixHashBytes(h, g_gl.modelMatrix.m, sizeof(g_gl.modelMatrix.m)); + QD3D12_MixHash(h, g_gl.currentMotionObjectId); + QD3D12_MixHashFloat(h, g_gl.currentGeometryFlag); + QD3D12_MixHashFloat(h, g_gl.currentSurfaceRoughness); + QD3D12_MixHashFloat(h, g_gl.currentMaterialType); + QD3D12_MixHash(h, g_gl.currentRayMaterialFlags); + QD3D12_MixHash(h, g_gl.frameSerial); + QD3D12_MixHash(h, g_gl.motionHistoryReset ? 1ull : 0ull); + + QD3D12_MixHash(h, g_gl.currentNormalMapTexture); + QD3D12_MixHashFloat(h, g_gl.currentNormalMapStrength); + QD3D12_MixHashFloat(h, g_gl.currentNormalMapYSign); + QD3D12_MixHash(h, g_gl.currentNeuralPOMTexture); + QD3D12_MixHash(h, g_gl.neuralPOMEnabled ? 1ull : 0ull); + QD3D12_MixHash(h, g_gl.currentGlowMapTexture); + QD3D12_MixHashFloat(h, g_gl.currentGlowMapStrength); + QD3D12_MixHash(h, g_gl.currentSpecularMapTexture); + QD3D12_MixHashFloat(h, g_gl.currentSpecularMapStrength); + + return h ? h : 1ull; +} + +static BatchKey QD3D12_GetOrBuildImmediateBatchKey( + GLenum mode, + size_t vertexCount, + TextureResource* const* boundTextures, + TextureResource* normalMapTex, + TextureResource* glowMapTex, + TextureResource* specularMapTex) +{ + const bool tessellationVertexCountOk = QD3D12_ImmediateVertexCountCanUseNormalMapTessellation(mode, vertexCount); + const uint64_t stateStamp = QD3D12_CurrentImmediateBatchStateStamp( + mode, + boundTextures, + normalMapTex, + glowMapTex, + specularMapTex, + tessellationVertexCountOk); + + if (stateStamp != 0 && + g_gl.cachedImmediateBatchKeyValid && + g_gl.cachedImmediateBatchStamp == stateStamp) + { + BatchKey key = g_gl.cachedImmediateBatchKey; + g_gl.currObjectMVPs[key.motionObjectId] = key.mvp; + return key; + } + + BatchKey key = BuildCurrentBatchKey(mode, boundTextures[0], boundTextures[1], boundTextures, normalMapTex, glowMapTex, specularMapTex, true, stateStamp == 0); + if (key.useTessellation && !tessellationVertexCountOk) + { + key.useTessellation = false; + if (stateStamp == 0) + QD3D12_FinalizeBatchKeyHash(key); + } + + if (stateStamp != 0) + { + key.fullHash = stateStamp; + g_gl.cachedImmediateBatchKey = key; + g_gl.cachedImmediateBatchStamp = stateStamp; + g_gl.cachedImmediateBatchKeyValid = true; + } + else + { + g_gl.cachedImmediateBatchKeyValid = false; + } + return key; } @@ -11304,12 +11497,7 @@ static QueuedBatch* QD3D12_PrepareImmediateBatch(GLenum mode, size_t n) UploadTexture(*specularMapTex); } - BatchKey key = BuildCurrentBatchKey(mode, boundTextures[0], boundTextures[1], boundTextures, normalMapTex, glowMapTex, specularMapTex, true); - if (key.useTessellation && !QD3D12_ImmediateVertexCountCanUseNormalMapTessellation(mode, n)) - { - key.useTessellation = false; - QD3D12_FinalizeBatchKeyHash(key); - } + BatchKey key = QD3D12_GetOrBuildImmediateBatchKey(mode, n, boundTextures, normalMapTex, glowMapTex, specularMapTex); const size_t markerCursor = g_gl.queryMarkers.size(); if (!g_gl.queuedBatches.empty() && @@ -11420,15 +11608,7 @@ static void FlushImmediate(GLenum mode, const GLVertex* src, size_t n) UploadTexture(*specularMapTex); } - TextureResource* tex0 = boundTextures[0]; - TextureResource* tex1 = boundTextures[1]; - - BatchKey key = BuildCurrentBatchKey(mode, tex0, tex1, boundTextures, normalMapTex, glowMapTex, specularMapTex, true); - if (key.useTessellation && !QD3D12_ImmediateVertexCountCanUseNormalMapTessellation(mode, n)) - { - key.useTessellation = false; - QD3D12_FinalizeBatchKeyHash(key); - } + BatchKey key = QD3D12_GetOrBuildImmediateBatchKey(mode, n, boundTextures, normalMapTex, glowMapTex, specularMapTex); const size_t markerCursor = g_gl.queryMarkers.size(); QueuedBatch* batch = nullptr;