mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 09:00:44 +00:00
Python helpers to generate and check a full trace from shader debug
This commit is contained in:
+68
-15
@@ -1,5 +1,6 @@
|
||||
import struct
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
import renderdoc
|
||||
from . import util
|
||||
|
||||
@@ -337,39 +338,91 @@ def decode_mesh_data(controller: rd.ReplayController, indices: List[int], displa
|
||||
|
||||
return ret
|
||||
|
||||
def shadervariable_equal(a: rd.ShaderVariable, b : rd.ShaderVariable):
|
||||
def str_vartype(t: rd.VarType) -> str:
|
||||
if t == rd.VarType.Bool:
|
||||
return "Bool"
|
||||
elif t == rd.VarType.ConstantBlock:
|
||||
return "ConstantBlock"
|
||||
elif t == rd.VarType.Double:
|
||||
return "Double"
|
||||
elif t == rd.VarType.Enum:
|
||||
return "Enum"
|
||||
elif t == rd.VarType.Float:
|
||||
return "Float"
|
||||
elif t == rd.VarType.GPUPointer:
|
||||
return "GPUPointer"
|
||||
elif t == rd.VarType.Half:
|
||||
return "Half"
|
||||
elif t == rd.VarType.ReadOnlyResource:
|
||||
return "ReadOnlyResource"
|
||||
elif t == rd.VarType.ReadWriteResource:
|
||||
return "ReadWriteResource"
|
||||
elif t == rd.VarType.Sampler:
|
||||
return "Sampler"
|
||||
elif t == rd.VarType.SByte:
|
||||
return "SByte"
|
||||
elif t == rd.VarType.SInt:
|
||||
return "SInt"
|
||||
elif t == rd.VarType.SLong:
|
||||
return "SLong"
|
||||
elif t == rd.VarType.SShort:
|
||||
return "SShort"
|
||||
elif t == rd.VarType.Struct:
|
||||
return "Struct"
|
||||
elif t == rd.VarType.UByte:
|
||||
return "UByte"
|
||||
elif t == rd.VarType.UInt:
|
||||
return "UInt"
|
||||
elif t == rd.VarType.ULong:
|
||||
return "ULong"
|
||||
elif t == rd.VarType.Unknown:
|
||||
return "Unknown"
|
||||
elif t == rd.VarType.UShort:
|
||||
return "UShort"
|
||||
return "???"
|
||||
|
||||
def shadervariable_equal(a: rd.ShaderVariable, b : rd.ShaderVariable) -> Tuple[bool, str]:
|
||||
difference = ""
|
||||
if a.rows != b.rows:
|
||||
return False
|
||||
difference = f"Rows differ: {a.rows} != {b.rows}"
|
||||
return (False, difference)
|
||||
if a.columns != b.columns:
|
||||
return False
|
||||
difference = f"Columns differ: {a.columns} != {b.columns}"
|
||||
return (False, difference)
|
||||
if a.name != b.name:
|
||||
return False
|
||||
difference = f"Names differ: {a.name} != {b.name}"
|
||||
return (False, difference)
|
||||
if a.type != b.type:
|
||||
return False
|
||||
difference = f"Types differ: {str_vartype(a.type)} != {str_vartype(b.type)}"
|
||||
return (False, difference)
|
||||
if a.flags != b.flags:
|
||||
return False
|
||||
difference = f"Flags differ: {a.flags} != {b.flags}"
|
||||
return (False, difference)
|
||||
if len(a.members) != len(b.members):
|
||||
return False
|
||||
difference = f"Member count differs: {len(a.members)} != {len(b.members)}"
|
||||
return (False, difference)
|
||||
|
||||
for i in range(a.rows * a.columns):
|
||||
if a.type == rd.VarType.UByte or a.type == rd.VarType.SByte:
|
||||
if a.value.u8v[i] != b.value.u8v[i]:
|
||||
return False
|
||||
return (False, f"Values differ at index {i}: {a.value.u8v[i]} != {b.value.u8v[i]}")
|
||||
elif a.type == rd.VarType.Half or a.type == rd.VarType.UShort or a.type == rd.VarType.SShort:
|
||||
if a.value.u16v[i] != b.value.u16v[i]:
|
||||
return False
|
||||
return (False, f"Values differ at index {i}: {a.value.u16v[i]} != {b.value.u16v[i]}")
|
||||
elif a.type == rd.VarType.Float or a.type == rd.VarType.UInt or a.type == rd.VarType.SInt or a.type == rd.VarType.Bool or a.type == rd.VarType.Enum:
|
||||
if a.value.u32v[i] != b.value.u32v[i]:
|
||||
return False
|
||||
return (False, f"Values differ at index {i}: {a.value.u32v[i]} != {b.value.u32v[i]}")
|
||||
elif a.type == rd.VarType.Double or a.type == rd.VarType.ULong or a.type == rd.VarType.SLong or a.type == rd.VarType.GPUPointer:
|
||||
if a.value.u64v[i] != b.value.u64v[i]:
|
||||
return False
|
||||
return (False, f"Values differ at index {i}: {a.value.u64v[i]} != {b.value.u64v[i]}")
|
||||
else:
|
||||
if a.value.u64v[i] != b.value.u64v[i]:
|
||||
return False
|
||||
return (False, f"Values differ at index {i}: {a.value.u64v[i]} != {b.value.u64v[i]}")
|
||||
|
||||
for m in range(len(a.members)):
|
||||
if not shadervariable_equal(a.members[m], b.members[m]):
|
||||
return False
|
||||
(ret, diff) = shadervariable_equal(a.members[m], b.members[m])
|
||||
if not ret:
|
||||
difference = f"Member[{m}] differs {diff}"
|
||||
return (False, difference)
|
||||
|
||||
return True
|
||||
return (True, "")
|
||||
@@ -629,6 +629,124 @@ class TestCase:
|
||||
|
||||
log.success("Backbuffer is identical to reference")
|
||||
|
||||
def log_shader_variable(self, var: rd.ShaderVariable) -> None:
|
||||
log.print(f"Shader Variable: {var.name} Type:{var.type} Rows:{var.rows} Columns:{var.columns} Flags:{var.flags} CountMembers:{len(var.members)}")
|
||||
|
||||
for i in range(var.rows * var.columns):
|
||||
type = var.type
|
||||
if type == rd.VarType.UByte or type == rd.VarType.SByte:
|
||||
log.print(f"Byte {i}: {var.value.u8v[i]}")
|
||||
elif type == rd.VarType.Half or type == rd.VarType.UShort or type == rd.VarType.SShort:
|
||||
log.print(f"Half {i}: {var.value.u16v[i]}")
|
||||
elif type == rd.VarType.Float:
|
||||
log.print(f"Float {i}: {var.value.f32v[i]}")
|
||||
elif type == rd.VarType.UInt or type == rd.VarType.SInt or type == rd.VarType.Bool or type == rd.VarType.Enum:
|
||||
log.print(f"Int {i}: {var.value.u32v[i]}")
|
||||
elif type == rd.VarType.Double:
|
||||
log.print(f"Double {i}: {var.value.f64v[i]}")
|
||||
elif type == rd.VarType.ULong or type == rd.VarType.SLong or type == rd.VarType.GPUPointer:
|
||||
log.print(f"Long {i}: {var.value.u64v[i]}")
|
||||
else:
|
||||
log.print(f"??? {i}: {var.value.u64v[i]}")
|
||||
|
||||
for m in range(len(var.members)):
|
||||
self.log_shader_variable(var.members[m])
|
||||
|
||||
def compare_shader_variable_change(self, expectedChange: rd.ShaderVariableChange, change: rd.ShaderVariableChange, showDiffs = True) -> bool:
|
||||
ret = True
|
||||
difference = ""
|
||||
(res, difference) = analyse.shadervariable_equal(expectedChange.before, change.before)
|
||||
if not res:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"ShaderVariableChange different before {expectedChange.before.name} {change.before.name} {difference}")
|
||||
ret = False
|
||||
(res, difference) = analyse.shadervariable_equal(expectedChange.after, change.after)
|
||||
if not res:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"ShaderVariableChange different after {expectedChange.after.name} {change.after.name} {difference}")
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
def compare_shader_variable_changes(self, expectedChanges: List[rd.ShaderVariableChange], changes: List[rd.ShaderVariableChange], showDiffs = True) -> bool:
|
||||
ret = True
|
||||
if (len(expectedChanges) != len(changes)):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different number of changes:{len(expectedChanges)} != {len(changes)}")
|
||||
return False
|
||||
for i in range(len(expectedChanges)):
|
||||
expected = expectedChanges[i]
|
||||
change = changes[i]
|
||||
if not self.compare_shader_variable_change(expected, change, showDiffs):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"ShaderVariableChange[{i}] does not match")
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
def compare_single_step(self, expectedState: rd.ShaderDebugState, state: rd.ShaderDebugState, showDiffs = True) -> bool:
|
||||
ret = True
|
||||
if expectedState.stepIndex != state.stepIndex:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different stepIndex: {expectedState.stepIndex} != {state.stepIndex}")
|
||||
ret = False
|
||||
if expectedState.flags != state.flags:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different flags: {expectedState.flags} != {state.flags}")
|
||||
ret = False
|
||||
if expectedState.nextInstruction != state.nextInstruction:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different nextInstruction: {expectedState.nextInstruction} != {state.nextInstruction}")
|
||||
ret = False
|
||||
if not self.compare_shader_variable_changes(expectedState.changes, state.changes, showDiffs):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different changes at nextInstruction:{expectedState.nextInstruction} stepIndex:{expectedState.stepIndex}")
|
||||
ret = False
|
||||
if len(expectedState.callstack) != len(state.callstack):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different callstack length: {len(expectedState.callstack)} != {len(state.callstack)}")
|
||||
return False
|
||||
for i in range(len(expectedState.callstack)):
|
||||
if expectedState.callstack[i] != state.callstack[i]:
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Different callstack entry[{i}]: {expectedState.callstack[i]} != {state.callstack[i]}")
|
||||
ret = False
|
||||
|
||||
return ret
|
||||
|
||||
def compare_full_traces(self, expectedStates: List[rd.ShaderDebugState], states: List[rd.ShaderDebugState], showDiffs = True) -> bool:
|
||||
ret = True
|
||||
if len(expectedStates) != len(states):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Traces have different number of states: {len(expectedStates)} != {len(states)}")
|
||||
return False
|
||||
for i in range(len(expectedStates)):
|
||||
if not self.compare_single_step(expectedStates[i], states[i], showDiffs):
|
||||
if not showDiffs:
|
||||
return False
|
||||
log.error(f"Trace state[{i}] does not match")
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
def generate_full_trace(self, trace: rd.ShaderDebugTrace) -> List[rd.ShaderDebugState]:
|
||||
allStates = []
|
||||
while True:
|
||||
states = self.controller.ContinueDebug(trace.debugger)
|
||||
if len(states) == 0:
|
||||
break
|
||||
for state in states:
|
||||
allStates.append(state)
|
||||
return allStates
|
||||
|
||||
def process_trace(self, trace: rd.ShaderDebugTrace, validate: bool = True):
|
||||
variables = {}
|
||||
cycles = 0
|
||||
@@ -980,8 +1098,9 @@ class TestCase:
|
||||
else:
|
||||
if c.after.name in variables:
|
||||
# Step Forwards: not-first appearance of a variable "before" must equal currently known value
|
||||
if not analyse.shadervariable_equal(c.before, variables[c.after.name]):
|
||||
raise TestFailureException(f"Step {i} ShaderVariableChange for '{c.after.name}' before does not match existing entry")
|
||||
(res, difference) = analyse.shadervariable_equal(c.before, variables[c.after.name])
|
||||
if not res:
|
||||
raise TestFailureException(f"Step {i} ShaderVariableChange for '{c.after.name}' before does not match existing entry {difference}")
|
||||
else:
|
||||
# Step Forwards: first appearance of a variable must have "before" = {}
|
||||
if c.before != rd.ShaderVariable():
|
||||
@@ -1006,8 +1125,9 @@ class TestCase:
|
||||
else:
|
||||
if c.before.name in variables:
|
||||
# Step Backwards: not-first appearance of a variable "after" must equal currently known value
|
||||
if not analyse.shadervariable_equal(c.after, variables[c.before.name]):
|
||||
raise TestFailureException(f"Step {i} ShaderVariableChange for '{c.before.name}' after does not match existing entry")
|
||||
(res, difference) = analyse.shadervariable_equal(c.after, variables[c.before.name])
|
||||
if not res:
|
||||
raise TestFailureException(f"Step {i} ShaderVariableChange for '{c.before.name}' after does not match existing entry {difference}")
|
||||
else:
|
||||
# Step Backwards: first appearance of a variable must have "after" = {}
|
||||
if c.after != rd.ShaderVariable():
|
||||
|
||||
Reference in New Issue
Block a user