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