Add test for MSAA evals to D3D11_Shader_Debug_Zoo

This commit is contained in:
Steve Karolewics
2020-03-04 19:11:56 +00:00
committed by Baldur Karlsson
parent 2ca43b82bd
commit a5583b83ee
5 changed files with 151 additions and 14 deletions
+23 -11
View File
@@ -2707,22 +2707,34 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position,
{
DebugHit *hit = (DebugHit *)(initialData + i * structStride);
if(winner == NULL || (winner->sample != sample && hit->sample == sample) ||
depthFunc == D3D11_COMPARISON_ALWAYS || depthFunc == D3D11_COMPARISON_NEVER ||
depthFunc == D3D11_COMPARISON_NOT_EQUAL || depthFunc == D3D11_COMPARISON_EQUAL)
if(winner == NULL)
{
// If we haven't picked a winner at all yet, use the first one
winner = hit;
evalSampleCache = ((float *)evalData) + evalSampleCacheData.size() * 4 * i;
continue;
}
if((depthFunc == D3D11_COMPARISON_LESS && hit->depth < winner->depth) ||
(depthFunc == D3D11_COMPARISON_LESS_EQUAL && hit->depth <= winner->depth) ||
(depthFunc == D3D11_COMPARISON_GREATER && hit->depth > winner->depth) ||
(depthFunc == D3D11_COMPARISON_GREATER_EQUAL && hit->depth >= winner->depth))
else if(hit->sample == sample)
{
if(hit->sample == sample)
// If this hit is for the sample we want, check whether it's a better pick
if(winner->sample != sample)
{
// The previously selected winner was for the wrong sample, use this one
winner = hit;
evalSampleCache = ((float *)evalData) + evalSampleCacheData.size() * 4 * i;
}
else if((depthFunc == D3D11_COMPARISON_ALWAYS || depthFunc == D3D11_COMPARISON_NEVER ||
depthFunc == D3D11_COMPARISON_NOT_EQUAL || depthFunc == D3D11_COMPARISON_EQUAL))
{
// For depth functions without an inequality comparison, use the last sample encountered
winner = hit;
evalSampleCache = ((float *)evalData) + evalSampleCacheData.size() * 4 * i;
}
else if((depthFunc == D3D11_COMPARISON_LESS && hit->depth < winner->depth) ||
(depthFunc == D3D11_COMPARISON_LESS_EQUAL && hit->depth <= winner->depth) ||
(depthFunc == D3D11_COMPARISON_GREATER && hit->depth > winner->depth) ||
(depthFunc == D3D11_COMPARISON_GREATER_EQUAL && hit->depth >= winner->depth))
{
// For depth functions with an inequality, find the hit that "wins" the most
winner = hit;
evalSampleCache = ((float *)evalData) + evalSampleCacheData.size() * 4 * i;
}
@@ -2844,7 +2856,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position,
global.sampleEvalCache[k] = var;
}
// advance past this data - always by float4 as that's the buffer st ride
// advance past this data - always by float4 as that's the buffer stride
evalSampleCache += 4;
}
+9 -3
View File
@@ -310,12 +310,18 @@ bool OperationFlushing(const DXBCBytecode::OpcodeType &op)
case OPCODE_GATHER4_PO_C:
return true;
// unclear if these flush and it's unlikely denorms will come up, so conservatively flush
case OPCODE_SAMPLE_INFO:
case OPCODE_SAMPLE_POS:
// don't flush eval ops as some inputs may be uint
case OPCODE_EVAL_CENTROID:
case OPCODE_EVAL_SAMPLE_INDEX:
case OPCODE_EVAL_SNAPPED:
return false;
// don't flush samplepos since an operand is scalar
case OPCODE_SAMPLE_POS:
return false;
// unclear if these flush and it's unlikely denorms will come up, so conservatively flush
case OPCODE_SAMPLE_INFO:
case OPCODE_LOD:
case OPCODE_DERIV_RTX:
case OPCODE_DERIV_RTX_COARSE:
@@ -560,6 +560,31 @@ float4 main(v2f IN) : SV_Target0
return float4(0.4f, 0.4f, 0.4f, 0.4f);
}
)EOSHADER";
std::string msaaPixel = R"EOSHADER(
struct v2f
{
float4 pos : SV_POSITION;
float4 col : COLOR0;
float2 uv : TEXCOORD0;
};
float4 main(v2f IN, uint samp : SV_SampleIndex) : SV_Target0
{
float2 uvCentroid = EvaluateAttributeCentroid(IN.uv);
float2 uvSamp0 = EvaluateAttributeAtSample(IN.uv, 0) - IN.uv;
float2 uvSampThis = EvaluateAttributeAtSample(IN.uv, samp) - IN.uv;
float2 uvOffset = EvaluateAttributeSnapped(IN.uv, int2(1, 1));
float x = (uvCentroid.x + uvCentroid.y) * 0.5f;
float y = (uvSamp0.x + uvSamp0.y) * 0.5f;
float z = (uvSampThis.x + uvSampThis.y) * 0.5f;
float w = (uvOffset.x + uvOffset.y) * 0.5f;
return float4(x, y, z, w);
}
)EOSHADER";
int main()
@@ -661,6 +686,21 @@ float4 main(v2f IN) : SV_Target0
ctx->PSSetShaderResources(0, ARRAY_COUNT(srvs), srvs);
// Create resources for MSAA draw
ID3DBlobPtr vsmsaablob = Compile(D3DDefaultVertex, "main", "vs_5_0");
ID3DBlobPtr psmsaablob = Compile(msaaPixel, "main", "ps_5_0");
CreateDefaultInputLayout(vsmsaablob);
ID3D11VertexShaderPtr vsmsaa = CreateVS(vsmsaablob);
ID3D11PixelShaderPtr psmsaa = CreatePS(psmsaablob);
ID3D11BufferPtr vbmsaa = MakeBuffer().Vertex().Data(DefaultTri);
ID3D11Texture2DPtr msaaTex =
MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 8, 8).Multisampled(4).RTV();
ID3D11RenderTargetViewPtr msaaRT = MakeRTV(msaaTex);
while(Running())
{
ClearRenderTargetView(fltRT, {0.2f, 0.2f, 0.2f, 1.0f});
@@ -684,6 +724,15 @@ float4 main(v2f IN) : SV_Target0
ctx->DrawInstanced(3, numTests, 0, 0);
ctx->OMSetRenderTargets(1, &msaaRT.GetInterfacePtr(), NULL);
RSSetViewport({0.0f, 0.0f, 8.0f, 8.0f, 0.0f, 1.0f});
IASetVertexBuffer(vbmsaa, sizeof(DefaultA2V), 0);
ctx->IASetInputLayout(defaultLayout);
ctx->VSSetShader(vsmsaa, NULL, 0);
ctx->PSSetShader(psmsaa, NULL, 0);
ctx->Draw(3, 0);
Present();
}
+34
View File
@@ -333,6 +333,40 @@ class TestCase:
log.success("Picked value at {},{} in {} is as expected".format(x, y, res_details.name))
def check_pixel_sample_value(self, tex: rd.ResourceId, x, y, sample, value, eps=util.FLT_EPSILON):
tex_details = self.get_texture(tex)
res_details = self.get_resource(tex)
if type(x) is float:
x = int((tex_details.width-1) * x)
if type(y) is float:
y = int((tex_details.height-1) * y)
cast = rd.CompType.Typeless
if tex_details.creationFlags & rd.TextureCategory.SwapBuffer:
cast = rd.CompType.UNormSRGB
# Reduce epsilon for RGBA8 textures if it's not already reduced
if tex_details.format.compByteWidth == 1 and eps == util.FLT_EPSILON:
eps = (1.0 / 255.0)
picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, rd.Subresource(0, 0, sample), cast)
if not util.value_compare(picked.floatValue, value, eps):
save_data = rd.TextureSave()
save_data.resourceId = tex
save_data.destType = rd.FileType.PNG
img_path = util.get_tmp_path('output.png')
self.controller.SaveTexture(save_data, img_path)
raise TestFailureException(
"Picked value {} at {},{} sample {} doesn't match expectation of {}".
format(picked.floatValue, x, y, sample, value), img_path)
log.success("Picked value at {},{} sample {} in {} is as expected".format(x, y, sample, res_details.name))
def check_triangle(self, out = None, back = None, fore = None, vp = None):
pipe: rd.PipeState = self.controller.GetPipelineState()
@@ -17,6 +17,8 @@ class D3D11_Shader_Debug_Zoo(rdtest.TestCase):
failed = False
# Loop over every test
rdtest.log.print("Performing general tests:")
rdtest.log.indent()
for test in range(draw.numInstances):
# Debug the shader
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(4 * test, 0, rd.ReplayController.NoPreference,
@@ -38,6 +40,40 @@ class D3D11_Shader_Debug_Zoo(rdtest.TestCase):
self.controller.FreeTrace(trace)
rdtest.log.success("Test {} matched as expected".format(test))
rdtest.log.dedent()
rdtest.log.print("Performing MSAA tests:")
rdtest.log.indent()
draw = draw.next
self.controller.SetFrameEvent(draw.eventId, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
for test in range(4):
# Debug the shader
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(4, 4, test,
rd.ReplayController.NoPreference)
# Validate that the correct sample index was debugged
inputs: List[rd.ShaderVariable] = list(trace.inputs)
sampRegister = self.find_input_source_var(trace, rd.ShaderBuiltin.MSAASampleIndex)
sampInput = [var for var in inputs if var.name == sampRegister.variables[0].name][0]
if sampInput.value.uv[0] != test:
rdtest.log.error("Test {} did not pick the correct sample.".format(test))
cycles, variables = self.process_trace(trace)
output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)
debugged = self.evalute_source_var(output, variables)
# Validate the debug output result
try:
self.check_pixel_sample_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, test, debugged.value.fv[0:4], 0.0)
except rdtest.TestFailureException as ex:
failed = True
rdtest.log.error("Test {} did not match. {}".format(test, str(ex)))
continue
rdtest.log.dedent()
if failed:
raise rdtest.TestFailureException("Some tests were not as expected")