From b070a371e2c64fac10ab446fa073c3931e4b380f Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 20 Dec 2017 23:41:08 +0000 Subject: [PATCH] Improve D3D11 predication handling, and track other asyncs independently * Instead of replaying predication, we now always skip it during replay, so all objects will render. This is much more consistent and understandable behaviour instead of things mysteriously disappearing with no obvious reason why. * We track the predication that would have happened and replay Begin/End pairs so that we can know if the predication *would* have failed. * This is displayed in the UI (currently in the raster state, for lack of a better location) with the pass/fail that would have happened. * This information can feed into other places for analysis like the pixel history. --- .../D3D11PipelineStateViewer.cpp | 23 ++- .../PipelineState/D3D11PipelineStateViewer.ui | 147 +++++++++++++----- qrenderdoc/Windows/PixelHistoryView.cpp | 2 + renderdoc/api/replay/d3d11_pipestate.h | 19 ++- renderdoc/api/replay/data_types.h | 4 +- renderdoc/driver/d3d11/d3d11_analyse.cpp | 8 + renderdoc/driver/d3d11/d3d11_context_wrap.cpp | 84 +++++++++- renderdoc/driver/d3d11/d3d11_debug.cpp | 12 ++ renderdoc/driver/d3d11/d3d11_debug.h | 2 + renderdoc/driver/d3d11/d3d11_device.h | 2 +- renderdoc/driver/d3d11/d3d11_device_wrap.cpp | 52 ++++++- renderdoc/driver/d3d11/d3d11_renderstate.cpp | 61 ++++++++ renderdoc/driver/d3d11/d3d11_renderstate.h | 8 + renderdoc/driver/d3d11/d3d11_replay.cpp | 8 + renderdoc/replay/renderdoc_serialise.inl | 17 +- 15 files changed, 393 insertions(+), 56 deletions(-) diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 67215c3ca..e6b526bda 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -77,7 +77,7 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, const QIcon &action = Icons::action(); const QIcon &action_hover = Icons::action_hover(); - RDLabel *shaderLabels[] = { + RDLabel *objectLabels[] = { ui->vsShader, ui->hsShader, ui->dsShader, ui->gsShader, ui->psShader, ui->csShader, ui->iaBytecode, }; @@ -137,7 +137,7 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, for(QToolButton *b : viewButtons) QObject::connect(b, &QToolButton::clicked, this, &D3D11PipelineStateViewer::shaderView_clicked); - for(RDLabel *b : shaderLabels) + for(RDLabel *b : objectLabels) { b->setAutoFillBackground(true); b->setBackgroundRole(QPalette::ToolTipBase); @@ -173,7 +173,7 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, addGridLines(ui->blendStateGridLayout, palette().color(QPalette::WindowText)); addGridLines(ui->depthStateGridLayout, palette().color(QPalette::WindowText)); - for(RDLabel *st : {ui->depthState, ui->blendState, ui->rastState}) + for(RDLabel *st : {ui->depthState, ui->blendState, ui->rastState, ui->predicate}) { st->setAutoFillBackground(true); st->setBackgroundRole(QPalette::ToolTipBase); @@ -847,6 +847,8 @@ void D3D11PipelineStateViewer::clearState() ui->stencilRef->setText(lit("FF")); ui->stencils->clear(); + + ui->predicateGroup->setVisible(false); } void D3D11PipelineStateViewer::setShaderState(const D3D11Pipe::Shader &stage, RDLabel *shader, @@ -1539,6 +1541,21 @@ void D3D11PipelineStateViewer::setState() ui->forcedSampleCount->setText(QString::number(state.m_RS.m_State.ForcedSampleCount)); ui->conservativeRaster->setPixmap(state.m_RS.m_State.ConservativeRasterization ? tick : cross); + //////////////////////////////////////////////// + // Predication + + if(state.m_Predicate.Obj == ResourceId()) + { + ui->predicateGroup->setVisible(false); + } + else + { + ui->predicateGroup->setVisible(true); + ui->predicate->setText(ToQStr(state.m_Predicate.Obj)); + ui->predicateValue->setText(state.m_Predicate.Value ? lit("TRUE") : lit("FALSE")); + ui->predicatePassing->setPixmap(state.m_Predicate.Passing ? tick : cross); + } + //////////////////////////////////////////////// // Output Merger diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui index 90f5184c8..9ced4226a 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.ui @@ -76,7 +76,7 @@ Show Disabled Items - + :/page_white_delete.png:/page_white_delete.png @@ -99,7 +99,7 @@ Show Empty Items - + :/page_white_database.png:/page_white_database.png @@ -122,7 +122,7 @@ Export - + :/save.png:/save.png @@ -313,7 +313,7 @@ View the mesh input data - :/wireframe_mesh.png + :/wireframe_mesh.png true @@ -368,7 +368,7 @@ - :/topologies/topo_trilist.svg + :/topologies/topo_trilist.svg Qt::AlignCenter @@ -418,7 +418,7 @@ View - + :/action.png:/action.png @@ -484,6 +484,12 @@ Qt::Horizontal + + + 0 + 0 + + @@ -616,7 +622,7 @@ View - + :/action.png:/action.png @@ -636,7 +642,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -656,7 +662,7 @@ Save - + :/save.png:/save.png @@ -987,7 +993,7 @@ View - + :/action.png:/action.png @@ -1007,7 +1013,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -1027,7 +1033,7 @@ Save - + :/save.png:/save.png @@ -1355,7 +1361,7 @@ View - + :/action.png:/action.png @@ -1375,7 +1381,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -1395,7 +1401,7 @@ Save - + :/save.png:/save.png @@ -1723,7 +1729,7 @@ View - + :/action.png:/action.png @@ -1743,7 +1749,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -1763,7 +1769,7 @@ Save - + :/save.png:/save.png @@ -2273,7 +2279,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2289,7 +2295,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2305,7 +2311,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2339,7 +2345,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2456,7 +2462,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2485,7 +2491,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -2536,7 +2542,7 @@ - + @@ -2591,7 +2597,7 @@ - + @@ -2646,6 +2652,67 @@ + + + + Predication + + + + + + QFrame::Box + + + 4 + + + + + + + Value: + + + + + + + + 12 + + + + FALSE + + + + + + + Passing: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + @@ -2705,7 +2772,7 @@ View - + :/action.png:/action.png @@ -2725,7 +2792,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -2745,7 +2812,7 @@ Save - + :/save.png:/save.png @@ -3239,7 +3306,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -3330,7 +3397,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -3411,7 +3478,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -3437,7 +3504,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -3618,7 +3685,7 @@ - :/cross.png + :/cross.png Qt::AlignCenter @@ -3853,7 +3920,7 @@ View - + :/action.png:/action.png @@ -3873,7 +3940,7 @@ Edit - + :/page_white_edit.png:/page_white_edit.png @@ -3893,7 +3960,7 @@ Save - + :/save.png:/save.png @@ -3969,7 +4036,7 @@ - + :/wrench.png:/wrench.png @@ -4314,8 +4381,6 @@ 1 - - - + diff --git a/qrenderdoc/Windows/PixelHistoryView.cpp b/qrenderdoc/Windows/PixelHistoryView.cpp index d0cf03e50..ac8dc4f6b 100644 --- a/qrenderdoc/Windows/PixelHistoryView.cpp +++ b/qrenderdoc/Windows/PixelHistoryView.cpp @@ -547,6 +547,8 @@ private: s += tr("\nDepth test failed"); if(mod.stencilTestFailed) s += tr("\nStencil test failed"); + if(mod.predicationSkipped) + s += tr("\nPredicated rendering skipped"); return s; } diff --git a/renderdoc/api/replay/d3d11_pipestate.h b/renderdoc/api/replay/d3d11_pipestate.h index 11f758a5b..d31b80ba5 100644 --- a/renderdoc/api/replay/d3d11_pipestate.h +++ b/renderdoc/api/replay/d3d11_pipestate.h @@ -704,10 +704,23 @@ struct OM View DepthTarget; DOCUMENT("``True`` if depth access to the depth-stencil target is read-only."); bool DepthReadOnly = false; - DOCUMENT("``True`` if stenncil access to the depth-stencil target is read-only."); + DOCUMENT("``True`` if stencil access to the depth-stencil target is read-only."); bool StencilReadOnly = false; }; +DOCUMENT("Describes the current state of predicated rendering."); +struct Predication +{ + DOCUMENT("The :class:`ResourceId` of the active predicate."); + ResourceId Obj; + + DOCUMENT("The value to go along with the predicate."); + bool Value = false; + + DOCUMENT("``True`` if the current predicate would render."); + bool Passing = false; +}; + DOCUMENT("The full current D3D11 pipeline state."); struct State { @@ -735,6 +748,9 @@ struct State DOCUMENT("A :class:`D3D11_OM` describing the output merger pipeline stage."); OM m_OM; + + DOCUMENT("A :class:`Predication` describing the predicated rendering state."); + Predication m_Predicate; }; }; // namespace D3D11Pipe @@ -759,4 +775,5 @@ DECLARE_REFLECTION_STRUCT(D3D11Pipe::Blend); DECLARE_REFLECTION_STRUCT(D3D11Pipe::BlendEquation); DECLARE_REFLECTION_STRUCT(D3D11Pipe::BlendState); DECLARE_REFLECTION_STRUCT(D3D11Pipe::OM); +DECLARE_REFLECTION_STRUCT(D3D11Pipe::Predication); DECLARE_REFLECTION_STRUCT(D3D11Pipe::State); diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index f36eebe44..c78b83a9b 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -1362,6 +1362,8 @@ pixel. bool depthTestFailed; DOCUMENT("``True`` if stencil testing eliminated this fragment."); bool stencilTestFailed; + DOCUMENT("``True`` if predicated rendering skipped this call."); + bool predicationSkipped; DOCUMENT(R"(Determine if this fragment passed all tests and wrote to the texture. @@ -1371,7 +1373,7 @@ pixel. bool passed() const { return !sampleMasked && !backfaceCulled && !depthClipped && !viewClipped && !scissorClipped && - !shaderDiscarded && !depthTestFailed && !stencilTestFailed; + !shaderDiscarded && !depthTestFailed && !stencilTestFailed && !predicationSkipped; } }; diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index a89ce485f..4e243814a 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -5167,6 +5167,9 @@ vector D3D11DebugManager::PixelHistory(vector eve // if the sample mask set at this event doesn't have the right bit set TestMustFail_SampleMask = 1 << 10, + + // if predication was failing at this event + Predication_Failed = 1 << 11, }; #if 1 @@ -5487,6 +5490,9 @@ vector D3D11DebugManager::PixelHistory(vector eve flags[ev] |= TestMustFail_SampleMask; } + if(!m_WrappedContext->GetCurrentPipelineState()->PredicationWouldPass()) + flags[ev] |= Predication_Failed; + m_pDevice->CreateRasterizerState(&rd, &newRS); m_pImmediateContext->RSSetState(newRS); SAFE_RELEASE(newRS); @@ -5916,6 +5922,8 @@ vector D3D11DebugManager::PixelHistory(vector eve mod.scissorClipped = true; if(flags[i] & TestMustFail_SampleMask) mod.sampleMasked = true; + if(flags[i] & Predication_Failed) + mod.predicationSkipped = true; m_WrappedDevice->ReplayLog(0, events[i].eventID, eReplay_WithoutDraw); diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 1659e02fc..320e888a7 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -6400,21 +6400,49 @@ bool WrappedID3D11DeviceContext::Serialise_Begin(SerialiserType &ser, ID3D11Asyn SERIALISE_CHECK_READ_ERRORS(); + if(IsReplayingAndReading() && pAsync) + { + ID3D11Asynchronous *unwrapped = NULL; + + // only replay predicates which can affect rendering, don't re-submit queries or counters (that + // might even interfere with queries we want to run) + if(WrappedID3D11Predicate::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + + // if you change this to replay other types, check with Serialise_CreateCounter which creates + // dummy queries to ensure it always succeeds. + + if(unwrapped) + m_pRealContext->Begin(unwrapped); + } + return true; } void WrappedID3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) { ID3D11Asynchronous *unwrapped = NULL; + ResourceId id; if(WrappedID3D11Query1::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Query1, pAsync); + id = ((WrappedID3D11Query1 *)pAsync)->GetResourceID(); + } else if(WrappedID3D11Predicate::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + id = ((WrappedID3D11Predicate *)pAsync)->GetResourceID(); + } else if(WrappedID3D11Counter::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); + id = ((WrappedID3D11Counter *)pAsync)->GetResourceID(); + } else + { RDCERR("Unexpected ID3D11Asynchronous"); + } SERIALISE_TIME_CALL(m_pRealContext->Begin(unwrapped)); @@ -6426,6 +6454,8 @@ void WrappedID3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) Serialise_Begin(GET_SERIALISER, pAsync); m_ContextRecord->AddChunk(scope.Get()); + + MarkResourceReferenced(id, eFrameRef_Read); } } @@ -6436,21 +6466,49 @@ bool WrappedID3D11DeviceContext::Serialise_End(SerialiserType &ser, ID3D11Asynch SERIALISE_CHECK_READ_ERRORS(); + if(IsReplayingAndReading() && pAsync) + { + ID3D11Asynchronous *unwrapped = NULL; + + // only replay predicates which can affect rendering, don't re-submit queries or counters (that + // might even interfere with queries we want to run) + if(WrappedID3D11Predicate::IsAlloc(pAsync)) + unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + + // if you change this to replay other types, check with Serialise_CreateCounter which creates + // dummy queries to ensure it always succeeds. + + if(unwrapped) + m_pRealContext->End(unwrapped); + } + return true; } void WrappedID3D11DeviceContext::End(ID3D11Asynchronous *pAsync) { ID3D11Asynchronous *unwrapped = NULL; + ResourceId id; if(WrappedID3D11Query1::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Query1, pAsync); + id = ((WrappedID3D11Query1 *)pAsync)->GetResourceID(); + } else if(WrappedID3D11Predicate::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); + id = ((WrappedID3D11Predicate *)pAsync)->GetResourceID(); + } else if(WrappedID3D11Counter::IsAlloc(pAsync)) + { unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); + id = ((WrappedID3D11Counter *)pAsync)->GetResourceID(); + } else + { RDCERR("Unexpected ID3D11Asynchronous"); + } SERIALISE_TIME_CALL(m_pRealContext->End(unwrapped)); @@ -6462,6 +6520,8 @@ void WrappedID3D11DeviceContext::End(ID3D11Asynchronous *pAsync) Serialise_End(GET_SERIALISER, pAsync); m_ContextRecord->AddChunk(scope.Get()); + + MarkResourceReferenced(id, eFrameRef_Read); } } @@ -6494,7 +6554,16 @@ bool WrappedID3D11DeviceContext::Serialise_SetPredication(SerialiserType &ser, if(IsReplayingAndReading()) { - m_pRealContext->SetPredication(pPredicate, PredicateValue ? TRUE : FALSE); + // we don't replay predication as it can be confusing and inconsistent. We just store the state + // so that we can manually check whether it *would* have passed or failed. + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->Predicate, pPredicate); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PredicateValue, + PredicateValue ? TRUE : FALSE); + + /* + m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, pPredicate), + PredicateValue ? TRUE : FALSE); + */ } return true; @@ -6504,6 +6573,13 @@ void WrappedID3D11DeviceContext::SetPredication(ID3D11Predicate *pPredicate, BOO { m_EmptyCommandList = false; + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->Predicate, pPredicate); + m_CurrentPipelineState->Change(m_CurrentPipelineState->PredicateValue, PredicateValue); + + // on replay don't actually apply any predication. Just update the state and bail + if(IsReplayMode(m_State)) + return; + SERIALISE_TIME_CALL( m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, pPredicate), PredicateValue)); @@ -6515,6 +6591,12 @@ void WrappedID3D11DeviceContext::SetPredication(ID3D11Predicate *pPredicate, BOO Serialise_SetPredication(GET_SERIALISER, pPredicate, PredicateValue); m_ContextRecord->AddChunk(scope.Get()); + + if(pPredicate) + { + ResourceId id = ((WrappedID3D11Predicate *)pPredicate)->GetResourceID(); + MarkResourceReferenced(id, eFrameRef_Read); + } } } diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index ca9752b08..49871877c 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -3819,6 +3819,18 @@ void D3D11DebugManager::ClearPostVSCache() m_PostVSData.clear(); } +void D3D11DebugManager::RenderForPredicate() +{ + // just somehow draw a quad that renders some pixels to fill the predicate with TRUE + m_WrappedContext->ClearState(); + D3D11_VIEWPORT viewport = {0, 0, 1, 1, 0.0f, 1.0f}; + m_WrappedContext->RSSetViewports(1, &viewport); + m_WrappedContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0); + m_WrappedContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + m_WrappedContext->OMSetRenderTargets(1, &m_DebugRender.PickPixelRT, NULL); + m_WrappedContext->Draw(3, 0); +} + MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage) { D3D11PostVSData postvs; diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 4cb8dc252..cad07c2cc 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -130,6 +130,8 @@ public: MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); void ClearPostVSCache(); + void RenderForPredicate(); + uint32_t GetStructCount(ID3D11UnorderedAccessView *uav); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, bytebuf &retData); void GetBufferData(ID3D11Buffer *buff, uint64_t offset, uint64_t length, bytebuf &retData); diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index 52d90146a..0d3da04a3 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -62,7 +62,7 @@ struct D3D11InitParams D3D_FEATURE_LEVEL FeatureLevels[16]; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0xD; + static const uint64_t CurrentVersion = 0xE; static bool IsSupportedVersion(uint64_t ver); }; diff --git a/renderdoc/driver/d3d11/d3d11_device_wrap.cpp b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp index c86c5f0ff..bf1830a50 100644 --- a/renderdoc/driver/d3d11/d3d11_device_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp @@ -2615,7 +2615,15 @@ HRESULT WrappedID3D11Device::CreateQuery(const D3D11_QUERY_DESC *pQueryDesc, ID3 SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateQuery); Serialise_CreateQuery(GET_SERIALISER, pQueryDesc, &wrapped); - m_DeviceRecord->AddChunk(scope.Get()); + WrappedID3D11Query1 *q = (WrappedID3D11Query1 *)wrapped; + ResourceId id = q->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); } *ppQuery = wrapped; @@ -2636,6 +2644,10 @@ bool WrappedID3D11Device::Serialise_CreatePredicate(SerialiserType &ser, if(IsReplayingAndReading()) { + // We don't use predicates directly, so removing this flag doesn't make any direct difference. + // It means we can query the result via GetData which we can't if the flag is set. + Descriptor.MiscFlags &= ~D3D11_QUERY_MISC_PREDICATEHINT; + ID3D11Predicate *ret; HRESULT hr = m_pDevice->CreatePredicate(&Descriptor, &ret); @@ -2652,6 +2664,12 @@ bool WrappedID3D11Device::Serialise_CreatePredicate(SerialiserType &ser, } AddResource(pPredicate, ResourceType::Query, "Predicate"); + + // prime the predicate with a true result, so that if we end up referencing a predicate that was + // filled in a previous frame that we don't have the data for, we default to passing. + m_pImmediateContext->Begin(ret); + GetDebugManager()->RenderForPredicate(); + m_pImmediateContext->End(ret); } return true; @@ -2681,7 +2699,15 @@ HRESULT WrappedID3D11Device::CreatePredicate(const D3D11_QUERY_DESC *pPredicateD SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreatePredicate); Serialise_CreatePredicate(GET_SERIALISER, pPredicateDesc, &wrapped); - m_DeviceRecord->AddChunk(scope.Get()); + WrappedID3D11Predicate *p = (WrappedID3D11Predicate *)wrapped; + ResourceId id = p->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); } *ppPredicate = wrapped; @@ -2702,8 +2728,14 @@ bool WrappedID3D11Device::Serialise_CreateCounter(SerialiserType &ser, if(IsReplayingAndReading()) { - ID3D11Counter *ret; - HRESULT hr = m_pDevice->CreateCounter(&Descriptor, &ret); + // counters may not always be available on the replay, so instead we create a timestamp query as + // a dummy. We never replay any counter fetch since it doesn't affect rendering, so the + // difference doesn't matter. + D3D11_QUERY_DESC dummyQueryDesc; + dummyQueryDesc.Query = D3D11_QUERY_TIMESTAMP; + dummyQueryDesc.MiscFlags = 0; + ID3D11Query *ret; + HRESULT hr = m_pDevice->CreateQuery(&dummyQueryDesc, &ret); if(FAILED(hr)) { @@ -2712,7 +2744,7 @@ bool WrappedID3D11Device::Serialise_CreateCounter(SerialiserType &ser, } else { - ret = new WrappedID3D11Counter(ret, this); + ret = new WrappedID3D11Query1(ret, this); GetResourceManager()->AddLiveResource(pCounter, ret); } @@ -2747,7 +2779,15 @@ HRESULT WrappedID3D11Device::CreateCounter(const D3D11_COUNTER_DESC *pCounterDes SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateCounter); Serialise_CreateCounter(GET_SERIALISER, pCounterDesc, &wrapped); - m_DeviceRecord->AddChunk(scope.Get()); + WrappedID3D11Counter *c = (WrappedID3D11Counter *)wrapped; + ResourceId id = c->GetResourceID(); + + RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL); + + D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->Length = 0; + + record->AddChunk(scope.Get()); } *ppCounter = wrapped; diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.cpp b/renderdoc/driver/d3d11/d3d11_renderstate.cpp index 12fdf5e29..5ecc6c5ce 100644 --- a/renderdoc/driver/d3d11/d3d11_renderstate.cpp +++ b/renderdoc/driver/d3d11/d3d11_renderstate.cpp @@ -41,6 +41,8 @@ D3D11RenderState::D3D11RenderState(D3D11RenderState::EmptyInit) RDCEraseEl(OM); RDCEraseEl(CS); RDCEraseEl(CSUAVs); + Predicate = NULL; + PredicateValue = FALSE; Clear(); m_ImmediatePipeline = false; @@ -61,6 +63,8 @@ D3D11RenderState::D3D11RenderState(const D3D11RenderState &other) RDCEraseEl(OM); RDCEraseEl(CS); RDCEraseEl(CSUAVs); + Predicate = NULL; + PredicateValue = FALSE; m_ImmediatePipeline = false; m_pDevice = NULL; @@ -84,6 +88,9 @@ void D3D11RenderState::CopyState(const D3D11RenderState &other) memcpy(&CS, &other.CS, sizeof(CS)); memcpy(&CSUAVs, &other.CSUAVs, sizeof(CSUAVs)); + Predicate = other.Predicate; + PredicateValue = other.PredicateValue; + m_ViewportScissorPartial = other.m_ViewportScissorPartial; AddRefs(); @@ -143,6 +150,8 @@ void D3D11RenderState::ReleaseRefs() ReleaseRef(OM.DepthView); + ReleaseRef(Predicate); + RDCEraseEl(IA); RDCEraseEl(VS); RDCEraseEl(HS); @@ -154,6 +163,7 @@ void D3D11RenderState::ReleaseRefs() RDCEraseEl(OM); RDCEraseEl(CS); RDCEraseEl(CSUAVs); + Predicate = NULL; } void D3D11RenderState::MarkReferenced(WrappedID3D11DeviceContext *ctx, bool initial) const @@ -254,6 +264,12 @@ void D3D11RenderState::MarkReferenced(WrappedID3D11DeviceContext *ctx, bool init ctx->MarkResourceReferenced(GetViewResourceResID(OM.DepthView), initial ? eFrameRef_Unknown : eFrameRef_Write); } + + if(Predicate) + { + ctx->MarkResourceReferenced(GetIDForResource(Predicate), + initial ? eFrameRef_Unknown : eFrameRef_Read); + } } void D3D11RenderState::CacheViewportPartial() @@ -394,6 +410,8 @@ void D3D11RenderState::AddRefs() TakeRef(OM.UAVs[i]); TakeRef(OM.DepthView); + + TakeRef(Predicate); } D3D11RenderState::D3D11RenderState(WrappedID3D11DeviceContext *context) @@ -490,6 +508,8 @@ D3D11RenderState::D3D11RenderState(WrappedID3D11DeviceContext *context) context->OMGetRenderTargetsAndUnorderedAccessViews( OM.UAVStartSlot, OM.RenderTargets, &OM.DepthView, OM.UAVStartSlot, D3D11_PS_CS_UAV_REGISTER_COUNT - OM.UAVStartSlot, OM.UAVs); + + context->GetPredication(&Predicate, &PredicateValue); } void D3D11RenderState::Clear() @@ -498,11 +518,42 @@ void D3D11RenderState::Clear() OM.BlendFactor[0] = OM.BlendFactor[1] = OM.BlendFactor[2] = OM.BlendFactor[3] = 1.0f; OM.SampleMask = 0xffffffff; + Predicate = NULL; + PredicateValue = FALSE; + for(size_t i = 0; i < ARRAY_COUNT(VS.CBCounts); i++) VS.CBCounts[i] = HS.CBCounts[i] = DS.CBCounts[i] = GS.CBCounts[i] = PS.CBCounts[i] = CS.CBCounts[i] = 4096; } +bool D3D11RenderState::PredicationWouldPass() +{ + if(Predicate == NULL) + return true; + + BOOL data = TRUE; + + HRESULT hr = S_FALSE; + + do + { + hr = m_pDevice->GetImmediateContext()->GetData(Predicate, &data, sizeof(BOOL), 0); + } while(hr == S_FALSE); + RDCASSERTEQUAL(hr, S_OK); + + // From SetPredication for PredicateValue: + // + // "If TRUE, rendering will be affected by when the predicate's conditions are met. If FALSE, + // rendering will be affected when the conditions are not met." + // + // Which is really confusingly worded. 'rendering will be affected' means 'no rendering will + // happen', and 'conditions are met' for e.g. an occlusion query means that it passed. + // Thus a passing occlusion query has value TRUE and is 'condition is met', so for a typical "skip + // when occlusion query fails" the value will be FALSE. + + return PredicateValue != data; +} + void D3D11RenderState::ApplyState(WrappedID3D11DeviceContext *context) { context->ClearState(); @@ -583,6 +634,8 @@ void D3D11RenderState::ApplyState(WrappedID3D11DeviceContext *context) context->OMSetRenderTargetsAndUnorderedAccessViews( OM.UAVStartSlot, OM.RenderTargets, OM.DepthView, OM.UAVStartSlot, D3D11_PS_CS_UAV_REGISTER_COUNT - OM.UAVStartSlot, OM.UAVs, UAV_keepcounts); + + context->SetPredication(Predicate, PredicateValue); } void D3D11RenderState::TakeRef(ID3D11DeviceChild *p) @@ -1268,6 +1321,12 @@ bool D3D11RenderState::IsBoundForWrite(ID3D11InputLayout *resource) return false; } +template <> +bool D3D11RenderState::IsBoundForWrite(ID3D11Predicate *resource) +{ + return false; +} + template <> bool D3D11RenderState::IsBoundForWrite(ID3D11ClassInstance *resource) { @@ -1472,6 +1531,8 @@ void DoSerialise(SerialiserType &ser, D3D11RenderState &el) SERIALISE_MEMBER(SO); SERIALISE_MEMBER(RS); SERIALISE_MEMBER(OM); + SERIALISE_MEMBER(Predicate); + SERIALISE_MEMBER(PredicateValue); if(ser.IsReading()) el.AddRefs(); diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.h b/renderdoc/driver/d3d11/d3d11_renderstate.h index 94f4f60b4..db4514e62 100644 --- a/renderdoc/driver/d3d11/d3d11_renderstate.h +++ b/renderdoc/driver/d3d11/d3d11_renderstate.h @@ -268,6 +268,11 @@ struct D3D11RenderState ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT]; } OM; + ID3D11Predicate *Predicate; + BOOL PredicateValue; + + bool PredicationWouldPass(); + void SetImmediatePipeline(WrappedID3D11Device *device) { m_ImmediatePipeline = true; @@ -311,6 +316,9 @@ private: template <> bool D3D11RenderState::IsBoundForWrite(ID3D11InputLayout *resource); +template <> +bool D3D11RenderState::IsBoundForWrite(ID3D11Predicate *resource); + template <> bool D3D11RenderState::IsBoundForWrite(ID3D11ClassInstance *resource); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 3acb1b9c8..4e8eaebeb 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1216,6 +1216,14 @@ void D3D11Replay::SavePipelineState() ret.m_OM.m_State.m_BackFace.FailOp = StencilOp::Keep; } } + + ///////////////////////////////////////////////// + // Predication + ///////////////////////////////////////////////// + + ret.m_Predicate.Obj = rm->GetOriginalID(GetIDForResource(rs->Predicate)); + ret.m_Predicate.Value = rs->PredicateValue == TRUE ? true : false; + ret.m_Predicate.Passing = rs->PredicationWouldPass(); } ReplayStatus D3D11Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 1efefe98b..e10faf142 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -768,8 +768,9 @@ void DoSerialise(SerialiserType &ser, PixelModification &el) SERIALISE_MEMBER(shaderDiscarded); SERIALISE_MEMBER(depthTestFailed); SERIALISE_MEMBER(stencilTestFailed); + SERIALISE_MEMBER(predicationSkipped); - SIZE_CHECK(96); + SIZE_CHECK(100); } template @@ -1072,6 +1073,16 @@ void DoSerialise(SerialiserType &ser, D3D11Pipe::OM &el) SIZE_CHECK(224); } +template +void DoSerialise(SerialiserType &ser, D3D11Pipe::Predication &el) +{ + SERIALISE_MEMBER(Obj); + SERIALISE_MEMBER(Value); + SERIALISE_MEMBER(Passing); + + SIZE_CHECK(16); +} + template void DoSerialise(SerialiserType &ser, D3D11Pipe::State &el) { @@ -1089,7 +1100,9 @@ void DoSerialise(SerialiserType &ser, D3D11Pipe::State &el) SERIALISE_MEMBER(m_RS); SERIALISE_MEMBER(m_OM); - SIZE_CHECK(1488); + SERIALISE_MEMBER(m_Predicate); + + SIZE_CHECK(1504); } #pragma endregion D3D11 pipeline state