From e32a9b1784be510a038af4c508a8165b86a44e7d Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Fri, 1 Sep 2023 16:53:01 +0100 Subject: [PATCH] D3D11: Improve pixel history discarded fragments Closes #3040 Include the discarded offset when indexing to get the post mod data per fragment Do not include the discarded offset when indexing to get the primitive ID per fragment (primitive ID uses a replacement shader which is not affected by discards in the original shader) Store the post mod depth data in slot 1 of the depth output to make the indexing simpler to keep track of discarded fragments Set the post mod data for discarded fragments (excluding the final fragment) to be the known texture after (which starts as the pre mod data and is updated for non-discarded fragments). --- renderdoc/driver/d3d11/d3d11_pixelhistory.cpp | 79 ++++++++++++------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp index 77f436b73..13931636f 100644 --- a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp +++ b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp @@ -2152,18 +2152,17 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event GetDebugManager()->PixelHistoryCopyPixel(colourCopyParams, postColSlot, 0); postColSlot++; - GetDebugManager()->PixelHistoryCopyPixel(depthCopyParams, depthSlot, 0); - depthSlot++; + GetDebugManager()->PixelHistoryCopyPixel(depthCopyParams, depthSlot, 1); } - m_pImmediateContext->OMSetDepthStencilState(m_PixelHistory.StencIncrEqDepthState, - history[h].fragIndex); - - m_pImmediateContext->ClearDepthStencilView( - shaddepthOutputDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, cleardepth, 0); - // fetch shader output value & primitive ID { + m_pImmediateContext->OMSetDepthStencilState(m_PixelHistory.StencIncrEqDepthState, + history[h].fragIndex); + + m_pImmediateContext->ClearDepthStencilView( + shaddepthOutputDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, cleardepth, 0); + m_pImmediateContext->OMGetBlendState(&curBS, blendFactor, &curSample); m_pImmediateContext->OMSetBlendState(NULL, blendFactor, curSample); @@ -2253,6 +2252,10 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event // offset. uint32_t discardedOffset = 0; + ModificationValue lastKnownGood = {}; + if(!history.isEmpty()) + lastKnownGood = history[0].preMod; + for(size_t h = 0; h < history.size(); h++) { const ActionDescription *action = m_pDevice->GetAction(history[h].eventId); @@ -2260,35 +2263,50 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event if(action->flags & ActionFlags::Clear) continue; + // reset discarded offset every event + if(h > 0 && history[h].eventId != history[h - 1].eventId) + { + discardedOffset = 0; + lastKnownGood = history[h].preMod; + } + // if we're not the last modification in our event, need to fetch post fragment value + bool lastMod = true; if(h + 1 < history.size() && history[h].eventId == history[h + 1].eventId) { + lastMod = false; // colour { - byte *data = pixstoreData + sizeof(Vec4f) * pixstoreStride * postColSlot; + uint32_t offsettedSlot = (postColSlot - discardedOffset); + byte *data = pixstoreData + sizeof(Vec4f) * pixstoreStride * offsettedSlot; memcpy(&history[h].postMod.col.uintValue[0], data, sizeof(Vec4f)); } - float *depthdata = (float *)(pixstoreDepthData + sizeof(Vec4f) * pixstoreStride * depthSlot); + { + uint32_t offsettedSlot = (depthSlot - discardedOffset); + RDCASSERT(discardedOffset <= depthSlot); + // post fragment depth is in slot 1 of the depth + float *depthdata = (float *)(pixstoreDepthData + + sizeof(Vec4f) * pixstoreStride * offsettedSlot + sizeof(Vec4f)); - // this is not exactly the right value when the original depth was D16, it will be slightly - // higher precision than the actual value but that's better than not having a value at all, - // and allows us to identify fragments within a draw which fail the depth test. - if(history[h].preMod.depth >= 0.0f) - history[h].postMod.depth = *depthdata; + // this is not exactly the right value when the original depth was D16, it will be slightly + // higher precision than the actual value but that's better than not having a value at all, + // and allows us to identify fragments within a draw which fail the depth test. + if(history[h].preMod.depth >= 0.0f) + history[h].postMod.depth = *depthdata; - // we can't retrieve stencil value after each fragment, as we use stencil to identify the - // fragment - if(history[h].preMod.stencil >= 0) - history[h].postMod.stencil = -2; - else - history[h].postMod.stencil = -1; + // we can't retrieve stencil value after each fragment, as we use stencil to identify the + // fragment + if(history[h].preMod.stencil >= 0) + history[h].postMod.stencil = -2; + else + history[h].postMod.stencil = -1; + } // in each case we only mark as "unknown" when the depth/stencil isn't already known to be // unbound postColSlot++; - depthSlot++; } // if we're not the first modification in our event, set our preMod to the previous postMod @@ -2297,12 +2315,6 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event history[h].preMod = history[h - 1].postMod; } - // reset discarded offset every event - if(h > 0 && history[h].eventId != history[h - 1].eventId) - { - discardedOffset = 0; - } - // fetch shader output value { bool someFragsClipped = history[h].primitiveID != 0; @@ -2311,13 +2323,14 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event { // shader output is always 4 32bit components, so we can copy straight uint32_t offsettedSlot = (shadColSlot - discardedOffset); - RDCASSERT(discardedOffset * 2 <= shadColSlot); + RDCASSERT(discardedOffset <= shadColSlot); byte *data = shadoutStoreData + sizeof(Vec4f) * pixstoreStride * offsettedSlot; memcpy(&history[h].shaderOut.col.uintValue[0], data, 4 * sizeof(float)); - // primitive ID is in the next slot after that + // primitive ID is in slot 1 and ignores any discards + data = shadoutStoreData + sizeof(Vec4f) * pixstoreStride * shadColSlot; memcpy(&history[h].primitiveID, data + sizeof(Vec4f), sizeof(uint32_t)); } @@ -2436,6 +2449,12 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event RDCEraseEl(history[h].shaderOut); history[h].shaderOut.depth = -1.0f; history[h].shaderOut.stencil = -1; + if(!lastMod) + history[h].postMod = lastKnownGood; + } + else + { + lastKnownGood = history[h].postMod; } }