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