Exemplo n.º 1
0
    def get_shading_rate_for_quad(self, tex, x, y):
        picked = [
            self.controller.PickPixel(tex, x + 0, y + 0, rd.Subresource(),
                                      rd.CompType.Typeless),
            self.controller.PickPixel(tex, x + 1, y + 0, rd.Subresource(),
                                      rd.CompType.Typeless),
            self.controller.PickPixel(tex, x + 0, y + 1, rd.Subresource(),
                                      rd.CompType.Typeless),
            self.controller.PickPixel(tex, x + 1, y + 1, rd.Subresource(),
                                      rd.CompType.Typeless)
        ]

        # all same - 2x2
        if all([p.floatValue == picked[0].floatValue for p in picked]):
            return "2x2"
        # X same Y diff - 2x1
        if (picked[0].floatValue == picked[1].floatValue) and (picked[2].floatValue == picked[3].floatValue) and \
                (picked[0].floatValue != picked[2].floatValue):
            return "2x1"
        # X diff Y same - 1x2
        if (picked[0].floatValue == picked[2].floatValue) and (picked[1].floatValue == picked[3].floatValue) and \
                (picked[0].floatValue != picked[1].floatValue):
            return "1x2"
        # all different - 1x1
        if all([p.floatValue != picked[0].floatValue for p in picked[1:]]):
            return "1x1"
        return "?x?"
Exemplo n.º 2
0
    def depth_target_test(self):
        test_marker: rd.DrawcallDescription = self.find_draw("Test Begin")
        self.controller.SetFrameEvent(test_marker.next.eventId, True)

        pipe: rd.PipeState = self.controller.GetPipelineState()

        rt: rd.BoundResource = pipe.GetDepthTarget()

        tex = rt.resourceId
        tex_details = self.get_texture(tex)

        sub = rd.Subresource()
        if tex_details.arraysize > 1:
            sub.slice = rt.firstSlice
        if tex_details.mips > 1:
            sub.mip = rt.firstMip

        begin_renderpass_eid = self.find_draw("Begin RenderPass").next.eventId
        background_eid = self.find_draw("Background").next.eventId
        test_eid = self.find_draw("Test Begin").next.eventId

        x, y = 200, 190
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True], [post_mod_depth, 1.0]],
            [[event_id, background_eid], [passed, True], [primitive_id, 0], [pre_mod_depth, 1.0], [post_mod_depth, 0.95]],
            [[event_id, test_eid], [passed, True], [depth_test_failed, False], [primitive_id, 0], [shader_out_depth, 0.5], [post_mod_depth, 0.5]],
            [[event_id, test_eid], [passed, False], [depth_test_failed, True], [primitive_id, 1], [shader_out_depth, 0.6], [post_mod_depth, 0.5]],
        ]
        self.check_events(events, modifs, False)
Exemplo n.º 3
0
    def check_pixel_value(self,
                          tex: rd.ResourceId,
                          x,
                          y,
                          value,
                          *,
                          sub=None,
                          cast=None,
                          eps=util.FLT_EPSILON):
        tex_details = self.get_texture(tex)
        res_details = self.get_resource(tex)

        if sub is None:
            sub = rd.Subresource(0, 0, 0)
        if cast is None:
            cast = rd.CompType.Typeless

        if tex_details is not None:
            if type(x) is float:
                x = int(((tex_details.width >> sub.mip) - 1) * x)
            if type(y) is float:
                y = int(((tex_details.height >> sub.mip) - 1) * y)

            if cast == rd.CompType.Typeless and tex_details.creationFlags & rd.TextureCategory.SwapBuffer:
                cast = rd.CompType.UNormSRGB

            # Reduce epsilon for RGBA8 textures if it's not already reduced
            if tex_details.format.compByteWidth == 1 and eps == util.FLT_EPSILON:
                eps = (1.0 / 255.0)

        picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, sub, cast)

        picked_value = picked.floatValue
        if cast == rd.CompType.UInt:
            picked_value = picked.uintValue
        elif cast == rd.CompType.SInt:
            picked_value = picked.intValue

        if not util.value_compare(picked_value, value, eps):
            save_data = rd.TextureSave()
            save_data.resourceId = tex
            save_data.destType = rd.FileType.PNG
            save_data.slice.sliceIndex = sub.slice
            save_data.mip = sub.mip
            save_data.sample.sampleIndex = sub.sample

            img_path = util.get_tmp_path('output.png')

            self.controller.SaveTexture(save_data, img_path)

            raise TestFailureException(
                "Picked value {} at {},{} doesn't match expectation of {}".
                format(picked_value, x, y, value), img_path)

        name = "Texture"
        if res_details is not None:
            name = res_details.name

        log.success("Picked value at {},{} in {} is as expected".format(
            x, y, name))
Exemplo n.º 4
0
        def get_minmax(r: rd.ReplayController):
            minvals, maxvals = r.GetMinMax(texid, rd.Subresource(),
                                           rd.CompType.Typeless)

            msg = '{} has min {:.4} and max {:.4} in red'.format(
                texname, minvals.floatValue[0], maxvals.floatValue[0])

            mqt.InvokeOntoUIThread(lambda: ctx.Extensions().MessageDialog(
                msg, "Extension message"))
Exemplo n.º 5
0
    def multisampled_image_test(self):
        test_marker: rd.DrawcallDescription = self.find_draw(
            "Multisampled: test")
        draw_eid = test_marker.next.eventId
        self.controller.SetFrameEvent(draw_eid, True)

        pipe: rd.PipeState = self.controller.GetPipelineState()
        rt: rd.BoundResource = pipe.GetOutputTargets()[0]
        sub = rd.Subresource()
        tex = rt.resourceId
        tex_details = self.get_texture(tex)
        if tex_details.arraysize > 1:
            sub.slice = rt.firstSlice

        beg_renderpass_eid = self.find_draw(
            "Multisampled: begin renderpass").next.eventId

        x, y = 100, 200
        sub.sample = 1
        rdtest.log.print("Testing pixel {}, {} at sample {}".format(
            x, y, sub.sample))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, beg_renderpass_eid], [passed, True],
             [post_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            [[event_id, draw_eid], [passed, True],
             [post_mod_col, (0.0, 0.0, 1.0, 1.0)]],
        ]
        self.check_events(events, modifs, True)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        sub.sample = 2
        rdtest.log.print("Testing pixel {}, {} at sample {}".format(
            x, y, sub.sample))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, beg_renderpass_eid], [passed, True],
             [post_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            [[event_id, draw_eid], [passed, True],
             [post_mod_col, (0.0, 1.0, 1.0, 1.0)]],
        ]
        self.check_events(events, modifs, True)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)
Exemplo n.º 6
0
    def check_capture(self):
        last_action: rd.ActionDescription = self.get_last_action()

        self.controller.SetFrameEvent(last_action.eventId, True)

        action: rd.ActionDescription = self.find_action('Duration')

        min_duration = float(action.customName.split(' = ')[1])

        if rd.IsReleaseBuild():
            if min_duration >= 15.0:
                raise rdtest.TestFailureException(
                    "Minimum duration noted {} ms is too high".format(
                        min_duration))
            rdtest.log.success(
                "Minimum duration ({}) is OK".format(min_duration))
        else:
            rdtest.log.print(
                "Not checking duration ({}) in non-release build".format(
                    min_duration))

        resources = self.controller.GetResources()
        for i in range(8):
            res: rd.ResourceDescription = [
                r for r in resources if r.name == 'Offscreen{}'.format(i)
            ][0]
            tex: rd.TextureDescription = self.get_texture(res.resourceId)

            data = self.controller.GetTextureData(res.resourceId,
                                                  rd.Subresource(0, 0, 0))

            pixels = [
                struct.unpack_from("4f", data, 16 * p)
                for p in range(tex.width * tex.height)
            ]

            unique_pixels = list(set(pixels))

            if len(unique_pixels) > 2:
                raise rdtest.TestFailureException(
                    "Too many pixel values found ({})".format(
                        len(unique_pixels)))

            if (0.0, 0.0, 0.0, 1.0) not in unique_pixels:
                raise rdtest.TestFailureException(
                    "Didn't find background colour in unique pixels list")

            unique_pixels.remove((0.0, 0.0, 0.0, 1.0))

            if not rdtest.value_compare(
                (0.8, 0.8, 0.8, 0.4), unique_pixels[0]):
                raise rdtest.TestFailureException(
                    "Didn't find foreground colour in unique pixels list")

            rdtest.log.success("{} has correct contents".format(res.name))
Exemplo n.º 7
0
    def secondary_cmd_test(self):
        secondary_marker: rd.DrawcallDescription = self.find_draw("Secondary: red and blue")
        self.controller.SetFrameEvent(secondary_marker.next.eventId, True)

        pipe: rd.PipeState = self.controller.GetPipelineState()
        rt: rd.BoundResource = pipe.GetOutputTargets()[0]
        sub = rd.Subresource()
        tex = rt.resourceId
        tex_details = self.get_texture(tex)
        if tex_details.arraysize > 1:
            sub.slice = rt.firstSlice
        if tex_details.mips > 1:
            sub.mip = rt.firstMip

        sec_beg_renderpass_eid = self.find_draw("Begin RenderPass Secondary").next.eventId
        background_eid = self.find_draw("Secondary: background").next.eventId
        culled_eid = self.find_draw("Secondary: culled").next.eventId
        sec_red_and_blue = self.find_draw("Secondary: red and blue").next.eventId

        # Test culling
        x, y = 70, 40
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, sec_beg_renderpass_eid], [passed, True], [post_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            [[event_id, background_eid], [passed, True], [pre_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            [[event_id, culled_eid], [passed, False], [culled, True]],
        ]
        self.check_events(events, modifs, True)
        self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)

        # Blue triangle
        x, y = 40, 40
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, sec_beg_renderpass_eid], [passed, True], [post_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            # This is the first event in the command buffer, should have pre-mod
            [[event_id, background_eid], [passed, True], [pre_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            # This is the last event in the command buffer, should have post-mod
            [[event_id, sec_red_and_blue], [passed, True], [post_mod_col, (0.0, 0.0, 1.0, 1.0)]],
        ]
        self.check_events(events, modifs, True)
        self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)

        # Didn't get post mod for background_eid
        self.controller.SetFrameEvent(background_eid, True)
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, sec_beg_renderpass_eid]],
            # The only event, should have both pre and post mod.
            [[event_id, background_eid], [passed, True], [pre_mod_col, (0.0, 1.0, 0.0, 1.0)], [post_mod_col, (1.0, 0.0, 1.0, 1.0)]],
        ]
        self.check_events(events, modifs, True)
        self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
Exemplo n.º 8
0
    def sample(self, row, col):
        ret = []
        for p in self.points:
            x = self.view[0] * col + p[0]
            y = self.view[1] * row + p[1]

            picked: rd.PixelValue = self.controller.PickPixel(
                self.tex, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless)
            ret.append(
                rdtest.value_compare(picked.floatValue, [0.0, 1.0, 1.0, 1.0]))
        return ret
Exemplo n.º 9
0
    def check_capture(self):
        last_draw: rd.DrawcallDescription = self.get_last_draw()

        self.controller.SetFrameEvent(last_draw.eventId, True)

        self.check_triangle(out=last_draw.copyDestination)

        self.check_export(self.capture_filename)

        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_PerVertex_var.gl_Position': [-0.5, 0.5, 0.0, 1.0],
                'vertOut.pos': [-0.5, 0.5, 0.0, 1.0],
                'vertOut.col': [0.0, 1.0, 0.0, 1.0],
                'vertOut.uv': [0.0, 0.0, 0.0, 1.0],
            },
            1: {
                'vtx': 1,
                'idx': 1,
                'gl_PerVertex_var.gl_Position': [0.0, -0.5, 0.0, 1.0],
                'vertOut.pos': [0.0, -0.5, 0.0, 1.0],
                'vertOut.col': [0.0, 1.0, 0.0, 1.0],
                'vertOut.uv': [0.0, 1.0, 0.0, 1.0],
            },
            2: {
                'vtx': 2,
                'idx': 2,
                'gl_PerVertex_var.gl_Position': [0.5, 0.5, 0.0, 1.0],
                'vertOut.pos': [0.5, 0.5, 0.0, 1.0],
                'vertOut.col': [0.0, 1.0, 0.0, 1.0],
                'vertOut.uv': [1.0, 0.0, 0.0, 1.0],
            },
        }

        self.check_mesh_data(postvs_ref, postvs_data)

        # Check that nothing breaks if we call typical enumeration functions on resources
        for res in self.controller.GetResources():
            res: rd.ResourceDescription

            self.controller.GetShaderEntryPoints(res.resourceId)
            self.controller.GetUsage(res.resourceId)
            self.controller.GetBufferData(res.resourceId, 0, 0)
            self.controller.GetTextureData(res.resourceId, rd.Subresource())
Exemplo n.º 10
0
    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)

        self.check_export(self.capture_filename)

        action = self.find_action("Draw")

        self.controller.SetFrameEvent(action.eventId, False)

        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)

        # Check that nothing breaks if we call typical enumeration functions on resources
        for res in self.controller.GetResources():
            res: rd.ResourceDescription

            self.controller.GetShaderEntryPoints(res.resourceId)
            self.controller.GetUsage(res.resourceId)
            self.controller.GetBufferData(res.resourceId, 0, 0)
            self.controller.GetTextureData(res.resourceId, rd.Subresource())
Exemplo n.º 11
0
    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-1) * x)
        if type(y) is float:
            y = int((tex_details.height-1) * y)

        picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless)

        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 get_output_hashes_of_eid(controller, event_id):
    controller.SetFrameEvent(event_id, True)

    resource_hashes = dict()

    pipeline_state = controller.GetPipelineState()

    color_targets = pipeline_state.GetOutputTargets()
    depth_targets = [pipeline_state.GetDepthTarget()]

    for bound_resource in (color_targets + depth_targets):
        if bound_resource.resourceId == rd.ResourceId.Null():
            continue

        # TODO: Should we check all slices and mips starting from firstMip and firstSlice?

        subresource = rd.Subresource(bound_resource.firstMip, bound_resource.firstSlice, 0)
        data = controller.GetTextureData(bound_resource.resourceId, subresource)

        sha1 = hashlib.sha1()
        sha1.update(data)

        subresource_desc = SubresourceDesc(bound_resource.firstMip, bound_resource.firstSlice)
        resource_hashes[ResourceKey(bound_resource.resourceId, subresource_desc)] = sha1.hexdigest()

    for stage in range(rd.ShaderStage.Count):
        rw_resources = pipeline_state.GetReadWriteResources(stage)
        for rw_resource_array in rw_resources:
            for bound_rw_resource in rw_resource_array.resources:
                if bound_rw_resource.resourceId == rd.ResourceId.Null():
                    continue

                data = controller.GetBufferData(bound_rw_resource.resourceId, 0, 0)

                sha1 = hashlib.sha1()
                sha1.update(data)

                subresource_desc = SubresourceDesc(0, 0)
                resource_hashes[ResourceKey(bound_rw_resource.resourceId, subresource_desc)] = sha1.hexdigest()

    return resource_hashes
Exemplo n.º 13
0
    def check_capture(self):
        self.check_textures()

        # Test render pass attachments
        draw = self.find_draw("TestStart")

        rpcol: rd.TextureDescription = self.get_texture(
            [res for res in self.controller.GetResources() if "RPCol" in res.name][0].resourceId)
        rpdepth: rd.TextureDescription = self.get_texture(
            [res for res in self.controller.GetResources() if "RPDepth" in res.name][0].resourceId)

        self.check(draw is not None)

        self.controller.SetFrameEvent(draw.next.eventId, True)

        # At the start they should be cleared

        for y in range(0, rpcol.height-1, 17):
            for x in range(0, rpcol.width-1, 17):
                self.check_pixel_value(rpcol.resourceId, x, y, [0.0, 1.0, 0.0, 1.0])
                self.check_pixel_value(rpdepth.resourceId, x, y, [0.4, float(0x40)/float(255), 0.0, 1.0])

        rdtest.log.success("Values are correct before the renderpass")

        draw = self.find_draw("TestMiddle")

        self.controller.SetFrameEvent(draw.next.eventId, True)

        for y in range(0, rpcol.height-1, 17):
            for x in range(0, rpcol.width-1, 17):

                # if we're in the rect, check for pattern colors
                if 50 <= x < 125 and 50 <= y < 125:
                    c: rd.PixelValue = self.controller.PickPixel(rpcol.resourceId, x, y, rd.Subresource(),
                                                                 rd.CompType.Typeless)
                    d: rd.PixelValue = self.controller.PickPixel(rpdepth.resourceId, x, y, rd.Subresource(),
                                                                 rd.CompType.Typeless)

                    if not rdtest.value_compare(c.floatValue, [0.0] * 4) and not rdtest.value_compare(c.floatValue,
                                                                                                      [1000.0] * 4):
                        raise rdtest.TestFailureException(
                            'middle color has unexpected value at {},{}: {}'.format(x, y, c.floatValue))

                    if not rdtest.value_compare(d.floatValue[0:2], [0.0] * 2) and not rdtest.value_compare(
                            d.floatValue[0:2], [1.0] * 2):
                        raise rdtest.TestFailureException(
                            'middle depth has unexpected value at {},{}: {}'.format(x, y, d.floatValue))
                else:
                    self.check_pixel_value(rpcol.resourceId, x, y, [0.0, 1.0, 0.0, 1.0])
                    self.check_pixel_value(rpdepth.resourceId, x, y, [0.4, float(0x40)/float(255), 0.0, 1.0])

        middle_col_bytes = self.controller.GetTextureData(rpcol.resourceId, rd.Subresource())
        middle_depth_bytes = self.controller.GetTextureData(rpdepth.resourceId, rd.Subresource())

        rdtest.log.success("Values are correct in the middle of the renderpass")

        draw = self.find_draw("TestEnd")

        self.controller.SetFrameEvent(draw.next.eventId, True)

        for y in range(0, rpcol.height-1, 17):
            for x in range(0, rpcol.width-1, 17):

                # if we're in the rect, check for pattern colors
                if 50 <= x < 125 and 50 <= y < 125:
                    c: rd.PixelValue = self.controller.PickPixel(rpcol.resourceId, x, y, rd.Subresource(),
                                                                 rd.CompType.Typeless)
                    d: rd.PixelValue = self.controller.PickPixel(rpdepth.resourceId, x, y, rd.Subresource(),
                                                                 rd.CompType.Typeless)

                    if not rdtest.value_compare(c.floatValue, [0.0] * 4) and not rdtest.value_compare(c.floatValue,
                                                                                                      [1000.0] * 4):
                        raise rdtest.TestFailureException(
                            'middle color has unexpected value at {},{}: {}'.format(x, y, c.floatValue))

                    if not rdtest.value_compare(d.floatValue[0:2], [0.0] * 2) and not rdtest.value_compare(
                            d.floatValue[0:2], [1.0] * 2):
                        raise rdtest.TestFailureException(
                            'middle depth has unexpected value at {},{}: {}'.format(x, y, d.floatValue))
                else:
                    self.check_pixel_value(rpcol.resourceId, x, y, [0.0, 1.0, 0.0, 1.0])
                    self.check_pixel_value(rpdepth.resourceId, x, y, [0.4, float(0x40)/float(255), 0.0, 1.0])

        rdtest.log.success("Values are correct after the renderpass")

        end_col_bytes = self.controller.GetTextureData(rpcol.resourceId, rd.Subresource())
        end_depth_bytes = self.controller.GetTextureData(rpdepth.resourceId, rd.Subresource())

        self.check(middle_col_bytes != end_col_bytes)
        self.check(middle_depth_bytes != end_depth_bytes)
Exemplo n.º 14
0
    def check_capture(self):
        action = self.get_last_action()

        self.controller.SetFrameEvent(action.eventId, False)

        # Should have barycentrics showing the closest vertex for each pixel in the triangle
        # Without relying on barycentric order, ensure that the three pixels are red, green, and blue
        pixels = []

        picked: rd.PixelValue = self.controller.PickPixel(
            action.copyDestination, 125, 215, rd.Subresource(),
            rd.CompType.UNorm)
        pixels.append(picked.floatValue[0:4])
        picked: rd.PixelValue = self.controller.PickPixel(
            action.copyDestination, 200, 85, rd.Subresource(),
            rd.CompType.UNorm)
        pixels.append(picked.floatValue[0:4])
        picked: rd.PixelValue = self.controller.PickPixel(
            action.copyDestination, 285, 215, rd.Subresource(),
            rd.CompType.UNorm)
        pixels.append(picked.floatValue[0:4])

        if (not (1.0, 0.0, 0.0, 1.0)
                in pixels) or (not (1.0, 0.0, 0.0, 1.0) in pixels) or (
                    not (1.0, 0.0, 0.0, 1.0) in pixels):
            raise rdtest.TestFailureException(
                "Expected red, green and blue in picked pixels. Got {}".format(
                    pixels))

        rdtest.log.success("Picked barycentric values are as expected")

        # find the cpuMax and gpuMax actions
        cpuMax = self.find_action("cpuMax")
        gpuMax = self.find_action("gpuMax")

        # The values should be identical
        cpuMax = int(cpuMax.customName[8:])
        gpuMax = int(gpuMax.customName[8:])

        if cpuMax != gpuMax or cpuMax == 0:
            raise rdtest.TestFailureException(
                "captured cpuMax and gpuMax are not equal and positive: {} vs {}"
                .format(cpuMax, gpuMax))

        rdtest.log.success("recorded cpuMax and gpuMax are as expected")

        outBuf = self.get_resource_by_name("outBuf")

        data = self.controller.GetBufferData(outBuf.resourceId, 0, 8)

        replayedGpuMax = struct.unpack("Q", data)[0]

        if replayedGpuMax != gpuMax:
            raise rdtest.TestFailureException(
                "captured gpuMax and replayed gpuMax are not equal: {} vs {}".
                format(gpuMax, replayedGpuMax))

        rdtest.log.success("replayed gpuMax is as expected")

        cs = self.get_resource_by_name("cs")
        pipe = rd.ResourceId()

        refl: rd.ShaderReflection = self.controller.GetShader(
            pipe, cs.resourceId,
            rd.ShaderEntryPoint("main", rd.ShaderStage.Compute))

        self.check(len(refl.readWriteResources) == 2)
        self.check([rw.name
                    for rw in refl.readWriteResources] == ["inUAV", "outUAV"])

        disasm = self.controller.DisassembleShader(pipe, refl, "")

        if "amd_u64_atomic" not in disasm:
            raise rdtest.TestFailureException(
                "Didn't find expected AMD opcode in disassembly: {}".format(
                    disasm))

        rdtest.log.success("compute shader disassembly is as expected")

        if refl.debugInfo.debuggable:
            self.controller.SetFrameEvent(
                self.find_action("Dispatch").eventId, False)

            trace: rd.ShaderDebugTrace = self.controller.DebugThread((0, 0, 0),
                                                                     (0, 0, 0))

            if trace.debugger is None:
                self.controller.FreeTrace(trace)

                raise rdtest.TestFailureException(
                    "Couldn't debug compute shader")

            cycles, variables = self.process_trace(trace)

            if cycles < 3:
                raise rdtest.TestFailureException(
                    "Compute shader has too few cycles {}".format(cycles))
        else:
            raise rdtest.TestFailureException(
                "Compute shader is listed as non-debuggable: {}".format(
                    refl.debugInfo.debugStatus))

        rdtest.log.success("compute shader debugged successfully")
Exemplo n.º 15
0
    def pixel_debug(self, draw: rd.DrawcallDescription):
        pipe: rd.PipeState = self.controller.GetPipelineState()

        if pipe.GetShader(rd.ShaderStage.Pixel) == rd.ResourceId.Null():
            rdtest.log.print("No pixel shader bound at {}: {}".format(draw.eventId, draw.name))
            return

        if len(pipe.GetOutputTargets()) == 0 and pipe.GetDepthTarget().resourceId == rd.ResourceId.Null():
            rdtest.log.print("No render targets bound at {}: {}".format(draw.eventId, draw.name))
            return

        if not (draw.flags & rd.DrawFlags.Drawcall):
            rdtest.log.print("{}: {} is not a debuggable drawcall".format(draw.eventId, draw.name))
            return

        viewport = pipe.GetViewport(0)

        # TODO, query for some pixel this drawcall actually touched.
        x = int(random.random()*viewport.width + viewport.x)
        y = int(random.random()*viewport.height + viewport.y)

        target = rd.ResourceId.Null()

        if len(pipe.GetOutputTargets()) > 0:
            valid_targets = [o.resourceId for o in pipe.GetOutputTargets() if o.resourceId != rd.ResourceId.Null()]
            rdtest.log.print("Valid targets at {} are {}".format(draw.eventId, valid_targets))
            if len(valid_targets) > 0:
                target = valid_targets[int(random.random()*len(valid_targets))]

        if target == rd.ResourceId.Null():
            target = pipe.GetDepthTarget().resourceId

        if target == rd.ResourceId.Null():
            rdtest.log.print("No targets bound! Can't fetch history at {}".format(draw.eventId))
            return

        rdtest.log.print("Fetching history for %d,%d on target %s" % (x, y, str(target)))

        history = self.controller.PixelHistory(target, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless)

        rdtest.log.success("Pixel %d,%d has %d history events" % (x, y, len(history)))

        lastmod: rd.PixelModification = None

        for i in range(len(history)-1, 0, -1):
            mod = history[i]
            draw = self.find_draw('', mod.eventId)

            rdtest.log.print("  hit %d at %d is %s (%s)" % (i, mod.eventId, draw.name, str(draw.flags)))

            if draw is None or not (draw.flags & rd.DrawFlags.Drawcall):
                continue

            lastmod = history[i]

            rdtest.log.print("Got a hit on a drawcall at event %d" % lastmod.eventId)

            if mod.sampleMasked or mod.backfaceCulled or mod.depthClipped or mod.viewClipped or mod.scissorClipped or mod.depthTestFailed or mod.stencilTestFailed:
                rdtest.log.print("This hit failed, looking for one that passed....")
                lastmod = None
                continue

            break

        if lastmod is not None:
            rdtest.log.print("Debugging pixel {},{} @ {}, primitive {}".format(x, y, lastmod.eventId, lastmod.primitiveID))
            self.controller.SetFrameEvent(lastmod.eventId, True)

            trace = self.controller.DebugPixel(x, y, 0, lastmod.primitiveID)

            if draw.outputs[0] == rd.ResourceId.Null():
                rdtest.log.success('Successfully debugged pixel in {} cycles, skipping result check due to no output'.format(len(trace.states)))
            elif draw.numInstances == 1:
                lastState: rd.ShaderDebugState = trace.states[-1]

                output_index = [o.resourceId for o in self.controller.GetPipelineState().GetOutputTargets()].index(target)
                rdtest.log.print("At event {} the target is index {}".format(lastmod.eventId, output_index))

                debugged: rd.ShaderVariable = lastState.outputs[output_index]

                debuggedValue = [debugged.value.f.x, debugged.value.f.y, debugged.value.f.z, debugged.value.f.w]

                if not rdtest.value_compare(lastmod.shaderOut.col.floatValue, [debugged.value.f.x, debugged.value.f.y, debugged.value.f.z, debugged.value.f.w]):
                    raise rdtest.TestFailureException("Debugged value {}: {} doesn't match history shader output {}".format(debugged.name, debuggedValue, lastmod.shaderOut.col.floatValue))

                rdtest.log.success('Successfully debugged pixel in {} cycles, result matches'.format(len(trace.states)))
            else:
                rdtest.log.success('Successfully debugged pixel in {} cycles, skipping result check due to instancing'.format(len(trace.states)))

            self.controller.SetFrameEvent(draw.eventId, True)
Exemplo n.º 16
0
    def check_capture(self):
        # Jump to the draw
        draw = self.find_draw("Draw")

        self.controller.SetFrameEvent(draw.eventId, False)

        pipe: rd.PipeState = self.controller.GetPipelineState()

        failed = False

        # Loop over every test
        rdtest.log.begin_section("General tests")
        for test in range(draw.numInstances):
            # Debug the shader
            trace: rd.ShaderDebugTrace = self.controller.DebugPixel(4 * test, 0, rd.ReplayController.NoPreference,
                                                                    rd.ReplayController.NoPreference)

            cycles, variables = self.process_trace(trace)

            output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)

            debugged = self.evaluate_source_var(output, variables)

            try:
                self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 4 * test, 0, debugged.value.f32v[0:4])
            except rdtest.TestFailureException as ex:
                failed = True
                rdtest.log.error("Test {} did not match. {}".format(test, str(ex)))
                continue
            finally:
                self.controller.FreeTrace(trace)

            rdtest.log.success("Test {} matched as expected".format(test))
        rdtest.log.end_section("General tests")

        rdtest.log.begin_section("MSAA tests")
        draw = draw.next
        self.controller.SetFrameEvent(draw.eventId, False)
        pipe: rd.PipeState = self.controller.GetPipelineState()
        for test in range(4):
            # Debug the shader
            trace: rd.ShaderDebugTrace = self.controller.DebugPixel(4, 4, test,
                                                                    rd.ReplayController.NoPreference)

            # Validate that the correct sample index was debugged
            sampRegister = self.find_input_source_var(trace, rd.ShaderBuiltin.MSAASampleIndex)
            sampInput = [var for var in trace.inputs if var.name == sampRegister.variables[0].name][0]
            if sampInput.value.u32v[0] != test:
                rdtest.log.error("Test {} did not pick the correct sample.".format(test))

            cycles, variables = self.process_trace(trace)

            output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)

            debugged = self.evaluate_source_var(output, variables)

            # Validate the debug output result
            try:
                self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, debugged.value.f32v[0:4], sub=rd.Subresource(0, 0, test))
            except rdtest.TestFailureException as ex:
                failed = True
                rdtest.log.error("Test {} did not match. {}".format(test, str(ex)))
                continue

        rdtest.log.end_section("MSAA tests")

        if failed:
            raise rdtest.TestFailureException("Some tests were not as expected")

        rdtest.log.success("All tests matched")
Exemplo n.º 17
0
    def check_test(self, fmt_name: str, name: str, test_mode: int):
        pipe: rd.PipeState = self.controller.GetPipelineState()

        image_view = (test_mode != Texture_Zoo.TEST_CAPTURE)

        if image_view:
            bound_res: rd.BoundResource = pipe.GetOutputTargets()[0]
        else:
            bound_res: rd.BoundResource = pipe.GetReadOnlyResources(
                rd.ShaderStage.Pixel)[0].resources[0]

        texs = self.controller.GetTextures()
        for t in texs:
            self.textures[t.resourceId] = t

        tex_id: rd.ResourceId = bound_res.resourceId
        tex: rd.TextureDescription = self.textures[tex_id]

        comp_type: rd.CompType = tex.format.compType
        if bound_res.typeCast != rd.CompType.Typeless:
            comp_type = bound_res.typeCast

        # When not running proxied, save non-typecasted textures to disk
        if not image_view and not self.proxied and (
                tex.format.compType == comp_type
                or tex.format.type == rd.ResourceFormatType.D24S8
                or tex.format.type == rd.ResourceFormatType.D32S8):
            save_data = rd.TextureSave()
            save_data.resourceId = tex_id
            save_data.destType = rd.FileType.DDS
            save_data.sample.mapToArray = True

            self.textures[self.filename] = tex

            path = rdtest.get_tmp_path(self.filename + '.dds')

            success: bool = self.controller.SaveTexture(save_data, path)

            if not success:
                try:
                    os.remove(path)
                except Exception:
                    pass

            save_data.destType = rd.FileType.PNG
            save_data.slice.sliceIndex = 0
            save_data.sample.sampleIndex = 0
            path = path.replace('.dds', '.png')

            if comp_type == rd.CompType.UInt:
                save_data.comp.blackPoint = 0.0
                save_data.comp.whitePoint = 255.0
            elif comp_type == rd.CompType.SInt:
                save_data.comp.blackPoint = -255.0
                save_data.comp.whitePoint = 0.0
            elif comp_type == rd.CompType.SNorm:
                save_data.comp.blackPoint = -1.0
                save_data.comp.whitePoint = 0.0

            success: bool = self.controller.SaveTexture(save_data, path)

            if not success:
                try:
                    os.remove(path)
                except Exception:
                    pass

        value0 = []

        comp_count = tex.format.compCount

        # When viewing PNGs only compare the components that the original texture had
        if test_mode == Texture_Zoo.TEST_PNG:
            comp_count = self.textures[self.filename]
            tex.msSamp = 0
            tex.arraysize = 1
            tex.depth = 1
            self.fake_msaa = 'MSAA' in name
        elif test_mode == Texture_Zoo.TEST_DDS:
            tex.arraysize = self.textures[self.filename].arraysize
            tex.msSamp = self.textures[self.filename].msSamp
            self.fake_msaa = 'MSAA' in name

        # HACK: We don't properly support BGRX, so just drop the alpha channel. We can't set this to compCount = 3
        # internally because that's a 24-bit format with no padding...
        if 'B8G8R8X8' in fmt_name:
            comp_count = 3

        # Completely ignore the alpha for BC1, our encoder doesn't pay attention to it
        if tex.format.type == rd.ResourceFormatType.BC1:
            comp_count = 3

        # Calculate format-appropriate epsilon
        eps_significand = 1.0
        # Account for the sRGB curve by more generous epsilon

        if comp_type == rd.CompType.UNormSRGB:
            eps_significand = 2.5
        # Similarly SNorm essentially loses a bit of accuracy due to us only using negative values
        elif comp_type == rd.CompType.SNorm:
            eps_significand = 2.0

        if tex.format.type == rd.ResourceFormatType.R4G4B4A4 or tex.format.type == rd.ResourceFormatType.R4G4:
            eps = (eps_significand / 15.0)
        elif rd.ResourceFormatType.BC1 <= tex.format.type <= rd.ResourceFormatType.BC3:
            eps = (eps_significand / 15.0)  # 4-bit precision in some channels
        elif tex.format.type == rd.ResourceFormatType.R5G5B5A1 or tex.format.type == rd.ResourceFormatType.R5G6B5:
            eps = (eps_significand / 31.0)
        elif tex.format.type == rd.ResourceFormatType.R11G11B10:
            eps = (eps_significand / 31.0)  # 5-bit mantissa in blue
        elif tex.format.type == rd.ResourceFormatType.R9G9B9E5:
            eps = (
                eps_significand / 63.0
            )  # we have 9 bits of data, but might lose 2-3 due to shared exponent
        elif tex.format.type == rd.ResourceFormatType.BC6 and tex.format.compType == rd.CompType.SNorm:
            eps = (eps_significand / 63.0
                   )  # Lose a bit worth of precision for the signed version
        elif rd.ResourceFormatType.BC4 <= tex.format.type <= rd.ResourceFormatType.BC7:
            eps = (eps_significand / 127.0)
        elif tex.format.compByteWidth == 1:
            eps = (eps_significand / 255.0)
        elif comp_type == rd.CompType.Depth and tex.format.compCount == 2:
            eps = (eps_significand / 255.0)  # stencil is only 8-bit
        elif tex.format.type == rd.ResourceFormatType.A8:
            eps = (eps_significand / 255.0)
        elif tex.format.type == rd.ResourceFormatType.R10G10B10A2:
            eps = (eps_significand / 1023.0)
        else:
            # half-floats have 11-bit mantissa. This epsilon is tight enough that we can be sure
            # any remaining errors are implementation inaccuracy and not our bug
            eps = (eps_significand / 2047.0)

        for mp in range(tex.mips):
            for sl in range(max(tex.arraysize, max(1, tex.depth >> mp))):
                z = 0
                if tex.depth > 1:
                    z = sl

                for sm in range(tex.msSamp):
                    for x in range(max(1, tex.width >> mp)):
                        for y in range(max(1, tex.height >> mp)):
                            picked: rd.PixelValue = self.pick(
                                tex_id, x, y, self.sub(mp, sl, sm), comp_type)

                            # each 3D slice cycles the x. This only affects the primary diagonal
                            offs_x = (x + z) % max(1, tex.width >> mp)

                            # The diagonal inverts the colors
                            inverted = (offs_x != y)

                            # second slice adds a coarse checkerboard pattern of inversion
                            if tex.arraysize > 1 and sl == 1 and (
                                (int(x / 2) % 2) != (int(y / 2) % 2)):
                                inverted = not inverted

                            if comp_type == rd.CompType.UInt or comp_type == rd.CompType.SInt:
                                expected = [10, 40, 70, 100]

                                if inverted:
                                    expected = list(reversed(expected))

                                expected = [
                                    c + 10 * (sm + mp) for c in expected
                                ]

                                if comp_type == rd.CompType.SInt:
                                    picked = picked.intValue
                                else:
                                    picked = picked.uintValue
                            elif (tex.format.type
                                  == rd.ResourceFormatType.D16S8
                                  or tex.format.type
                                  == rd.ResourceFormatType.D24S8
                                  or tex.format.type
                                  == rd.ResourceFormatType.D32S8):
                                # depth/stencil is a bit special
                                expected = [0.1, 10, 100, 0.85]

                                if inverted:
                                    expected = list(reversed(expected))

                                expected[0] += 0.075 * (sm + mp)
                                expected[1] += 10 * (sm + mp)

                                # Normalise stencil value
                                expected[1] = expected[1] / 255.0

                                picked = picked.floatValue
                            else:
                                expected = [0.1, 0.35, 0.6, 0.85]

                                if inverted:
                                    expected = list(reversed(expected))

                                expected = [
                                    c + 0.075 * (sm + mp) for c in expected
                                ]

                                picked = picked.floatValue

                            # SNorm/SInt is negative
                            if comp_type == rd.CompType.SNorm or comp_type == rd.CompType.SInt:
                                expected = [-c for c in expected]

                            # BGRA textures have a swizzle applied
                            if tex.format.BGRAOrder():
                                expected[0:3] = reversed(expected[0:3])

                            # alpha channel in 10:10:10:2 has extremely low precision, and the ULP requirements mean
                            # we basically can't trust anything between 0 and 1 on float formats. Just round in that
                            # case as it still lets us differentiate between alpha 0.0-0.5 and 0.5-1.0
                            if tex.format.type == rd.ResourceFormatType.R10G10B10A2:
                                if comp_type == rd.CompType.UInt:
                                    expected[3] = min(3, expected[3])
                                else:
                                    expected[3] = round(expected[3]) * 1.0
                                    picked[3] = round(picked[3]) * 1.0

                            # Handle 1-bit alpha
                            if tex.format.type == rd.ResourceFormatType.R5G5B5A1:
                                expected[
                                    3] = 1.0 if expected[3] >= 0.5 else 0.0
                                picked[3] = 1.0 if picked[3] >= 0.5 else 0.0

                            # A8 picked values come out in alpha, but we want to compare against the single channel
                            if tex.format.type == rd.ResourceFormatType.A8:
                                picked[0] = picked[3]

                            # Clamp to number of components in the texture
                            expected = expected[0:comp_count]
                            picked = picked[0:comp_count]

                            if mp == 0 and sl == 0 and sm == 0 and x == 0 and y == 0:
                                value0 = picked

                            # For SRGB textures picked values will come out as linear
                            def srgb2linear(f):
                                if f <= 0.04045:
                                    return f / 12.92
                                else:
                                    return ((f + 0.055) / 1.055)**2.4

                            if comp_type == rd.CompType.UNormSRGB:
                                expected[0:3] = [
                                    srgb2linear(x) for x in expected[0:3]
                                ]

                            if test_mode == Texture_Zoo.TEST_PNG:
                                orig_comp = self.textures[
                                    self.filename].format.compType
                                if orig_comp == rd.CompType.SNorm or orig_comp == rd.CompType.SInt:
                                    expected = [1.0 - x for x in expected]

                            if not rdtest.value_compare(picked, expected, eps):
                                raise rdtest.TestFailureException(
                                    "At ({},{}) of slice {}, mip {}, sample {} of {} {} got {}. Expected {}"
                                    .format(x, y, sl, mp, sm, name, fmt_name,
                                            picked, expected))

        if not image_view:
            output_tex = pipe.GetOutputTargets()[0].resourceId

            # in the test captures pick the output texture, it should be identical to the
            # (0,0) pixel in slice 0, mip 0, sample 0
            view: rd.Viewport = pipe.GetViewport(0)

            val: rd.PixelValue = self.pick(
                pipe.GetOutputTargets()[0].resourceId,
                int(view.x + view.width / 2), int(view.y + view.height / 2),
                rd.Subresource(), rd.CompType.Typeless)

            picked = val.floatValue

            # A8 picked values come out in alpha, but we want to compare against the single channel
            if tex.format.type == rd.ResourceFormatType.A8:
                picked[0] = picked[3]

            # Clamp to number of components in the texture
            picked = picked[0:comp_count]

            # Up-convert any non-float expected values to floats
            value0 = [float(x) for x in value0]

            # For depth/stencil images, one of either depth or stencil should match
            if comp_type == rd.CompType.Depth and len(value0) == 2:
                if picked[0] == 0.0:
                    value0[0] = 0.0
                    # normalise stencil value if it isn't already
                    if picked[1] > 1.0:
                        picked[1] /= 255.0
                elif picked[0] > 1.0:
                    # un-normalised stencil being rendered in red, match against our stencil expectation
                    picked[0] /= 255.0
                    value0[0] = value0[1]
                    value0[1] = 0.0
                else:
                    value0[1] = 0.0

            if not rdtest.value_compare(picked, value0, eps):
                raise rdtest.TestFailureException(
                    "In {} {} Top-left pixel as rendered is {}. Expected {}".
                    format(name, fmt_name, picked, value0))
Exemplo n.º 18
0
    def check_capture(self):
        if not self.controller.GetAPIProperties().shaderDebugging:
            rdtest.log.success("Shader debugging not enabled, skipping test")
            return

        failed = False

        shaderModels = ["sm_5_0", "sm_5_1"]
        for sm in range(len(shaderModels)):
            rdtest.log.begin_section(shaderModels[sm] + " tests")

            # Jump to the action
            test_marker: rd.ActionDescription = self.find_action(
                shaderModels[sm])
            action = test_marker.next
            self.controller.SetFrameEvent(action.eventId, False)

            pipe: rd.PipeState = self.controller.GetPipelineState()

            if not pipe.GetShaderReflection(
                    rd.ShaderStage.Pixel).debugInfo.debuggable:
                rdtest.log.print("Skipping undebuggable shader at {}.".format(
                    action.eventId))
                return

            # Loop over every test
            for test in range(action.numInstances):
                # Debug the shader
                trace: rd.ShaderDebugTrace = self.controller.DebugPixel(
                    4 * test, 0, rd.ReplayController.NoPreference,
                    rd.ReplayController.NoPreference)

                cycles, variables = self.process_trace(trace)

                output = self.find_output_source_var(
                    trace, rd.ShaderBuiltin.ColorOutput, 0)

                debugged = self.evaluate_source_var(output, variables)

                try:
                    self.check_pixel_value(
                        pipe.GetOutputTargets()[0].resourceId, 4 * test, 0,
                        debugged.value.f32v[0:4])
                except rdtest.TestFailureException as ex:
                    failed = True
                    rdtest.log.error("Test {} did not match. {}".format(
                        test, str(ex)))
                    continue
                finally:
                    self.controller.FreeTrace(trace)

                rdtest.log.success("Test {} matched as expected".format(test))

            rdtest.log.end_section(shaderModels[sm] + " tests")

        rdtest.log.begin_section("MSAA tests")
        test_marker: rd.ActionDescription = self.find_action("MSAA")
        action = test_marker.next
        self.controller.SetFrameEvent(action.eventId, False)
        pipe: rd.PipeState = self.controller.GetPipelineState()
        for test in range(4):
            # Debug the shader
            trace: rd.ShaderDebugTrace = self.controller.DebugPixel(
                4, 4, test, rd.ReplayController.NoPreference)

            # Validate that the correct sample index was debugged
            sampRegister = self.find_input_source_var(
                trace, rd.ShaderBuiltin.MSAASampleIndex)
            sampInput = [
                var for var in trace.inputs
                if var.name == sampRegister.variables[0].name
            ][0]
            if sampInput.value.u32v[0] != test:
                rdtest.log.error(
                    "Test {} did not pick the correct sample.".format(test))

            cycles, variables = self.process_trace(trace)

            output = self.find_output_source_var(trace,
                                                 rd.ShaderBuiltin.ColorOutput,
                                                 0)

            debugged = self.evaluate_source_var(output, variables)

            # Validate the debug output result
            try:
                self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId,
                                       4,
                                       4,
                                       debugged.value.f32v[0:4],
                                       sub=rd.Subresource(0, 0, test))
            except rdtest.TestFailureException as ex:
                failed = True
                rdtest.log.error("Test {} did not match. {}".format(
                    test, str(ex)))
                continue

        rdtest.log.end_section("MSAA tests")

        test_marker: rd.ActionDescription = self.find_action("VertexSample")
        action = test_marker.next
        self.controller.SetFrameEvent(action.eventId, False)
        pipe: rd.PipeState = self.controller.GetPipelineState()

        # Debug the vertex shader
        trace: rd.ShaderDebugTrace = self.controller.DebugVertex(0, 0, 0, 0)

        cycles, variables = self.process_trace(trace)

        output = self.find_output_source_var(trace, rd.ShaderBuiltin.Undefined,
                                             1)

        debugged = self.evaluate_source_var(output, variables)

        if not rdtest.value_compare(debugged.value.f32v[0:4],
                                    [0.3, 0.5, 0.8, 1.0]):
            failed = True
            rdtest.log.error(
                "Vertex shader color output did not match expectation ({}). {}"
                .format(str(debugged.value.f32v[0:4]), str(ex)))

        rdtest.log.success("VertexSample VS was debugged correctly")

        # Debug the pixel shader
        trace: rd.ShaderDebugTrace = self.controller.DebugPixel(
            51, 51, 0, rd.ReplayController.NoPreference)

        cycles, variables = self.process_trace(trace)

        output = self.find_output_source_var(trace,
                                             rd.ShaderBuiltin.ColorOutput, 0)

        debugged = self.evaluate_source_var(output, variables)

        # Validate the debug output result
        try:
            self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 51,
                                   51, debugged.value.f32v[0:4])
        except rdtest.TestFailureException as ex:
            failed = True
            rdtest.log.error(
                "Vertex sample pixel shader output did not match. {}".format(
                    str(ex)))

        rdtest.log.success("VertexSample PS was debugged correctly")

        if failed:
            raise rdtest.TestFailureException(
                "Some tests were not as expected")

        test_marker: rd.ActionDescription = self.find_action("Banned")
        action = test_marker.next
        self.controller.SetFrameEvent(action.eventId, False)
        pipe: rd.PipeState = self.controller.GetPipelineState()

        # Debug the vertex shader
        trace: rd.ShaderDebugTrace = self.controller.DebugVertex(0, 0, 0, 0)

        cycles, variables = self.process_trace(trace)

        output = self.find_output_source_var(trace, rd.ShaderBuiltin.Position,
                                             0)

        debugged = self.evaluate_source_var(output, variables)

        if not rdtest.value_compare(debugged.value.f32v[0:4],
                                    [-0.5, -0.5, 0.0, 1.0]):
            failed = True
            rdtest.log.error(
                "Banned signature vertex shader position did not match expectation ({}). {}"
                .format(str(debugged.value.f32v[0:4]), str(ex)))

        rdtest.log.success("Banned signature VS was debugged correctly")

        # Debug the pixel shader
        trace: rd.ShaderDebugTrace = self.controller.DebugPixel(
            64, 64, 0, rd.ReplayController.NoPreference)

        cycles, variables = self.process_trace(trace)

        output = self.find_output_source_var(trace,
                                             rd.ShaderBuiltin.ColorOutput, 0)

        debugged = self.evaluate_source_var(output, variables)

        # Validate the debug output result
        try:
            self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 64,
                                   64, debugged.value.f32v[0:4])
        except rdtest.TestFailureException as ex:
            failed = True
            rdtest.log.error(
                "Vertex sample pixel shader output did not match. {}".format(
                    str(ex)))

        rdtest.log.success("Banned signature PS was debugged correctly")

        if failed:
            raise rdtest.TestFailureException(
                "Some tests were not as expected")

        rdtest.log.success("All tests matched")
Exemplo n.º 19
0
    def multisampled_image_test(self):
        test_marker: rd.ActionDescription = self.find_action(
            "Multisampled: test")
        action_eid = test_marker.next.eventId
        self.controller.SetFrameEvent(action_eid, True)

        pipe: rd.PipeState = self.controller.GetPipelineState()
        rt: rd.BoundResource = pipe.GetOutputTargets()[0]

        if self.is_depth:
            rt: rd.BoundResource = pipe.GetDepthTarget()

        sub = rd.Subresource()
        tex = rt.resourceId
        tex_details = self.get_texture(tex)
        if tex_details.arraysize > 1:
            sub.slice = rt.firstSlice

        beg_renderpass_eid = self.find_action(
            "Multisampled: begin renderpass").next.eventId

        x, y = 140, 130
        sub.sample = 1
        rdtest.log.print("Testing pixel {}, {} at sample {}".format(
            x, y, sub.sample))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)

        events = [
            [[event_id, beg_renderpass_eid], [passed, True],
             [post_mod_depth, 0.0]],
            [[event_id, action_eid], [passed, True], [primitive_id, 0],
             [pre_mod_depth, 0.0], [shader_out_depth, 0.9],
             [post_mod_depth, 0.9]],
            [[event_id, action_eid], [passed, True], [primitive_id, 1],
             [shader_out_depth, 0.95], [post_mod_depth, 0.95]],
        ]

        if not self.is_depth:
            events[0] += [[post_mod_col, (0.0, 1.0, 0.0, 1.0)]]
            events[1] += [[shader_out_col, (1.0, 0.0, 1.0, 2.75)],
                          [post_mod_col, (1.0, 0.0, 1.0, 1.0)]]
            events[2] += [[shader_out_col, (0.0, 0.0, 1.0, 2.75)],
                          [post_mod_col, (0.0, 0.0, 1.0, 1.0)]]

        self.check_events(events, modifs, True)

        if self.is_depth:
            self.check_pixel_value(
                tex,
                x,
                y, [
                    modifs[-1].postMod.depth,
                    float(modifs[-1].postMod.stencil) / 255.0, 0.0, 1.0
                ],
                sub=sub,
                cast=rt.typeCast)
        else:
            self.check_pixel_value(tex,
                                   x,
                                   y,
                                   value_selector(modifs[-1].postMod.col),
                                   sub=sub,
                                   cast=rt.typeCast)

        sub.sample = 2
        rdtest.log.print("Testing pixel {}, {} at sample {}".format(
            x, y, sub.sample))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, beg_renderpass_eid], [passed, True],
             [post_mod_depth, 0.0]],
            [[event_id, action_eid], [passed, True], [primitive_id, 0],
             [pre_mod_depth, 0.0], [shader_out_depth, 0.9],
             [post_mod_depth, 0.9]],
            [[event_id, action_eid], [passed, True], [primitive_id, 1],
             [shader_out_depth, 0.95], [post_mod_depth, 0.95]],
        ]

        if not self.is_depth:
            events[0] += [[post_mod_col, (0.0, 1.0, 0.0, 1.0)]]
            events[1] += [[shader_out_col, (1.0, 0.0, 1.0, 2.75)],
                          [post_mod_col, (1.0, 0.0, 1.0, 1.0)]]
            events[2] += [[shader_out_col, (0.0, 1.0, 1.0, 2.75)],
                          [post_mod_col, (0.0, 1.0, 1.0, 1.0)]]

        self.check_events(events, modifs, True)

        if self.is_depth:
            self.check_pixel_value(
                tex,
                x,
                y, [
                    modifs[-1].postMod.depth,
                    float(modifs[-1].postMod.stencil) / 255.0, 0.0, 1.0
                ],
                sub=sub,
                cast=rt.typeCast)
        else:
            self.check_pixel_value(tex,
                                   x,
                                   y,
                                   value_selector(modifs[-1].postMod.col),
                                   sub=sub,
                                   cast=rt.typeCast)
Exemplo n.º 20
0
    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")
Exemplo n.º 21
0
    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")
Exemplo n.º 22
0
    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()
Exemplo n.º 23
0
    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(rd.MeshDataStage.VSOut, 0,
                                      draw.numIndices)

        postvs_ref = {
            0: {
                'vtx': 0,
                'idx': 0,
                'gl_Position': [-0.5, -0.5, 0.0, 1.0],
                'v2fcol': [1.0, 0.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, 0.0, 1.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")
Exemplo n.º 24
0
    def check_capture(self):
        actions = self.controller.GetRootActions()

        for d in self.controller.GetRootActions():
            # Only process test actions
            if not d.customName.startswith('Test'):
                continue

            # Go to the last child action
            self.controller.SetFrameEvent(d.children[-1].eventId, True)

            if any(['UInt tex' in d.customName for d in d.children]):
                value_selector = lambda x: x.uintValue
                shader_out = (0, 1, 1234, 5)
            elif any(['SInt tex' in d.customName for d in d.children]):
                value_selector = lambda x: x.intValue
                shader_out = (0, 1, -1234, 5)
            else:
                value_selector = lambda x: x.floatValue
                shader_out = (0.0, 1.0, 0.1234, 0.5)

            pipe: rd.PipeState = self.controller.GetPipelineState()

            rt: rd.BoundResource = pipe.GetOutputTargets()[0]

            vp: rd.Viewport = pipe.GetViewport(0)

            tex = rt.resourceId
            x, y = (int(vp.width / 2), int(vp.height / 2))

            tex_details = self.get_texture(tex)

            sub = rd.Subresource()
            if tex_details.arraysize > 1:
                sub.slice = rt.firstSlice
            if tex_details.mips > 1:
                sub.mip = rt.firstMip

            modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)

            # Should be at least two modifications in every test - clear and action
            self.check(len(modifs) >= 2)

            # Check that the modifications are self consistent - postmod of each should match premod of the next
            for i in range(len(modifs) - 1):
                if value_selector(modifs[i].postMod.col) != value_selector(modifs[i + 1].preMod.col):
                    raise rdtest.TestFailureException(
                        "postmod at {}: {} doesn't match premod at {}: {}".format(modifs[i].eventId,
                                                                                  value_selector(modifs[i].postMod.col),
                                                                                  modifs[i + 1].eventId,
                                                                                  value_selector(modifs[i].preMod.col)))

                if self.get_action(modifs[i].eventId).flags & rd.ActionFlags.Drawcall:
                    if not rdtest.value_compare(value_selector(modifs[i].shaderOut.col), shader_out):
                        raise rdtest.TestFailureException(
                            "Shader output {} isn't as expected {}".format(value_selector(modifs[i].shaderOut.col),
                                                                           shader_out))

            rdtest.log.success("shader output and premod/postmod is consistent")

            # The current pixel value should match the last postMod
            self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)

            # Also the red channel should be zero, as it indicates errors
            self.check(float(value_selector(modifs[-1].postMod.col)[0]) == 0.0)
Exemplo n.º 25
0
    def pixel_debug(self, draw: rd.DrawcallDescription):
        pipe: rd.PipeState = self.controller.GetPipelineState()

        if pipe.GetShader(rd.ShaderStage.Pixel) == rd.ResourceId.Null():
            rdtest.log.print("No pixel shader bound at {}: {}".format(draw.eventId, draw.name))
            return

        if len(pipe.GetOutputTargets()) == 0 and pipe.GetDepthTarget().resourceId == rd.ResourceId.Null():
            rdtest.log.print("No render targets bound at {}: {}".format(draw.eventId, draw.name))
            return

        if not (draw.flags & rd.DrawFlags.Drawcall):
            rdtest.log.print("{}: {} is not a debuggable drawcall".format(draw.eventId, draw.name))
            return

        viewport = pipe.GetViewport(0)

        # TODO, query for some pixel this drawcall actually touched.
        x = int(random.random()*viewport.width + viewport.x)
        y = int(random.random()*viewport.height + viewport.y)

        target = rd.ResourceId.Null()

        if len(pipe.GetOutputTargets()) > 0:
            valid_targets = [o.resourceId for o in pipe.GetOutputTargets() if o.resourceId != rd.ResourceId.Null()]
            rdtest.log.print("Valid targets at {} are {}".format(draw.eventId, valid_targets))
            if len(valid_targets) > 0:
                target = valid_targets[int(random.random()*len(valid_targets))]

        if target == rd.ResourceId.Null():
            target = pipe.GetDepthTarget().resourceId

        if target == rd.ResourceId.Null():
            rdtest.log.print("No targets bound! Can't fetch history at {}".format(draw.eventId))
            return

        rdtest.log.print("Fetching history for %d,%d on target %s" % (x, y, str(target)))

        history = self.controller.PixelHistory(target, x, y, rd.Subresource(0, 0, 0), rd.CompType.Typeless)

        rdtest.log.success("Pixel %d,%d has %d history events" % (x, y, len(history)))

        lastmod: rd.PixelModification = None

        for i in reversed(range(len(history))):
            mod = history[i]
            draw = self.find_draw('', mod.eventId)

            if draw is None or not (draw.flags & rd.DrawFlags.Drawcall):
                continue

            rdtest.log.print("  hit %d at %d is %s (%s)" % (i, mod.eventId, draw.name, str(draw.flags)))

            lastmod = history[i]

            rdtest.log.print("Got a hit on a drawcall at event %d" % lastmod.eventId)

            if mod.sampleMasked or mod.backfaceCulled or mod.depthClipped or mod.viewClipped or mod.scissorClipped or mod.shaderDiscarded or mod.depthTestFailed or mod.stencilTestFailed:
                rdtest.log.print("This hit failed, looking for one that passed....")
                lastmod = None
                continue

            if not mod.shaderOut.IsValid():
                rdtest.log.print("This hit's shader out is not valid, looking for one that valid....")
                lastmod = None
                continue

            break

        if target == pipe.GetDepthTarget().resourceId:
            rdtest.log.print("Not doing pixel debug for depth output")
            return

        if lastmod is not None:
            rdtest.log.print("Debugging pixel {},{} @ {}, primitive {}".format(x, y, lastmod.eventId, lastmod.primitiveID))
            self.controller.SetFrameEvent(lastmod.eventId, True)

            pipe: rd.PipeState = self.controller.GetPipelineState()

            trace = self.controller.DebugPixel(x, y, 0, lastmod.primitiveID)

            if trace.debugger is None:
                self.controller.FreeTrace(trace)

                rdtest.log.print("No debug result")
                return

            cycles, variables = self.process_trace(trace)

            output_index = [o.resourceId for o in pipe.GetOutputTargets()].index(target)

            if draw.outputs[0] == rd.ResourceId.Null():
                rdtest.log.success('Successfully debugged pixel in {} cycles, skipping result check due to no output'.format(cycles))
                self.controller.FreeTrace(trace)
            elif (draw.flags & rd.DrawFlags.Instanced) and draw.numInstances > 1:
                rdtest.log.success('Successfully debugged pixel in {} cycles, skipping result check due to instancing'.format(cycles))
                self.controller.FreeTrace(trace)
            elif pipe.GetColorBlends()[output_index].writeMask == 0:
                rdtest.log.success('Successfully debugged pixel in {} cycles, skipping result check due to write mask'.format(cycles))
                self.controller.FreeTrace(trace)
            else:
                rdtest.log.print("At event {} the target is index {}".format(lastmod.eventId, output_index))

                output_sourcevar = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, output_index)

                if output_sourcevar is not None:
                    debugged = self.evaluate_source_var(output_sourcevar, variables)

                    self.controller.FreeTrace(trace)

                    debuggedValue = list(debugged.value.f32v[0:4])

                    # For now, ignore debugged values that are uninitialised. This is an application bug but it causes
                    # false reports of problems
                    for idx in range(4):
                        if debugged.value.u32v[idx] == 0xcccccccc:
                            debuggedValue[idx] = lastmod.shaderOut.col.floatValue[idx]

                    # Unfortunately we can't ever trust that we should get back a matching results, because some shaders
                    # rely on undefined/inaccurate maths that we don't emulate.
                    # So the best we can do is log an error for manual verification
                    is_eq, diff_amt = rdtest.value_compare_diff(lastmod.shaderOut.col.floatValue, debuggedValue, eps=5.0E-06)
                    if not is_eq:
                        rdtest.log.error(
                            "Debugged value {} at EID {} {},{}: {} difference. {} doesn't exactly match history shader output {}".format(
                                debugged.name, lastmod.eventId, x, y, diff_amt, debuggedValue, lastmod.shaderOut.col.floatValue))

                    rdtest.log.success('Successfully debugged pixel in {} cycles, result matches'.format(cycles))
                else:
                    # This could be an application error - undefined but seen in the wild
                    rdtest.log.error("At EID {} No output variable declared for index {}".format(lastmod.eventId, output_index))

            self.controller.SetFrameEvent(draw.eventId, True)
Exemplo n.º 26
0
    def check_test(self, fmt_name: str, name: str, test_mode: int):
        pipe: rd.PipeState = self.controller.GetPipelineState()

        image_view = (test_mode != Texture_Zoo.TEST_CAPTURE)

        if image_view:
            bound_res: rd.BoundResource = pipe.GetOutputTargets()[0]
        else:
            bound_res: rd.BoundResource = pipe.GetReadOnlyResources(
                rd.ShaderStage.Pixel)[0].resources[0]

        texs = self.controller.GetTextures()
        for t in texs:
            self.textures[t.resourceId] = t

        tex_id: rd.ResourceId = bound_res.resourceId
        tex: rd.TextureDescription = self.textures[tex_id]

        comp_type: rd.CompType = tex.format.compType
        if bound_res.typeCast != rd.CompType.Typeless:
            comp_type = bound_res.typeCast

        # When not running proxied, save non-typecasted textures to disk
        if not image_view and not self.proxied and (
                tex.format.compType == comp_type
                or tex.format.type == rd.ResourceFormatType.D24S8
                or tex.format.type == rd.ResourceFormatType.D32S8):
            save_data = rd.TextureSave()
            save_data.resourceId = tex_id
            save_data.destType = rd.FileType.DDS
            save_data.sample.mapToArray = True

            self.textures[self.filename] = tex

            path = rdtest.get_tmp_path(self.filename + '.dds')

            success: bool = self.controller.SaveTexture(save_data, path)

            if not success:
                if self.d3d_mode:
                    raise rdtest.TestFailureException(
                        "Couldn't save DDS to {} on D3D.".format(
                            self.filename))

                try:
                    os.remove(path)
                except Exception:
                    pass

            save_data.destType = rd.FileType.PNG
            save_data.slice.sliceIndex = 0
            save_data.sample.sampleIndex = 0
            path = path.replace('.dds', '.png')

            if comp_type == rd.CompType.UInt:
                save_data.comp.blackPoint = 0.0
                save_data.comp.whitePoint = 255.0
            elif comp_type == rd.CompType.SInt:
                save_data.comp.blackPoint = -255.0
                save_data.comp.whitePoint = 0.0
            elif comp_type == rd.CompType.SNorm:
                save_data.comp.blackPoint = -1.0
                save_data.comp.whitePoint = 0.0

            success: bool = self.controller.SaveTexture(save_data, path)

            if not success:
                try:
                    os.remove(path)
                except Exception:
                    pass

        value0 = []

        comp_count = tex.format.compCount

        # When viewing PNGs only compare the components that the original texture had
        if test_mode == Texture_Zoo.TEST_PNG:
            comp_count = self.textures[self.filename]
            tex.msSamp = 0
            tex.arraysize = 1
            tex.depth = 1
            self.fake_msaa = 'MSAA' in name
        elif test_mode == Texture_Zoo.TEST_DDS:
            tex.arraysize = self.textures[self.filename].arraysize
            tex.msSamp = self.textures[self.filename].msSamp
            self.fake_msaa = 'MSAA' in name

        # HACK: We don't properly support BGRX, so just drop the alpha channel. We can't set this to compCount = 3
        # internally because that's a 24-bit format with no padding...
        if 'B8G8R8X8' in fmt_name:
            comp_count = 3

        # Completely ignore the alpha for BC1, our encoder doesn't pay attention to it
        if tex.format.type == rd.ResourceFormatType.BC1:
            comp_count = 3

        # Calculate format-appropriate epsilon
        eps_significand = 1.0
        # Account for the sRGB curve by more generous epsilon

        if comp_type == rd.CompType.UNormSRGB:
            eps_significand = 2.5
        # Similarly SNorm essentially loses a bit of accuracy due to us only using negative values
        elif comp_type == rd.CompType.SNorm:
            eps_significand = 2.0

        if tex.format.type == rd.ResourceFormatType.R4G4B4A4 or tex.format.type == rd.ResourceFormatType.R4G4:
            eps = (eps_significand / 15.0)
        elif rd.ResourceFormatType.BC1 <= tex.format.type <= rd.ResourceFormatType.BC3:
            eps = (eps_significand / 15.0)  # 4-bit precision in some channels
        elif tex.format.type == rd.ResourceFormatType.R5G5B5A1 or tex.format.type == rd.ResourceFormatType.R5G6B5:
            eps = (eps_significand / 31.0)
        elif tex.format.type == rd.ResourceFormatType.R11G11B10:
            eps = (eps_significand / 31.0)  # 5-bit mantissa in blue
        elif tex.format.type == rd.ResourceFormatType.R9G9B9E5:
            eps = (
                eps_significand / 63.0
            )  # we have 9 bits of data, but might lose 2-3 due to shared exponent
        elif tex.format.type == rd.ResourceFormatType.BC6 and tex.format.compType == rd.CompType.SNorm:
            eps = (eps_significand / 63.0
                   )  # Lose a bit worth of precision for the signed version
        elif rd.ResourceFormatType.BC4 <= tex.format.type <= rd.ResourceFormatType.BC7:
            eps = (eps_significand / 127.0)
        elif tex.format.compByteWidth == 1:
            eps = (eps_significand / 255.0)
        elif comp_type == rd.CompType.Depth and tex.format.compCount == 2:
            eps = (eps_significand / 255.0)  # stencil is only 8-bit
        elif tex.format.type == rd.ResourceFormatType.A8:
            eps = (eps_significand / 255.0)
        elif tex.format.type == rd.ResourceFormatType.R10G10B10A2:
            eps = (eps_significand / 1023.0)
        else:
            # half-floats have 11-bit mantissa. This epsilon is tight enough that we can be sure
            # any remaining errors are implementation inaccuracy and not our bug
            eps = (eps_significand / 2047.0)

        for mp in range(tex.mips):
            for sl in range(max(tex.arraysize, max(1, tex.depth >> mp))):
                z = 0
                if tex.depth > 1:
                    z = sl

                for sm in range(tex.msSamp):
                    cur_sub = self.sub(mp, sl, sm)

                    tex_display = rd.TextureDisplay()
                    tex_display.resourceId = tex_id
                    tex_display.subresource = cur_sub
                    tex_display.flipY = self.opengl_mode
                    tex_display.typeCast = comp_type
                    tex_display.alpha = False
                    tex_display.scale = 1.0 / float(1 << mp)
                    tex_display.backgroundColor = rd.FloatVector(
                        0.0, 0.0, 0.0, 1.0)

                    if comp_type == rd.CompType.UInt:
                        tex_display.rangeMin = 0.0
                        tex_display.rangeMax = 255.0
                    elif comp_type == rd.CompType.SInt:
                        tex_display.rangeMin = -255.0
                        tex_display.rangeMax = 0.0
                    elif comp_type == rd.CompType.SNorm:
                        tex_display.rangeMin = -1.0
                        tex_display.rangeMax = 0.0

                    self.out.SetTextureDisplay(tex_display)

                    self.out.Display()

                    pixels: bytes = self.out.ReadbackOutputTexture()
                    dim = self.out.GetDimensions()

                    stencilpixels = None

                    # Grab stencil separately
                    if tex.format.type == rd.ResourceFormatType.D16S8 or tex.format.type == rd.ResourceFormatType.D24S8 or tex.format.type == rd.ResourceFormatType.D32S8:
                        tex_display.red = False
                        tex_display.green = True
                        tex_display.blue = False
                        tex_display.alpha = False

                        self.out.SetTextureDisplay(tex_display)
                        self.out.Display()

                        stencilpixels: bytes = self.out.ReadbackOutputTexture()

                    # Grab alpha if needed (since the readback output is RGB only)
                    if comp_count == 4 or tex.format.type == rd.ResourceFormatType.A8:
                        tex_display.red = False
                        tex_display.green = False
                        tex_display.blue = False
                        tex_display.alpha = True

                        self.out.SetTextureDisplay(tex_display)
                        self.out.Display()

                        alphapixels: bytes = self.out.ReadbackOutputTexture()

                    all_good = True

                    for x in range(max(1, tex.width >> mp)):
                        if not all_good:
                            break
                        for y in range(max(1, tex.height >> mp)):
                            expected = self.get_expected_value(
                                comp_count, comp_type, cur_sub, test_mode, tex,
                                x, y, z)

                            # for this test to work the expected values have to be within the range we selected for
                            # display above
                            for i in expected:
                                if i < tex_display.rangeMin or tex_display.rangeMax < i:
                                    raise rdtest.TestFailureException(
                                        "expected value {} is outside of texture display range! {} - {}"
                                        .format(i, tex_display.rangeMin,
                                                tex_display.rangeMax))

                            # convert the expected values to range-adapted values
                            for i in range(len(expected)):
                                expected[i] = (expected[i] -
                                               tex_display.rangeMin) / (
                                                   tex_display.rangeMax -
                                                   tex_display.rangeMin)

                            # get the bytes from the displayed pixel
                            offs = y * dim[0] * 3 + x * 3
                            displayed = [
                                int(a) for a in pixels[offs:offs + comp_count]
                            ]
                            if comp_count == 4:
                                del displayed[3]
                                displayed.append(int(alphapixels[offs]))
                            if stencilpixels is not None:
                                del displayed[1:]
                                displayed.append(int(stencilpixels[offs]))
                            if tex.format.type == rd.ResourceFormatType.A8:
                                displayed = [int(alphapixels[offs])]

                            # normalise the displayed values
                            for i in range(len(displayed)):
                                displayed[i] = float(displayed[i]) / 255.0

                            # For SRGB textures match linear picked values. We do this for alpha too since it's rendered
                            # via RGB
                            if comp_type == rd.CompType.UNormSRGB:
                                displayed[0:4] = [
                                    srgb2linear(x) for x in displayed[0:4]
                                ]

                            # alpha channel in 10:10:10:2 has extremely low precision, and the ULP requirements mean
                            # we basically can't trust anything between 0 and 1 on float formats. Just round in that
                            # case as it still lets us differentiate between alpha 0.0-0.5 and 0.5-1.0
                            if tex.format.type == rd.ResourceFormatType.R10G10B10A2 and comp_type != rd.CompType.UInt:
                                displayed[3] = round(displayed[3]) * 1.0

                            # Handle 1-bit alpha
                            if tex.format.type == rd.ResourceFormatType.R5G5B5A1:
                                displayed[
                                    3] = 1.0 if displayed[3] >= 0.5 else 0.0

                            # Need an additional 1/255 epsilon to account for us going via a 8-bit backbuffer for display
                            if not rdtest.value_compare(
                                    displayed, expected, 1.0 / 255.0 + eps):
                                #rdtest.log.print(
                                #    "Quick-checking ({},{}) of slice {}, mip {}, sample {} of {} {} got {}. Expected {}.".format(
                                #        x, y, sl, mp, sm, name, fmt_name, displayed, expected) +
                                #    "Falling back to pixel picking tests.")
                                # Currently this seems to fail in some proxy scenarios with sRGB, but since it's not a
                                # real error we just silently swallow it
                                all_good = False
                                break

                    if all_good:
                        continue

                    for x in range(max(1, tex.width >> mp)):
                        for y in range(max(1, tex.height >> mp)):
                            expected = self.get_expected_value(
                                comp_count, comp_type, cur_sub, test_mode, tex,
                                x, y, z)
                            picked = self.get_picked_pixel_value(
                                comp_count, comp_type, cur_sub, tex, tex_id, x,
                                y)

                            if mp == 0 and sl == 0 and sm == 0 and x == 0 and y == 0:
                                value0 = picked

                            if not rdtest.value_compare(picked, expected, eps):
                                raise rdtest.TestFailureException(
                                    "At ({},{}) of slice {}, mip {}, sample {} of {} {} got {}. Expected {}"
                                    .format(x, y, sl, mp, sm, name, fmt_name,
                                            picked, expected))

        if not image_view:
            output_tex = pipe.GetOutputTargets()[0].resourceId

            # in the test captures pick the output texture, it should be identical to the
            # (0,0) pixel in slice 0, mip 0, sample 0
            view: rd.Viewport = pipe.GetViewport(0)

            val: rd.PixelValue = self.pick(
                pipe.GetOutputTargets()[0].resourceId,
                int(view.x + view.width / 2), int(view.y + view.height / 2),
                rd.Subresource(), rd.CompType.Typeless)

            picked = list(val.floatValue)

            # A8 picked values come out in alpha, but we want to compare against the single channel
            if tex.format.type == rd.ResourceFormatType.A8:
                picked[0] = picked[3]

            # Clamp to number of components in the texture
            picked = picked[0:comp_count]

            # If we didn't get a value0 (because we did all texture render compares) then fetch it here
            if len(value0) == 0:
                value0 = self.get_picked_pixel_value(comp_count, comp_type,
                                                     rd.Subresource(), tex,
                                                     tex_id, 0, 0)

            # Up-convert any non-float expected values to floats
            value0 = [float(x) for x in value0]

            # For depth/stencil images, one of either depth or stencil should match
            if comp_type == rd.CompType.Depth and len(value0) == 2:
                if picked[0] == 0.0:
                    value0[0] = 0.0
                    # normalise stencil value if it isn't already
                    if picked[1] > 1.0:
                        picked[1] /= 255.0
                elif picked[0] > 1.0:
                    # un-normalised stencil being rendered in red, match against our stencil expectation
                    picked[0] /= 255.0
                    value0[0] = value0[1]
                    value0[1] = 0.0
                else:
                    if picked[1] == 0.0:
                        value0[1] = 0.0
                    if picked[1] > 1.0:
                        picked[1] /= 255.0

            if not rdtest.value_compare(picked, value0, eps):
                raise rdtest.TestFailureException(
                    "In {} {} Top-left pixel as rendered is {}. Expected {}".
                    format(name, fmt_name, picked, value0))
Exemplo n.º 27
0
    def primary_test(self):
        test_marker: rd.ActionDescription = self.find_action("Test Begin")
        self.controller.SetFrameEvent(test_marker.next.eventId, True)

        pipe: rd.PipeState = self.controller.GetPipelineState()

        rt: rd.BoundResource = pipe.GetOutputTargets()[0]

        tex = rt.resourceId
        tex_details = self.get_texture(tex)

        sub = rd.Subresource()
        if tex_details.arraysize > 1:
            sub.slice = rt.firstSlice
        if tex_details.mips > 1:
            sub.mip = rt.firstMip

        begin_renderpass_eid = self.find_action(
            "Begin RenderPass").next.eventId
        depth_write_eid = self.find_action("Depth Write").next.eventId
        stencil_write_eid = self.find_action("Stencil Write").next.eventId
        unbound_fs_eid = self.find_action(
            "Unbound Fragment Shader").next.eventId
        background_eid = self.find_action("Background").next.eventId
        cull_eid = self.find_action("Cull Front").next.eventId
        test_eid = self.find_action("Test Begin").next.eventId
        fixed_scissor_fail_eid = self.find_action(
            "Fixed Scissor Fail").next.eventId
        fixed_scissor_pass_eid = self.find_action(
            "Fixed Scissor Pass").next.eventId
        dynamic_stencil_ref_eid = self.find_action(
            "Dynamic Stencil Ref").next.eventId
        dynamic_stencil_mask_eid = self.find_action(
            "Dynamic Stencil Mask").next.eventId
        depth_test_eid = self.find_action("Depth Test").next.eventId
        depth_bounds_prep_eid = self.find_action(
            "Depth Bounds Prep").next.eventId
        depth_bounds_clip_eid = self.find_action(
            "Depth Bounds Clip").next.eventId

        # For pixel 190, 149 inside the red triangle
        x, y = 190, 149
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, unbound_fs_eid], [passed, True], [unboundPS, True],
             [primitive_id, 0]],
            [[event_id, stencil_write_eid], [passed, True]],
            [[event_id, background_eid], [depth_test_failed, True],
             [post_mod_col, (1.0, 0.0, 0.0, 1.0)]],
            [[event_id, test_eid], [stencil_test_failed, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 190, 150
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, depth_write_eid], [passed, True]],
            [[event_id, background_eid], [depth_test_failed, True]],
            [[event_id, cull_eid], [culled, True]],
            [[event_id, test_eid], [depth_test_failed, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 200, 50
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, background_eid], [passed, True]],
            [[event_id, test_eid], [passed, True], [primitive_id, 7]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 150, 250
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, background_eid], [shader_discarded, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 330, 145
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, test_eid], [passed, True], [primitive_id, 3],
             [shader_out_col, (0.0, 0.0, 0.0, 2.75)]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 340, 145
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, test_eid], [passed, False], [depth_clipped, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 330, 105
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, depth_bounds_prep_eid], [passed, True],
             [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
            [[event_id, depth_bounds_clip_eid], [passed, True],
             [primitive_id, 0], [shader_out_col, (0.0, 1.0, 0.0, 2.75)]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 320, 105
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, depth_bounds_prep_eid], [passed, True],
             [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
            [[event_id, depth_bounds_clip_eid], [passed, False],
             [depth_bounds_failed, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        x, y = 345, 105
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, depth_bounds_prep_eid], [passed, True],
             [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
            [[event_id, depth_bounds_clip_eid], [passed, False],
             [depth_bounds_failed, True]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        rdtest.log.print("Testing dynamic state pipelines")
        self.controller.SetFrameEvent(dynamic_stencil_mask_eid, True)

        x, y = 100, 250
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, background_eid], [passed, True]],
            [[event_id, fixed_scissor_fail_eid], [scissor_clipped, True]],
            [[event_id, fixed_scissor_pass_eid], [passed, True],
             [shader_out_col, (0.0, 1.0, 0.0, 2.75)],
             [post_mod_col, (0.0, 1.0, 0.0, 1.0)]],
            [[event_id, dynamic_stencil_ref_eid], [passed, True],
             [shader_out_col, (0.0, 0.0, 1.0, 2.75)],
             [post_mod_col, (0.0, 0.0, 1.0, 1.0)]],
            [[event_id, dynamic_stencil_mask_eid], [passed, True],
             [shader_out_col, (0.0, 1.0, 1.0, 2.75)],
             [post_mod_col, (0.0, 1.0, 1.0, 1.0)]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)

        rdtest.log.print("Testing depth test for per fragment reporting")
        self.controller.SetFrameEvent(depth_test_eid, True)

        x, y = 275, 260
        rdtest.log.print("Testing pixel {}, {}".format(x, y))
        modifs: List[rd.PixelModification] = self.controller.PixelHistory(
            tex, x, y, sub, rt.typeCast)
        events = [
            [[event_id, begin_renderpass_eid], [passed, True]],
            [[event_id, background_eid], [passed, True]],
            [[event_id, depth_test_eid], [primitive_id, 0],
             [depth_test_failed, True],
             [shader_out_col, (1.0, 1.0, 1.0, 2.75)], [shader_out_depth, 0.97],
             [post_mod_col, (1.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.95]],
            [[event_id, depth_test_eid], [primitive_id, 1],
             [depth_test_failed, False],
             [shader_out_col, (1.0, 1.0, 0.0, 2.75)], [shader_out_depth, 0.20],
             [post_mod_col, (1.0, 1.0, 0.0, 1.0)], [post_mod_depth, 0.20]],
            [[event_id, depth_test_eid], [primitive_id, 2],
             [depth_test_failed, True],
             [shader_out_col, (1.0, 0.0, 0.0, 2.75)], [shader_out_depth, 0.30],
             [post_mod_col, (1.0, 1.0, 0.0, 1.0)], [post_mod_depth, 0.20]],
            [[event_id, depth_test_eid], [primitive_id, 3],
             [depth_test_failed, False],
             [shader_out_col, (0.0, 0.0, 1.0, 2.75)], [shader_out_depth, 0.10],
             [post_mod_col, (0.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.10]],
            [[event_id, depth_test_eid], [primitive_id, 4],
             [depth_test_failed, False],
             [shader_out_col, (1.0, 1.0, 1.0, 2.75)], [shader_out_depth, 0.05],
             [post_mod_col, (0.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.10]],
        ]
        self.check_events(events, modifs, False)
        self.check_pixel_value(tex,
                               x,
                               y,
                               value_selector(modifs[-1].postMod.col),
                               sub=sub,
                               cast=rt.typeCast)
Exemplo n.º 28
0
 def sub(self, mip: int, slice: int, sample: int):
     if self.fake_msaa:
         return rd.Subresource(mip, slice * 2 + sample, 0)
     else:
         return rd.Subresource(mip, slice, sample)
Exemplo n.º 29
0
    def check_capture(self):
        first_action = self.get_first_action()

        found = False
        sdfile = self.controller.GetStructuredFile()
        for e in first_action.events:
            c: rd.SDChunk = sdfile.chunks[e.chunkIndex]
            if 'Unmap' in c.name:
                found = True

        if not found:
            raise rdtest.TestFailureException(
                "Expected an Unmap() chunk in frame 0, but couldn't find it!")

        last_action: rd.ActionDescription = self.get_last_action()

        self.controller.SetFrameEvent(last_action.eventId, True)

        self.check_triangle(out=last_action.copyDestination)

        self.check_export(self.capture_filename)

        action = self.find_action("Draw")

        self.controller.SetFrameEvent(action.eventId, False)

        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)

        # Check that nothing breaks if we call typical enumeration functions on resources
        for res in self.controller.GetResources():
            res: rd.ResourceDescription

            self.controller.GetShaderEntryPoints(res.resourceId)
            self.controller.GetUsage(res.resourceId)
            self.controller.GetBufferData(res.resourceId, 0, 0)
            self.controller.GetTextureData(res.resourceId, rd.Subresource())
Exemplo n.º 30
0
    def check_capture(self):
        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, rd.Subresource(0, 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, rd.Subresource(0, 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")

        self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5,
                               [1.0, 1.0, 0.0, 0.2])

        rdtest.log.success("Picked value is as expected")