From d8fa0b624d98acafa36559df9fc31882f66b7591 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 7 Apr 2020 18:37:13 +0100 Subject: [PATCH] Implement derivatives --- .../driver/shaders/spirv/spirv_debug.cpp | 131 +++++++++++++++++- renderdoc/driver/shaders/spirv/spirv_debug.h | 2 +- .../shaders/spirv/spirv_debug_setup.cpp | 45 +++--- util/test/demos/vk/vk_shader_debug_zoo.cpp | 82 +++++++++-- 4 files changed, 227 insertions(+), 33 deletions(-) diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index 8183860fa..035069028 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -253,7 +253,7 @@ void ThreadState::JumpToLabel(Id target) } void ThreadState::StepNext(ShaderDebugState *state, - const rdcarray> &prevWorkgroup) + const rdcarray> &prevWorkgroup) { Iter it = debugger.GetIterForInstruction(nextInstruction); nextInstruction++; @@ -387,6 +387,135 @@ void ThreadState::StepNext(ShaderDebugState *state, break; } + ////////////////////////////////////////////////////////////////////////////// + // + // Derivative opcodes + // + ////////////////////////////////////////////////////////////////////////////// + + // spec allows the implementation to choose what DPdx means (coarse or fine), so we choose + // coarse which seems a reasonable default. In future we could driver-detect the selection in + // use (assuming it's not dynamic base on circumstances) + case Op::DPdx: + case Op::DPdxCoarse: + { + // these all share a format + OpDPdx deriv(it); + + // coarse derivatives are identical across the quad, based on the top-left. + ShaderVariable var = prevWorkgroup[0][deriv.p]; + ShaderVariable other = prevWorkgroup[1][deriv.p]; + + for(uint8_t c = 0; c < var.columns; c++) + var.value.fv[c] = other.value.fv[c] - var.value.fv[c]; + + SetDst(state, deriv.result, var); + + break; + } + case Op::DPdy: + case Op::DPdyCoarse: + { + // these all share a format + OpDPdx deriv(it); + + // coarse derivatives are identical across the quad, based on the top-left. + ShaderVariable var = prevWorkgroup[0][deriv.p]; + ShaderVariable other = prevWorkgroup[2][deriv.p]; + + for(uint8_t c = 0; c < var.columns; c++) + var.value.fv[c] = other.value.fv[c] - var.value.fv[c]; + + SetDst(state, deriv.result, var); + + break; + } + case Op::DPdxFine: + case Op::DPdyFine: + { + // these all share a format + OpDPdxFine deriv(it); + + const bool xdirection = (opdata.op == Op::DPdxFine); + + ShaderVariable a, b; + + // we need to figure out the exact pair to use + int x = workgroupIndex & 1; + int y = workgroupIndex / 2; + + if(x == 0) + { + if(y == 0) + { + // top-left + if(xdirection) + { + a = prevWorkgroup[0][deriv.p]; + b = prevWorkgroup[1][deriv.p]; + } + else + { + a = prevWorkgroup[0][deriv.p]; + b = prevWorkgroup[2][deriv.p]; + } + } + else + { + // bottom-left + if(xdirection) + { + a = prevWorkgroup[2][deriv.p]; + b = prevWorkgroup[3][deriv.p]; + } + else + { + a = prevWorkgroup[0][deriv.p]; + b = prevWorkgroup[2][deriv.p]; + } + } + } + else + { + if(y == 0) + { + // top-right + if(xdirection) + { + a = prevWorkgroup[0][deriv.p]; + b = prevWorkgroup[1][deriv.p]; + } + else + { + a = prevWorkgroup[1][deriv.p]; + b = prevWorkgroup[3][deriv.p]; + } + } + else + { + // bottom-right + if(xdirection) + { + a = prevWorkgroup[2][deriv.p]; + b = prevWorkgroup[3][deriv.p]; + } + else + { + a = prevWorkgroup[1][deriv.p]; + b = prevWorkgroup[3][deriv.p]; + } + } + } + + // do the subtract + for(uint8_t c = 0; c < a.columns; c++) + a.value.fv[c] = b.value.fv[c] - a.value.fv[c]; + + SetDst(state, deriv.result, a); + + break; + } + ////////////////////////////////////////////////////////////////////////////// // // Composite/vector opcodes diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index 16377a370..9147be145 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -93,7 +93,7 @@ struct ThreadState ~ThreadState(); void EnterFunction(ShaderDebugState *state, const rdcarray &arguments); - void StepNext(ShaderDebugState *state, const rdcarray> &prevWorkgroup); + void StepNext(ShaderDebugState *state, const rdcarray> &prevWorkgroup); void FillCallstack(ShaderDebugState &state); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index a40a9d5d0..a954ea328 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -337,16 +337,30 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader } } - // now that the globals are allocated and their storage won't move, we can take pointers to them - for(size_t i = 0; i < active.inputs.size(); i++) - active.ids[inputIDs[i]] = MakePointerVariable(inputIDs[i], &active.inputs[i]); - for(size_t i = 0; i < active.outputs.size(); i++) - active.ids[outputIDs[i]] = MakePointerVariable(outputIDs[i], &active.outputs[i]); - for(size_t i = 0; i < global.constantBlocks.size(); i++) - active.ids[cbufferIDs[i]] = MakePointerVariable(cbufferIDs[i], &global.constantBlocks[i]); - std::sort(outputIDs.begin(), outputIDs.end()); + for(uint32_t i = 0; i < workgroupSize; i++) + { + ThreadState &lane = workgroup[i]; + if(i != activeLaneIndex) + { + lane.nextInstruction = active.nextInstruction; + lane.inputs = active.inputs; + lane.outputs = active.outputs; + lane.ids = active.ids; + // mark as inactive/helper lane + lane.done = true; + } + + // now that the globals are allocated and their storage won't move, we can take pointers to them + for(size_t i = 0; i < lane.inputs.size(); i++) + lane.ids[inputIDs[i]] = MakePointerVariable(inputIDs[i], &lane.inputs[i]); + for(size_t i = 0; i < lane.outputs.size(); i++) + lane.ids[outputIDs[i]] = MakePointerVariable(outputIDs[i], &lane.outputs[i]); + for(size_t i = 0; i < global.constantBlocks.size(); i++) + lane.ids[cbufferIDs[i]] = MakePointerVariable(cbufferIDs[i], &global.constantBlocks[i]); + } + // only outputs are considered mutable liveGlobals.append(outputIDs); @@ -390,19 +404,6 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader ret->constantBlocks = global.constantBlocks; ret->inputs = active.inputs; - for(uint32_t i = 0; i < workgroupSize; i++) - { - if(i == activeLaneIndex) - continue; - - workgroup[i].nextInstruction = active.nextInstruction; - workgroup[i].inputs = active.inputs; - workgroup[i].outputs = active.outputs; - workgroup[i].ids = active.ids; - // mark as inactive/helper lane - workgroup[i].done = true; - } - if(stage == ShaderStage::Pixel) { // apply derivatives to generate the correct inputs for the quad neighbours @@ -467,7 +468,7 @@ rdcarray Debugger::ContinueDebug() if(active.Finished()) return ret; - rdcarray> oldworkgroup; + rdcarray> oldworkgroup; oldworkgroup.resize(workgroup.size()); diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index aedc4597f..03aa11722 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -115,18 +115,82 @@ void main() float zero = linearData.zeroVal.x; float tiny = linearData.tinyVal; - int intval = flatData.intval; + int intval = int(flatData.intval); uint test = flatData.test; + vec2 inpos = linearData.inpos; + vec2 inposIncreased = linearData.inposIncreased; + Color = vec4(0,0,0,0); - if(test == 0) + switch(test) { - Color = vec4(1.0f, 2.0f, 3.0f, 4.0f); - } - else if(test == 1) - { - Color = gl_FragCoord; + case 0: + { + Color = gl_FragCoord; + break; + } + case 1: + { + Color = dFdx(gl_FragCoord); + break; + } + case 2: + { + Color = dFdy(gl_FragCoord); + break; + } + case 3: + { + Color = dFdxCoarse(gl_FragCoord); + break; + } + case 4: + { + Color = dFdyCoarse(gl_FragCoord); + break; + } + case 5: + { + Color = dFdxFine(gl_FragCoord); + break; + } + case 6: + { + Color = dFdyFine(gl_FragCoord); + break; + } + case 7: + { + Color = dFdx(vec4(inpos, inposIncreased)); + break; + } + case 8: + { + Color = dFdy(vec4(inpos, inposIncreased)); + break; + } + case 9: + { + Color = dFdxCoarse(vec4(inpos, inposIncreased)); + break; + } + case 10: + { + Color = dFdyCoarse(vec4(inpos, inposIncreased)); + break; + } + case 11: + { + Color = dFdxFine(vec4(inpos, inposIncreased)); + break; + } + case 12: + { + Color = dFdyFine(vec4(inpos, inposIncreased)); + break; + } + default: break; } } @@ -226,8 +290,8 @@ void main() if(!Init()) return 3; - size_t lastTest = pixel_glsl.rfind("test == "); - lastTest += sizeof("test == ") - 1; + size_t lastTest = pixel_glsl.rfind("case "); + lastTest += sizeof("case ") - 1; const uint32_t numGLSLTests = atoi(pixel_glsl.c_str() + lastTest) + 1;