def vert_debug(self, draw: rd.DrawcallDescription): pipe: rd.PipeState = self.controller.GetPipelineState() if pipe.GetShader(rd.ShaderStage.Vertex) == rd.ResourceId.Null(): rdtest.log.print("No vertex shader 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 vtx = int(random.random() * draw.numIndices) inst = 0 idx = vtx if draw.numIndices == 0: rdtest.log.print("Empty drawcall (0 vertices), skipping") return if draw.flags & rd.DrawFlags.Instanced: inst = int(random.random() * draw.numInstances) if draw.numInstances == 0: rdtest.log.print("Empty drawcall (0 instances), skipping") return if draw.flags & rd.DrawFlags.Indexed: ib = pipe.GetIBuffer() mesh = rd.MeshFormat() mesh.indexResourceId = ib.resourceId mesh.indexByteStride = draw.indexByteWidth mesh.indexByteOffset = ib.byteOffset + draw.indexOffset * draw.indexByteWidth mesh.baseVertex = draw.baseVertex indices = rdtest.fetch_indices(self.controller, mesh, 0, vtx, 1) if len(indices) < 1: rdtest.log.print("No index buffer, skipping") return idx = indices[0] rdtest.log.print("Debugging vtx %d idx %d (inst %d)" % (vtx, idx, inst)) trace = self.controller.DebugVertex(vtx, inst, idx, draw.instanceOffset, draw.vertexOffset) rdtest.log.success('Successfully debugged vertex in {} cycles'.format( len(trace.states)))
def vert_debug(self, draw: rd.DrawcallDescription): pipe: rd.PipeState = self.controller.GetPipelineState() refl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Vertex) if pipe.GetShader(rd.ShaderStage.Vertex) == rd.ResourceId.Null(): rdtest.log.print("No vertex shader 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 vtx = int(random.random()*draw.numIndices) inst = 0 idx = vtx if draw.numIndices == 0: rdtest.log.print("Empty drawcall (0 vertices), skipping") return if draw.flags & rd.DrawFlags.Instanced: inst = int(random.random()*draw.numInstances) if draw.numInstances == 0: rdtest.log.print("Empty drawcall (0 instances), skipping") return if draw.flags & rd.DrawFlags.Indexed: ib = pipe.GetIBuffer() mesh = rd.MeshFormat() mesh.indexResourceId = ib.resourceId mesh.indexByteStride = ib.byteStride mesh.indexByteOffset = ib.byteOffset + draw.indexOffset * ib.byteStride mesh.indexByteSize = ib.byteSize mesh.baseVertex = draw.baseVertex indices = rdtest.fetch_indices(self.controller, draw, mesh, 0, vtx, 1) if len(indices) < 1: rdtest.log.print("No index buffer, skipping") return idx = indices[0] striprestart_index = pipe.GetStripRestartIndex() & ((1 << (ib.byteStride*8)) - 1) if pipe.IsStripRestartEnabled() and idx == striprestart_index: return rdtest.log.print("Debugging vtx %d idx %d (inst %d)" % (vtx, idx, inst)) postvs = self.get_postvs(draw, rd.MeshDataStage.VSOut, first_index=vtx, num_indices=1, instance=inst) trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0) if trace.debugger is None: self.controller.FreeTrace(trace) rdtest.log.print("No debug result") return cycles, variables = self.process_trace(trace) outputs = 0 for var in trace.sourceVars: var: rd.SourceVariableMapping if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0: name = var.name if name not in postvs[0].keys(): raise rdtest.TestFailureException("Don't have expected output for {}".format(name)) expect = postvs[0][name] value = self.evaluate_source_var(var, variables) if len(expect) != value.columns: raise rdtest.TestFailureException( "Output {} at EID {} has different size ({} values) to expectation ({} values)" .format(name, draw.eventId, value.columns, len(expect))) compType = rd.VarTypeCompType(value.type) if compType == rd.CompType.UInt: debugged = list(value.value.u32v[0:value.columns]) elif compType == rd.CompType.SInt: debugged = list(value.value.s32v[0:value.columns]) else: debugged = list(value.value.f32v[0:value.columns]) # For now, ignore debugged values that are uninitialised. This is an application bug but it causes false # reports of problems for comp in range(4): if value.value.u32v[comp] == 0xcccccccc: debugged[comp] = expect[comp] # 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(expect, debugged, eps=5.0E-06) if not is_eq: rdtest.log.error( "Debugged value {} at EID {} vert {} (idx {}) instance {}: {} difference. {} doesn't exactly match postvs output {}".format( name, draw.eventId, vtx, idx, inst, diff_amt, debugged, expect)) outputs = outputs + 1 rdtest.log.success('Successfully debugged vertex in {} cycles, {}/{} outputs match' .format(cycles, outputs, len(refl.outputSignature))) self.controller.FreeTrace(trace)