For each matching event determine which tests it fails (if any).

This commit is contained in:
baldurk
2014-07-13 18:57:34 +01:00
parent cbcfc135b3
commit 53afb34e71
+410 -4
View File
@@ -2730,7 +2730,9 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
vector<ID3D11Query*> occl;
occl.reserve(events.size());
// reserve 4 pixels per draw on average. Pre/Shaderout/Post required at minimum,
ID3D11Query *testQueries[6] = {0}; // one query for each test we do per-drawcall
// reserve 6 pixels per draw on average. Pre/Shaderout/Post required at minimum,
// and hopefully overdraw within draws will average to only 2 times.
uint32_t pixstoreSlots = (uint32_t)(events.size() * 6);
@@ -2776,8 +2778,9 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
// additional flags we can trivially detect on the CPU for edge cases
TestMustFail_Scissor = 1<<6, // if the scissor is enabled, pixel lies outside all regions (could be only one)
TestMustFail_DepthTesting = 1<<7, // if the comparison func is NEVER
TestMustFail_StencilTesting = 1<<8, // if the comparison func is NEVER for both faces, or one face is backface culled and the other is NEVER
TestMustPass_Scissor = 1<<7, // if the scissor is enabled, pixel lies inside all regions (could be only one)
TestMustFail_DepthTesting = 1<<8, // if the comparison func is NEVER
TestMustFail_StencilTesting = 1<<9, // if the comparison func is NEVER for both faces, or one face is backface culled and the other is NEVER
};
#if 1
@@ -2796,6 +2799,9 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
m_pDevice->CreateQuery(&occlDesc, &q);
occl.push_back(q);
}
for(size_t i=0; i < ARRAY_COUNT(testQueries); i++)
m_pDevice->CreateQuery(&occlDesc, &testQueries[i]);
D3D11_BLEND_DESC nopBlendStateDesc = {0}; // no blending enabled anywhere, 0 write mask
ID3D11BlendState *nopBlendState = NULL;
@@ -2820,6 +2826,7 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
ID3D11RasterizerState *curRS = NULL;
ID3D11RasterizerState *newRS = NULL;
ID3D11DepthStencilState *newDS = NULL;
ID3D11PixelShader *curPS = NULL;
ID3D11ClassInstance *curInst[D3D11_SHADER_MAX_INTERFACES] = { NULL };
UINT curNumInst = 0;
@@ -2931,6 +2938,7 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
{
// see if we can find at least one scissor region this pixel could fall into
bool inRegion = false;
bool inAllRegions = true;
for(UINT i=0; i < curNumScissors && i < curNumViews; i++)
{
@@ -2941,12 +2949,17 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
)
{
inRegion = true;
break;
}
else
{
inAllRegions = false;
}
}
if(!inRegion)
flags[ev] |= TestMustFail_Scissor;
if(inAllRegions)
flags[ev] |= TestMustPass_Scissor;
}
if(curBS)
@@ -3022,6 +3035,8 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
m_pImmediateContext->End(occl[ev]);
// TODO, if drawcall has side-effects (i.e UAVs bound) replay from start of log here?
m_pImmediateContext->PSSetShader(curPS, curInst, curNumInst);
m_pImmediateContext->RSSetState(curRS);
m_pImmediateContext->RSSetScissorRects(curNumScissors, curScissors);
@@ -3214,11 +3229,399 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
}
}
// complex case - need to determine how many fragments from this draw wrote to the pixel and generate a
// PixelModification event for all of them.
//
// Is there any value in doing this anyway for non-blended cases where other fragments are completely discarded?
if(flags[i] & Blending_Enabled)
{
}
if(flags[i] & TestMustFail_DepthTesting)
mod.depthTestFailed = true;
if(flags[i] & TestMustFail_StencilTesting)
mod.stencilTestFailed = true;
if(flags[i] & TestMustFail_Scissor)
mod.scissorClipped = true;
bool dirty = false;
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
curNumScissors = curNumViews = 16;
m_pImmediateContext->RSGetViewports(&curNumViews, curViewports);
m_pImmediateContext->RSGetScissorRects(&curNumScissors, curScissors);
m_pImmediateContext->RSGetState(&curRS);
m_pImmediateContext->OMGetDepthStencilState(&curDS, &stencilRef);
blendFactor[0] = blendFactor[1] = blendFactor[2] = blendFactor[3] = 1.0f;
curSample = ~0U;
D3D11_RASTERIZER_DESC rdesc = {
/*FillMode =*/ D3D11_FILL_SOLID,
/*CullMode =*/ D3D11_CULL_BACK,
/*FrontCounterClockwise =*/ FALSE,
/*DepthBias =*/ D3D11_DEFAULT_DEPTH_BIAS,
/*DepthBiasClamp =*/ D3D11_DEFAULT_DEPTH_BIAS_CLAMP,
/*SlopeScaledDepthBias =*/ D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
/*DepthClipEnable =*/ TRUE,
/*ScissorEnable =*/ FALSE,
/*MultisampleEnable =*/ FALSE,
/*AntialiasedLineEnable =*/ FALSE,
};
if(curRS)
curRS->GetDesc(&rdesc);
D3D11_DEPTH_STENCIL_DESC dsdesc = {
/*DepthEnable =*/ TRUE,
/*DepthWriteMask =*/ D3D11_DEPTH_WRITE_MASK_ALL,
/*DepthFunc =*/ D3D11_COMPARISON_LESS,
/*StencilEnable =*/ FALSE,
/*StencilReadMask =*/ D3D11_DEFAULT_STENCIL_READ_MASK,
/*StencilWriteMask =*/ D3D11_DEFAULT_STENCIL_WRITE_MASK,
/*FrontFace =*/ { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_COMPARISON_ALWAYS },
/*BackFace =*/ { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_COMPARISON_ALWAYS },
};
if(curDS)
curDS->GetDesc(&dsdesc);
for(UINT v=0; v < curNumViews; v++)
{
// calculate scissor, relative to this viewport, that encloses only (x,y) pixel
// if (x,y) pixel isn't in viewport, make empty rect)
if(xf < curViewports[v].TopLeftX ||
yf < curViewports[v].TopLeftY ||
xf >= curViewports[v].TopLeftX + curViewports[v].Width ||
yf >= curViewports[v].TopLeftY + curViewports[v].Height)
{
newScissors[v].left = newScissors[v].top = newScissors[v].bottom = newScissors[v].right = 0;
}
else
{
newScissors[v].left = LONG(xf - curViewports[v].TopLeftX);
newScissors[v].top = LONG(yf - curViewports[v].TopLeftY);
newScissors[v].right = newScissors[v].left+1;
newScissors[v].bottom = newScissors[v].top+1;
}
}
// for each test we only disable pipeline rejection tests that fall *after* it.
// e.g. to get an idea if a pixel failed backface culling or not, we enable only backface
// culling and disable everything else (since it happens first).
// For depth testing, we leave all tests enabled up to then - as we only want to know which
// pixels were rejected by the depth test, not pixels that might have passed the depth test
// had they not been discarded earlier by backface culling or depth clipping.
if(flags[i] & TestEnabled_BackfaceCulling)
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
rd.DepthClipEnable = FALSE;
// leave backface culling mode as normal
m_pDevice->CreateRasterizerState(&rd, &newRS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(nopDSState, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumViews, newScissors);
m_pImmediateContext->Begin(testQueries[0]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[0]);
SAFE_RELEASE(newRS);
}
if(flags[i] & TestEnabled_DepthClip)
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
// leave depth clip mode as normal
// leave backface culling mode as normal
m_pDevice->CreateRasterizerState(&rd, &newRS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(nopDSState, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumViews, newScissors);
m_pImmediateContext->Begin(testQueries[1]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[1]);
SAFE_RELEASE(newRS);
}
// only check scissor if test is enabled and we don't know if it's pass or fail yet
if((flags[i] & (TestEnabled_Scissor|TestMustPass_Scissor|TestMustFail_Scissor)) == TestEnabled_Scissor)
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
// leave depth clip mode as normal
// leave backface culling mode as normal
// newScissors has scissor regions calculated to hit our target pixel on every viewport, but we must
// intersect that with the original scissors regions for correct testing behaviour.
// This amounts to making any scissor region that doesn't overlap with the target pixel empty.
//
// Note that in the case of only one scissor region we can trivially detect pass/fail of the test against
// our pixel on the CPU so we won't come in here (see check above against MustFail/MustPass). So we will
// only do this in the case where we have multiple scissor regions/viewports, some intersecting the pixel
// and some not. So we make the not intersecting scissor regions empty so our occlusion query tests to see
// if any pixels were written to the "passing" viewports
D3D11_RECT intersectScissors[16] = {0};
memcpy(intersectScissors, newScissors, sizeof(intersectScissors));
for(UINT s=0; s < curNumScissors; s++)
{
if(curScissors[i].left > newScissors[i].left ||
curScissors[i].right < newScissors[i].right ||
curScissors[i].top > newScissors[i].top ||
curScissors[i].bottom < newScissors[i].bottom)
{
// scissor region from the log doesn't touch our target pixel, make empty.
intersectScissors[i].left = intersectScissors[i].right = intersectScissors[i].top = intersectScissors[i].bottom = 0;
}
}
m_pDevice->CreateRasterizerState(&rd, &newRS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(nopDSState, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumScissors, intersectScissors);
m_pImmediateContext->Begin(testQueries[2]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[2]);
SAFE_RELEASE(newRS);
}
// test shader discard
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
// leave depth clip mode as normal
// leave backface culling mode as normal
m_pDevice->CreateRasterizerState(&rd, &newRS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(nopDSState, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumViews, newScissors);
m_pImmediateContext->Begin(testQueries[3]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[3]);
SAFE_RELEASE(newRS);
}
if(flags[i] & TestEnabled_DepthTesting)
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
// leave depth clip mode as normal
// leave backface culling mode as normal
m_pDevice->CreateRasterizerState(&rd, &newRS);
D3D11_DEPTH_STENCIL_DESC dsd = dsdesc;
dsd.StencilEnable = FALSE;
dsd.StencilReadMask = 0;
dsd.StencilWriteMask = 0;
m_pDevice->CreateDepthStencilState(&dsd, &newDS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(newDS, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumViews, newScissors);
m_pImmediateContext->Begin(testQueries[4]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[4]);
SAFE_RELEASE(newRS);
SAFE_RELEASE(newDS);
}
if(flags[i] & TestEnabled_StencilTesting)
{
D3D11_RASTERIZER_DESC rd = rdesc;
rd.ScissorEnable = TRUE;
rd.DepthClipEnable = FALSE;
rd.CullMode = D3D11_CULL_NONE;
m_pDevice->CreateRasterizerState(&rd, &newRS);
// leave depthstencil testing exactly as is, because a depth-fail means
// stencil isn't run
m_pDevice->CreateDepthStencilState(&dsdesc, &newDS);
if(dirty)
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_WithoutDraw);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(nopBlendState, blendFactor, curSample);
m_pImmediateContext->OMSetDepthStencilState(newDS, stencilRef);
m_pImmediateContext->RSSetState(newRS);
m_pImmediateContext->RSSetScissorRects(curNumViews, newScissors);
m_pImmediateContext->Begin(testQueries[5]);
m_WrappedDevice->ReplayLog(frameID, 0, events[i], eReplay_OnlyDraw);
dirty = true;
m_pImmediateContext->End(testQueries[5]);
SAFE_RELEASE(newRS);
SAFE_RELEASE(newDS);
}
SAFE_RELEASE(curRS);
mod.shaderOut.value_f[0] = mod.postMod.value_f[0];
mod.shaderOut.value_f[1] = mod.postMod.value_f[1];
mod.shaderOut.value_f[2] = mod.postMod.value_f[2];
mod.shaderOut.value_f[3] = mod.postMod.value_f[3];
// we check these in the order defined, as a positive from the backface cull test
// will invalidate tests later (as they will also be backface culled)
do
{
if(flags[i] & TestEnabled_BackfaceCulling)
{
do
{
hr = m_pImmediateContext->GetData(testQueries[0], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.backfaceCulled = (occlData == 0);
if(mod.backfaceCulled)
break;
}
if(flags[i] & TestEnabled_DepthClip)
{
do
{
hr = m_pImmediateContext->GetData(testQueries[1], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.depthClipped = (occlData == 0);
if(mod.depthClipped)
break;
}
if(!mod.backfaceCulled && (flags[i] & (TestEnabled_Scissor|TestMustPass_Scissor|TestMustFail_Scissor)) == TestEnabled_Scissor)
{
do
{
hr = m_pImmediateContext->GetData(testQueries[2], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.scissorClipped = (occlData == 0);
if(mod.scissorClipped)
break;
}
{
do
{
hr = m_pImmediateContext->GetData(testQueries[3], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.shaderDiscarded = (occlData == 0);
if(mod.shaderDiscarded)
break;
}
if(flags[i] & TestEnabled_DepthTesting)
{
do
{
hr = m_pImmediateContext->GetData(testQueries[4], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.depthTestFailed = (occlData == 0);
if(mod.depthTestFailed)
break;
}
if(flags[i] & TestEnabled_StencilTesting)
{
do
{
hr = m_pImmediateContext->GetData(testQueries[5], &occlData, sizeof(occlData), 0);
} while(hr == S_FALSE);
RDCASSERT(hr == S_OK);
mod.stencilTestFailed = (occlData == 0);
if(mod.stencilTestFailed)
break;
}
} while (0);
history.push_back(mod);
RDCDEBUG("Event %u is visible", events[i]);
@@ -3230,6 +3633,9 @@ vector<PixelModification> D3D11DebugManager::PixelHistory(uint32_t frameID, vect
}
m_pImmediateContext->Unmap(pixstore, 0);
for(size_t i=0; i < ARRAY_COUNT(testQueries); i++)
SAFE_RELEASE(testQueries[i]);
SAFE_RELEASE(nopBlendState);
SAFE_RELEASE(nopDSState);