def check_capture(self): out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) for base_event_name in ["sm5.0", "sm5.1", "sm6.0"]: base = self.find_action(base_event_name) if base is None: continue base_event = base.eventId rdtest.log.print("Checking tests on {}".format(base_event_name)) super(D3D12_Overlay_Test, self).check_capture(base_event) rdtest.log.success( "Base tests worked on {}".format(base_event_name)) # Don't check any pixel values, but ensure all overlays at least work with no viewport/scissor bound sub_marker: rd.ActionDescription = self.find_action( "NoView draw", base_event) self.controller.SetFrameEvent(sub_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: continue rdtest.log.success( "Checking overlay {} with no viewport/scissor".format( str(overlay))) tex.overlay = overlay out.SetTextureDisplay(tex) out.Display() overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() rdtest.log.success( "Overlay {} rendered with no viewport/scissor".format( str(overlay))) rdtest.log.success( "extended tests worked on {}".format(base_event_name)) out.Shutdown()
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [1.0, 0.0, 0.0, 1.0]): raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) rdtest.log.success("picked value is as expected") out.Shutdown()
def check_pixel_value(self, tex: rd.ResourceId, x, y, 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 * x) if type(y) is float: y = int(tex_details.height * y) if self.pickout is None: self.pickout: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(self.pickout is not None) texdisplay = rd.TextureDisplay() texdisplay.resourceId = tex self.pickout.SetTextureDisplay(texdisplay) picked: rd.PixelValue = self.pickout.PickPixel(tex, False, x, y, 0, 0, 0) if not util.value_compare(picked.floatValue, value, eps): raise TestFailureException( "Picked value {} at {},{} doesn't match expectation of {}". format(picked.floatValue, x, y, value)) log.success("Picked value at {},{} in {} is as expected".format( x, y, res_details.name))
def check_capture(self): rdtest.log.success("Got {} captures as expected".format( self.demos_frame_count)) draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.Drawcall tex.resourceId = pipe.GetOutputTargets()[0].resourceId out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) out.SetTextureDisplay(tex) out.Display() overlay_id = out.GetDebugOverlayTexID() v = pipe.GetViewport(0) self.check_pixel_value(overlay_id, int(0.5 * v.width), int(0.5 * v.height), [0.8, 0.1, 0.8, 1.0], eps=1.0 / 256.0) out.Shutdown() rdtest.log.success("Overlay color is as expected")
def check_capture(self): # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) # find the first draw draw = self.find_draw("Draw") # check the centre pixel of the viewport is white self.controller.SetFrameEvent(draw.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) view: rd.Viewport = pipe.GetViewport(0) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(view.width / 2), int(view.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [1.0, 1.0, 1.0, 1.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Picked value for first draw is as expected") # find the second draw draw = self.find_draw("Draw", draw.eventId + 1) pipe: rd.PipeState = self.controller.GetPipelineState() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) view: rd.Viewport = pipe.GetViewport(0) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(view.width / 2), int(view.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [1.0, 1.0, 1.0, 1.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Picked value for second draw is as expected")
def check_capture(self): apiprops: rd.APIProperties = self.controller.GetAPIProperties() if not apiprops.rgpCapture: rdtest.log.print("RGP capture not tested") return path = self.controller.CreateRGPProfile(rd.CreateHeadlessWindowingData(100, 100)) if os.path.exists(path) and os.path.getsize(path) > 100: rdtest.log.success("RGP capture created successfully") else: raise rdtest.TestFailureException("RGP capture failed")
def check_capture(self): super(VK_Overlay_Test, self).check_capture() out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) # Don't check any pixel values, but ensure all overlays at least work with rasterizer discard and no # viewport/scissor bound sub_marker: rd.DrawcallDescription = self.find_draw("Discard Test") self.controller.SetFrameEvent(sub_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: continue rdtest.log.success( "Checking overlay {} with rasterizer discard".format( str(overlay))) tex.overlay = overlay out.SetTextureDisplay(tex) out.Display() overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() rdtest.log.success( "Overlay {} rendered with rasterizer discard".format( str(overlay))) out.Shutdown()
def check_capture(self): # Jump to the draw draw = self.find_draw("Draw") self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) # Loop over every test for test in range(draw.numInstances): # Pick the pixel picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, 4 * test, 0, 0, 0, 0) # Debug the shader trace: rd.ShaderDebugTrace = self.controller.DebugPixel( 4 * test, 0, rd.ReplayController.NoPreference, rd.ReplayController.NoPreference) last_state: rd.ShaderDebugState = trace.states[-1] if not rdtest.value_compare(picked.floatValue, last_state.outputs[0].value.fv[0:4]): raise rdtest.TestFailureException( "Test {}: debugged output {} doesn't match actual output {}" .format(test, last_state.outputs[0].value.fv[0:4], picked.floatValue)) rdtest.log.success("Test {} matched as expected".format(test)) rdtest.log.success("All tests matched")
def check_capture(self, capture_filename: str, controller: rd.ReplayController): self.controller = controller self.pipeType = self.controller.GetAPIProperties().pipelineType self.opengl_mode = (self.controller.GetAPIProperties().pipelineType == rd.GraphicsAPI.OpenGL) self.d3d_mode = rd.IsD3D( self.controller.GetAPIProperties().pipelineType) failed = False try: # First check with the local controller self.check_capture_with_controller('') except rdtest.TestFailureException as ex: rdtest.log.error(str(ex)) failed = True # Now shut it down self.controller.Shutdown() self.controller = None # Launch a remote server rdtest.launch_remote_server() # Wait for it to start time.sleep(0.5) ret: Tuple[rd.ResultCode, rd.RemoteServer] = rd.CreateRemoteServerConnection( 'localhost') result, remote = ret if result != rd.ResultCode.Succeeded: time.sleep(2) ret: Tuple[rd.ResultCode, rd.RemoteServer] = rd.CreateRemoteServerConnection( 'localhost') result, remote = ret if result != rd.ResultCode.Succeeded: raise rdtest.TestFailureException( "Couldn't connect to remote server: {}".format(str(result))) proxies = remote.LocalProxies() try: # Try D3D11 and GL as proxies, D3D12/Vulkan technically don't have proxying implemented even though they # will be listed in proxies for api in ['D3D11', 'OpenGL']: if api not in proxies: continue try: ret: Tuple[rd.ResultCode, rd.ReplayController] = remote.OpenCapture( proxies.index(api), capture_filename, rd.ReplayOptions(), None) result, self.controller = ret # Now check with the proxy self.check_capture_with_controller(api) except ValueError: continue except rdtest.TestFailureException as ex: rdtest.log.error(str(ex)) failed = True finally: remote.CloseCapture(self.controller) self.controller = None finally: remote.ShutdownServerAndConnection() # Now iterate over all the temp images saved out, load them as captures, and check the texture. dir_path = rdtest.get_tmp_path('') was_opengl = self.opengl_mode # We iterate in filename order, so that dds files get opened before png files. for file in os.scandir(dir_path): if '.dds' not in file.name and '.png' not in file.name: continue cap = rd.OpenCaptureFile() result = cap.OpenFile(file.path, 'rdc', None) if result != rd.ResultCode.Succeeded: rdtest.log.error("Couldn't open {}".format(file.name)) failed = True continue ret: Tuple[rd.ResultCode, rd.ReplayController] = cap.OpenCapture( rd.ReplayOptions(), None) result, self.controller = ret if result != rd.ResultCode.Succeeded: rdtest.log.error("Couldn't open {}".format(file.name)) failed = True continue self.filename = file.name.replace('.dds', '').replace('.png', '') [a, b] = file.name.replace('.dds', ' (DDS)').replace('.png', ' (PNG)').split('@') self.controller.SetFrameEvent( self.controller.GetRootActions()[0].eventId, True) try: self.opengl_mode = False fmt: rd.ResourceFormat = self.controller.GetTextures( )[0].format is_compressed = (rd.ResourceFormatType.BC1 <= fmt.type <= rd.ResourceFormatType.BC7 or fmt.type == rd.ResourceFormatType.EAC or fmt.type == rd.ResourceFormatType.ETC2 or fmt.type == rd.ResourceFormatType.ASTC or fmt.type == rd.ResourceFormatType.PVRTC) # OpenGL saves all non-compressed images to disk with a flip, since that's the expected order for # most formats. The effect of this is that we should apply the opengl_mode workaround for all files # *except* compressed textures if was_opengl and not is_compressed: self.opengl_mode = True self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check_test( a, b, Texture_Zoo.TEST_DDS if '.dds' in file.name else Texture_Zoo.TEST_PNG) self.out.Shutdown() self.out = None rdtest.log.success("{} loaded with the correct data".format( file.name)) except rdtest.TestFailureException as ex: rdtest.log.error(str(ex)) failed = True self.controller.Shutdown() self.controller = None if failed: raise rdtest.TestFailureException( "Some tests were not as expected")
def check_capture_with_controller(self, proxy_api: str): self.controller: rd.ReplayController any_failed = False if proxy_api != '': rdtest.log.print('Running with {} local proxy'.format(proxy_api)) self.proxied = True else: rdtest.log.print('Running on direct replay') self.proxied = False self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) for d in self.controller.GetRootActions(): if 'slice tests' in d.customName: for sub in d.children: if sub.flags & rd.ActionFlags.Drawcall: self.controller.SetFrameEvent(sub.eventId, True) pipe = self.controller.GetPipelineState() tex_id = pipe.GetReadOnlyResources( rd.ShaderStage.Pixel)[0].resources[0].resourceId for mip in [0, 1]: for sl in [16, 17, 18]: expected = [0.0, 0.0, 1.0, 1.0] if sl == 17: expected = [0.0, 1.0, 0.0, 1.0] cur_sub = rd.Subresource(mip, sl) comp_type = rd.CompType.Typeless # test that pixel picking sees the right things picked = self.controller.PickPixel( tex_id, 15, 15, cur_sub, comp_type) if not rdtest.value_compare( picked.floatValue, expected): raise rdtest.TestFailureException( "Expected to pick {} at slice {} mip {}, got {}" .format(expected, sl, mip, picked.floatValue)) rdtest.log.success( 'Picked pixel is correct at slice {} mip {}' .format(sl, mip)) # Render output texture a three scales - below 100%, 100%, above 100% tex_display = rd.TextureDisplay() tex_display.resourceId = tex_id tex_display.subresource = cur_sub tex_display.typeCast = comp_type # convert the unorm values to byte values for comparison expected = [ int(a * 255) for a in expected[0:3] ] for scale in [0.9, 1.0, 1.1]: tex_display.scale = scale self.out.SetTextureDisplay(tex_display) self.out.Display() pixels: bytes = self.out.ReadbackOutputTexture( ) actual = [int(a) for a in pixels[0:3]] if not rdtest.value_compare( actual, expected): raise rdtest.TestFailureException( "Expected to display {} at slice {} mip {} scale {}%, got {}" .format(expected, sl, mip, int(scale * 100), actual)) rdtest.log.success( 'Displayed pixel is correct at scale {}% in slice {} mip {}' .format(int(scale * 100), sl, mip)) elif sub.flags & rd.ActionFlags.SetMarker: rdtest.log.print( 'Checking {} for slice display'.format( sub.customName)) continue # Check each region for the tests within if d.flags & rd.ActionFlags.PushMarker: name = '' tests_run = 0 failed = False # Iterate over actions in this region for sub in d.children: sub: rd.ActionDescription if sub.flags & rd.ActionFlags.SetMarker: name = sub.customName # Check this action if sub.flags & rd.ActionFlags.Drawcall: tests_run = tests_run + 1 try: # Set this event as current self.controller.SetFrameEvent(sub.eventId, True) self.filename = (d.customName + '@' + name).replace('->', '_') self.check_test(d.customName, name, Texture_Zoo.TEST_CAPTURE) except rdtest.TestFailureException as ex: failed = any_failed = True rdtest.log.error(str(ex)) if not failed: rdtest.log.success( "All {} texture tests for {} are OK".format( tests_run, d.customName)) self.out.Shutdown() self.out = None if not any_failed: if proxy_api != '': rdtest.log.success( 'All textures are OK with {} as local proxy'.format( proxy_api)) else: rdtest.log.success("All textures are OK on direct replay") else: raise rdtest.TestFailureException( "Some tests were not as expected")
def check_capture(self): self.check_final_backbuffer() for level in ["Primary", "Secondary"]: rdtest.log.print("Checking {} indirect calls".format(level)) dispatches = self.find_draw("{}: Dispatches".format(level)) # Set up a ReplayOutput and TextureSave for quickly testing the drawcall highlight overlay out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) self.check(out is not None) out.SetDimensions(100, 100) tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.Drawcall save_data = rd.TextureSave() save_data.destType = rd.FileType.PNG # Rewind to the start of the capture draw: rd.DrawcallDescription = dispatches.children[0] while draw.previous is not None: draw = draw.previous # Ensure we can select all draws while draw is not None: self.controller.SetFrameEvent(draw.eventId, False) draw = draw.next rdtest.log.success("Selected all {} draws".format(level)) self.check(dispatches and len(dispatches.children) == 3) self.check(dispatches.children[0].dispatchDimension == [0, 0, 0]) self.check(dispatches.children[1].dispatchDimension == [1, 1, 1]) self.check(dispatches.children[2].dispatchDimension == [3, 4, 5]) rdtest.log.success( "{} Indirect dispatches are the correct dimensions".format( level)) self.controller.SetFrameEvent(dispatches.children[2].eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() ssbo: rd.BoundResource = pipe.GetReadWriteResources( rd.ShaderStage.Compute)[0].resources[0] data: bytes = self.controller.GetBufferData(ssbo.resourceId, 0, 0) rdtest.log.print("Got {} bytes of uints".format(len(data))) uints = [ struct.unpack_from('=4L', data, offs) for offs in range(0, len(data), 16) ] for x in range(0, 6): # 3 groups of 2 threads each for y in range(0, 8): # 3 groups of 2 threads each for z in range(0, 5): # 5 groups of 1 thread each idx = 100 + z * 8 * 6 + y * 6 + x if not rdtest.value_compare(uints[idx], [x, y, z, 12345]): raise rdtest.TestFailureException( 'expected thread index data @ {},{},{}: {} is not as expected: {}' .format(x, y, z, uints[idx], [x, y, z, 12345])) rdtest.log.success( "Dispatched buffer contents are as expected for {}".format( level)) empties = self.find_draw("{}: Empty draws".format(level)) self.check(empties and len(empties.children) == 2) draw: rd.DrawcallDescription for draw in empties.children: self.check(draw.numIndices == 0) self.check(draw.numInstances == 0) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have empty PostVS postvs_data = self.get_postvs(rd.MeshDataStage.VSOut, 0, 1) self.check(len(postvs_data) == 0) self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} empty draws are empty".format(level)) indirects = self.find_draw("{}: Indirect draws".format(level)) self.check('vkCmdDrawIndirect' in indirects.children[0].name) self.check( 'vkCmdDrawIndexedIndirect' in indirects.children[1].name) self.check(len(indirects.children[1].children) == 2) rdtest.log.success( "Correct number of {} indirect draws".format(level)) # vkCmdDrawIndirect(...) draw = indirects.children[0] self.check(draw.numIndices == 3) self.check(draw.numInstances == 2) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.8, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.7, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.6, -0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format(level, draw.name)) # vkCmdDrawIndexedIndirect[0](...) draw = indirects.children[1].children[0] self.check(draw.numIndices == 3) self.check(draw.numInstances == 3) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.6, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.5, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.4, -0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format(level, draw.name)) # vkCmdDrawIndexedIndirect[1](...) draw = indirects.children[1].children[1] self.check(draw.numIndices == 6) self.check(draw.numInstances == 2) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.4, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.3, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.2, -0.8, 0.0, 1.0] }, 3: { 'vtx': 3, 'idx': 3, 'gl_PerVertex.gl_Position': [-0.1, -0.5, 0.0, 1.0] }, 4: { 'vtx': 4, 'idx': 4, 'gl_PerVertex.gl_Position': [0.0, -0.8, 0.0, 1.0] }, 5: { 'vtx': 5, 'idx': 5, 'gl_PerVertex.gl_Position': [0.1, -0.8, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format(level, draw.name)) indirect_count_root = self.find_draw( "{}: KHR_draw_indirect_count".format(level)) if indirect_count_root is not None: self.check(indirect_count_root.children[0].name == '{}: Empty count draws'.format(level)) self.check(indirect_count_root.children[1].name == '{}: Indirect count draws'.format(level)) empties = indirect_count_root.children[0] self.check(empties and len(empties.children) == 2) draw: rd.DrawcallDescription for draw in empties.children: self.check(draw.numIndices == 0) self.check(draw.numInstances == 0) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have empty PostVS postvs_data = self.get_postvs(rd.MeshDataStage.VSOut, 0, 1) self.check(len(postvs_data) == 0) self.check_overlay(draw.eventId, out, tex, save_data) # vkCmdDrawIndirectCountKHR draw_indirect = indirect_count_root.children[1].children[0] self.check(draw_indirect and len(draw_indirect.children) == 1) # vkCmdDrawIndirectCountKHR[0] draw = draw_indirect.children[0] self.check(draw.numIndices == 3) self.check(draw.numInstances == 4) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.8, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.7, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.6, 0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format( level, draw.name)) # vkCmdDrawIndexedIndirectCountKHR draw_indirect = indirect_count_root.children[1].children[1] self.check(draw_indirect and len(draw_indirect.children) == 3) # vkCmdDrawIndirectCountKHR[0] draw = draw_indirect.children[0] self.check(draw.numIndices == 3) self.check(draw.numInstances == 1) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.6, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.5, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.4, 0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format( level, draw.name)) # vkCmdDrawIndirectCountKHR[1] draw = draw_indirect.children[1] self.check(draw.numIndices == 0) self.check(draw.numInstances == 0) self.controller.SetFrameEvent(draw.eventId, False) postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) self.check(len(postvs_data) == 0) self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format( level, draw.name)) # vkCmdDrawIndirectCountKHR[2] draw = draw_indirect.children[2] self.check(draw.numIndices == 6) self.check(draw.numInstances == 2) self.controller.SetFrameEvent(draw.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex.gl_Position': [-0.4, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex.gl_Position': [-0.3, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex.gl_Position': [-0.2, 0.2, 0.0, 1.0] }, 3: { 'vtx': 3, 'idx': 3, 'gl_PerVertex.gl_Position': [-0.1, 0.5, 0.0, 1.0] }, 4: { 'vtx': 4, 'idx': 4, 'gl_PerVertex.gl_Position': [0.0, 0.2, 0.0, 1.0] }, 5: { 'vtx': 5, 'idx': 5, 'gl_PerVertex.gl_Position': [0.1, 0.2, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay(draw.eventId, out, tex, save_data) rdtest.log.success("{} {} is as expected".format( level, draw.name)) else: rdtest.log.print("KHR_draw_indirect_count not tested")
def check_capture(self): action = self.find_action("Color Draw") self.check(action is not None) action = action.next self.controller.SetFrameEvent(action.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [0.0, 1.0, 0.0, 1.0]) rdtest.log.success("Captured loaded with color as expected") postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut, 0, action.numIndices) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'SV_POSITION': [-0.5, -0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [0.0, 0.0], }, 1: { 'vtx': 1, 'idx': 1, 'SV_POSITION': [0.0, 0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [0.0, 1.0], }, 2: { 'vtx': 2, 'idx': 2, 'SV_POSITION': [0.5, -0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [1.0, 0.0], }, } self.check_mesh_data(postvs_ref, postvs_data) rdtest.log.success("Mesh data is correct") tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.Drawcall tex.resourceId = pipe.GetOutputTargets()[0].resourceId out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) out.SetTextureDisplay(tex) out.Display() overlay_id = out.GetDebugOverlayTexID() v = pipe.GetViewport(0) self.check_pixel_value(overlay_id, int(0.5 * v.width), int(0.5 * v.height), [0.8, 0.1, 0.8, 1.0], eps=1.0 / 256.0) out.Shutdown() res = self.get_resource_by_name("Sampler Heap") sdfile = self.controller.GetStructuredFile() chunk = sdfile.chunks[res.initialisationChunks[-1]] desc1234 = chunk.GetChild(2).GetChild(1234).GetChild(3) rdtest.log.comment('desc1234: ' + desc1234.name) # filter self.check( desc1234.GetChild(0).AsString() == 'D3D12_FILTER_ANISOTROPIC') self.check(desc1234.GetChild(0).AsInt() == 0x55) # wrapping self.check( desc1234.GetChild(1).AsString() == 'D3D12_TEXTURE_ADDRESS_MODE_BORDER') self.check(desc1234.GetChild(1).AsInt() == 4) # MaxAnisotropy self.check(desc1234.GetChild(1).AsInt() == 4) # MinLod self.check(desc1234.GetChild(8).AsFloat() == 1.5) rdtest.log.success("Overlay color is as expected")
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetGraphicsPipelineObject(), pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 0, cbuf.resourceId, cbuf.byteOffset)) # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself # float4 a; var_check.check('a').rows(1).cols(4).value([0.0, 1.0, 2.0, 3.0]) # float3 b; var_check.check('b').rows(1).cols(3).value([4.0, 5.0, 6.0]) # float2 c; float2 d; var_check.check('c').rows(1).cols(2).value([8.0, 9.0]) var_check.check('d').rows(1).cols(2).value([10.0, 11.0]) # float e; float3 f; var_check.check('e').rows(1).cols(1).value([12.0]) var_check.check('f').rows(1).cols(3).value([13.0, 14.0, 15.0]) # float g; float2 h; float i; var_check.check('g').rows(1).cols(1).value([16.0]) var_check.check('h').rows(1).cols(2).value([17.0, 18.0]) var_check.check('i').rows(1).cols(1).value([19.0]) # float j; float2 k; var_check.check('j').rows(1).cols(1).value([20.0]) var_check.check('k').rows(1).cols(2).value([21.0, 22.0]) # float2 l; float m; var_check.check('l').rows(1).cols(2).value([24.0, 25.0]) var_check.check('m').rows(1).cols(1).value([26.0]) # float n[4]; var_check.check('n').rows(0).cols(0).arraySize(4).members({ 0: lambda x: x.rows(1).cols(1).value([28.0]), 1: lambda x: x.rows(1).cols(1).value([32.0]), 2: lambda x: x.rows(1).cols(1).value([36.0]), 3: lambda x: x.rows(1).cols(1).value([40.0]), }) # float4 dummy1; var_check.check('dummy1') # float o[4]; var_check.check('o').rows(0).cols(0).arraySize(4).members({ 0: lambda x: x.rows(1).cols(1).value([48.0]), 1: lambda x: x.rows(1).cols(1).value([52.0]), 2: lambda x: x.rows(1).cols(1).value([56.0]), 3: lambda x: x.rows(1).cols(1).value([60.0]), }) # float p; var_check.check('p').rows(1).cols(1).value([61.0]) # float4 dummy2; var_check.check('dummy2') # float4 dummygl1; # float4 dummygl2; var_check.check('dummygl1') var_check.check('dummygl2') # column_major float4x4 q; var_check.check('q').rows(4).cols(4).column_major().value([ 76.0, 80.0, 84.0, 88.0, 77.0, 81.0, 85.0, 89.0, 78.0, 82.0, 86.0, 90.0, 79.0, 83.0, 87.0, 91.0 ]) # row_major float4x4 r; var_check.check('r').rows(4).cols(4).row_major().value([ 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0, 101.0, 102.0, 103.0, 104.0, 105.0, 106.0, 107.0 ]) # column_major float3x4 s; var_check.check('s').rows(3).cols(4).column_major().value([ 108.0, 112.0, 116.0, 120.0, 109.0, 113.0, 117.0, 121.0, 110.0, 114.0, 118.0, 122.0 ]) # float4 dummy3; var_check.check('dummy3') # row_major float3x4 t; var_check.check('t').rows(3).cols(4).row_major().value([ 128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0, 137.0, 138.0, 139.0 ]) # float4 dummy4; var_check.check('dummy4') # column_major float2x3 u; var_check.check('u').rows(2).cols(3).column_major().value( [144.0, 148.0, 152.0, 145.0, 149.0, 153.0]) # float4 dummy5; var_check.check('dummy5') # row_major float2x3 v; var_check.check('v').rows(2).cols(3).row_major().value( [160.0, 161.0, 162.0, 164.0, 165.0, 166.0]) # float4 dummy6; var_check.check('dummy6') # column_major float2x2 w; var_check.check('w').rows(2).cols(2).column_major().value( [172.0, 176.0, 173.0, 177.0]) # float4 dummy7; var_check.check('dummy7') # row_major float2x2 x; var_check.check('x').rows(2).cols(2).row_major().value( [184.0, 185.0, 188.0, 189.0]) # float4 dummy8; var_check.check('dummy8') # row_major float2x2 y; var_check.check('y').rows(2).cols(2).row_major().value( [196.0, 197.0, 200.0, 201.0]) # float z; var_check.check('z').rows(1).cols(1).value([202.0]) # float4 gldummy3; var_check.check('gldummy3') # row_major float4x1 aa; var_check.check('aa').rows(4).cols(1).value( [208.0, 212.0, 216.0, 220.0]) # column_major float4x1 ab; var_check.check('ab').rows(4).cols(1).value( [224.0, 225.0, 226.0, 227.0]) # float4 multiarray[3][2]; # this is flattened to just multiarray[6] var_check.check('multiarray').rows(0).cols(0).arraySize(6).members({ 0: lambda x: x.rows(1).cols(4).value([228.0, 229.0, 230.0, 231.0]), 1: lambda x: x.rows(1).cols(4).value([232.0, 233.0, 234.0, 235.0]), 2: lambda x: x.rows(1).cols(4).value([236.0, 237.0, 238.0, 239.0]), 3: lambda x: x.rows(1).cols(4).value([240.0, 241.0, 242.0, 243.0]), 4: lambda x: x.rows(1).cols(4).value([244.0, 245.0, 246.0, 247.0]), 5: lambda x: x.rows(1).cols(4).value([248.0, 249.0, 250.0, 251.0]), }) # struct float3_1 { float3 a; float b; }; # struct nested { float3_1 a; float4 b[4]; float3_1 c[4]; }; # nested structa[2]; var_check.check('structa').rows(0).cols(0).arraySize(2).members({ # structa[0] 0: lambda s: s.rows(0).cols(0).structSize(3).members({ 'a': lambda x: x.rows(0).cols(0).structSize(2).members({ 'a': lambda y: y.rows(1).cols(3).value([252.0, 253.0, 254.0]), 'b': lambda y: y.rows(1).cols(1).value([255.0]), }), 'b': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(1).cols(4).value( [256.0, 257.0, 258.0, 259.0]), 1: lambda y: y.rows(1).cols(4).value( [260.0, 261.0, 262.0, 263.0]), 2: lambda y: y.rows(1).cols(4).value( [264.0, 265.0, 266.0, 267.0]), 3: lambda y: y.rows(1).cols(4).value( [268.0, 269.0, 270.0, 271.0]), }), 'c': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [272.0, 273.0, 274.0]), 'b': lambda z: z.rows(1).cols(1).value([275.0]), }), 1: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [276.0, 277.0, 278.0]), 'b': lambda z: z.rows(1).cols(1).value([279.0]), }), 2: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [280.0, 281.0, 282.0]), 'b': lambda z: z.rows(1).cols(1).value([283.0]), }), 3: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [284.0, 285.0, 286.0]), 'b': lambda z: z.rows(1).cols(1).value([287.0]), }), }), }), # structa[1] 1: lambda s: s.rows(0).cols(0).structSize(3).members({ 'a': lambda x: x.rows(0).cols(0).structSize(2).members({ 'a': lambda y: y.rows(1).cols(3).value([288.0, 289.0, 290.0]), 'b': lambda y: y.rows(1).cols(1).value([291.0]), }), 'b': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(1).cols(4).value( [292.0, 293.0, 294.0, 295.0]), 1: lambda y: y.rows(1).cols(4).value( [296.0, 297.0, 298.0, 299.0]), 2: lambda y: y.rows(1).cols(4).value( [300.0, 301.0, 302.0, 303.0]), 3: lambda y: y.rows(1).cols(4).value( [304.0, 305.0, 306.0, 307.0]), }), 'c': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [308.0, 309.0, 310.0]), 'b': lambda z: z.rows(1).cols(1).value([311.0]), }), 1: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [312.0, 313.0, 314.0]), 'b': lambda z: z.rows(1).cols(1).value([315.0]), }), 2: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [316.0, 317.0, 318.0]), 'b': lambda z: z.rows(1).cols(1).value([319.0]), }), 3: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [320.0, 321.0, 322.0]), 'b': lambda z: z.rows(1).cols(1).value([323.0]), }), }), }), }) # column_major float3x2 ac; var_check.check('ac').rows(3).cols(2).column_major().value( [324.0, 328.0, 325.0, 329.0, 326.0, 330.0]) # row_major float3x2 ad; var_check.check('ad').rows(3).cols(2).row_major().value( [332.0, 333.0, 336.0, 337.0, 340.0, 341.0]) # column_major float3x2 ae[2]; var_check.check('ae').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(3).cols(2).column_major().value( [344.0, 348.0, 345.0, 349.0, 346.0, 350.0]), 1: lambda x: x.rows(3).cols(2).column_major().value( [352.0, 356.0, 353.0, 357.0, 354.0, 358.0]), }) # row_major float3x2 af[2]; var_check.check('af').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(3).cols(2).row_major().value( [360.0, 361.0, 364.0, 365.0, 368.0, 369.0]), 1: lambda x: x.rows(3).cols(2).row_major().value( [372.0, 373.0, 376.0, 377.0, 380.0, 381.0]), }) # float2 dummy9; var_check.check('dummy9') # float2 dummy10; var_check.check('dummy10') # row_major float2x2 ag; var_check.check('ag').rows(2).cols(2).row_major().value( [388.0, 389.0, 392.0, 393.0]) # float2 dummy11; var_check.check('dummy11') # float2 dummy12; var_check.check('dummy12') # column_major float2x2 ah; var_check.check('ah').rows(2).cols(2).column_major().value( [400.0, 404.0, 401.0, 405.0]) # row_major float2x2 ai[2]; var_check.check('ai').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(2).row_major().value( [408.0, 409.0, 412.0, 413.0]), 1: lambda x: x.rows(2).cols(2).row_major().value( [416.0, 417.0, 420.0, 421.0]), }) # column_major float2x2 aj[2]; var_check.check('aj').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(2).column_major().value( [424.0, 428.0, 425.0, 429.0]), 1: lambda x: x.rows(2).cols(2).column_major().value( [432.0, 436.0, 433.0, 437.0]), }) # float4 test; var_check.check('test').rows(1).cols(4).value( [440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("CBuffer variables are as expected") tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Picked value is as expected") cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetGraphicsPipelineObject(), pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 1, cbuf.resourceId, cbuf.byteOffset)) # float4 zero; var_check.check('root_zero').rows(1).cols(4).value( [0.0, 0.0, 0.0, 0.0]) # float4 a; var_check.check('root_a').rows(1).cols(4).value( [10.0, 20.0, 30.0, 40.0]) # float2 b; var_check.check('root_b').rows(1).cols(2).value([50.0, 60.0]) # float2 c; var_check.check('root_c').rows(1).cols(2).value([70.0, 80.0]) # float3_1 d; var_check.check('root_d').rows(0).cols(0).structSize(2).members({ 'a': lambda y: y.rows(1).cols(3).value([90.0, 100.0, 110.0]), 'b': lambda y: y.rows(1).cols(1).value([120.0]), }) var_check.done() rdtest.log.success("Root signature variables are as expected") out.Shutdown()
def check_capture(self): self.check_final_backbuffer() out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) self.check(out is not None) out.SetDimensions(100, 100) test_marker: rd.DrawcallDescription = self.find_draw("Test") self.controller.SetFrameEvent(test_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue # Unfortunately line-fill rendering seems to vary too much by IHV, so gives inconsistent results if overlay == rd.DebugOverlay.Wireframe: continue tex.overlay = overlay out.SetTextureDisplay(tex) overlay_path = rdtest.get_tmp_path(str(overlay) + '.png') ref_path = self.get_ref_path(str(overlay) + '.png') save_data = rd.TextureSave() save_data.resourceId = out.GetDebugOverlayTexID() save_data.destType = rd.FileType.PNG save_data.comp.blackPoint = 0.0 save_data.comp.whitePoint = 1.0 tolerance = 2 # These overlays return grayscale above 1, so rescale to an expected range. if (overlay == rd.DebugOverlay.QuadOverdrawDraw or overlay == rd.DebugOverlay.QuadOverdrawPass or overlay == rd.DebugOverlay.TriangleSizeDraw or overlay == rd.DebugOverlay.TriangleSizePass): save_data.comp.whitePoint = 10.0 # These overlays modify the underlying texture, so we need to save it out instead of the overlay if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: save_data.resourceId = tex.resourceId self.controller.SaveTexture(save_data, overlay_path) if not rdtest.image_compare(overlay_path, ref_path, tolerance): raise rdtest.TestFailureException("Reference and output image differ for overlay {}".format(str(overlay)), overlay_path, ref_path) rdtest.log.success("Reference and output image are identical for {}".format(str(overlay))) save_data = rd.TextureSave() save_data.resourceId = pipe.GetDepthTarget().resourceId save_data.destType = rd.FileType.PNG save_data.channelExtract = 0 tmp_path = rdtest.get_tmp_path('depth.png') ref_path = self.get_ref_path('depth.png') self.controller.SaveTexture(save_data, tmp_path) if not rdtest.image_compare(tmp_path, ref_path): raise rdtest.TestFailureException("Reference and output image differ for depth {}", tmp_path, ref_path) rdtest.log.success("Reference and output image are identical for depth") save_data.channelExtract = 1 tmp_path = rdtest.get_tmp_path('stencil.png') ref_path = self.get_ref_path('stencil.png') self.controller.SaveTexture(save_data, tmp_path) if not rdtest.image_compare(tmp_path, ref_path): raise rdtest.TestFailureException("Reference and output image differ for stencil {}", tmp_path, ref_path) rdtest.log.success("Reference and output image are identical for stencil") out.Shutdown()
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) ref = { 0: { 'SNorm': [1.0, -1.0, 1.0, -1.0], 'UNorm': [12345.0/65535.0, 6789.0/65535.0, 1234.0/65535.0, 567.0/65535.0], 'UScaled': [12345.0, 6789.0, 1234.0, 567.0], 'UInt': [12345, 6789, 1234, 567], 'Double': [9.8765432109, -5.6789012345], 'Array[0]': [1.0, 2.0], 'Array[1]': [3.0, 4.0], 'Array[2]': [5.0, 6.0], 'Matrix:row0': [7.0, 8.0], 'Matrix:row1': [9.0, 10.0], }, 1: { 'SNorm': [32766.0/32767.0, -32766.0/32767.0, 16000.0/32767.0, -16000.0/32767.0], 'UNorm': [56.0/65535.0, 7890.0/65535.0, 123.0/65535.0, 4567.0/65535.0], 'UScaled': [56.0, 7890.0, 123.0, 4567.0], 'UInt': [56, 7890, 123, 4567], 'Double': [-7.89012345678, 6.54321098765], 'Array[0]': [11.0, 12.0], 'Array[1]': [13.0, 14.0], 'Array[2]': [15.0, 16.0], 'Matrix:row0': [17.0, 18.0], 'Matrix:row1': [19.0, 20.0], }, 2: { 'SNorm': [5.0/32767.0, -5.0/32767.0, 0.0, 0.0], 'UNorm': [8765.0/65535.0, 43210.0/65535.0, 987.0/65535.0, 65432.0/65535.0], 'UScaled': [8765.0, 43210.0, 987.0, 65432.0], 'UInt': [8765, 43210, 987, 65432], 'Double': [0.1234567890123, 4.5678901234], 'Array[0]': [21.0, 22.0], 'Array[1]': [23.0, 24.0], 'Array[2]': [25.0, 26.0], 'Matrix:row0': [27.0, 28.0], 'Matrix:row1': [29.0, 30.0], }, } # Copy the ref values and prepend 'In' in_ref = {} for idx in ref: in_ref[idx] = {} for key in ref[idx]: in_ref[idx]['In' + key] = ref[idx][key] # Copy the ref values and prepend 'Out' out_ref = {} for idx in ref: out_ref[idx] = {} for key in ref[idx]: out_ref[idx]['Out' + key] = ref[idx][key] vsout_ref = copy.deepcopy(out_ref) gsout_ref = out_ref vsout_ref[0]['gl_PerVertex.gl_Position'] = [-0.5, 0.5, 0.0, 1.0] gsout_ref[0]['gl_PerVertex.gl_Position'] = [0.5, -0.5, 0.4, 1.2] vsout_ref[1]['gl_PerVertex.gl_Position'] = [0.0, -0.5, 0.0, 1.0] gsout_ref[1]['gl_PerVertex.gl_Position'] = [-0.5, 0.0, 0.4, 1.2] vsout_ref[2]['gl_PerVertex.gl_Position'] = [0.5, 0.5, 0.0, 1.0] gsout_ref[2]['gl_PerVertex.gl_Position'] = [0.5, 0.5, 0.4, 1.2] self.check_mesh_data(in_ref, self.get_vsin(draw)) rdtest.log.success("Vertex input data is as expected") self.check_mesh_data(vsout_ref, self.get_postvs(rd.MeshDataStage.VSOut)) rdtest.log.success("Vertex output data is as expected") # This is optional to account for drivers without XFB postgs_data = self.get_postvs(rd.MeshDataStage.GSOut) if len(postgs_data) > 0: self.check_mesh_data(gsout_ref, postgs_data) rdtest.log.success("Geometry output data is as expected") else: rdtest.log.print("Geometry output not tested") pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [0.0, 1.0, 0.0, 1.0]): raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) rdtest.log.success("Triangle picked value is as expected") out.Shutdown()
def check_capture(self): out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) test_marker: rd.DrawcallDescription = self.find_draw("Test") self.controller.SetFrameEvent(test_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId # Check the actual output is as expected first. # Background around the outside self.check_pixel_value(tex.resourceId, 0.1, 0.1, [0.2, 0.2, 0.2, 1.0]) self.check_pixel_value(tex.resourceId, 0.8, 0.1, [0.2, 0.2, 0.2, 1.0]) self.check_pixel_value(tex.resourceId, 0.5, 0.95, [0.2, 0.2, 0.2, 1.0]) # Large dark grey triangle self.check_pixel_value(tex.resourceId, 0.5, 0.1, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(tex.resourceId, 0.5, 0.9, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(tex.resourceId, 0.2, 0.9, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(tex.resourceId, 0.8, 0.9, [0.1, 0.1, 0.1, 1.0]) # Red upper half triangle self.check_pixel_value(tex.resourceId, 0.3, 0.4, [1.0, 0.0, 0.0, 1.0]) # Blue lower half triangle self.check_pixel_value(tex.resourceId, 0.3, 0.6, [0.0, 0.0, 1.0, 1.0]) # Floating clipped triangle self.check_pixel_value(tex.resourceId, 335, 140, [0.0, 0.0, 0.0, 1.0]) self.check_pixel_value(tex.resourceId, 340, 140, [0.2, 0.2, 0.2, 1.0]) # Triangle size triangles self.check_pixel_value(tex.resourceId, 200, 51, [1.0, 0.5, 1.0, 1.0]) self.check_pixel_value(tex.resourceId, 200, 65, [1.0, 1.0, 0.0, 1.0]) self.check_pixel_value(tex.resourceId, 200, 79, [0.0, 1.0, 1.0, 1.0]) self.check_pixel_value(tex.resourceId, 200, 93, [0.0, 1.0, 0.0, 1.0]) for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue # Unfortunately line-fill rendering seems to vary too much by IHV, so gives inconsistent results if overlay == rd.DebugOverlay.Wireframe: continue tex.overlay = overlay out.SetTextureDisplay(tex) overlay_path = rdtest.get_tmp_path(str(overlay) + '.png') ref_path = self.get_ref_path(str(overlay) + '.png') save_data = rd.TextureSave() save_data.resourceId = out.GetDebugOverlayTexID() save_data.destType = rd.FileType.PNG save_data.typeCast = rd.CompType.Typeless save_data.comp.blackPoint = 0.0 save_data.comp.whitePoint = 1.0 tolerance = 2 # These overlays return grayscale above 1, so rescale to an expected range. if (overlay == rd.DebugOverlay.QuadOverdrawDraw or overlay == rd.DebugOverlay.QuadOverdrawPass or overlay == rd.DebugOverlay.TriangleSizeDraw or overlay == rd.DebugOverlay.TriangleSizePass): save_data.comp.whitePoint = 10.0 # These overlays modify the underlying texture, so we need to save it out instead of the overlay if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: save_data.resourceId = tex.resourceId save_data.typeCast = rd.CompType.UNormSRGB self.controller.SaveTexture(save_data, overlay_path) if not rdtest.png_compare(overlay_path, ref_path, tolerance): raise rdtest.TestFailureException( "Reference and output image differ for overlay {}".format( str(overlay)), overlay_path, ref_path) rdtest.log.success( "Reference and output image are identical for {}".format( str(overlay))) save_data = rd.TextureSave() save_data.resourceId = pipe.GetDepthTarget().resourceId save_data.destType = rd.FileType.PNG save_data.channelExtract = 0 tmp_path = rdtest.get_tmp_path('depth.png') ref_path = self.get_ref_path('depth.png') self.controller.SaveTexture(save_data, tmp_path) if not rdtest.png_compare(tmp_path, ref_path): raise rdtest.TestFailureException( "Reference and output image differ for depth {}", tmp_path, ref_path) rdtest.log.success( "Reference and output image are identical for depth") save_data.channelExtract = 1 tmp_path = rdtest.get_tmp_path('stencil.png') ref_path = self.get_ref_path('stencil.png') self.controller.SaveTexture(save_data, tmp_path) if not rdtest.png_compare(tmp_path, ref_path): raise rdtest.TestFailureException( "Reference and output image differ for stencil {}", tmp_path, ref_path) rdtest.log.success( "Reference and output image are identical for stencil") self.check_clearbeforedraw_depth(out, pipe.GetDepthTarget().resourceId) out.Shutdown()
def check_capture_with_controller(self, proxy_api: str): any_failed = False if proxy_api != '': rdtest.log.print('Running with {} local proxy'.format(proxy_api)) self.proxied = True else: rdtest.log.print('Running on direct replay') self.proxied = False self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) for d in self.controller.GetDrawcalls(): # Check each region for the tests within if d.flags & rd.DrawFlags.PushMarker: name = '' tests_run = 0 failed = False # Iterate over drawcalls in this region for sub in d.children: sub: rd.DrawcallDescription if sub.flags & rd.DrawFlags.SetMarker: name = sub.name # Check this draw if sub.flags & rd.DrawFlags.Drawcall: tests_run = tests_run + 1 try: # Set this event as current self.controller.SetFrameEvent(sub.eventId, True) self.filename = (d.name + '@' + name).replace( '->', '_') self.check_test(d.name, name, Texture_Zoo.TEST_CAPTURE) except rdtest.TestFailureException as ex: failed = any_failed = True rdtest.log.error(str(ex)) if not failed: rdtest.log.success( "All {} texture tests for {} are OK".format( tests_run, d.name)) self.out.Shutdown() self.out = None if not any_failed: if proxy_api != '': rdtest.log.success( 'All textures are OK with {} as local proxy'.format( proxy_api)) else: rdtest.log.success("All textures are OK on direct replay") else: raise rdtest.TestFailureException( "Some tests were not as expected")
def check_capture(self): id = self.get_last_draw().copyDestination tex_details = self.get_texture(id) self.controller.SetFrameEvent(self.get_last_draw().eventId, True) data = self.controller.GetTextureData(id, rd.Subresource(0, 0, 0)) first_pixel = struct.unpack_from("BBBB", data, 0) val = [255, 0, 255, 255] if not rdtest.value_compare(first_pixel, val): raise rdtest.TestFailureException( "First pixel should be clear color {}, not {}".format( val, first_pixel)) magic_pixel = struct.unpack_from("BBBB", data, (50 * tex_details.width + 320) * 4) # allow 127 or 128 for alpha val = [0, 0, 255, magic_pixel[3]] if not rdtest.value_compare(magic_pixel, val) or magic_pixel[3] not in [127, 128]: raise rdtest.TestFailureException( "Pixel @ 320,50 should be blue: {}, not {}".format( val, magic_pixel)) rdtest.log.success("Decoded pixels from texture data are correct") img_path = rdtest.get_tmp_path('preserved_alpha.png') self.controller.SetFrameEvent(self.get_last_draw().eventId, True) save_data = rd.TextureSave() save_data.resourceId = id save_data.destType = rd.FileType.PNG save_data.alpha = rd.AlphaMapping.Discard # this should not discard the alpha self.controller.SaveTexture(save_data, img_path) data = rdtest.png_load_data(img_path) magic_pixel = struct.unpack_from("BBBB", data[-1 - 50], 320 * 4) val = [0, 0, 255, magic_pixel[3]] if not rdtest.value_compare(magic_pixel, val) or magic_pixel[3] not in [127, 128]: raise rdtest.TestFailureException( "Pixel @ 320,50 should be blue: {}, not {}".format( val, magic_pixel)) draw = self.find_draw("Draw") self.controller.SetFrameEvent(draw.eventId, False) postvs_data = self.get_postvs(draw, rd.MeshDataStage.VSOut, 0, draw.numIndices) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_Position': [-0.5, -0.5, 0.0, 1.0], 'v2fcol': [0.0, 1.0, 0.0, 1.0], }, 1: { 'vtx': 1, 'idx': 1, 'gl_Position': [0.0, 0.5, 0.0, 1.0], 'v2fcol': [0.0, 1.0, 0.0, 1.0], }, 2: { 'vtx': 2, 'idx': 2, 'gl_Position': [0.5, -0.5, 0.0, 1.0], 'v2fcol': [0.0, 1.0, 0.0, 1.0], }, } self.check_mesh_data(postvs_ref, postvs_data) results = self.controller.FetchCounters([ rd.GPUCounter.RasterizedPrimitives, rd.GPUCounter.VSInvocations, rd.GPUCounter.FSInvocations ]) results = [r for r in results if r.eventId == draw.eventId] if len(results) != 3: raise rdtest.TestFailureException( "Expected 3 results, got {} results".format(len(results))) for r in results: r: rd.CounterResult val = r.value.u32 if r.counter == rd.GPUCounter.RasterizedPrimitives: if not rdtest.value_compare(val, 1): raise rdtest.TestFailureException( "RasterizedPrimitives result {} is not as expected". format(val)) else: rdtest.log.success( "RasterizedPrimitives result is as expected") elif r.counter == rd.GPUCounter.VSInvocations: if not rdtest.value_compare(val, 3): raise rdtest.TestFailureException( "VSInvocations result {} is not as expected".format( val)) else: rdtest.log.success("VSInvocations result is as expected") elif r.counter == rd.GPUCounter.FSInvocations: if val < int(0.1 * tex_details.width * tex_details.height): raise rdtest.TestFailureException( "FSInvocations result {} is not as expected".format( val)) else: rdtest.log.success("FSInvocations result is as expected") else: raise rdtest.TestFailureException( "Unexpected counter result {}".format(r.counter)) rdtest.log.success("Counter data retrieved successfully") draw = self.find_draw("NoScissor") self.check(draw is not None) draw = draw.next pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.Drawcall tex.resourceId = pipe.GetOutputTargets()[0].resourceId out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) out.SetTextureDisplay(tex) out.Display() overlay_id = out.GetDebugOverlayTexID() v = pipe.GetViewport(0) self.check_pixel_value(overlay_id, int(0.5 * v.width), int(0.5 * v.height), [0.8, 0.1, 0.8, 1.0], eps=1.0 / 256.0) out.Shutdown() rdtest.log.success("Overlay color is as expected")
def check_capture(self): # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) tex = rd.TextureDisplay() # At each draw, the centre pixel of the viewport should be green draw = self.get_first_draw() while draw is not None: self.controller.SetFrameEvent(draw.eventId, False) if draw.flags & rd.DrawFlags.Drawcall: tex.resourceId = self.controller.GetPipelineState( ).GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) view: rd.Viewport = self.controller.GetPipelineState( ).GetViewport(0) x, y = int(view.x + view.width / 2), int(view.y + view.height / 2) # convert to top-left co-ordinates for use with PickPixel y = self.get_texture(tex.resourceId).height - y picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, x, y, 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [0.0, 1.0, 0.0, 1.0]): raise rdtest.TestFailureException( "Picked value {} at {} doesn't match expected green". format(picked.floatValue, (x, y))) draw = draw.next rdtest.log.success("Draws are all green") # Now save the backbuffer to disk ref_path = rdtest.get_tmp_path('backbuffer.png') save_data = rd.TextureSave() save_data.resourceId = tex.resourceId save_data.destType = rd.FileType.PNG self.controller.SaveTexture(save_data, ref_path) # Open the capture and grab the thumbnail, check that it is all green too (dirty way of verifying we didn't # break in-app updates but somehow end up with the right data) cap = rd.OpenCaptureFile() # Open a particular file status = cap.OpenFile(self.capture_filename, '', None) # Make sure the file opened successfully if status != rd.ReplayStatus.Succeeded: cap.Shutdown() raise rdtest.TestFailureException("Couldn't open '{}': {}".format( self.capture_filename, str(status))) thumb: rd.Thumbnail = cap.GetThumbnail(rd.FileType.PNG, 0) tmp_path = rdtest.get_tmp_path('thumbnail.png') with open(tmp_path, 'wb') as f: f.write(thumb.data) # The original thumbnail should also be identical, since we have the uncompressed extended thumbnail. if not rdtest.png_compare(tmp_path, ref_path): raise rdtest.TestFailureException( "Reference backbuffer and thumbnail image differ", tmp_path, ref_path) rdtest.log.success("Thumbnail is identical to reference") out.Shutdown()
def check_capture(self): last_action: rd.ActionDescription = self.get_last_action() self.controller.SetFrameEvent(last_action.eventId, True) self.check_triangle(out=last_action.copyDestination) rdtest.log.success("Triangle output looks correct") action = self.find_action('CmdDraw') self.controller.SetFrameEvent(action.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() vkpipe = self.controller.GetVulkanPipelineState() binding = vkpipe.graphics.descriptorSets[0].bindings[0] if binding.dynamicallyUsedCount != 1: raise rdtest.TestFailureException( "Bind 0 doesn't have the right used count {}".format( binding.dynamicallyUsedCount)) if not binding.binds[15].dynamicallyUsed: raise rdtest.TestFailureException( "Graphics bind 0[15] isn't dynamically used") refl: rd.ShaderReflection = pipe.GetShaderReflection( rd.ShaderStage.Vertex) self.check(len(refl.readOnlyResources) == 0) postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, first_index=0, num_indices=1, instance=0) trace: rd.ShaderDebugTrace = self.controller.DebugVertex(0, 0, 0, 0) if trace.debugger is None: raise rdtest.TestFailureException("No vertex debug result") cycles, variables = self.process_trace(trace) outputs = 0 for var in trace.sourceVars: var: rd.SourceVariableMapping if var.variables[ 0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0: name = var.name if name not in postvs[0].keys(): raise rdtest.TestFailureException( "Don't have expected output for {}".format(name)) expect = postvs[0][name] value = self.evaluate_source_var(var, variables) if len(expect) != value.columns: raise rdtest.TestFailureException( "Vertex output {} has different size ({} values) to expectation ({} values)" .format(name, action.eventId, value.columns, len(expect))) compType = rd.VarTypeCompType(value.type) if compType == rd.CompType.UInt: debugged = list(value.value.u32v[0:value.columns]) elif compType == rd.CompType.SInt: debugged = list(value.value.s32v[0:value.columns]) else: debugged = list(value.value.f32v[0:value.columns]) is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06) if not is_eq: rdtest.log.error( "Debugged vertex output value {}: {} difference. {} doesn't exactly match postvs output {}" .format(name, action.eventId, diff_amt, debugged, expect)) outputs = outputs + 1 rdtest.log.success( 'Successfully debugged vertex in {} cycles, {}/{} outputs match'. format(cycles, outputs, len(refl.outputSignature))) self.controller.FreeTrace(trace) history = self.controller.PixelHistory( pipe.GetOutputTargets()[0].resourceId, 200, 150, rd.Subresource(0, 0, 0), rd.CompType.Typeless) # should be a clear then a draw self.check(len(history) == 2) self.check( self.find_action('', history[0].eventId).flags & rd.ActionFlags.Clear) self.check( self.find_action('', history[1].eventId).eventId == action.eventId) self.check(history[1].Passed()) if not rdtest.value_compare(history[1].shaderOut.col.floatValue, (0.0, 1.0, 0.0, 1.0)): raise rdtest.TestFailureException( "History for drawcall output is wrong: {}".format( history[1].shaderOut.col.floatValue)) trace = self.controller.DebugPixel(200, 150, 0, 0) refl: rd.ShaderReflection = pipe.GetShaderReflection( rd.ShaderStage.Pixel) self.check(len(refl.readOnlyResources) == 1) if trace.debugger is None: raise rdtest.TestFailureException("No pixel debug result") cycles, variables = self.process_trace(trace) output_sourcevar = self.find_output_source_var( trace, rd.ShaderBuiltin.ColorOutput, 0) if output_sourcevar is None: raise rdtest.TestFailureException( "Couldn't get colour output value") debugged = self.evaluate_source_var(output_sourcevar, variables) self.controller.FreeTrace(trace) debuggedValue = list(debugged.value.f32v[0:4]) is_eq, diff_amt = rdtest.value_compare_diff( history[1].shaderOut.col.floatValue, debuggedValue, eps=5.0E-06) if not is_eq: rdtest.log.error( "Debugged pixel value {}: {} difference. {} doesn't exactly match history shader output {}" .format(debugged.name, diff_amt, debuggedValue, history[1].shaderOut.col.floatValue)) rdtest.log.success( 'Successfully debugged pixel in {} cycles, result matches'.format( cycles)) out = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId tex.overlay = rd.DebugOverlay.TriangleSizeDraw out.SetTextureDisplay(tex) out.Display() overlay_id = out.GetDebugOverlayTexID() self.check_pixel_value(overlay_id, 200, 150, [14992.0, 14992.0, 14992.0, 1.0]) rdtest.log.success("Triangle size overlay gave correct output") out.Shutdown()
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetGraphicsPipelineObject(), pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 0, cbuf.resourceId, cbuf.byteOffset)) # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself # vec4 a; var_check.check('a').cols(4).rows(1).value([0.0, 1.0, 2.0, 3.0]) # vec3 b; var_check.check('b').cols(3).rows(1).value([4.0, 5.0, 6.0]) # vec2 c; vec2 d; var_check.check('c').cols(2).rows(1).value([8.0, 9.0]) var_check.check('d').cols(2).rows(1).value([10.0, 11.0]) # float e; vec3 f; var_check.check('e').cols(1).rows(1).value([12.0]) var_check.check('f').cols(3).rows(1).value([16.0, 17.0, 18.0]) # vec4 dummy0; var_check.check('dummy0') # float j; vec2 k; var_check.check('j').cols(1).rows(1).value([24.0]) var_check.check('k').cols(2).rows(1).value([26.0, 27.0]) # vec2 l; float m; var_check.check('l').cols(2).rows(1).value([28.0, 29.0]) var_check.check('m').cols(1).rows(1).value([30.0]) # float n[4]; var_check.check('n').cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(1).rows(1).value([32.0]), 1: lambda x: x.cols(1).rows(1).value([36.0]), 2: lambda x: x.cols(1).rows(1).value([40.0]), 3: lambda x: x.cols(1).rows(1).value([44.0]), }) # vec4 dummy1; var_check.check('dummy1') # float o[4]; var_check.check('o').cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(1).rows(1).value([52.0]), 1: lambda x: x.cols(1).rows(1).value([56.0]), 2: lambda x: x.cols(1).rows(1).value([60.0]), 3: lambda x: x.cols(1).rows(1).value([64.0]), }) # float p; var_check.check('p').cols(1).rows(1).value([68.0]) # vec4 dummy2; var_check.check('dummy2') # column_major vec4x4 q; var_check.check('q').cols(4).rows(4).column_major().value([ 76.0, 80.0, 84.0, 88.0, 77.0, 81.0, 85.0, 89.0, 78.0, 82.0, 86.0, 90.0, 79.0, 83.0, 87.0, 91.0 ]) # row_major vec4x4 r; var_check.check('r').cols(4).rows(4).row_major().value([ 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0, 101.0, 102.0, 103.0 ]) # column_major vec4x3 s; var_check.check('s').cols(4).rows(3).column_major().value([ 108.0, 112.0, 116.0, 120.0, 109.0, 113.0, 117.0, 121.0, 110.0, 114.0, 118.0, 122.0 ]) # vec4 dummy3; var_check.check('dummy3') # row_major vec4x3 t; var_check.check('t').cols(4).rows(3).row_major().value([ 128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0, 137.0, 138.0, 139.0 ]) # vec4 dummy4; var_check.check('dummy4') # column_major vec2x3 u; var_check.check('u').cols(3).rows(2).column_major().value( [144.0, 148.0, 152.0, 145.0, 149.0, 153.0]) # vec4 dummy5; var_check.check('dummy5') # row_major vec3x2 v; var_check.check('v').cols(3).rows(2).row_major().value( [160.0, 161.0, 162.0, 164.0, 165.0, 166.0]) # vec4 dummy6; var_check.check('dummy6') # column_major vec3x2 w; var_check.check('w').cols(2).rows(2).column_major().value( [172.0, 176.0, 173.0, 177.0]) # vec4 dummy7; var_check.check('dummy7') # row_major vec3x2 x; var_check.check('x').cols(2).rows(2).row_major().value( [184.0, 185.0, 188.0, 189.0]) # vec4 dummy8; var_check.check('dummy8') # row_major vec2x2 y; var_check.check('y').cols(2).rows(2).row_major().value( [196.0, 197.0, 200.0, 201.0]) # float z; var_check.check('z').cols(1).rows(1).value([204.0]) # vec4 dummy9; var_check.check('dummy9') # vec4 multiarray[3][2]; var_check.check('multiarray').cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([228.0, 229.0, 230.0, 231.0] ), 1: lambda y: y.cols(4).rows(1).value([232.0, 233.0, 234.0, 235.0] ), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([236.0, 237.0, 238.0, 239.0] ), 1: lambda y: y.cols(4).rows(1).value([240.0, 241.0, 242.0, 243.0] ), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([244.0, 245.0, 246.0, 247.0] ), 1: lambda y: y.cols(4).rows(1).value([248.0, 249.0, 250.0, 251.0] ), }), }) # struct vec3_1 { vec3 a; float b; }; # struct nested { vec3_1 a; vec4 b[4]; vec3_1 c[4]; }; # nested structa[2]; var_check.check('structa').cols(0).rows(0).arraySize(2).members({ # structa[0] 0: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).structSize(2).members({ 'a': lambda y: y.cols(3).rows(1).value([252.0, 253.0, 254.0]), 'b': lambda y: y.cols(1).rows(1).value([255.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(4).rows(1).value( [256.0, 257.0, 258.0, 259.0]), 1: lambda y: y.cols(4).rows(1).value( [260.0, 261.0, 262.0, 263.0]), 2: lambda y: y.cols(4).rows(1).value( [264.0, 265.0, 266.0, 267.0]), 3: lambda y: y.cols(4).rows(1).value( [268.0, 269.0, 270.0, 271.0]), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [272.0, 273.0, 274.0]), 'b': lambda z: z.cols(1).rows(1).value([275.0]), }), 1: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [276.0, 277.0, 278.0]), 'b': lambda z: z.cols(1).rows(1).value([279.0]), }), 2: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [280.0, 281.0, 282.0]), 'b': lambda z: z.cols(1).rows(1).value([283.0]), }), 3: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [284.0, 285.0, 286.0]), 'b': lambda z: z.cols(1).rows(1).value([287.0]), }), }), }), # structa[1] 1: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).structSize(2).members({ 'a': lambda y: y.cols(3).rows(1).value([288.0, 289.0, 290.0]), 'b': lambda y: y.cols(1).rows(1).value([291.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(4).rows(1).value( [292.0, 293.0, 294.0, 295.0]), 1: lambda y: y.cols(4).rows(1).value( [296.0, 297.0, 298.0, 299.0]), 2: lambda y: y.cols(4).rows(1).value( [300.0, 301.0, 302.0, 303.0]), 3: lambda y: y.cols(4).rows(1).value( [304.0, 305.0, 306.0, 307.0]), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [308.0, 309.0, 310.0]), 'b': lambda z: z.cols(1).rows(1).value([311.0]), }), 1: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [312.0, 313.0, 314.0]), 'b': lambda z: z.cols(1).rows(1).value([315.0]), }), 2: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [316.0, 317.0, 318.0]), 'b': lambda z: z.cols(1).rows(1).value([319.0]), }), 3: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [320.0, 321.0, 322.0]), 'b': lambda z: z.cols(1).rows(1).value([323.0]), }), }), }), }) # column_major mat2x3 ac; var_check.check('ac').cols(2).rows(3).column_major().value( [324.0, 328.0, 325.0, 329.0, 326.0, 330.0]) # row_major mat2x3 ad; var_check.check('ad').cols(2).rows(3).row_major().value( [332.0, 333.0, 336.0, 337.0, 340.0, 341.0]) # column_major mat2x3 ae[2]; var_check.check('ae').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(3).column_major().value( [344.0, 348.0, 345.0, 349.0, 346.0, 350.0]), 1: lambda x: x.cols(2).rows(3).column_major().value( [352.0, 356.0, 353.0, 357.0, 354.0, 358.0]), }) # row_major mat2x3 af[2]; var_check.check('af').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(3).row_major().value( [360.0, 361.0, 364.0, 365.0, 368.0, 369.0]), 1: lambda x: x.cols(2).rows(3).row_major().value( [372.0, 373.0, 376.0, 377.0, 380.0, 381.0]), }) # vec2 dummy10; var_check.check('dummy10') # row_major mat2x2 ag; var_check.check('ag').cols(2).rows(2).row_major().value( [388.0, 389.0, 392.0, 393.0]) # vec2 dummy12; var_check.check('dummy11') # column_major float2x2 ah; var_check.check('ah').cols(2).rows(2).column_major().value( [400.0, 404.0, 401.0, 405.0]) # row_major mat2x2 ai[2]; var_check.check('ai').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(2).row_major().value( [408.0, 409.0, 412.0, 413.0]), 1: lambda x: x.cols(2).rows(2).row_major().value( [416.0, 417.0, 420.0, 421.0]), }) # column_major mat2x2 aj[2]; var_check.check('aj').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(2).column_major().value( [424.0, 428.0, 425.0, 429.0]), 1: lambda x: x.cols(2).rows(2).column_major().value( [432.0, 436.0, 433.0, 437.0]), }) # vec4 test; var_check.check('test').rows(1).cols(4).value( [440.0, 441.0, 442.0, 443.0]) # to save duplicating if this array changes, we calculate out from the start, as the array is tightly packed base = 444.0 exp_vals = lambda wi, yi, xi: [ base + wi * 24.0 + yi * 8.0 + xi * 4.0 + c * 1.0 for c in range(0, 4) ] # vec4 multiarray2[4][3][2]; var_check.check('multiarray2').cols(0).rows(0).arraySize(4).members({ 0: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 0, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 1, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 2, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 2, 1)), }), }), 1: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 0, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 1, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 2, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 2, 1)), }), }), 2: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 0, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 1, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 2, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 2, 1)), }), }), 3: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 0, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 1, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 2, 0)), 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 2, 1)), }), }), }) var_check.done() rdtest.log.success("CBuffer variables are as expected") tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Picked value is as expected") cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetGraphicsPipelineObject(), pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 1, cbuf.resourceId, cbuf.byteOffset)) # For bare uniforms we have partial data - only values used in the shader need to get assigned locations and # some drivers are aggressive about stripping any others. Only uniforms with locations get upload values. # Hence some of these checks don't check for the value - that means they might not be present # vec4 A; var_check.check('A').cols(4).rows(1).value([10.0, 20.0, 30.0, 40.0]) # vec2 B; var_check.check('B').cols(2).rows(1).value([50.0, 60.0]) # vec3 C; var_check.check('C').cols(3).rows(1).value([70.0, 80.0, 90.0]) # mat2x3 D; var_check.check('D').cols(2).rows(3).value( [100.0, 130.0, 110.0, 140.0, 120.0, 150.0]) # float E[3]; var_check.check('E').cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(1).rows(1).value([160.0]), 1: lambda x: x.cols(1).rows(1).value([170.0]), 2: lambda x: x.cols(1).rows(1).value([180.0]), }) # vec4 F[3][2][2]; # Multidimensional arrays are represented as structs with N members # Due to lacking reflection, we skip structSize() checks, but check everything else if it's present (if it's # not, it will be skipped) var_check.check('F').cols(0).rows(0).members({ '[0]': lambda x: x.cols(0).rows(0).members({ '[0]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [190.0, 200.0, 210.0, 220.0]), 1: lambda x: x.cols(4).rows(1).value( [230.0, 240.0, 250.0, 260.0]), }), '[1]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [270.0, 280.0, 290.0, 300.0]), 1: lambda x: x.cols(4).rows(1).value( [310.0, 320.0, 330.0, 340.0]), }), }), '[1]': lambda x: x.cols(0).rows(0).members({ '[0]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [350.0, 360.0, 370.0, 380.0]), 1: lambda x: x.cols(4).rows(1).value( [390.0, 400.0, 410.0, 420.0]), }), '[1]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [430.0, 440.0, 450.0, 460.0]), 1: lambda x: x.cols(4).rows(1).value( [470.0, 480.0, 490.0, 500.0]), }), }), '[2]': lambda x: x.cols(0).rows(0).members({ '[0]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [510.0, 520.0, 530.0, 540.0]), 1: lambda x: x.cols(4).rows(1).value( [550.0, 560.0, 570.0, 580.0]), }), '[1]': lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(4).rows(1).value( [590.0, 600.0, 610.0, 620.0]), 1: lambda x: x.cols(4).rows(1).value( [630.0, 640.0, 650.0, 660.0]), }), }), }) # struct vec3_1 { vec3 a; float b; }; # struct nested { vec3_1 a; vec4 b[4]; vec3_1 c[4]; }; # nested G[2]; # Due to lacking reflection, we don't know that G[x].a.a exists, as we only reference G[n].a.b # Similarly we don't know that G[x].c[y].b exists var_check.check('G').cols(0).rows(0).arraySize(2).members({ # G[0] 0: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).members({ 'a': lambda y: y.cols(3).rows(1).value([680.0, 690.0, 700.0]), 'b': lambda y: y.cols(1).rows(1).value([710.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members( { 0: lambda y: y.cols(4).rows(1), 1: lambda y: y.cols(4).rows(1), 2: lambda y: y.cols(4).rows(1), 3: lambda y: y.cols(4).rows(1), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 1: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 2: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 3: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), }), }), # G[1] 1: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).members({ 'a': lambda y: y.cols(3).rows(1).value([1040.0, 1050.0, 1060.0] ), 'b': lambda y: y.cols(1).rows(1).value([1070.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(4).rows(1).value( [1080.0, 1090.0, 1100.0, 1110.0]), 1: lambda y: y.cols(4).rows(1).value( [1120.0, 1130.0, 1140.0, 1150.0]), 2: lambda y: y.cols(4).rows(1).value( [1160.0, 1170.0, 1180.0, 1190.0]), 3: lambda y: y.cols(4).rows(1).value( [1200.0, 1210.0, 1220.0, 1230.0]), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 1: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 2: lambda y: y.cols(0).rows(0).members( { 'a': lambda z: z.cols(3).rows(1), 'b': lambda z: z.cols(1).rows(1), }), 3: lambda y: y.cols(0).rows(0).members({ 'a': lambda z: z.cols(3).rows(1).value( [1360.0, 1370.0, 1380.0]), 'b': lambda z: z.cols(1).rows(1), }), }), }), }) var_check.done() rdtest.log.success("Bare uniform variables are as expected") out.Shutdown()
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Vertex cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 0, cbuf.resourceId, cbuf.byteOffset)) # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself # float a; var_check.check('a').cols(1).rows(1).type(rd.VarType.Float).value( [1.0]) # vec2 b; var_check.check('b').cols(2).rows(1).type(rd.VarType.Float).value( [2.0, 0.0]) # vec3 c; var_check.check('c').cols(3).rows(1).type(rd.VarType.Float).value( [0.0, 3.0]) # float d[2]; var_check.check('d').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([4.0]), 1: lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([5.0]), }) # mat2x3 e; var_check.check('e').cols(2).rows(3).column_major().type( rd.VarType.Float).value([6.0, 999.0, 7.0, 0.0, 0.0, 0.0]) # mat2x3 f[2]; var_check.check('f').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(3).column_major().type( rd.VarType.Float).value([8.0, 999.0, 9.0, 0.0, 0.0, 0.0]), 1: lambda x: x.cols(2).rows(3).column_major().type(rd.VarType.Float). value([10.0, 999.0, 11.0, 0.0, 0.0, 0.0]), }) # float g; var_check.check('g').cols(1).rows(1).type(rd.VarType.Float).value( [12.0]) # struct S # { # float a; # vec2 b; # double c; # float d; # vec3 e; # float f; # }; # S h; var_check.check('h').cols(0).rows(0).structSize(6).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0]), 'b': lambda x: x.cols(2).rows(1).type(rd.VarType.Float).value([0.0]), 'c': lambda x: x.cols(1).rows(1).type(rd.VarType.Double).longvalue( [13.0]), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([14.0]), 'e': lambda x: x.cols(3).rows(1).type(rd.VarType.Float).value([0.0]), 'f': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0]), }) # S i[2]; var_check.check('i').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(0).rows(0).structSize(6).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0] ), 'b': lambda x: x.cols(2).rows(1).type(rd.VarType.Float).value([0.0] ), 'c': lambda x: x.cols(1).rows(1).type(rd.VarType.Double).longvalue( [15.0]), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0] ), 'e': lambda x: x.cols(3).rows(1).type(rd.VarType.Float).value([0.0] ), 'f': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0] ), }), 1: lambda x: x.cols(0).rows(0).structSize(6).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0] ), 'b': lambda x: x.cols(2).rows(1).type(rd.VarType.Float).value([0.0] ), 'c': lambda x: x.cols(1).rows(1).type(rd.VarType.Double).longvalue( [0.0]), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value( [16.0]), 'e': lambda x: x.cols(3).rows(1).type(rd.VarType.Float).value([0.0] ), 'f': lambda x: x.cols(1).rows(1).type(rd.VarType.Float).value([0.0] ), }), }) # i8vec4 pad1; var_check.check('pad1') # int8_t j; var_check.check('j').cols(1).rows(1).type(rd.VarType.SByte).value([17]) # struct S8 # { # int8_t a; # i8vec4 b; # i8vec2 c[4]; # }; # S8 k; var_check.check('k').cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([0]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SByte).value( [0, 0, 0, 0]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 18]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), }), }) # S8 l[2]; var_check.check('l').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([19]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SByte).value( [0, 0, 0, 0]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 20]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), }), }), 1: lambda x: x.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([21]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SByte).value( [0, 0, 0, 0]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 22]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SByte).value( [0, 0]), }), }) }) # int8_t m; var_check.check('m').cols(1).rows(1).type(rd.VarType.SByte).value( [-23]) # struct S16 # { # uint16_t a; # i16vec4 b; # i16vec2 c[4]; # int8_t d; # }; # S16 n; var_check.check('n').cols(0).rows(0).structSize(4).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.UShort).value([65524]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SShort).value( [0, 0, 0, -2424]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), }), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([25]), }) # i8vec4 pad2; var_check.check('pad2') # uint8_t o; var_check.check('o').cols(1).rows(1).type(rd.VarType.UByte).value( [226]) # S16 p[2]; var_check.check('p').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(0).rows(0).structSize(4).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.UShort).value([0]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SShort).value( [0, 0, 2727, 0]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), }), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([28]), }), 1: lambda x: x.cols(0).rows(0).structSize(4).members({ 'a': lambda x: x.cols(1).rows(1).type(rd.VarType.UShort).value([0]), 'b': lambda x: x.cols(4).rows(1).type(rd.VarType.SShort).value( [0, 0, 0, 2929]), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 1: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 2: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), 3: lambda x: x.cols(2).rows(1).type(rd.VarType.SShort).value( [0, 0]), }), 'd': lambda x: x.cols(1).rows(1).type(rd.VarType.SByte).value([0]), }) }) # i8vec4 pad3; var_check.check('pad3') # uint64_t q; var_check.check('q').cols(1).rows(1).type(rd.VarType.ULong).longvalue( [30303030303030]) # int64_t r; var_check.check('r').cols(1).rows(1).type(rd.VarType.SLong).longvalue( [-31313131313131]) # half s; var_check.check('s').cols(1).rows(1).type(rd.VarType.Half).value( [16.25]) # int8_t test; var_check.check('test').cols(1).rows(1).type(rd.VarType.SByte).value( [42]) var_check.done() rdtest.log.success("CBuffer variables are as expected") tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) # We just output green from the shader when the value is as expected if not rdtest.value_compare(picked.floatValue, [0.0, 1.0, 0.0, 0.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Picked value is as expected") out.Shutdown()
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel # Verify that the GLSL draw is first disasm = self.controller.DisassembleShader( pipe.GetGraphicsPipelineObject(), pipe.GetShaderReflection(stage), '') self.check('GLSL' in disasm) cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 0, cbuf.resourceId, cbuf.byteOffset)) # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself # vec4 a; var_check.check('a').cols(4).rows(1).value([0.0, 1.0, 2.0, 3.0]) # vec3 b; var_check.check('b').cols(3).rows(1).value([4.0, 5.0, 6.0]) # vec2 c; vec2 d; var_check.check('c').cols(2).rows(1).value([8.0, 9.0]) var_check.check('d').cols(2).rows(1).value([10.0, 11.0]) # float e; vec3 f; var_check.check('e').cols(1).rows(1).value([12.0]) var_check.check('f').cols(3).rows(1).value([16.0, 17.0, 18.0]) # vec4 dummy0; var_check.check('dummy0') # float j; vec2 k; var_check.check('j').cols(1).rows(1).value([24.0]) var_check.check('k').cols(2).rows(1).value([26.0, 27.0]) # vec2 l; float m; var_check.check('l').cols(2).rows(1).value([28.0, 29.0]) var_check.check('m').cols(1).rows(1).value([30.0]) # float n[4]; var_check.check('n').cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(1).rows(1).value([32.0]), 1: lambda x: x.cols(1).rows(1).value([36.0]), 2: lambda x: x.cols(1).rows(1).value([40.0]), 3: lambda x: x.cols(1).rows(1).value([44.0]), }) # vec4 dummy1; var_check.check('dummy1') # float o[4]; var_check.check('o').cols(0).rows(0).arraySize(4).members({ 0: lambda x: x.cols(1).rows(1).value([52.0]), 1: lambda x: x.cols(1).rows(1).value([56.0]), 2: lambda x: x.cols(1).rows(1).value([60.0]), 3: lambda x: x.cols(1).rows(1).value([64.0]), }) # float p; var_check.check('p').cols(1).rows(1).value([68.0]) # vec4 dummy2; var_check.check('dummy2') # column_major vec4x4 q; var_check.check('q').cols(4).rows(4).column_major().value([ 76.0, 80.0, 84.0, 88.0, 77.0, 81.0, 85.0, 89.0, 78.0, 82.0, 86.0, 90.0, 79.0, 83.0, 87.0, 91.0 ]) # row_major vec4x4 r; var_check.check('r').cols(4).rows(4).row_major().value([ 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0, 101.0, 102.0, 103.0 ]) # column_major vec4x3 s; var_check.check('s').cols(4).rows(3).column_major().value([ 108.0, 112.0, 116.0, 120.0, 109.0, 113.0, 117.0, 121.0, 110.0, 114.0, 118.0, 122.0 ]) # vec4 dummy3; var_check.check('dummy3') # row_major vec4x3 t; var_check.check('t').cols(4).rows(3).row_major().value([ 128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0, 137.0, 138.0, 139.0 ]) # vec4 dummy4; var_check.check('dummy4') # column_major vec2x3 u; var_check.check('u').cols(3).rows(2).column_major().value( [144.0, 148.0, 152.0, 145.0, 149.0, 153.0]) # vec4 dummy5; var_check.check('dummy5') # row_major vec3x2 v; var_check.check('v').cols(3).rows(2).row_major().value( [160.0, 161.0, 162.0, 164.0, 165.0, 166.0]) # vec4 dummy6; var_check.check('dummy6') # column_major vec3x2 w; var_check.check('w').cols(2).rows(2).column_major().value( [172.0, 176.0, 173.0, 177.0]) # vec4 dummy7; var_check.check('dummy7') # row_major vec3x2 x; var_check.check('x').cols(2).rows(2).row_major().value( [184.0, 185.0, 188.0, 189.0]) # vec4 dummy8; var_check.check('dummy8') # row_major vec2x2 y; var_check.check('y').cols(2).rows(2).row_major().value( [196.0, 197.0, 200.0, 201.0]) # float z; var_check.check('z').cols(1).rows(1).value([204.0]) # vec4 dummy9; var_check.check('dummy9') # vec4 multiarray[3][2]; var_check.check('multiarray').cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([228.0, 229.0, 230.0, 231.0] ), 1: lambda y: y.cols(4).rows(1).value([232.0, 233.0, 234.0, 235.0] ), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([236.0, 237.0, 238.0, 239.0] ), 1: lambda y: y.cols(4).rows(1).value([240.0, 241.0, 242.0, 243.0] ), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([244.0, 245.0, 246.0, 247.0] ), 1: lambda y: y.cols(4).rows(1).value([248.0, 249.0, 250.0, 251.0] ), }), }) # struct vec3_1 { vec3 a; float b; }; # struct nested { vec3_1 a; vec4 b[4]; vec3_1 c[4]; }; # nested structa[2]; var_check.check('structa').cols(0).rows(0).arraySize(2).members({ # structa[0] 0: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).structSize(2).members({ 'a': lambda y: y.cols(3).rows(1).value([252.0, 253.0, 254.0]), 'b': lambda y: y.cols(1).rows(1).value([255.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(4).rows(1).value( [256.0, 257.0, 258.0, 259.0]), 1: lambda y: y.cols(4).rows(1).value( [260.0, 261.0, 262.0, 263.0]), 2: lambda y: y.cols(4).rows(1).value( [264.0, 265.0, 266.0, 267.0]), 3: lambda y: y.cols(4).rows(1).value( [268.0, 269.0, 270.0, 271.0]), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [272.0, 273.0, 274.0]), 'b': lambda z: z.cols(1).rows(1).value([275.0]), }), 1: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [276.0, 277.0, 278.0]), 'b': lambda z: z.cols(1).rows(1).value([279.0]), }), 2: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [280.0, 281.0, 282.0]), 'b': lambda z: z.cols(1).rows(1).value([283.0]), }), 3: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [284.0, 285.0, 286.0]), 'b': lambda z: z.cols(1).rows(1).value([287.0]), }), }), }), # structa[1] 1: lambda s: s.cols(0).rows(0).structSize(3).members({ 'a': lambda x: x.cols(0).rows(0).structSize(2).members({ 'a': lambda y: y.cols(3).rows(1).value([288.0, 289.0, 290.0]), 'b': lambda y: y.cols(1).rows(1).value([291.0]), }), 'b': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(4).rows(1).value( [292.0, 293.0, 294.0, 295.0]), 1: lambda y: y.cols(4).rows(1).value( [296.0, 297.0, 298.0, 299.0]), 2: lambda y: y.cols(4).rows(1).value( [300.0, 301.0, 302.0, 303.0]), 3: lambda y: y.cols(4).rows(1).value( [304.0, 305.0, 306.0, 307.0]), }), 'c': lambda x: x.cols(0).rows(0).arraySize(4).members({ 0: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [308.0, 309.0, 310.0]), 'b': lambda z: z.cols(1).rows(1).value([311.0]), }), 1: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [312.0, 313.0, 314.0]), 'b': lambda z: z.cols(1).rows(1).value([315.0]), }), 2: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [316.0, 317.0, 318.0]), 'b': lambda z: z.cols(1).rows(1).value([319.0]), }), 3: lambda y: y.cols(0).rows(0).structSize(2).members({ 'a': lambda z: z.cols(3).rows(1).value( [320.0, 321.0, 322.0]), 'b': lambda z: z.cols(1).rows(1).value([323.0]), }), }), }), }) # column_major mat2x3 ac; var_check.check('ac').cols(2).rows(3).column_major().value( [324.0, 328.0, 325.0, 329.0, 326.0, 330.0]) # row_major mat2x3 ad; var_check.check('ad').cols(2).rows(3).row_major().value( [332.0, 333.0, 336.0, 337.0, 340.0, 341.0]) # column_major mat2x3 ae[2]; var_check.check('ae').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(3).column_major().value( [344.0, 348.0, 345.0, 349.0, 346.0, 350.0]), 1: lambda x: x.cols(2).rows(3).column_major().value( [352.0, 356.0, 353.0, 357.0, 354.0, 358.0]), }) # row_major mat2x3 af[2]; var_check.check('af').cols(0).rows(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(3).row_major().value( [360.0, 361.0, 364.0, 365.0, 368.0, 369.0]), 1: lambda x: x.cols(2).rows(3).row_major().value( [372.0, 373.0, 376.0, 377.0, 380.0, 381.0]), }) # vec2 dummy10; var_check.check('dummy10') # row_major mat2x2 ag; var_check.check('ag').cols(2).rows(2).row_major().value( [388.0, 389.0, 392.0, 393.0]) # vec2 dummy11; var_check.check('dummy11') # column_major mat2x2 ah; var_check.check('ah').cols(2).rows(2).column_major().value( [400.0, 404.0, 401.0, 405.0]) # row_major mat2x2 ai[2]; var_check.check('ai').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(2).row_major().value( [408.0, 409.0, 412.0, 413.0]), 1: lambda x: x.cols(2).rows(2).row_major().value( [416.0, 417.0, 420.0, 421.0]), }) # column_major mat2x2 aj[2]; var_check.check('aj').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.cols(2).rows(2).column_major().value( [424.0, 428.0, 425.0, 429.0]), 1: lambda x: x.cols(2).rows(2).column_major().value( [432.0, 436.0, 433.0, 437.0]), }) # vec4 test; var_check.check('test').rows(1).cols(4).value( [440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("GLSL CBuffer variables are as expected") tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("GLSL picked value is as expected") # Check the specialization constants cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 1, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 1, cbuf.resourceId, cbuf.byteOffset)) # int A; # Default value 10, untouched var_check.check('A').type(rd.VarType.SInt).rows(1).cols(1).value([10]) # float B; # Value 20 from spec constants var_check.check('B').type(rd.VarType.Float).rows(1).cols(1).value( [20.0]) # bool C; # Value True from spec constants var_check.check('C').type(rd.VarType.UInt).rows(1).cols(1).value([1]) var_check.done() rdtest.log.success("Specialization constants are as expected") # Move to the HLSL draw draw = draw.next self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() # Verify that this is the HLSL draw disasm = self.controller.DisassembleShader( pipe.GetGraphicsPipelineObject(), pipe.GetShaderReflection(stage), '') self.check('HLSL' in disasm) cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) var_check = rdtest.ConstantBufferChecker( self.controller.GetCBufferVariableContents( pipe.GetShader(stage), pipe.GetShaderEntryPoint(stage), 0, cbuf.resourceId, cbuf.byteOffset)) # For more detailed reference for the below checks, see the commented definition of the cbuffer # in the shader source code in the demo itself # float4 a; var_check.check('a').rows(1).cols(4).value([0.0, 1.0, 2.0, 3.0]) # float3 b; var_check.check('b').rows(1).cols(3).value([4.0, 5.0, 6.0]) # float2 c; float2 d; var_check.check('c').rows(1).cols(2).value([8.0, 9.0]) var_check.check('d').rows(1).cols(2).value([10.0, 11.0]) # float e; float3 f; var_check.check('e').rows(1).cols(1).value([12.0]) var_check.check('f').rows(1).cols(3).value([13.0, 14.0, 15.0]) # float g; float2 h; float i; var_check.check('g').rows(1).cols(1).value([16.0]) var_check.check('h').rows(1).cols(2).value([17.0, 18.0]) var_check.check('i').rows(1).cols(1).value([19.0]) # float j; float2 k; var_check.check('j').rows(1).cols(1).value([20.0]) var_check.check('k').rows(1).cols(2).value([21.0, 22.0]) # float2 l; float m; var_check.check('l').rows(1).cols(2).value([24.0, 25.0]) var_check.check('m').rows(1).cols(1).value([26.0]) # float n[4]; var_check.check('n').rows(0).cols(0).arraySize(4).members({ 0: lambda x: x.rows(1).cols(1).value([28.0]), 1: lambda x: x.rows(1).cols(1).value([32.0]), 2: lambda x: x.rows(1).cols(1).value([36.0]), 3: lambda x: x.rows(1).cols(1).value([40.0]), }) # float4 dummy1; var_check.check('dummy1') # float o[4]; var_check.check('o').rows(0).cols(0).arraySize(4).members({ 0: lambda x: x.rows(1).cols(1).value([48.0]), 1: lambda x: x.rows(1).cols(1).value([52.0]), 2: lambda x: x.rows(1).cols(1).value([56.0]), 3: lambda x: x.rows(1).cols(1).value([60.0]), }) # float p; with std140 vulkan packing var_check.check('p').rows(1).cols(1).value([64.0]) # float4 dummy2; var_check.check('dummy2') # float4 gldummy; var_check.check('gldummy') # HLSL majorness is flipped to match column-major SPIR-V with row-major HLSL. # This means column major declared matrices will show up as row major in any reflection and SPIR-V # it also means that dimensions are flipped, so a float3x4 is declared as a float4x3, and a 'row' # is really a column, and vice-versa a 'column' is really a row. # column_major float4x4 q; var_check.check('q').rows(4).cols(4).row_major().value([ 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0 ]) # row_major float4x4 r; var_check.check('r').rows(4).cols(4).column_major().value([ 92.0, 96.0, 100.0, 104.0, 93.0, 97.0, 101.0, 105.0, 94.0, 98.0, 102.0, 106.0, 95.0, 99.0, 103.0, 107.0 ]) # column_major float3x4 s; var_check.check('s').rows(4).cols(3).row_major().value([ 108.0, 109.0, 110.0, 112.0, 113.0, 114.0, 116.0, 117.0, 118.0, 120.0, 121.0, 122.0 ]) # float4 dummy3; var_check.check('dummy3') # row_major float3x4 t; var_check.check('t').rows(4).cols(3).column_major().value([ 128.0, 132.0, 136.0, 129.0, 133.0, 137.0, 130.0, 134.0, 138.0, 131.0, 135.0, 139.0 ]) # float4 dummy4; var_check.check('dummy4') # column_major float2x3 u; var_check.check('u').rows(3).cols(2).row_major().value( [144.0, 145.0, 148.0, 149.0, 152.0, 153.0]) # float4 dummy5; var_check.check('dummy5') # row_major float2x3 v; var_check.check('v').rows(3).cols(2).column_major().value( [160.0, 164.0, 161.0, 165.0, 162.0, 166.0]) # float4 dummy6; var_check.check('dummy6') # column_major float2x2 w; var_check.check('w').rows(2).cols(2).row_major().value( [172.0, 173.0, 176.0, 177.0]) # float4 dummy7; var_check.check('dummy7') # row_major float2x2 x; var_check.check('x').rows(2).cols(2).column_major().value( [184.0, 188.0, 185.0, 189.0]) # float4 dummy8; var_check.check('dummy8') # row_major float2x2 y; var_check.check('y').rows(2).cols(2).column_major().value( [196.0, 200.0, 197.0, 201.0]) # float z; var_check.check('z').rows(1).cols(1).value([204.0]) # Temporarily until SPIR-V support for degenerate HLSL matrices is determined var_check.check('dummy9') # row_major float4x1 aa; #var_check.check('aa').rows(1).cols(4).value([208.0, 212.0, 216.0, 220.0]) # column_major float4x1 ab; #var_check.check('ab').rows(1).cols(4).value([224.0, 225.0, 226.0, 227.0]) # float4 multiarray[3][2]; var_check.check('multiarray').cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([228.0, 229.0, 230.0, 231.0] ), 1: lambda y: y.cols(4).rows(1).value([232.0, 233.0, 234.0, 235.0] ), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([236.0, 237.0, 238.0, 239.0] ), 1: lambda y: y.cols(4).rows(1).value([240.0, 241.0, 242.0, 243.0] ), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ 0: lambda y: y.cols(4).rows(1).value([244.0, 245.0, 246.0, 247.0] ), 1: lambda y: y.cols(4).rows(1).value([248.0, 249.0, 250.0, 251.0] ), }), }) # struct float3_1 { float3 a; float b; }; # struct nested { float3_1 a; float4 b[4]; float3_1 c[4]; }; # nested structa[2]; var_check.check('structa').rows(0).cols(0).arraySize(2).members({ # structa[0] 0: lambda s: s.rows(0).cols(0).structSize(3).members({ 'a': lambda x: x.rows(0).cols(0).structSize(2).members({ 'a': lambda y: y.rows(1).cols(3).value([252.0, 253.0, 254.0]), 'b': lambda y: y.rows(1).cols(1).value([255.0]), }), 'b': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(1).cols(4).value( [256.0, 257.0, 258.0, 259.0]), 1: lambda y: y.rows(1).cols(4).value( [260.0, 261.0, 262.0, 263.0]), 2: lambda y: y.rows(1).cols(4).value( [264.0, 265.0, 266.0, 267.0]), 3: lambda y: y.rows(1).cols(4).value( [268.0, 269.0, 270.0, 271.0]), }), 'c': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [272.0, 273.0, 274.0]), 'b': lambda z: z.rows(1).cols(1).value([275.0]), }), 1: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [276.0, 277.0, 278.0]), 'b': lambda z: z.rows(1).cols(1).value([279.0]), }), 2: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [280.0, 281.0, 282.0]), 'b': lambda z: z.rows(1).cols(1).value([283.0]), }), 3: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [284.0, 285.0, 286.0]), 'b': lambda z: z.rows(1).cols(1).value([287.0]), }), }), }), # structa[1] 1: lambda s: s.rows(0).cols(0).structSize(3).members({ 'a': lambda x: x.rows(0).cols(0).structSize(2).members({ 'a': lambda y: y.rows(1).cols(3).value([288.0, 289.0, 290.0]), 'b': lambda y: y.rows(1).cols(1).value([291.0]), }), 'b': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(1).cols(4).value( [292.0, 293.0, 294.0, 295.0]), 1: lambda y: y.rows(1).cols(4).value( [296.0, 297.0, 298.0, 299.0]), 2: lambda y: y.rows(1).cols(4).value( [300.0, 301.0, 302.0, 303.0]), 3: lambda y: y.rows(1).cols(4).value( [304.0, 305.0, 306.0, 307.0]), }), 'c': lambda x: x.rows(0).cols(0).arraySize(4).members({ 0: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [308.0, 309.0, 310.0]), 'b': lambda z: z.rows(1).cols(1).value([311.0]), }), 1: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [312.0, 313.0, 314.0]), 'b': lambda z: z.rows(1).cols(1).value([315.0]), }), 2: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [316.0, 317.0, 318.0]), 'b': lambda z: z.rows(1).cols(1).value([319.0]), }), 3: lambda y: y.rows(0).cols(0).structSize(2).members({ 'a': lambda z: z.rows(1).cols(3).value( [320.0, 321.0, 322.0]), 'b': lambda z: z.rows(1).cols(1).value([323.0]), }), }), }), }) # column_major float3x2 ac; var_check.check('ac').rows(2).cols(3).row_major().value( [324.0, 325.0, 326.0, 328.0, 329.0, 330.0]) # row_major float3x2 ad; var_check.check('ad').rows(2).cols(3).column_major().value( [332.0, 336.0, 340.0, 333.0, 337.0, 341.0]) # column_major float3x2 ae[2]; var_check.check('ae').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(3).row_major().value( [344.0, 345.0, 346.0, 348.0, 349.0, 350.0]), 1: lambda x: x.rows(2).cols(3).row_major().value( [352.0, 353.0, 354.0, 356.0, 357.0, 358.0]), }) # row_major float3x2 af[2]; var_check.check('af').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(3).column_major().value( [360.0, 364.0, 368.0, 361.0, 365.0, 369.0]), 1: lambda x: x.rows(2).cols(3).column_major().value( [372.0, 376.0, 380.0, 373.0, 377.0, 381.0]), }) # float2 dummy10; var_check.check('dummy10') # float2 dummy11; var_check.check('dummy11') # row_major float2x2 ag; var_check.check('ag').rows(2).cols(2).column_major().value( [388.0, 392.0, 389.0, 393.0]) # float2 dummy12; var_check.check('dummy12') # float2 dummy13; var_check.check('dummy13') # column_major float2x2 ah; var_check.check('ah').rows(2).cols(2).row_major().value( [400.0, 401.0, 404.0, 405.0]) # row_major float2x2 ai[2]; var_check.check('ai').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(2).column_major().value( [408.0, 412.0, 409.0, 413.0]), 1: lambda x: x.rows(2).cols(2).column_major().value( [416.0, 420.0, 417.0, 421.0]), }) # column_major float2x2 aj[2]; var_check.check('aj').rows(0).cols(0).arraySize(2).members({ 0: lambda x: x.rows(2).cols(2).row_major().value( [424.0, 425.0, 428.0, 429.0]), 1: lambda x: x.rows(2).cols(2).row_major().value( [432.0, 433.0, 436.0, 437.0]), }) # float4 test; var_check.check('test').rows(1).cols(4).value( [440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("HLSL CBuffer variables are as expected") picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("HLSL picked value is as expected") out.Shutdown()
def check_capture(self): draw = self.get_last_draw() self.check(draw is not None) draw = draw.previous self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) pipe: rd.PipeState = self.controller.GetPipelineState() self.tex = rd.TextureDisplay() self.tex.resourceId = pipe.GetOutputTargets()[0].resourceId self.out.SetTextureDisplay(self.tex) texdetails = self.get_texture(self.tex.resourceId) # Top left we expect a regular line segment. s = self.sample(0, 0) # All points should be the line color if not rdtest.value_compare(s, [True, True, True]): raise rdtest.TestFailureException( "Normal line picked values {} doesn't match expectation". format(s)) # Next row is unstippled. The lines should either be all present, or not present names = ["Rectangle", "Bresenham", "Rectangle Round"] for col in [0, 1, 2]: s = self.sample(1, col) n = "Unstippled {}".format(names[col]) if s[0]: if not rdtest.value_compare(s, [True, True, True]): raise rdtest.TestFailureException( "{} picked values {} doesn't match expectation".format( n, s)) rdtest.log.success("{} line looks as expected".format(n)) else: if not rdtest.value_compare(s, [False, False, False]): raise rdtest.TestFailureException( "{} picked values {} doesn't match expectation".format( n, s)) rdtest.log.success("{} line not supported".format(n)) # Final row is stippled. The lines should be present on each end, and not present in the middle # (or not present at all) for col in [0, 1, 2]: s = self.sample(2, col) n = "Stippled {}".format(names[col]) if s[0]: if not rdtest.value_compare(s, [True, False, True]): raise rdtest.TestFailureException( "{} picked values {} doesn't match expectation".format( n, s)) rdtest.log.success("{} line looks as expected".format(n)) else: if not rdtest.value_compare(s, [False, False, False]): raise rdtest.TestFailureException( "{} picked values {} doesn't match expectation".format( n, s)) rdtest.log.success("{} line not supported".format(n)) rdtest.log.success("All lines look as expected") self.out.Shutdown()
def check_capture(self, capture_filename: str, controller: rd.ReplayController): self.controller = controller self.controller.SetFrameEvent( self.find_draw("Quad").next.eventId, False) self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(200, 200), rd.ReplayOutputType.Mesh) pipe: rd.PipeState = self.controller.GetPipelineState() self.cfg = rd.MeshDisplay() cam: rd.Camera = rd.InitCamera(rd.CameraType.FPSLook) cam.SetPosition(0, 0, 0) cam.SetFPSRotation(0, 0, 0) self.cfg.type = rd.MeshDataStage.VSOut self.cfg.cam = cam # Position is always first, so getting the postvs data will give us inst0: rd.MeshFormat = self.controller.GetPostVSData( 0, 0, self.cfg.type) self.cfg.position = inst0 # after position we have float2 Color2 then float4 Color4 self.cfg.second = self.cfg.position self.cfg.second.vertexByteOffset += 16 self.cfg.second.vertexByteOffset += 8 if pipe.HasAlignedPostVSData(self.cfg.type): self.cfg.second.vertexByteOffset += 8 # Configure an ortho camera, even though we don't really have a camera self.cfg.ortho = True self.cfg.position.nearPlane = 1.0 self.cfg.position.farPlane = 100.0 self.cfg.aspect = 1.0 self.cfg.wireframeDraw = True self.cfg.position.meshColor = rd.FloatVector(1.0, 0.0, 1.0, 1.0) self.cache_output() # We should have a single quad, check each outside edge and the inside diagonal. # All these line segments should have some colors (not including the background checkerboard or the frustum) self.check_region((55, 95, 65, 95), lambda x: x != []) # Left edge self.check_region((85, 60, 85, 70), lambda x: x != []) # Top edge self.check_region((105, 100, 115, 100), lambda x: x != []) # Right edge self.check_region((90, 130, 90, 140), lambda x: x != []) # Bottom edge self.check_region((65, 120, 75, 120), lambda x: x != []) # Bottom-Left of diagonal self.check_region((105, 70, 110, 70), lambda x: x != []) # Top-right of diagonal rdtest.log.success("Base rendering is as expected") self.cfg.solidShadeMode = rd.SolidShade.Secondary self.cfg.wireframeDraw = False # allow for blending with white for the frustum isred = lambda col: col[0] > col[1] and col[1] == col[2] isgreen = lambda col: col[1] > col[0] and col[0] == col[2] isblue = lambda col: col[2] > col[0] and col[0] == col[1] isredgreen = lambda col: isred(col) or isgreen(col) or col[2] == 0 isyellow = lambda col: col[0] == col[1] and col[2] < col[1] self.cache_output() # The secondary color should be completely green self.check_region((85, 70, 85, 125), lambda x: all([isgreen(i) for i in x])) self.check_region((65, 100, 105, 100), lambda x: all([isgreen(i) for i in x])) # this line segment isn't in the first instance self.check_region((65, 55, 105, 55), lambda x: x == []) # this line segment isn't in the second instance self.check_region((65, 125, 105, 125), lambda x: all([isgreen(i) for i in x])) rdtest.log.success("Secondary rendering of instance 0 is as expected") # Out of bounds should look the same as without highlighting at all, check the corners are all still green self.cfg.highlightVert = 9 self.cache_output() self.check_region((55, 60, 65, 70), lambda x: all([isgreen(i) for i in x])) self.check_region((105, 60, 115, 70), lambda x: all([isgreen(i) for i in x])) self.check_region((55, 130, 65, 140), lambda x: all([isgreen(i) for i in x])) self.check_region((105, 130, 115, 140), lambda x: all([isgreen(i) for i in x])) vert_regions = [ (55, 60, 65, 70), (110, 60, 120, 70), (55, 130, 65, 140), (110, 60, 120, 70), (110, 130, 120, 140), (55, 130, 65, 140), ] for vert in range(6): self.cfg.highlightVert = vert self.cache_output() tri = int(vert / 3) # Check that the triangle we're highlighting is red and the other is green if tri == 0: self.check_region((65, 75, 75, 85), lambda x: all([isred(i) for i in x])) self.check_region((100, 115, 110, 125), lambda x: all([isgreen(i) for i in x])) else: self.check_region((65, 75, 75, 85), lambda x: all([isgreen(i) for i in x])) self.check_region((100, 115, 110, 125), lambda x: all([isred(i) for i in x])) # The corners that touch should be red and green - that is no other colours but red and green, but at least # some red and some green self.check_region( (65, 115, 75, 125), lambda x: all([isredgreen(i) for i in x]) and any( [isred(i) for i in x]) and any([isgreen(i) for i in x])) # check that there's blue in this vertex's region self.check_region(vert_regions[vert], lambda x: any([isblue(i) for i in x])) rdtest.log.success("Rendering of highlighted vertices is as expected") self.cfg.highlightVert = rd.MeshDisplay.NoHighlight # If we render from the float2 color we shouldn't get any blue self.cfg.second.vertexByteOffset = self.cfg.position.vertexByteOffset = inst0.vertexByteOffset self.cfg.second.vertexByteOffset += 16 self.cfg.second.format.compCount = 2 self.cache_output() # If we render from the float2 color we shouldn't get any blue since it's only a two-component value self.check_region((85, 70, 85, 125), lambda x: all([isredgreen(i) for i in x])) self.check_region((65, 100, 105, 100), lambda x: all([isredgreen(i) for i in x])) self.check_region((65, 55, 105, 55), lambda x: x == []) self.check_region((65, 125, 105, 125), lambda x: all([isredgreen(i) for i in x])) rdtest.log.success( "Rendering of float2 color secondary in instance 0 is as expected") self.cfg.highlightVert = rd.MeshDisplay.NoHighlight inst1: rd.MeshFormat = self.controller.GetPostVSData( 1, 0, self.cfg.type) self.cfg.curInstance = 1 self.cfg.second.vertexResourceId = self.cfg.position.vertexResourceId = inst1.vertexResourceId self.cfg.second.vertexByteOffset = self.cfg.position.vertexByteOffset = inst1.vertexByteOffset self.cfg.second.vertexByteOffset += 16 self.cfg.second.vertexByteOffset += 8 if pipe.HasAlignedPostVSData(self.cfg.type): self.cfg.second.vertexByteOffset += 8 self.cache_output() # The secondary color should be completely yellow self.check_region((85, 70, 85, 125), lambda x: all([isyellow(i) for i in x])) self.check_region((65, 100, 105, 100), lambda x: all([isyellow(i) for i in x])) # this line segment isn't in the first instance self.check_region((65, 55, 105, 55), lambda x: all([isyellow(i) for i in x])) # this line segment isn't in the second instance self.check_region((65, 125, 105, 125), lambda x: x == []) rdtest.log.success("Secondary rendering of instance 1 is as expected") # If we render from the float2 color we shouldn't get any blue self.cfg.second.vertexByteOffset = self.cfg.position.vertexByteOffset = inst1.vertexByteOffset self.cfg.second.vertexByteOffset += 16 self.cfg.second.format.compCount = 2 self.cache_output() # If we render from the float2 color we shouldn't get any blue since it's only a two-component value self.check_region((85, 70, 85, 125), lambda x: all([isredgreen(i) for i in x])) self.check_region((65, 100, 105, 100), lambda x: all([isredgreen(i) for i in x])) self.check_region((65, 55, 105, 55), lambda x: all([isredgreen(i) for i in x])) self.check_region((65, 125, 105, 125), lambda x: x == []) rdtest.log.success( "Rendering of float2 color secondary in instance 1 is as expected") self.cfg.solidShadeMode = rd.SolidShade.NoSolid self.cfg.showAllInstances = True self.cache_output() # wireframe for original quad should still be present self.check_region((55, 95, 65, 95), lambda x: x != []) self.check_region((85, 60, 85, 70), lambda x: x != []) self.check_region((105, 100, 115, 100), lambda x: x != []) self.check_region((90, 130, 90, 140), lambda x: x != []) self.check_region((65, 120, 75, 120), lambda x: x != []) self.check_region((105, 70, 110, 70), lambda x: x != []) # But now we'll have an additional instance self.check_region((75, 55, 85, 55), lambda x: x != []) self.check_region((125, 85, 135, 85), lambda x: x != []) self.check_region((105, 110, 105, 120), lambda x: x != []) self.cfg.showWholePass = True self.cache_output() # same again self.check_region((55, 95, 65, 95), lambda x: x != []) self.check_region((85, 60, 85, 70), lambda x: x != []) self.check_region((105, 100, 115, 100), lambda x: x != []) self.check_region((90, 130, 90, 140), lambda x: x != []) self.check_region((65, 120, 75, 120), lambda x: x != []) self.check_region((105, 70, 110, 70), lambda x: x != []) self.check_region((75, 55, 85, 55), lambda x: x != []) self.check_region((125, 85, 135, 85), lambda x: x != []) self.check_region((105, 110, 105, 120), lambda x: x != []) # But now an extra previous draw self.check_region((30, 105, 40, 105), lambda x: x != []) self.check_region((50, 80, 50, 90), lambda x: x != []) self.check_region((45, 130, 55, 130), lambda x: x != []) self.check_region((30, 150, 40, 150), lambda x: x != []) rdtest.log.success("Mesh rendering is as expected") self.cfg.showWholePass = False self.cfg.showAllInstances = False # Go back to instance 0. We can ignore cfg.second now self.cfg.curInstance = 0 self.cfg.position.vertexResourceId = inst0.vertexResourceId self.cfg.position.vertexByteOffset = inst0.vertexByteOffset self.cache_output() # Just above top-left, no result self.check_vertex(55, 60, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) # Just inside top-left, first vertex self.check_vertex(65, 70, (0, 0)) # Outside top-right, inside the second instance, but because we only have one instance showing should return # no result self.check_vertex(115, 60, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) self.check_vertex(80, 60, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) # In the first triangle near the top right self.check_vertex(105, 70, (1, 0)) # In the second triangle near the top right self.check_vertex(110, 70, (3, 0)) # In the second triangle near the middle, would be in the second instance self.check_vertex(95, 110, (4, 0)) # In the second triangle near the bottom right self.check_vertex(110, 130, (4, 0)) rdtest.log.success("Instance 0 picking is as expected") # if we look at only instance 1, the results should change self.cfg.curInstance = 1 self.cfg.position.vertexResourceId = inst1.vertexResourceId self.cfg.position.vertexByteOffset = inst1.vertexByteOffset self.cache_output() self.check_vertex(55, 60, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) self.check_vertex(65, 70, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) self.check_vertex(115, 60, (1, 1)) self.check_vertex(80, 60, (0, 1)) self.check_vertex(105, 70, (1, 1)) self.check_vertex(110, 70, (1, 1)) self.check_vertex(95, 110, (5, 1)) self.check_vertex(110, 130, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) rdtest.log.success("Instance 1 picking is as expected") # Now look at both instances together, this goes 'in order' so if there is overlap the first instance wins self.cfg.showAllInstances = True self.cache_output() self.check_vertex(55, 60, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) self.check_vertex(65, 70, (0, 0)) self.check_vertex(115, 60, (1, 1)) self.check_vertex(80, 60, (0, 1)) self.check_vertex(105, 70, (1, 0)) self.check_vertex(110, 70, (3, 0)) self.check_vertex(95, 110, (4, 0)) self.check_vertex(110, 130, (4, 0)) rdtest.log.success("Both instance picking is as expected") self.controller.SetFrameEvent( self.find_draw("Points").next.eventId, False) # Only one instance, just check we can see the points self.cfg.curInstance = 0 self.cfg.position = self.controller.GetPostVSData(0, 0, self.cfg.type) self.cfg.position.nearPlane = 1.0 self.cfg.position.farPlane = 100.0 self.cache_output() # Picking points doesn't have any primitive, it should pick as long as it's close to the point self.check_vertex(55, 60, (0, 0)) self.check_vertex(65, 70, (0, 0)) self.check_vertex(105, 65, (1, 0)) self.check_vertex(115, 135, (2, 0)) self.check_vertex(65, 130, (3, 0)) self.check_vertex(60, 125, (3, 0)) rdtest.log.success("Point picking is as expected") self.controller.SetFrameEvent( self.find_draw("Stride 0").next.eventId, False) self.cfg.position = self.controller.GetPostVSData(0, 0, self.cfg.type) self.cfg.position.nearPlane = 1.0 self.cfg.position.farPlane = 100.0 self.cache_output() # Stride of 0 is unusual but valid, ensure vertex picking still works self.check_vertex(55, 60, (0, 0)) self.check_vertex(65, 70, (0, 0)) self.check_vertex(105, 65, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult)) self.check_vertex(115, 135, (rd.ReplayOutput.NoResult, rd.ReplayOutput.NoResult))
def check_capture(self): draw = self.find_draw("Color Draw") self.check(draw is not None) draw = draw.next self.controller.SetFrameEvent(draw.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [0.0, 1.0, 0.0, 1.0]) rdtest.log.success("Captured loaded with color as expected") postvs_data = self.get_postvs(draw, rd.MeshDataStage.VSOut, 0, draw.numIndices) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'SV_POSITION': [-0.5, -0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [0.0, 0.0], }, 1: { 'vtx': 1, 'idx': 1, 'SV_POSITION': [0.0, 0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [0.0, 1.0], }, 2: { 'vtx': 2, 'idx': 2, 'SV_POSITION': [0.5, -0.5, 0.0, 1.0], 'COLOR': [0.0, 1.0, 0.0, 1.0], 'TEXCOORD': [1.0, 0.0], }, } self.check_mesh_data(postvs_ref, postvs_data) rdtest.log.success("Mesh data is correct") tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.Drawcall tex.resourceId = pipe.GetOutputTargets()[0].resourceId out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) out.SetTextureDisplay(tex) out.Display() overlay_id = out.GetDebugOverlayTexID() v = pipe.GetViewport(0) self.check_pixel_value(overlay_id, int(0.5 * v.width), int(0.5 * v.height), [0.8, 0.1, 0.8, 1.0], eps=1.0 / 256.0) out.Shutdown() rdtest.log.success("Overlay color is as expected")
def check_capture(self): draw = self.find_draw("Draw") self.check(draw is not None) self.controller.SetFrameEvent(draw.eventId, False) # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) ref = { 0: { 'SNORM': [1.0, -1.0, 1.0, -1.0], 'UNORM': [ 12345.0 / 65535.0, 6789.0 / 65535.0, 1234.0 / 65535.0, 567.0 / 65535.0 ], 'UINT': [12345, 6789, 1234, 567], 'ARRAY0': [1.0, 2.0], 'ARRAY1': [3.0, 4.0], 'ARRAY2': [5.0, 6.0], 'MATRIX0': [7.0, 8.0], 'MATRIX1': [9.0, 10.0], }, 1: { 'SNORM': [ 32766.0 / 32767.0, -32766.0 / 32767.0, 16000.0 / 32767.0, -16000.0 / 32767.0 ], 'UNORM': [ 56.0 / 65535.0, 7890.0 / 65535.0, 123.0 / 65535.0, 4567.0 / 65535.0 ], 'UINT': [56, 7890, 123, 4567], 'ARRAY0': [11.0, 12.0], 'ARRAY1': [13.0, 14.0], 'ARRAY2': [15.0, 16.0], 'MATRIX0': [17.0, 18.0], 'MATRIX1': [19.0, 20.0], }, 2: { 'SNORM': [5.0 / 32767.0, -5.0 / 32767.0, 0.0, 0.0], 'UNORM': [ 8765.0 / 65535.0, 43210.0 / 65535.0, 987.0 / 65535.0, 65432.0 / 65535.0 ], 'UINT': [8765, 43210, 987, 65432], 'ARRAY0': [21.0, 22.0], 'ARRAY1': [23.0, 24.0], 'ARRAY2': [25.0, 26.0], 'MATRIX0': [27.0, 28.0], 'MATRIX1': [29.0, 30.0], }, } in_ref = copy.deepcopy(ref) vsout_ref = copy.deepcopy(ref) gsout_ref = ref vsout_ref[0]['SV_Position'] = [-0.5, 0.5, 0.0, 1.0] gsout_ref[0]['SV_Position'] = [0.5, -0.5, 0.4, 1.2] vsout_ref[1]['SV_Position'] = [0.0, -0.5, 0.0, 1.0] gsout_ref[1]['SV_Position'] = [-0.5, 0.0, 0.4, 1.2] vsout_ref[2]['SV_Position'] = [0.5, 0.5, 0.0, 1.0] gsout_ref[2]['SV_Position'] = [0.5, 0.5, 0.4, 1.2] self.check_mesh_data(in_ref, self.get_vsin(draw)) rdtest.log.success("Vertex input data is as expected") self.check_mesh_data(vsout_ref, self.get_postvs(rd.MeshDataStage.VSOut)) rdtest.log.success("Vertex output data is as expected") self.check_mesh_data(gsout_ref, self.get_postvs(rd.MeshDataStage.GSOut)) rdtest.log.success("Geometry output data is as expected") pipe: rd.PipeState = self.controller.GetPipelineState() tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) texdetails = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [0.0, 1.0, 0.0, 1.0]): raise rdtest.TestFailureException( "Picked value {} doesn't match expectation".format( picked.floatValue)) rdtest.log.success("Triangle picked value is as expected") out.Shutdown()
def check_capture(self): out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) test_marker: rd.DrawcallDescription = self.find_draw("Test") self.controller.SetFrameEvent(test_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() col_tex: rd.ResourceId = pipe.GetOutputTargets()[0].resourceId tex = rd.TextureDisplay() tex.resourceId = col_tex # Check the actual output is as expected first. # Background around the outside self.check_pixel_value(col_tex, 0.1, 0.1, [0.2, 0.2, 0.2, 1.0]) self.check_pixel_value(col_tex, 0.8, 0.1, [0.2, 0.2, 0.2, 1.0]) self.check_pixel_value(col_tex, 0.5, 0.95, [0.2, 0.2, 0.2, 1.0]) # Large dark grey triangle self.check_pixel_value(col_tex, 0.5, 0.1, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(col_tex, 0.5, 0.9, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(col_tex, 0.2, 0.9, [0.1, 0.1, 0.1, 1.0]) self.check_pixel_value(col_tex, 0.8, 0.9, [0.1, 0.1, 0.1, 1.0]) # Red upper half triangle self.check_pixel_value(col_tex, 0.3, 0.4, [1.0, 0.0, 0.0, 1.0]) # Blue lower half triangle self.check_pixel_value(col_tex, 0.3, 0.6, [0.0, 0.0, 1.0, 1.0]) # Floating clipped triangle self.check_pixel_value(col_tex, 335, 140, [0.0, 0.0, 0.0, 1.0]) self.check_pixel_value(col_tex, 340, 140, [0.2, 0.2, 0.2, 1.0]) # Triangle size triangles self.check_pixel_value(col_tex, 200, 51, [1.0, 0.5, 1.0, 1.0]) self.check_pixel_value(col_tex, 200, 65, [1.0, 1.0, 0.0, 1.0]) self.check_pixel_value(col_tex, 200, 79, [0.0, 1.0, 1.0, 1.0]) self.check_pixel_value(col_tex, 200, 93, [0.0, 1.0, 0.0, 1.0]) for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue # We'll test the clear-before-X overlays seperately, for both colour and depth if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: continue rdtest.log.print("Checking overlay {} in main draw".format(str(overlay))) tex.overlay = overlay out.SetTextureDisplay(tex) out.Display() eps = 1.0 / 256.0 overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() # We test a few key spots: # 4 points along the left side of the big triangle, above/in/below its intersection with the tri behind # 4 points outside all triangles # The overlap between the big tri and the bottom tri, and between it and the right backface culled tri # The bottom tri's part that sticks out # The two parts of the backface culled tri that stick out # The depth clipped tri, in and out of clipping # The 4 triangle size test triangles if overlay == rd.DebugOverlay.Drawcall: self.check_pixel_value(overlay_id, 150, 90, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 0.0, 0.0, 0.5], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 0.0, 0.0, 0.5], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 0.0, 0.0, 0.5], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 0.0, 0.0, 0.5], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 135, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [0.8, 0.1, 0.8, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [0.8, 0.1, 0.8, 1.0], eps=eps) elif overlay == rd.DebugOverlay.Wireframe: # Wireframe we only test a limited set to avoid hitting implementation variations of line raster # We also have to fudge a little because the lines might land on adjacent pixels x = 142 picked: rd.PixelValue = self.controller.PickPixel(overlay_id, x, 150, rd.Subresource(), rd.CompType.Typeless) if picked.floatValue[3] == 0.0: x = 141 self.check_pixel_value(overlay_id, x, 90, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, x, 130, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, x, 160, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, x, 200, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [200.0/255.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [200.0/255.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [200.0/255.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [200.0/255.0, 1.0, 0.0, 0.0], eps=eps) y = 149 picked: rd.PixelValue = self.controller.PickPixel(overlay_id, 325, y, rd.Subresource(), rd.CompType.Typeless) if picked.floatValue[3] == 0.0: y = 150 self.check_pixel_value(overlay_id, 325, y, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 340, y, [200.0/255.0, 1.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.Depth: self.check_pixel_value(overlay_id, 150, 90, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [0.0, 1.0, 0.0, 1.0], eps=eps) # Intersection with lesser depth - depth fail self.check_pixel_value(overlay_id, 150, 160, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [0.0, 1.0, 0.0, 1.0], eps=eps) # Backface culled triangle self.check_pixel_value(overlay_id, 285, 135, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [0.0, 1.0, 0.0, 1.0], eps=eps) # Depth clipped part of tri self.check_pixel_value(overlay_id, 340, 145, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.Stencil: self.check_pixel_value(overlay_id, 150, 90, [0.0, 1.0, 0.0, 1.0], eps=eps) # Intersection with different stencil - stencil fail self.check_pixel_value(overlay_id, 150, 130, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [0.0, 1.0, 0.0, 1.0], eps=eps) # Backface culled triangle self.check_pixel_value(overlay_id, 285, 135, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [0.0, 1.0, 0.0, 1.0], eps=eps) # Depth clipped part of tri self.check_pixel_value(overlay_id, 340, 145, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.BackfaceCull: self.check_pixel_value(overlay_id, 150, 90, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 1.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [0.0, 1.0, 0.0, 1.0], eps=eps) # Backface culled triangle self.check_pixel_value(overlay_id, 285, 135, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [0.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.ViewportScissor: # Inside viewport self.check_pixel_value(overlay_id, 50, 50, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) self.check_pixel_value(overlay_id, 350, 50, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) self.check_pixel_value(overlay_id, 50, 250, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) self.check_pixel_value(overlay_id, 350, 250, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) # Viewport border self.check_pixel_value(overlay_id, 12, 12, [0.1, 0.1, 0.1, 1.0], eps=eps) # Outside viewport (not on scissor border) self.check_pixel_value(overlay_id, 6, 6, [0.0, 0.0, 0.0, 0.0], eps=eps) # Scissor border self.check_pixel_value(overlay_id, 0, 0, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 20, 0, [0.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 40, 0, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 60, 0, [0.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 60, 0, [0.0, 0.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.QuadOverdrawDraw: self.check_pixel_value(overlay_id, 150, 90, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 135, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [1.0, 1.0, 1.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.QuadOverdrawPass: self.check_pixel_value(overlay_id, 150, 90, [1.0, 1.0, 1.0, 1.0], eps=eps) # Do an extra tap here where we overlap with the extreme-background largest triangle, to show that # overdraw self.check_pixel_value(overlay_id, 150, 100, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [2.0, 2.0, 2.0, 2.0], eps=eps) # Two of these have overdraw from the pass due to the large background triangle self.check_pixel_value(overlay_id, 125, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [3.0, 3.0, 3.0, 3.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 285, 135, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [1.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 200, 51, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [2.0, 2.0, 2.0, 2.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [2.0, 2.0, 2.0, 2.0], eps=eps) elif overlay == rd.DebugOverlay.TriangleSizeDraw: eps = 1.0 self.check_pixel_value(overlay_id, 150, 90, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [2128.0, 2128.0, 2128.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [2128.0, 2128.0, 2128.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 135, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [531.0, 531.0, 531.0, 531.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.0, 0.0, 0.0, 0.0], eps=eps) eps = 0.01 self.check_pixel_value(overlay_id, 200, 51, [8.305, 8.305, 8.305, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [5.316, 5.316, 5.316, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [3.0, 3.0, 3.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [1.33, 1.33, 1.33, 1.0], eps=eps) elif overlay == rd.DebugOverlay.TriangleSizePass: eps = 1.0 self.check_pixel_value(overlay_id, 150, 90, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 130, [3324.0, 3324.0, 3324.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 160, [3324.0, 3324.0, 3324.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 150, 200, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 125, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 125, 250, [43072.0, 43072.0, 43072.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 60, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 250, 250, [43072.0, 43072.0, 43072.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 175, [2128.0, 2128.0, 2128.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 250, 150, [10632.0, 10632.0, 10632.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 220, 190, [2128.0, 2128.0, 2128.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 285, 135, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(overlay_id, 285, 165, [43072.0, 43072.0, 43072.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 330, 145, [531.0, 531.0, 531.0, 531.0], eps=eps) self.check_pixel_value(overlay_id, 340, 145, [0.0, 0.0, 0.0, 0.0], eps=eps) eps = 0.01 self.check_pixel_value(overlay_id, 200, 51, [8.305, 8.305, 8.305, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 65, [5.316, 5.316, 5.316, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 79, [3.0, 3.0, 3.0, 1.0], eps=eps) self.check_pixel_value(overlay_id, 200, 93, [1.33, 1.33, 1.33, 1.0], eps=eps) rdtest.log.success("Picked pixels are as expected for {}".format(str(overlay))) # Now check clear-before-X by hand, for colour and for depth depth_tex: rd.ResourceId = pipe.GetDepthTarget().resourceId eps = 1.0/256.0 # Check colour and depth before-hand self.check_pixel_value(col_tex, 250, 250, [0.1, 0.1, 0.1, 1.0], eps=eps) self.check_pixel_value(col_tex, 125, 125, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 125, 175, [0.0, 0.0, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 50, 50, [0.2, 0.2, 0.2, 1.0], eps=eps) self.check_pixel_value(col_tex, 291, 150, [0.977, 0.977, 0.977, 1.0], eps=0.075) self.check_pixel_value(col_tex, 200, 51, [1.0, 0.5, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 65, [1.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 79, [0.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) eps = 0.001 self.check_pixel_value(depth_tex, 160, 135, [0.9, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 160, 165, [0.0, 0.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 150, [0.5, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 250, [0.95, 0.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 50, 50, [1.0, 0.0/255.0, 0.0, 1.0], eps=eps) # Check clear before pass tex.resourceId = col_tex tex.overlay = rd.DebugOverlay.ClearBeforePass out.SetTextureDisplay(tex) out.Display() eps = 1.0/256.0 self.check_pixel_value(col_tex, 250, 250, [0.1, 0.1, 0.1, 1.0], eps=eps) self.check_pixel_value(col_tex, 125, 125, [1.0, 0.0, 0.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 125, 175, [0.0, 0.0, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 50, 50, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(col_tex, 291, 150, [0.977, 0.977, 0.977, 1.0], eps=0.075) self.check_pixel_value(col_tex, 200, 51, [1.0, 0.5, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 65, [1.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 79, [0.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) tex.resourceId = depth_tex tex.overlay = rd.DebugOverlay.ClearBeforePass out.SetTextureDisplay(tex) out.Display() eps = 0.001 self.check_pixel_value(depth_tex, 160, 135, [0.9, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 160, 165, [0.0, 0.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 150, [0.5, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 250, [0.95, 0.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 50, 50, [1.0, 0.0/255.0, 0.0, 1.0], eps=eps) rdtest.log.success("Clear before pass colour and depth values as expected") # Check clear before draw tex.resourceId = col_tex tex.overlay = rd.DebugOverlay.ClearBeforeDraw out.SetTextureDisplay(tex) out.Display() eps = 1.0/256.0 # These are all pass triangles, should be cleared self.check_pixel_value(col_tex, 250, 250, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(col_tex, 125, 125, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(col_tex, 125, 175, [0.0, 0.0, 0.0, 0.0], eps=eps) self.check_pixel_value(col_tex, 50, 50, [0.0, 0.0, 0.0, 0.0], eps=eps) # These should be identical self.check_pixel_value(col_tex, 291, 150, [0.977, 0.977, 0.977, 1.0], eps=0.075) self.check_pixel_value(col_tex, 200, 51, [1.0, 0.5, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 65, [1.0, 1.0, 0.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 79, [0.0, 1.0, 1.0, 1.0], eps=eps) self.check_pixel_value(col_tex, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) tex.resourceId = depth_tex tex.overlay = rd.DebugOverlay.ClearBeforeDraw out.SetTextureDisplay(tex) out.Display() eps = 0.001 # Without the pass, depth/stencil results are different self.check_pixel_value(depth_tex, 160, 135, [0.5, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 160, 165, [0.5, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 150, [0.5, 85.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 250, 250, [1.0, 0.0/255.0, 0.0, 1.0], eps=eps) self.check_pixel_value(depth_tex, 50, 50, [1.0, 0.0/255.0, 0.0, 1.0], eps=eps) rdtest.log.success("Clear before draw colour and depth values as expected") rdtest.log.success("All overlays as expected for main draw") # Now test overlays on a render-to-slice/mip case for mip in [2, 3]: sub_marker: rd.DrawcallDescription = self.find_draw("Subresources mip {}".format(mip)) self.controller.SetFrameEvent(sub_marker.next.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() col_tex = pipe.GetOutputTargets()[0].resourceId sub = rd.Subresource(pipe.GetOutputTargets()[0].firstMip, 0, 0) for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: continue # These overlays are just displaymodes really, not actually separate overlays if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: continue if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: continue rdtest.log.success("Checking overlay {} with mip/slice rendering".format(str(overlay))) tex.resourceId = col_tex tex.overlay = overlay tex.subresource = sub out.SetTextureDisplay(tex) out.Display() overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() shift = 0 if mip == 3: shift = 1 # All values in mip 0 should be 0 for all overlays self.check_pixel_value(overlay_id, 200, 150, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) self.check_pixel_value(overlay_id, 197, 147, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) self.check_pixel_value(overlay_id, 203, 153, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) rdtest.log.success("Other mips are empty as expected for overlay {}".format(str(overlay))) if overlay == rd.DebugOverlay.Drawcall: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [0.8, 0.1, 0.8, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.0, 0.0, 0.0, 0.5], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [0.8, 0.1, 0.8, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 0.0, 0.0, 0.5], sub=sub, eps=eps) elif overlay == rd.DebugOverlay.Wireframe: self.check_pixel_value(overlay_id, 36 >> shift, 36 >> shift, [200.0 / 255.0, 1.0, 0.0, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 36 >> shift, 50 >> shift, [200.0 / 255.0, 1.0, 0.0, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [200.0 / 255.0, 1.0, 0.0, 0.0], sub=sub, eps=eps) elif overlay == rd.DebugOverlay.Depth or overlay == rd.DebugOverlay.Stencil: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [0.0, 1.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.0, 1.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [1.0, 0.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 1.0, 0.0, 0.0], sub=sub) elif overlay == rd.DebugOverlay.BackfaceCull: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [0.0, 1.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.0, 1.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [1.0, 0.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 1.0, 0.0, 0.0], sub=sub) elif overlay == rd.DebugOverlay.ViewportScissor: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) if mip == 2: self.check_pixel_value(overlay_id, 6, 6, [0.1, 0.1, 0.1, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 4, 4, [0.0, 0.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 0, 0, [1.0, 1.0, 1.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 20, 0, [0.0, 0.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 40, 0, [1.0, 1.0, 1.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 60, 0, [0.0, 0.0, 0.0, 1.0], sub=sub) else: self.check_pixel_value(overlay_id, 4, 4, [0.1, 0.1, 0.1, 1.0], sub=sub, eps=eps) self.check_pixel_value(overlay_id, 0, 0, [1.0, 1.0, 1.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 20, 0, [0.0, 0.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 40, 0, [1.0, 1.0, 1.0, 1.0], sub=sub) elif overlay == rd.DebugOverlay.QuadOverdrawDraw or overlay == rd.DebugOverlay.QuadOverdrawPass: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [1.0, 1.0, 1.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.0, 0.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 0.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 50 >> shift, 45 >> shift, [2.0, 2.0, 2.0, 2.0], sub=sub) elif overlay == rd.DebugOverlay.TriangleSizeDraw or overlay == rd.DebugOverlay.TriangleSizePass: if mip == 2: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [585.0, 585.0, 585.0, 1.0], sub=sub) else: self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, [151.75, 151.75, 151.75, 1.0], sub=sub) self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, [0.0, 0.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [0.0, 0.0, 0.0, 0.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 0.0, 0.0, 0.0], sub=sub) if mip == 2: self.check_pixel_value(overlay_id, 50 >> shift, 45 >> shift, [117.0, 117.0, 117.0, 1.0], sub=sub) else: self.check_pixel_value(overlay_id, 50 >> shift, 45 >> shift, [30.359375, 30.359375, 30.359375, 1.0], sub=sub) rdtest.log.success("Picked values are correct for mip {} overlay {}".format(sub.mip, str(overlay))) out.Shutdown()
def check_capture(self): fill = self.find_action("vkCmdFillBuffer") self.check(fill is not None) buffer_usage = {} for usage in self.controller.GetUsage(fill.copyDestination): usage: rd.EventUsage if usage.eventId not in buffer_usage: buffer_usage[usage.eventId] = [] buffer_usage[usage.eventId].append(usage.usage) # The texture is the backbuffer tex = self.get_last_action().copyDestination for level in ["Primary", "Secondary"]: rdtest.log.print("Checking {} indirect calls".format(level)) final = self.find_action("{}: Final".format(level)) indirect_count_root = self.find_action( "{}: KHR_action_indirect_count".format(level)) self.controller.SetFrameEvent(final.eventId, False) # Check the top row, non indirect count and always present self.check_pixel_value(tex, 60, 60, [1.0, 0.0, 0.0, 1.0]) self.check_pixel_value(tex, 100, 60, [0.0, 0.0, 1.0, 1.0]) self.check_pixel_value(tex, 145, 35, [1.0, 1.0, 0.0, 1.0]) self.check_pixel_value(tex, 205, 35, [0.0, 1.0, 1.0, 1.0]) # if present, check bottom row of indirect count as well as post-count calls if indirect_count_root is not None: self.check_pixel_value(tex, 60, 220, [0.0, 1.0, 0.0, 1.0]) self.check_pixel_value(tex, 100, 220, [1.0, 0.0, 1.0, 1.0]) self.check_pixel_value(tex, 145, 185, [0.5, 1.0, 0.0, 1.0]) self.check_pixel_value(tex, 205, 185, [0.5, 0.0, 1.0, 1.0]) self.check_pixel_value(tex, 340, 40, [1.0, 0.5, 0.0, 1.0]) self.check_pixel_value(tex, 340, 115, [1.0, 0.5, 0.5, 1.0]) self.check_pixel_value(tex, 340, 190, [1.0, 0.0, 0.5, 1.0]) dispatches = self.find_action("{}: Dispatches".format(level)) # Set up a ReplayOutput and TextureSave for quickly testing the action highlight overlay self.out: rd.ReplayOutput = self.controller.CreateOutput( rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(self.out is not None) # Rewind to the start of the capture action: rd.ActionDescription = dispatches.children[0] while action.previous is not None: action = action.previous # Ensure we can select all actions while action is not None: self.controller.SetFrameEvent(action.eventId, False) action = action.next rdtest.log.success("Selected all {} actions".format(level)) self.check(dispatches and len(real_action_children(dispatches)) == 3) self.check(dispatches.children[0].dispatchDimension == (0, 0, 0)) self.check(dispatches.children[1].dispatchDimension == (1, 1, 1)) self.check(dispatches.children[2].dispatchDimension == (3, 4, 5)) rdtest.log.success( "{} Indirect dispatches are the correct dimensions".format( level)) self.controller.SetFrameEvent(dispatches.children[2].eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() ssbo: rd.BoundResource = pipe.GetReadWriteResources( rd.ShaderStage.Compute)[0].resources[0] data: bytes = self.controller.GetBufferData(ssbo.resourceId, 0, 0) rdtest.log.print("Got {} bytes of uints".format(len(data))) uints = [ struct.unpack_from('=4L', data, offs) for offs in range(0, len(data), 16) ] for x in range(0, 6): # 3 groups of 2 threads each for y in range(0, 8): # 3 groups of 2 threads each for z in range(0, 5): # 5 groups of 1 thread each idx = 100 + z * 8 * 6 + y * 6 + x if not rdtest.value_compare(uints[idx], [x, y, z, 12345]): raise rdtest.TestFailureException( 'expected thread index data @ {},{},{}: {} is not as expected: {}' .format(x, y, z, uints[idx], [x, y, z, 12345])) rdtest.log.success( "Dispatched buffer contents are as expected for {}".format( level)) empties = self.find_action("{}: Empty draws".format(level)) self.check(empties and len(real_action_children(empties)) == 2) action: rd.ActionDescription for action in real_action_children(empties): self.check(action.numIndices == 0) self.check(action.numInstances == 0) self.controller.SetFrameEvent(action.eventId, False) # Check that we have empty PostVS postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut, 0, 1) self.check(len(postvs_data) == 0) # No samples should be passing in the empties self.check_overlay([]) rdtest.log.success("{} empty actions are empty".format(level)) indirects = self.find_action("{}: Indirect draws".format(level)) self.check('vkCmdDrawIndirect' in indirects.children[0].customName) self.check( 'vkCmdDrawIndexedIndirect' in indirects.children[1].customName) self.check(len(real_action_children(indirects.children[1])) == 2) rdtest.log.success( "Correct number of {} indirect draws".format(level)) # vkCmdDrawIndirect(...) action = indirects.children[0] self.check(action.numIndices == 3) self.check(action.numInstances == 2) self.controller.SetFrameEvent(action.eventId, False) self.check( rd.ResourceUsage.Indirect in buffer_usage[action.eventId]) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex_var.gl_Position': [-0.8, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex_var.gl_Position': [-0.7, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex_var.gl_Position': [-0.6, -0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(60, 40)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) self.check(rd.ResourceUsage.Indirect in buffer_usage[ indirects.children[1].eventId]) # vkCmdDrawIndexedIndirect[0](...) action = indirects.children[1].children[0] self.check(action.numIndices == 3) self.check(action.numInstances == 3) self.controller.SetFrameEvent(action.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 6, 'gl_PerVertex_var.gl_Position': [-0.6, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 7, 'gl_PerVertex_var.gl_Position': [-0.5, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 8, 'gl_PerVertex_var.gl_Position': [-0.4, -0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(100, 40)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) # vkCmdDrawIndexedIndirect[1](...) action = indirects.children[1].children[1] self.check(action.numIndices == 6) self.check(action.numInstances == 2) self.controller.SetFrameEvent(action.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) postvs_ref = { 0: { 'vtx': 0, 'idx': 9, 'gl_PerVertex_var.gl_Position': [-0.4, -0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 10, 'gl_PerVertex_var.gl_Position': [-0.3, -0.8, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 11, 'gl_PerVertex_var.gl_Position': [-0.2, -0.8, 0.0, 1.0] }, 3: { 'vtx': 3, 'idx': 12, 'gl_PerVertex_var.gl_Position': [-0.1, -0.5, 0.0, 1.0] }, 4: { 'vtx': 4, 'idx': 13, 'gl_PerVertex_var.gl_Position': [0.0, -0.8, 0.0, 1.0] }, 5: { 'vtx': 5, 'idx': 14, 'gl_PerVertex_var.gl_Position': [0.1, -0.8, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(140, 40), (200, 40)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) if indirect_count_root is not None: self.check(indirect_count_root.children[0].customName == '{}: Empty count draws'.format(level)) self.check(indirect_count_root.children[1].customName == '{}: Indirect count draws'.format(level)) empties = indirect_count_root.children[0] self.check(empties and len(real_action_children(empties)) == 3) action: rd.ActionDescription for action in real_action_children(empties.children): self.check(action.numIndices == 0) self.check(action.numInstances == 0) self.controller.SetFrameEvent(action.eventId, False) # Check that we have empty PostVS postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut, 0, 1) self.check(len(postvs_data) == 0) self.check_overlay([], no_overlay=True) # vkCmdDrawIndirectCountKHR action_indirect = indirect_count_root.children[1].children[0] self.check(rd.ResourceUsage.Indirect in buffer_usage[ action_indirect.eventId]) self.check(action_indirect and len(real_action_children(action_indirect)) == 1) # vkCmdDrawIndirectCountKHR[0] action = action_indirect.children[0] self.check(action.numIndices == 3) self.check(action.numInstances == 4) self.controller.SetFrameEvent(action.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 0, 'gl_PerVertex_var.gl_Position': [-0.8, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 1, 'gl_PerVertex_var.gl_Position': [-0.7, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 2, 'gl_PerVertex_var.gl_Position': [-0.6, 0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(60, 190)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) # vkCmdDrawIndexedIndirectCountKHR action_indirect = indirect_count_root.children[1].children[1] self.check(action_indirect and len(real_action_children(action_indirect)) == 3) # vkCmdDrawIndirectCountKHR[0] action = action_indirect.children[0] self.check(action.numIndices == 3) self.check(action.numInstances == 1) self.controller.SetFrameEvent(action.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 15, 'gl_PerVertex_var.gl_Position': [-0.6, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 16, 'gl_PerVertex_var.gl_Position': [-0.5, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 17, 'gl_PerVertex_var.gl_Position': [-0.4, 0.5, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(100, 190)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) # vkCmdDrawIndirectCountKHR[1] action = action_indirect.children[1] self.check(action.numIndices == 0) self.check(action.numInstances == 0) self.controller.SetFrameEvent(action.eventId, False) postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) self.check(len(postvs_data) == 0) self.check_overlay([]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) # vkCmdDrawIndirectCountKHR[2] action = action_indirect.children[2] self.check(action.numIndices == 6) self.check(action.numInstances == 2) self.controller.SetFrameEvent(action.eventId, False) # Check that we have PostVS as expected postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut) # These indices are the *output* indices, which have been rebased/remapped, so are not the same as the input # indices postvs_ref = { 0: { 'vtx': 0, 'idx': 18, 'gl_PerVertex_var.gl_Position': [-0.4, 0.5, 0.0, 1.0] }, 1: { 'vtx': 1, 'idx': 19, 'gl_PerVertex_var.gl_Position': [-0.3, 0.2, 0.0, 1.0] }, 2: { 'vtx': 2, 'idx': 20, 'gl_PerVertex_var.gl_Position': [-0.2, 0.2, 0.0, 1.0] }, 3: { 'vtx': 3, 'idx': 21, 'gl_PerVertex_var.gl_Position': [-0.1, 0.5, 0.0, 1.0] }, 4: { 'vtx': 4, 'idx': 22, 'gl_PerVertex_var.gl_Position': [0.0, 0.2, 0.0, 1.0] }, 5: { 'vtx': 5, 'idx': 23, 'gl_PerVertex_var.gl_Position': [0.1, 0.2, 0.0, 1.0] }, } self.check_mesh_data(postvs_ref, postvs_data) self.check(len(postvs_data) == len( postvs_ref)) # We shouldn't have any extra vertices self.check_overlay([(140, 190), (200, 190)]) rdtest.log.success("{} {} is as expected".format( level, action.customName)) # Now check that the draws post-count are correctly highlighted self.controller.SetFrameEvent( self.find_action( "{}: Post-count 1".format(level)).children[0].eventId, False) self.check_overlay([(340, 40)]) self.controller.SetFrameEvent( self.find_action( "{}: Post-count 2".format(level)).children[0].eventId, False) self.check_overlay([(340, 190)]) self.controller.SetFrameEvent( self.find_action( "{}: Post-count 3".format(level)).children[0].eventId, False) self.check_overlay([(340, 115)]) else: rdtest.log.print("KHR_action_indirect_count not tested")
def check_capture(self): # Make an output so we can pick pixels out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) self.check(out is not None) draw = self.find_draw("Draw") self.controller.SetFrameEvent(draw.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() bind: rd.ShaderBindpointMapping = pipe.GetBindpointMapping(rd.ShaderStage.Fragment) texs: List[rd.BoundResourceArray] = pipe.GetReadOnlyResources(rd.ShaderStage.Fragment) if len(bind.readOnlyResources) != 2: raise rdtest.TestFailureException( "Expected 2 textures bound, not {}".format(len(bind.readOnlyResources))) if bind.readOnlyResources[0].bind != 2: raise rdtest.TestFailureException( "First texture should be on slot 2, not {}".format(bind.readOnlyResources[0].bind)) id = texs[2].resources[0].resourceId tex_details = self.get_texture(id) res_details = self.get_resource(id) if res_details.name != "Red 2D": raise rdtest.TestFailureException("First texture should be Red 2D texture, not {}".format(res_details.name)) if tex_details.dimension != 2: raise rdtest.TestFailureException( "First texture should be 2D texture, not {}".format(tex_details.dimension)) if tex_details.width != 8 or tex_details.height != 8: raise rdtest.TestFailureException( "First texture should be 8x8, not {}x{}".format(tex_details.width, tex_details.height)) data = self.controller.GetTextureData(id, 0, 0) first_pixel = struct.unpack_from("BBBB", data, 0) if not rdtest.value_compare(first_pixel, (255, 0, 0, 255)): raise rdtest.TestFailureException("Texture should contain red, not {}".format(first_pixel)) rdtest.log.success("First texture is as expected") if bind.readOnlyResources[1].bind != 3: raise rdtest.TestFailureException( "First texture should be on slot 3, not {}".format(texs[0].bindPoint.bind)) id = texs[3].resources[0].resourceId tex_details = self.get_texture(id) res_details = self.get_resource(id) if res_details.name != "Green 3D": raise rdtest.TestFailureException( "First texture should be Green 3D texture, not {}".format(res_details.name)) if tex_details.dimension != 3: raise rdtest.TestFailureException( "First texture should be 3D texture, not {}".format(tex_details.dimension)) if tex_details.width != 4 or tex_details.height != 4 or tex_details.depth != 4: raise rdtest.TestFailureException( "First texture should be 4x4x4, not {}x{}x{}".format(tex_details.width, tex_details.height, tex_details.depth)) data = self.controller.GetTextureData(id, 0, 0) first_pixel = struct.unpack_from("BBBB", data, 0) if not rdtest.value_compare(first_pixel, (0, 255, 0, 255)): raise rdtest.TestFailureException("Texture should contain green, not {}".format(first_pixel)) rdtest.log.success("Second texture is as expected") tex = rd.TextureDisplay() tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) tex_details = self.get_texture(tex.resourceId) picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, int(tex_details.width / 2), int(tex_details.height / 2), 0, 0, 0) if not rdtest.value_compare(picked.floatValue, [1.0, 1.0, 0.0, 0.2]): raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) rdtest.log.success("Picked value is as expected") out.Shutdown()