def check_clearbeforedraw_depth(self, out, depthId): # Test ClearBeforeDraw with a depth target tex = rd.TextureDisplay() tex.overlay = rd.DebugOverlay.ClearBeforeDraw tex.resourceId = depthId out.SetTextureDisplay(tex) out.GetDebugOverlayTexID() # Called to refresh the overlay overlay = rd.DebugOverlay.ClearBeforeDraw test_name = str(overlay) + '.Depth' overlay_path = rdtest.get_tmp_path(test_name + '.png') ref_path = self.get_ref_path(test_name + '.png') save_data = rd.TextureSave() save_data.resourceId = depthId save_data.destType = rd.FileType.PNG save_data.channelExtract = 0 tolerance = 2 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(test_name), overlay_path, ref_path) rdtest.log.success("Reference and output image are identical for {}".format(test_name))
def check_capture(self): self.check_final_backbuffer() # 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. ref_path = self.get_ref_path('backbuffer.png') 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")
def check_capture(self): tex = rd.TextureDisplay() # At each action, the centre pixel of the viewport should be green action = self.get_first_action() while action is not None: self.controller.SetFrameEvent(action.eventId, False) if action.flags & rd.ActionFlags.Drawcall: pipe = self.controller.GetPipelineState() tex = self.controller.GetPipelineState().GetOutputTargets()[0].resourceId 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).height - y self.check_pixel_value(tex, x, y, [0.0, 1.0, 0.0, 1.0]) action = action.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 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")
def check_overlay(self, eventId: int, out: rd.ReplayOutput, tex: rd.TextureDisplay, save_data: rd.TextureSave): pipe: rd.PipeState = self.controller.GetPipelineState() # Check that the highlight draw overlay is empty tex.resourceId = pipe.GetOutputTargets()[0].resourceId out.SetTextureDisplay(tex) overlay_path = rdtest.get_tmp_path(str(self.overlay_idx) + '_draw.png') ref_path = self.get_ref_path(str(self.overlay_idx) + '_draw.png') save_data.resourceId = out.GetDebugOverlayTexID() self.controller.SaveTexture(save_data, overlay_path) if not rdtest.png_compare(overlay_path, ref_path): raise rdtest.TestFailureException("Reference and output image differ @ EID {}".format(str(eventId)), ref_path, overlay_path) self.overlay_idx = self.overlay_idx + 1
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.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.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(self): action: rd.ActionDescription = self.find_action("Degenerate") self.controller.SetFrameEvent(action.next.eventId, True) pipe: rd.VKState = self.controller.GetVulkanPipelineState() if pipe.multisample.rasterSamples != 4: raise rdtest.TestFailureException("MSAA sample count is {}, not 1".format(pipe.multisample.rasterSamples)) sampleLoc: rd.VKSampleLocations = pipe.multisample.sampleLocations if sampleLoc.gridWidth != 1: raise rdtest.TestFailureException("Sample locations grid width is {}, not 1".format(sampleLoc.gridWidth)) if sampleLoc.gridHeight != 1: raise rdtest.TestFailureException("Sample locations grid height is {}, not 1".format(sampleLoc.gridHeight)) # [0] and [1] should be identical, as should [2] and [3], but they should be different from each other if not sampleLoc.customLocations[0] == sampleLoc.customLocations[1]: raise rdtest.TestFailureException("In degenerate case, sample locations [0] and [1] don't match: {} vs {}" .format(sampleLoc.customLocations[0], sampleLoc.customLocations[1])) if not sampleLoc.customLocations[2] == sampleLoc.customLocations[3]: raise rdtest.TestFailureException("In degenerate case, sample locations [2] and [3] don't match: {} vs {}" .format(sampleLoc.customLocations[2], sampleLoc.customLocations[3])) if sampleLoc.customLocations[1] == sampleLoc.customLocations[2]: raise rdtest.TestFailureException("In degenerate case, sample locations [1] and [2] DO match: {} vs {}" .format(sampleLoc.customLocations[1], sampleLoc.customLocations[2])) action: rd.ActionDescription = self.find_action("Rotated") self.controller.SetFrameEvent(action.next.eventId, True) pipe: rd.VKState = self.controller.GetVulkanPipelineState() if pipe.multisample.rasterSamples != 4: raise rdtest.TestFailureException("MSAA sample count is {}, not 1".format(pipe.multisample.rasterSamples)) sampleLoc: rd.VKSampleLocations = pipe.multisample.sampleLocations if sampleLoc.gridWidth != 1: raise rdtest.TestFailureException("Sample locations grid width is {}, not 1".format(sampleLoc.gridWidth)) if sampleLoc.gridHeight != 1: raise rdtest.TestFailureException("Sample locations grid height is {}, not 1".format(sampleLoc.gridHeight)) # All sample locations should be unique if sampleLoc.customLocations[0] == sampleLoc.customLocations[1]: raise rdtest.TestFailureException("In rotated case, sample locations [0] and [1] DO match: {} vs {}" .format(sampleLoc.customLocations[0], sampleLoc.customLocations[1])) if sampleLoc.customLocations[1] == sampleLoc.customLocations[2]: raise rdtest.TestFailureException("In rotated case, sample locations [1] and [2] DO match: {} vs {}" .format(sampleLoc.customLocations[1], sampleLoc.customLocations[2])) if sampleLoc.customLocations[2] == sampleLoc.customLocations[3]: raise rdtest.TestFailureException("In rotated case, sample locations [2] and [3] DO match: {} vs {}" .format(sampleLoc.customLocations[2], sampleLoc.customLocations[3])) rdtest.log.success("Pipeline state is correct") # Grab the multisampled image's ID here save_data = rd.TextureSave() curpass: rd.VKCurrentPass = pipe.currentPass save_data.resourceId = curpass.framebuffer.attachments[curpass.renderpass.colorAttachments[0]].imageResourceId save_data.destType = rd.FileType.PNG save_data.sample.mapToArray = False dim = (0, 0) fmt: rd.ResourceFormat = None texs = self.controller.GetTextures() for tex in texs: tex: rd.TextureDescription if tex.resourceId == save_data.resourceId: dim = (tex.width, tex.height) fmt = tex.format if dim == (0,0): raise rdtest.TestFailureException("Couldn't get dimensions of texture") halfdim = (dim[0] >> 1, dim[1]) if (fmt.type != rd.ResourceFormatType.Regular or fmt.compByteWidth != 1 or fmt.compCount != 4): raise rdtest.TestFailureException("Texture is not RGBA8 as expected: {}".format(fmt.Name())) stride = fmt.compByteWidth * fmt.compCount * dim[0] last_action: rd.ActionDescription = self.get_last_action() self.controller.SetFrameEvent(last_action.eventId, True) # Due to the variability of rasterization between implementations or even drivers, # we don't want to check against a 'known good'. # So instead we verify that at the first degenerate action each pair of two sample's images are identical and that # in the rotated grid case each sample's image is distinct. # In future we could also check that the degenerate case 'stretches' the triangle up, as with the way the # geometry is defined the second sample image should be a superset (i.e. strictly more samples covered). rotated_paths = [] degenerate_paths = [] for sample in range(0, 4): tmp_path = rdtest.get_tmp_path('sample{}.png'.format(sample)) degenerate_path = rdtest.get_tmp_path('degenerate{}.png'.format(sample)) rotated_path = rdtest.get_tmp_path('rotated{}.png'.format(sample)) rotated_paths.append(rotated_path) degenerate_paths.append(degenerate_path) save_data.sample.sampleIndex = sample self.controller.SaveTexture(save_data, tmp_path) combined_data = rdtest.png_load_data(tmp_path) # crop left for degenerate, and crop right for rotated degenerate = [] rotated = [] for row in range(0, dim[1]): srcstart = row * stride len = halfdim[0] * fmt.compCount degenerate.append(combined_data[row][0:len]) rotated.append(combined_data[row][len:]) rdtest.png_save(degenerate_path, degenerate, halfdim, True) rdtest.png_save(rotated_path, rotated, halfdim, True) # first two degenerate images should be identical, as should the last two, and they should be different. if not rdtest.png_compare(degenerate_paths[0], degenerate_paths[1], 0): raise rdtest.TestFailureException("Degenerate grid sample 0 and 1 are different", degenerate_paths[0], degenerate_paths[1]) if not rdtest.png_compare(degenerate_paths[2], degenerate_paths[3], 0): raise rdtest.TestFailureException("Degenerate grid sample 2 and 3 are different", degenerate_paths[2], degenerate_paths[3]) if rdtest.png_compare(degenerate_paths[1], degenerate_paths[2], 0): raise rdtest.TestFailureException("Degenerate grid sample 1 and 2 are identical", degenerate_paths[1], degenerate_paths[2]) rdtest.log.success("Degenerate grid sample images are as expected") # all rotated images should be different for A in range(0, 4): for B in range(A+1, 4): if rdtest.png_compare(rotated_paths[A], rotated_paths[B], 0): raise rdtest.TestFailureException("Rotated grid sample {} and {} are identical".format(A, B), rotated_paths[A], rotated_paths[B]) rdtest.log.success("Rotated grid sample images are 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()