diff --git a/util/test/tests/D3D12/D3D12_Pixel_History.py b/util/test/tests/D3D12/D3D12_Pixel_History.py new file mode 100644 index 000000000..669335238 --- /dev/null +++ b/util/test/tests/D3D12/D3D12_Pixel_History.py @@ -0,0 +1,473 @@ +import renderdoc as rd +import rdtest +from typing import List + + +def value_selector(x): return x.floatValue +def passed(x): return x.Passed() +def event_id(x): return x.eventId +def culled(x): return x.backfaceCulled +def depth_test_failed(x): return x.depthTestFailed +def depth_clipped(x): return x.depthClipped +def depth_bounds_failed(x): return x.depthBoundsFailed +def scissor_clipped(x): return x.scissorClipped +def stencil_test_failed(x): return x.stencilTestFailed +def shader_discarded(x): return x.shaderDiscarded + +def get_shader_out_color(x): return x.shaderOut.col.floatValue +def get_shader_out_depth(x): return x.shaderOut.depth + +def get_pre_mod_color(x): return x.preMod.col.floatValue +def get_pre_mod_depth(x): return x.preMod.depth + +def get_post_mod_color(x): return x.postMod.col.floatValue +def get_post_mod_depth(x): return x.postMod.depth + +def primitive_id(x): return x.primitiveID +def unboundPS(x): return x.unboundPS + +class D3D12_Pixel_History(rdtest.TestCase): + demos_test_name = 'D3D12_Pixel_History' + demos_frame_cap = 5 + + def check_capture(self): + apiprops: rd.APIProperties = self.controller.GetAPIProperties() + + if not apiprops.pixelHistory: + rdtest.log.print("D3D12 pixel history not tested") + return + + # Disabling SM6.6 test as the test setup is not doing anything special for it yet + tests = ["SM5.1", "SM6.0"] #, "SM6.6"] + for t in tests: + rdtest.log.print("Testing " + t) + + self.is_depth = False + rdtest.log.print("Testing primary") + self.primary_test("Begin " + t) + rdtest.log.print("Testing secondary") + self.secondary_cmd_test("Begin " + t) + + self.is_depth = True + rdtest.log.print("Testing depth") + self.depth_target_test("Begin " + t) + + # Disabling MSAA test for now as it is failing on some hardware + # self.is_depth = False + # rdtest.log.print("Testing MSAA") + #self.multisampled_image_test("Begin " + t) + + def primary_test(self, begin_name: str): + begin_renderpass_action = self.find_action(begin_name) + if begin_renderpass_action is None: + rdtest.log.print("Test not found") + return + + begin_renderpass_eid = begin_renderpass_action.next.eventId + test_marker: rd.ActionDescription = self.find_action("Test Begin", begin_renderpass_eid) + self.controller.SetFrameEvent(test_marker.next.eventId, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + rt: rd.BoundResource = pipe.GetOutputTargets()[0] + + tex = rt.resourceId + tex_details = self.get_texture(tex) + + sub = rd.Subresource() + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + if tex_details.mips > 1: + sub.mip = rt.firstMip + + depth_write_eid = self.find_action("Depth Write", begin_renderpass_eid).next.eventId + stencil_write_eid = self.find_action("Stencil Write", begin_renderpass_eid).next.eventId + unbound_fs_eid = self.find_action("Unbound Fragment Shader", begin_renderpass_eid).next.eventId + background_eid = self.find_action("Background", begin_renderpass_eid).next.eventId + cull_eid = self.find_action("Cull Front", begin_renderpass_eid).next.eventId + test_eid = self.find_action("Test Begin", begin_renderpass_eid).next.eventId + fixed_scissor_fail_eid = self.find_action("Fixed Scissor Fail", begin_renderpass_eid).next.eventId + fixed_scissor_pass_eid = self.find_action("Fixed Scissor Pass", begin_renderpass_eid).next.eventId + dynamic_stencil_ref_eid = self.find_action("Dynamic Stencil Ref", begin_renderpass_eid).next.eventId + dynamic_stencil_mask_eid = self.find_action("Dynamic Stencil Mask", begin_renderpass_eid).next.eventId + depth_test_eid = self.find_action("Depth Test", begin_renderpass_eid).next.eventId + depth_bounds_prep_eid = self.find_action("Depth Bounds Prep", begin_renderpass_eid).next.eventId + depth_bounds_clip_eid = self.find_action("Depth Bounds Clip", begin_renderpass_eid).next.eventId + + # For pixel 190, 149 inside the red triangle + x, y = 190, 149 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, unbound_fs_eid], [passed, True], [unboundPS, True], [primitive_id, 0]], + [[event_id, stencil_write_eid], [passed, True]], + [[event_id, background_eid], [depth_test_failed, True], [get_post_mod_color, (1.0, 0.0, 0.0, 1.0)]], + [[event_id, test_eid], [stencil_test_failed, True]], + ] + + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 190, 150 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_write_eid], [passed, True]], + [[event_id, background_eid], [depth_test_failed, True]], + [[event_id, cull_eid], [culled, True]], + [[event_id, test_eid], [depth_test_failed, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 200, 50 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, background_eid], [passed, True]], + [[event_id, test_eid], [passed, True], [primitive_id, 7]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 150, 250 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, background_eid], [shader_discarded, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 330, 145 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, test_eid], [passed, True], [primitive_id, 3], [get_shader_out_color, (0.0, 0.0, 0.0, 2.75)]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 340, 145 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, test_eid], [passed, False], [depth_clipped, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 330, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [get_shader_out_color, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, True], [primitive_id, 0], [get_shader_out_color, (0.0, 1.0, 0.0, 2.75)]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 320, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [get_shader_out_color, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + x, y = 345, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [get_shader_out_color, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + rdtest.log.print("Testing dynamic state pipelines") + self.controller.SetFrameEvent(dynamic_stencil_mask_eid, True) + + x, y = 100, 250 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, background_eid], [passed, True]], + [[event_id, fixed_scissor_fail_eid], [scissor_clipped, True]], + [[event_id, fixed_scissor_pass_eid], [passed, True], [get_shader_out_color, (0.0, 1.0, 0.0, 2.75)], + [get_post_mod_color, (0.0, 1.0, 0.0, 1.0)]], + [[event_id, dynamic_stencil_ref_eid], [passed, True], [get_shader_out_color, (0.0, 0.0, 1.0, 2.75)], + [get_post_mod_color, (0.0, 0.0, 1.0, 1.0)]], + [[event_id, dynamic_stencil_mask_eid], [passed, True], [get_shader_out_color, (0.0, 1.0, 1.0, 2.75)], + [get_post_mod_color, (0.0, 1.0, 1.0, 1.0)]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + rdtest.log.print("Testing depth test for per fragment reporting") + self.controller.SetFrameEvent(depth_test_eid, True) + + x, y = 275, 260 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, background_eid], [passed, True]], + [[event_id, depth_test_eid], [primitive_id, 0], [depth_test_failed, True], + [get_shader_out_color, (1.0, 1.0, 1.0, 2.75)], [get_shader_out_depth, 0.97], [get_post_mod_color, (1.0, 0.0, 1.0, 1.0)], + [get_post_mod_depth, 0.95]], + [[event_id, depth_test_eid], [primitive_id, 1], [depth_test_failed, False], + [get_shader_out_color, (1.0, 1.0, 0.0, 2.75)], [get_shader_out_depth, 0.20], [get_post_mod_color, (1.0, 1.0, 0.0, 1.0)], + [get_post_mod_depth, 0.20]], + [[event_id, depth_test_eid], [primitive_id, 2], [depth_test_failed, True], + [get_shader_out_color, (1.0, 0.0, 0.0, 2.75)], [get_shader_out_depth, 0.30], [get_post_mod_color, (1.0, 1.0, 0.0, 1.0)], + [get_post_mod_depth, 0.20]], + [[event_id, depth_test_eid], [primitive_id, 3], [depth_test_failed, False], + [get_shader_out_color, (0.0, 0.0, 1.0, 2.75)], [get_shader_out_depth, 0.10], [get_post_mod_color, (0.0, 0.0, 1.0, 1.0)], + [get_post_mod_depth, 0.10]], + [[event_id, depth_test_eid], [primitive_id, 4], [depth_test_failed, False], + [get_shader_out_color, (1.0, 1.0, 1.0, 2.75)], [get_shader_out_depth, 0.05], [get_post_mod_color, (0.0, 0.0, 1.0, 1.0)], + [get_post_mod_depth, 0.10]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + def multisampled_image_test(self, pass_name: str): + begin_pass_action = self.find_action(pass_name) + if begin_pass_action is None: + rdtest.log.print("Test not found") + return + + pass_start_eid = begin_pass_action.next.eventId + + test_marker: rd.ActionDescription = self.find_action("Multisampled: test", pass_start_eid) + action_eid = test_marker.next.eventId + self.controller.SetFrameEvent(action_eid, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + rt: rd.BoundResource = pipe.GetOutputTargets()[0] + + if self.is_depth: + rt: rd.BoundResource = pipe.GetDepthTarget() + + sub = rd.Subresource() + tex = rt.resourceId + tex_details = self.get_texture(tex) + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + + beg_renderpass_eid = self.find_action("Begin MSAA", pass_start_eid).next.eventId + + x, y = 140, 130 + sub.sample = 1 + rdtest.log.print("Testing pixel {}, {} at sample {}".format(x, y, sub.sample)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + + events = [ + [[event_id, beg_renderpass_eid], [passed, True], [get_post_mod_depth, 0.0]], + [[event_id, action_eid], [passed, True], [primitive_id, 0], [get_pre_mod_depth, 0.0], [get_shader_out_depth, 0.9], + [get_post_mod_depth, 0.9]], + [[event_id, action_eid], [passed, True], [primitive_id, 1], [get_shader_out_depth, 0.95], [get_post_mod_depth, 0.95]], + ] + + if not self.is_depth: + events[0] += [[get_post_mod_color, (0.0, 1.0, 0.0, 1.0)]] + events[1] += [[get_shader_out_color, (1.0, 0.0, 1.0, 2.75)], [get_post_mod_color, (1.0, 0.0, 1.0, 1.0)]] + events[2] += [[get_shader_out_color, (0.0, 0.0, 1.0, 2.75)], [get_post_mod_color, (0.0, 0.0, 1.0, 1.0)]] + + self.check_events(events, modifs, True) + + if self.is_depth: + self.check_pixel_value(tex, x, y, [modifs[-1].postMod.depth, float(modifs[-1].postMod.stencil)/255.0, 0.0, 1.0], sub=sub, cast=rt.typeCast) + else: + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + sub.sample = 2 + rdtest.log.print("Testing pixel {}, {} at sample {}".format(x, y, sub.sample)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, beg_renderpass_eid], [passed, True], [get_post_mod_depth, 0.0]], + [[event_id, action_eid], [passed, True], [primitive_id, 0], [get_pre_mod_depth, 0.0], [get_shader_out_depth, 0.9], + [get_post_mod_depth, 0.9]], + [[event_id, action_eid], [passed, True], [primitive_id, 1], [get_shader_out_depth, 0.95], [get_post_mod_depth, 0.95]], + ] + + if not self.is_depth: + events[0] += [[get_post_mod_color, (0.0, 1.0, 0.0, 1.0)]] + events[1] += [[get_shader_out_color, (1.0, 0.0, 1.0, 2.75)], [get_post_mod_color, (1.0, 0.0, 1.0, 1.0)]] + events[2] += [[get_shader_out_color, (0.0, 1.0, 1.0, 2.75)], [get_post_mod_color, (0.0, 1.0, 1.0, 1.0)]] + + self.check_events(events, modifs, True) + + if self.is_depth: + self.check_pixel_value(tex, x, y, + [modifs[-1].postMod.depth, float(modifs[-1].postMod.stencil) / 255.0, 0.0, 1.0], + sub=sub, cast=rt.typeCast) + else: + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + def secondary_cmd_test(self, pass_name: str): + begin_pass_action = self.find_action(pass_name) + if begin_pass_action is None: + rdtest.log.print("Test not found") + return + + pass_start_eid = begin_pass_action.next.eventId + + secondary_marker: rd.ActionDescription = self.find_action("Secondary: red and blue", pass_start_eid) + self.controller.SetFrameEvent(secondary_marker.next.eventId, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + rt: rd.BoundResource = pipe.GetOutputTargets()[0] + sub = rd.Subresource() + tex = rt.resourceId + tex_details = self.get_texture(tex) + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + if tex_details.mips > 1: + sub.mip = rt.firstMip + + sec_beg_renderpass_eid = self.find_action("Begin RenderPass Secondary", pass_start_eid).next.eventId + background_eid = self.find_action("Secondary: background", pass_start_eid).next.eventId + culled_eid = self.find_action("Secondary: culled", pass_start_eid).next.eventId + sec_red_and_blue = self.find_action("Secondary: red and blue", pass_start_eid).next.eventId + + # Test culling + x, y = 70, 40 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, sec_beg_renderpass_eid], [passed, True], [get_post_mod_color, (0.0, 1.0, 0.0, 1.0)]], + [[event_id, background_eid], [passed, True], [get_pre_mod_color, (0.0, 1.0, 0.0, 1.0)]], + [[event_id, culled_eid], [passed, False], [culled, True]], + ] + self.check_events(events, modifs, True) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + # Blue triangle + x, y = 40, 40 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, sec_beg_renderpass_eid], [passed, True], [get_post_mod_color, (0.0, 1.0, 0.0, 1.0)]], + # This is the first event in the command buffer, should have pre-mod + [[event_id, background_eid], [passed, True], [get_pre_mod_color, (0.0, 1.0, 0.0, 1.0)]], + # This is the last event in the command buffer, should have post-mod + [[event_id, sec_red_and_blue], [passed, True], [get_post_mod_color, (0.0, 0.0, 1.0, 1.0)]], + ] + self.check_events(events, modifs, True) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + # Didn't get post mod for background_eid + self.controller.SetFrameEvent(background_eid, True) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, sec_beg_renderpass_eid]], + # The only event, should have both pre and post mod. + [[event_id, background_eid], [passed, True], [get_pre_mod_color, (0.0, 1.0, 0.0, 1.0)], [get_post_mod_color, (1.0, 0.0, 1.0, 1.0)]], + ] + self.check_events(events, modifs, True) + self.check_pixel_value(tex, x, y, get_post_mod_color(modifs[-1]), sub=sub, cast=rt.typeCast) + + def depth_target_test(self, begin_name: str): + begin_pass_action = self.find_action(begin_name) + if begin_pass_action is None: + rdtest.log.print("Test not found") + return + + # Advance one more than the color test since DSV clear is a separate event than RT clear + begin_renderpass_eid = begin_pass_action.next.next.eventId + + test_marker: rd.ActionDescription = self.find_action("Test Begin", begin_renderpass_eid) + + self.controller.SetFrameEvent(test_marker.next.eventId, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + rt: rd.BoundResource = pipe.GetDepthTarget() + + tex = rt.resourceId + tex_details = self.get_texture(tex) + + sub = rd.Subresource() + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + if tex_details.mips > 1: + sub.mip = rt.firstMip + + background_eid = self.find_action("Background", begin_renderpass_eid).next.eventId + test_eid = self.find_action("Test Begin", begin_renderpass_eid).next.eventId + + x, y = 200, 190 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True], [get_post_mod_depth, 1.0]], + [[event_id, background_eid], [passed, True], [primitive_id, 0], [get_pre_mod_depth, 1.0], [get_post_mod_depth, 0.95]], + [[event_id, test_eid], [passed, True], [depth_test_failed, False], [primitive_id, 0], [get_shader_out_depth, 0.5], [get_post_mod_depth, 0.5]], + [[event_id, test_eid], [passed, False], [depth_test_failed, True], [primitive_id, 1], [get_shader_out_depth, 0.6], [get_post_mod_depth, 0.5]], + ] + self.check_events(events, modifs, False) + + def check_events(self, events, modifs, hasSecondary): + self.check(len(modifs) == len(events), "Expected {} events, got {}".format(len(events), len(modifs))) + # Check for consistency first. For secondary command buffers, + # might not have all information, so don't check for consistency + if not hasSecondary: + self.check_modifs_consistent(modifs) + for i in range(len(modifs)): + for c in range(len(events[i])): + expected = events[i][c][1] + actual = events[i][c][0](modifs[i]) + if not rdtest.value_compare(actual, expected, eps=1.0/256.0): + raise rdtest.TestFailureException( + "eventId {}, primitiveID {}: testing {} expected {}, got {}".format(modifs[i].eventId, modifs[i].primitiveID, + events[i][c][0].__name__, + expected, + actual)) + + def check_modifs_consistent(self, modifs): + # postmod of each should match premod of the next + for i in range(len(modifs) - 1): + a = get_post_mod_color(modifs[i]) + b = get_pre_mod_color(modifs[i + 1]) + + if self.is_depth: + a = (modifs[i].postMod.depth, modifs[i].postMod.stencil) + b = (modifs[i + 1].preMod.depth, modifs[i + 1].preMod.stencil) + + if a != b: + raise rdtest.TestFailureException( + "postmod at {} primitive {}: {} doesn't match premod at {} primitive {}: {}".format(modifs[i].eventId, + modifs[i].primitiveID, + a, + modifs[i + 1].eventId, + modifs[i + 1].primitiveID, + b)) + + # Check that if the test failed, its postmod is the same as premod + for i in range(len(modifs)): + if not modifs[i].Passed(): + a = get_pre_mod_color(modifs[i]) + b = get_post_mod_color(modifs[i]) + + if self.is_depth: + a = (modifs[i].preMod.depth, modifs[i].preMod.stencil) + b = (modifs[i].postMod.depth, modifs[i].postMod.stencil) + + if not rdtest.value_compare(a, b): + raise rdtest.TestFailureException( + "postmod at {} primitive {}: {} doesn't match premod: {}".format(modifs[i].eventId, + modifs[i].primitiveID, b, a))