From 7f8e5555449ced17d446bcff3e01f50f54c5baa0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 9 Nov 2020 11:26:19 +0000 Subject: [PATCH] Update remaining I/O handling to support non-32-bit types * This includes the shader input interface, and storage/cbuffer access. --- .../driver/shaders/spirv/spirv_debug.cpp | 5 +- renderdoc/driver/shaders/spirv/spirv_debug.h | 10 +- .../shaders/spirv/spirv_debug_setup.cpp | 442 +++++++++--------- renderdoc/driver/vulkan/vk_shaderdebug.cpp | 136 +++--- 4 files changed, 290 insertions(+), 303 deletions(-) diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index e57327c8a..ad5e0924e 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -2697,6 +2697,8 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray ShaderVariable result; result.type = resultType.scalar().Type(); + result.rows = 1; + result.columns = RDCMAX(1U, resultType.vector().count) & 0xff; DebugAPIWrapper::TextureType texType = debugger.GetTextureType(img); @@ -2735,9 +2737,6 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray } } - result.rows = 1; - result.columns = RDCMAX(1U, resultType.vector().count) & 0xff; - SetDst(read.result, result); break; } diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index c2e7bf2ff..d5cdbcd83 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -92,14 +92,14 @@ public: struct DerivativeDeltas { - Vec4f ddxcoarse; - Vec4f ddycoarse; - Vec4f ddxfine; - Vec4f ddyfine; + ShaderVariable ddxcoarse; + ShaderVariable ddycoarse; + ShaderVariable ddxfine; + ShaderVariable ddyfine; }; virtual DerivativeDeltas GetDerivative(ShaderBuiltin builtin, uint32_t location, - uint32_t component) = 0; + uint32_t component, VarType type) = 0; }; typedef ShaderVariable (*ExtInstImpl)(ThreadState &, uint32_t, const rdcarray &); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index edbc24010..3d5569193 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -26,6 +26,7 @@ #include "common/formatting.h" #include "spirv_op_helpers.h" #include "spirv_reflect.h" +#include "var_dispatch_helpers.h" // this could be cleaner if ShaderVariable wasn't a very public struct, but it's not worth it so // we just reserve value slots that we know won't be used in opaque variables @@ -89,6 +90,20 @@ static uint32_t VarByteSize(const ShaderVariable &var) RDCMAX(1U, (uint32_t)var.columns); } +static void *VarElemPointer(ShaderVariable &var, uint32_t comp) +{ + RDCASSERTNOTEQUAL(var.type, VarType::Unknown); + byte *ret = (byte *)var.value.u64v; + return ret + comp * VarTypeByteSize(var.type); +} + +static const void *VarElemPointer(const ShaderVariable &var, uint32_t comp) +{ + RDCASSERTNOTEQUAL(var.type, VarType::Unknown); + const byte *ret = (const byte *)var.value.u64v; + return ret + comp * VarTypeByteSize(var.type); +} + namespace rdcspv { void AssignValue(ShaderVariable &dst, const ShaderVariable &src) @@ -779,8 +794,7 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s else { // matrix case is more complicated. Either read column by column or row by row - // depending on - // majorness + // depending on majorness uint32_t matrixStride = curDecorations.matrixStride; if(!(curDecorations.flags & Decorations::HasMatrixStride)) @@ -791,18 +805,19 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s if(curDecorations.flags & Decorations::ColMajor) { - ShaderValue tmp; + ShaderVariable tmp; + tmp.type = var.type; uint32_t colSize = VarTypeByteSize(var.type) * var.rows; for(uint32_t c = 0; c < var.columns; c++) { // read the column this->apiWrapper->ReadBufferValue(bindpoint, offset + c * matrixStride, colSize, - &tmp.uv[0]); + VarElemPointer(tmp, 0)); // now write it into the appropiate elements in the destination ShaderValue for(uint32_t r = 0; r < var.rows; r++) - var.value.uv[r * var.columns + c] = tmp.uv[r]; + copyComp(var, r * var.columns + c, tmp, r, var.type); } } else @@ -814,7 +829,7 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s // read the column into the destination ShaderValue, which is tightly packed with // rows this->apiWrapper->ReadBufferValue(bindpoint, offset + r * matrixStride, rowSize, - &var.value.uv[r * var.columns]); + VarElemPointer(var, r * var.columns)); } } } @@ -1493,30 +1508,26 @@ ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const { apiWrapper->ReadBufferValue(bind, offset + r * matrixStride, VarTypeByteSize(var.type) * var.columns, - &var.value.uv[r * var.columns]); + VarElemPointer(var, r * var.columns)); } } else { - ShaderValue tmp = {}; + ShaderVariable tmp; + tmp.type = var.type; + // read column-wise for(uint8_t c = 0; c < var.columns; c++) { apiWrapper->ReadBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type) * var.rows, &tmp.uv[c * var.rows]); + VarTypeByteSize(var.type) * var.rows, + VarElemPointer(tmp, c * var.rows)); } // transpose into our row major storage for(uint8_t r = 0; r < var.rows; r++) - { for(uint8_t c = 0; c < var.columns; c++) - { - if(VarTypeByteSize(var.type) == 8) - var.value.u64v[r * var.columns + c] = tmp.u64v[c * var.rows + r]; - else - var.value.uv[r * var.columns + c] = tmp.uv[c * var.rows + r]; - } - } + copyComp(var, r * var.columns + c, tmp, c * var.rows + r, var.type); } } else if(type.type == DataType::VectorType) @@ -1525,24 +1536,20 @@ ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const { // we can read a vector at a time if the matrix is column major apiWrapper->ReadBufferValue(bind, offset, VarTypeByteSize(var.type) * var.columns, - var.value.uv); + VarElemPointer(var, 0)); } else { for(uint8_t c = 0; c < var.columns; c++) { - if(VarTypeByteSize(var.type) == 8) - apiWrapper->ReadBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type), &var.value.u64v[c]); - else - apiWrapper->ReadBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type), &var.value.uv[c]); + apiWrapper->ReadBufferValue(bind, offset + c * matrixStride, VarTypeByteSize(var.type), + VarElemPointer(var, VarTypeByteSize(var.type) * c)); } } } else if(type.type == DataType::ScalarType) { - apiWrapper->ReadBufferValue(bind, offset, VarTypeByteSize(var.type), var.value.uv); + apiWrapper->ReadBufferValue(bind, offset, VarTypeByteSize(var.type), VarElemPointer(var, 0)); } }; @@ -1569,7 +1576,7 @@ ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const uint32_t scalar0 = (uint32_t)ptr.value.u64v[Scalar0VariableSlot]; uint32_t scalar1 = (uint32_t)ptr.value.u64v[Scalar1VariableSlot]; - ShaderValue val = {}; + ShaderVariable tmp = ret; if(ret.rows > 1) { @@ -1580,29 +1587,19 @@ ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const { // two indices - selecting a scalar. scalar0 is the first index in the chain so it chooses // column - if(VarTypeByteSize(ret.type) == 8) - val.u64v[0] = ret.value.u64v[scalar1 * ret.columns + scalar0]; - else - val.uv[0] = ret.value.uv[scalar1 * ret.columns + scalar0]; + copyComp(ret, 0, tmp, scalar1 * ret.columns + scalar0); // it's a scalar now, even if it was a matrix before ret.rows = ret.columns = 1; - ret.value = val; } else if(scalar0 != ~0U) { // one index, selecting a column for(uint32_t row = 0; row < ret.rows; row++) - { - if(VarTypeByteSize(ret.type) == 8) - val.u64v[row] = ret.value.u64v[row * ret.columns + scalar0]; - else - val.uv[row] = ret.value.uv[row * ret.columns + scalar0]; - } + copyComp(ret, row, tmp, row * ret.columns + scalar0); // it's a vector now, even if it was a matrix before ret.rows = 1; - ret.value = val; } } else @@ -1612,14 +1609,10 @@ ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const // vector case, selecting a scalar (if anything) if(scalar0 != ~0U) { - if(VarTypeByteSize(ret.type) == 8) - val.u64v[0] = ret.value.u64v[scalar0]; - else - val.uv[0] = ret.value.uv[scalar0]; + copyComp(ret, 0, tmp, scalar0); // it's a scalar now, even if it was a matrix before ret.columns = 1; - ret.value = val; } } @@ -1687,30 +1680,24 @@ void Debugger::WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariab { apiWrapper->WriteBufferValue(bind, offset + r * matrixStride, VarTypeByteSize(var.type) * var.columns, - &var.value.uv[r * var.columns]); + VarElemPointer(var, r * var.columns)); } } else { - ShaderValue tmp = {}; + ShaderVariable tmp; // transpose from our row major storage for(uint8_t r = 0; r < var.rows; r++) - { for(uint8_t c = 0; c < var.columns; c++) - { - if(VarTypeByteSize(var.type) == 8) - tmp.u64v[c * var.rows + r] = var.value.u64v[r * var.columns + c]; - else - tmp.uv[c * var.rows + r] = var.value.uv[r * var.columns + c]; - } - } + copyComp(tmp, c * var.rows + r, var, r * var.columns + c, var.type); // read column-wise for(uint8_t c = 0; c < var.columns; c++) { apiWrapper->WriteBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type) * var.rows, &tmp.uv[c * var.rows]); + VarTypeByteSize(var.type) * var.rows, + VarElemPointer(tmp, c * var.rows)); } } } @@ -1720,24 +1707,18 @@ void Debugger::WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariab { // we can write a vector at a time if the matrix is column major apiWrapper->WriteBufferValue(bind, offset, VarTypeByteSize(var.type) * var.columns, - var.value.uv); + VarElemPointer(var, 0)); } else { for(uint8_t c = 0; c < var.columns; c++) - { - if(VarTypeByteSize(var.type) == 8) - apiWrapper->WriteBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type), &var.value.u64v[c]); - else - apiWrapper->WriteBufferValue(bind, offset + c * matrixStride, - VarTypeByteSize(var.type), &var.value.uv[c]); - } + apiWrapper->WriteBufferValue(bind, offset + c * matrixStride, VarTypeByteSize(var.type), + VarElemPointer(var, c)); } } else if(type.type == DataType::ScalarType) { - apiWrapper->WriteBufferValue(bind, offset, VarTypeByteSize(var.type), var.value.uv); + apiWrapper->WriteBufferValue(bind, offset, VarTypeByteSize(var.type), VarElemPointer(var, 0)); } }; @@ -1770,21 +1751,13 @@ void Debugger::WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariab { // two indices - selecting a scalar. scalar0 is the first index in the chain so it chooses // column - if(VarTypeByteSize(storage->type) == 8) - storage->value.u64v[scalar1 * storage->columns + scalar0] = val.value.u64v[0]; - else - storage->value.uv[scalar1 * storage->columns + scalar0] = val.value.uv[0]; + copyComp(*storage, scalar1 * storage->columns + scalar0, val, 0); } else if(scalar0 != ~0U) { // one index, selecting a column for(uint32_t row = 0; row < storage->rows; row++) - { - if(VarTypeByteSize(storage->type) == 8) - storage->value.u64v[row * storage->columns + scalar0] = val.value.u64v[row]; - else - storage->value.uv[row * storage->columns + scalar0] = val.value.uv[row]; - } + copyComp(*storage, row * storage->columns + scalar0, val, row); } } else @@ -1792,10 +1765,7 @@ void Debugger::WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariab ClampScalars(apiWrapper, *storage, scalar0); // vector case, selecting a scalar - if(VarTypeByteSize(storage->type) == 8) - storage->value.u64v[scalar0] = val.value.u64v[0]; - else - storage->value.uv[scalar0] = val.value.uv[0]; + copyComp(*storage, scalar0, val, 0); } } } @@ -2057,8 +2027,8 @@ uint32_t Debugger::WalkVariable( uint32_t childOffset = 0; - ShaderVariable len = GetActiveLane().ids[type.length]; - for(uint32_t i = 0; i < len.value.u.x; i++) + uint32_t len = uintComp(GetActiveLane().ids[type.length], 0); + for(uint32_t i = 0; i < len; i++) { if(outVar) { @@ -2101,11 +2071,167 @@ uint32_t Debugger::WalkVariable( return numLocations; } +template +static void ApplyDerivative(uint32_t activeLaneIndex, uint32_t quadIndex, FloatType *dst, + DebugAPIWrapper::DerivativeDeltas &derivs) +{ + // We make the assumption that the coarse derivatives are generated from (0,0) in the quad, and + // fine derivatives are generated from the destination index and its neighbours in X and Y. + // This isn't spec'd but we must assume something and this will hopefully get us closest to + // reproducing actual results. + // + // For debugging, we need members of the quad to be able to generate coarse and fine + // derivatives. + // + // For (0,0) we only need the coarse derivatives to get our neighbours (1,0) and (0,1) which + // will give us coarse and fine derivatives being identical. + // + // For the others we will need to use a combination of coarse and fine derivatives to get the + // diagonal element in the quad. In the examples below, remember that the quad indices are: + // + // +---+---+ + // | 0 | 1 | + // +---+---+ + // | 2 | 3 | + // +---+---+ + // + // And that we have definitions of the derivatives: + // + // ddx_coarse = (1,0) - (0,0) + // ddy_coarse = (0,1) - (0,0) + // + // i.e. the same for all members of the quad + // + // ddx_fine = (x,y) - (1-x,y) + // ddy_fine = (x,y) - (x,1-y) + // + // i.e. the difference to the neighbour of our desired invocation (the one we have the actual + // inputs for, from gathering above). + // + // So e.g. if our thread is at (1,1) destIdx = 3 + // + // (1,0) = (1,1) - ddx_fine + // (0,1) = (1,1) - ddy_fine + // (0,0) = (1,1) - ddy_fine - ddx_coarse + // + // and ddy_coarse is unused. For (1,0) destIdx = 1: + // + // (1,1) = (1,0) + ddy_fine + // (0,1) = (1,0) - ddx_coarse + ddy_coarse + // (0,0) = (1,0) - ddx_coarse + // + // and ddx_fine is unused (it's identical to ddx_coarse anyway) + + // in the diagrams below * marks the active lane index. + // + // V and ^ == coarse ddy + // , and ` == fine ddy + // < and > == coarse ddx + // { and } == fine ddx + // + // We are basically making one or two cardinal direction moves from the starting point + // (activeLaneIndex) to the end point (quadIndex). + RDCASSERTNOTEQUAL(activeLaneIndex, quadIndex); + +#define ADD_DERIV(src) \ + for(int i = 0; i < 4; i++) \ + dst[i] += ((FloatType *)src.value.u64v)[i]; +#define SUB_DERIV(src) \ + for(int i = 0; i < 4; i++) \ + dst[i] -= ((FloatType *)src.value.u64v)[i]; + + switch(activeLaneIndex) + { + case 0: + { + // +---+---+ + // |*0 > 1 | + // +-V-+-V-+ + // | 2 | 3 | + // +---+---+ + switch(quadIndex) + { + case 0: break; + case 1: ADD_DERIV(derivs.ddxcoarse); break; + case 2: ADD_DERIV(derivs.ddycoarse); break; + case 3: + ADD_DERIV(derivs.ddxcoarse); + ADD_DERIV(derivs.ddycoarse); + break; + default: break; + } + break; + } + case 1: + { + // we need to use fine to get from 1 to 3 as coarse only ever involves 0->1 and 0->2 + // +---+---+ + // | 0 < 1*| + // +-V-+-,-+ + // | 2 | 3 | + // +---+---+ + switch(quadIndex) + { + case 0: SUB_DERIV(derivs.ddxcoarse); break; + case 1: break; + case 2: + SUB_DERIV(derivs.ddxcoarse); + ADD_DERIV(derivs.ddycoarse); + break; + case 3: ADD_DERIV(derivs.ddyfine); break; + default: break; + } + break; + } + case 2: + { + // +---+---+ + // | 0 > 1 | + // +-^-+---+ + // |*2 } 3 | + // +---+---+ + switch(quadIndex) + { + case 0: SUB_DERIV(derivs.ddycoarse); break; + case 1: + SUB_DERIV(derivs.ddycoarse); + ADD_DERIV(derivs.ddxcoarse); + break; + case 2: break; + case 3: ADD_DERIV(derivs.ddxfine); break; + default: break; + } + break; + } + case 3: + { + // +---+---+ + // | 0 < 1 | + // +---+-`-+ + // | 2 { 3*| + // +---+---+ + switch(quadIndex) + { + case 0: + SUB_DERIV(derivs.ddyfine); + SUB_DERIV(derivs.ddxcoarse); + break; + case 1: SUB_DERIV(derivs.ddyfine); break; + case 2: SUB_DERIV(derivs.ddxfine); break; + case 3: break; + default: break; + } + break; + } + default: break; + } +} + uint32_t Debugger::ApplyDerivatives(uint32_t quadIndex, const Decorations &curDecorations, uint32_t location, const DataType &inType, ShaderVariable &outVar) { // only floats have derivatives - if(outVar.type == VarType::Float) + if(outVar.type == VarType::Float || outVar.type == VarType::Half || outVar.type == VarType::Double) { ShaderBuiltin builtin = ShaderBuiltin::Undefined; if(curDecorations.flags & Decorations::HasBuiltIn) @@ -2121,157 +2247,19 @@ uint32_t Debugger::ApplyDerivatives(uint32_t quadIndex, const Decorations &curDe } } - // We make the assumption that the coarse derivatives are generated from (0,0) in the quad, and - // fine derivatives are generated from the destination index and its neighbours in X and Y. - // This isn't spec'd but we must assume something and this will hopefully get us closest to - // reproducing actual results. - // - // For debugging, we need members of the quad to be able to generate coarse and fine - // derivatives. - // - // For (0,0) we only need the coarse derivatives to get our neighbours (1,0) and (0,1) which - // will give us coarse and fine derivatives being identical. - // - // For the others we will need to use a combination of coarse and fine derivatives to get the - // diagonal element in the quad. In the examples below, remember that the quad indices are: - // - // +---+---+ - // | 0 | 1 | - // +---+---+ - // | 2 | 3 | - // +---+---+ - // - // And that we have definitions of the derivatives: - // - // ddx_coarse = (1,0) - (0,0) - // ddy_coarse = (0,1) - (0,0) - // - // i.e. the same for all members of the quad - // - // ddx_fine = (x,y) - (1-x,y) - // ddy_fine = (x,y) - (x,1-y) - // - // i.e. the difference to the neighbour of our desired invocation (the one we have the actual - // inputs for, from gathering above). - // - // So e.g. if our thread is at (1,1) destIdx = 3 - // - // (1,0) = (1,1) - ddx_fine - // (0,1) = (1,1) - ddy_fine - // (0,0) = (1,1) - ddy_fine - ddx_coarse - // - // and ddy_coarse is unused. For (1,0) destIdx = 1: - // - // (1,1) = (1,0) + ddy_fine - // (0,1) = (1,0) - ddx_coarse + ddy_coarse - // (0,0) = (1,0) - ddx_coarse - // - // and ddx_fine is unused (it's identical to ddx_coarse anyway) - if(curDecorations.flags & Decorations::HasLocation) location = curDecorations.location; DebugAPIWrapper::DerivativeDeltas derivs = - apiWrapper->GetDerivative(builtin, location, component); + apiWrapper->GetDerivative(builtin, location, component, outVar.type); - Vec4f &dst = *(Vec4f *)outVar.value.fv; - - // in the diagrams below * marks the active lane index. - // - // V and ^ == coarse ddy - // , and ` == fine ddy - // < and > == coarse ddx - // { and } == fine ddx - // - // We are basically making one or two cardinal direction moves from the starting point - // (activeLaneIndex) to the end point (quadIndex). - RDCASSERTNOTEQUAL(activeLaneIndex, quadIndex); - - switch(activeLaneIndex) - { - case 0: - { - // +---+---+ - // |*0 > 1 | - // +-V-+-V-+ - // | 2 | 3 | - // +---+---+ - switch(quadIndex) - { - case 0: break; - case 1: dst += derivs.ddxcoarse; break; - case 2: dst += derivs.ddycoarse; break; - case 3: - dst += derivs.ddxcoarse; - dst += derivs.ddycoarse; - break; - default: break; - } - break; - } - case 1: - { - // we need to use fine to get from 1 to 3 as coarse only ever involves 0->1 and 0->2 - // +---+---+ - // | 0 < 1*| - // +-V-+-,-+ - // | 2 | 3 | - // +---+---+ - switch(quadIndex) - { - case 0: dst -= derivs.ddxcoarse; break; - case 1: break; - case 2: - dst -= derivs.ddxcoarse; - dst += derivs.ddycoarse; - break; - case 3: dst += derivs.ddyfine; break; - default: break; - } - break; - } - case 2: - { - // +---+---+ - // | 0 > 1 | - // +-^-+---+ - // |*2 } 3 | - // +---+---+ - switch(quadIndex) - { - case 0: dst -= derivs.ddycoarse; break; - case 1: - dst -= derivs.ddycoarse; - dst += derivs.ddxcoarse; - break; - case 2: break; - case 3: dst += derivs.ddxfine; break; - default: break; - } - break; - } - case 3: - { - // +---+---+ - // | 0 < 1 | - // +---+-`-+ - // | 2 { 3*| - // +---+---+ - switch(quadIndex) - { - case 0: - dst -= derivs.ddyfine; - dst -= derivs.ddxcoarse; - break; - case 1: dst -= derivs.ddyfine; break; - case 2: dst -= derivs.ddxfine; break; - case 3: break; - default: break; - } - break; - } - default: break; - } + if(outVar.type == VarType::Float) + ApplyDerivative(activeLaneIndex, quadIndex, outVar.value.fv, derivs); + else if(outVar.type == VarType::Half) + ApplyDerivative(activeLaneIndex, quadIndex, + (half_float::half *)outVar.value.u16v, derivs); + else if(outVar.type == VarType::Double) + ApplyDerivative(activeLaneIndex, quadIndex, outVar.value.dv, derivs); } // each row consumes a new location diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index 9849ed001..2dbe455af 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -26,6 +26,7 @@ #include "driver/shaders/spirv/spirv_debug.h" #include "driver/shaders/spirv/spirv_editor.h" #include "driver/shaders/spirv/spirv_op_helpers.h" +#include "driver/shaders/spirv/var_dispatch_helpers.h" #include "maths/formatpacking.h" #include "vk_core.h" #include "vk_debug.h" @@ -377,19 +378,22 @@ public: if(data.width == 0) return false; - if(coord.value.uv[0] > data.width || coord.value.uv[1] > data.height || - coord.value.uv[2] > data.depth) + uint32_t coords[4]; + for(int i = 0; i < 4; i++) + coords[i] = uintComp(coord, i); + + if(coords[0] > data.width || coords[1] > data.height || coords[2] > data.depth) { m_pDriver->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::RuntimeWarning, StringFormat::Fmt( "Out of bounds access to image, coord %u,%u,%u outside of dimensions %ux%ux%u", - coord.value.uv[0], coord.value.uv[1], coord.value.uv[2], data.width, data.height, - data.depth)); + coords[0], coords[1], coords[2], data.width, data.height, data.depth)); return false; } - memcpy(output.value.uv, data.texel(coord.value.uv, sample), data.texelSize); + RDCASSERTEQUAL(data.texelSize, VarTypeByteSize(output.type) * output.columns); + memcpy(output.value.u64v, data.texel(coords, sample), data.texelSize); return true; } @@ -402,19 +406,22 @@ public: if(data.width == 0) return false; - if(coord.value.uv[0] > data.width || coord.value.uv[1] > data.height || - coord.value.uv[2] > data.depth) + uint32_t coords[4]; + for(int i = 0; i < 4; i++) + coords[i] = uintComp(coord, i); + + if(coords[0] > data.width || coords[1] > data.height || coords[2] > data.depth) { m_pDriver->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::RuntimeWarning, StringFormat::Fmt( "Out of bounds access to image, coord %u,%u,%u outside of dimensions %ux%ux%u", - coord.value.uv[0], coord.value.uv[1], coord.value.uv[2], data.width, data.height, - data.depth)); + coords[0], coords[1], coords[2], data.width, data.height, data.depth)); return false; } - memcpy(data.texel(coord.value.uv, sample), value.value.uv, data.texelSize); + RDCASSERTEQUAL(data.texelSize, VarTypeByteSize(value.type) * value.columns); + memcpy(data.texel(coords, sample), value.value.u64v, data.texelSize); return true; } @@ -440,28 +447,18 @@ public: const uint32_t typeSize = VarTypeByteSize(var.type); if(var.rows == 1) { - if(component > 3) - RDCERR("Unexpected component %u ", component); + if(component + var.columns > 4) + RDCERR("Unexpected component %u for column count %u", component, var.columns); - if(typeSize == 8) - memcpy(var.value.u64v, &location_inputs[location].value.u64v[component], - var.rows * var.columns * typeSize); - else - memcpy(var.value.uv, &location_inputs[location].value.uv[component], - var.rows * var.columns * typeSize); + for(uint8_t c = 0; c < var.columns; c++) + copyComp(var, c, location_inputs[location], component + c, var.type); } else { + RDCASSERTEQUAL(component, 0); for(uint8_t r = 0; r < var.rows; r++) - { for(uint8_t c = 0; c < var.columns; c++) - { - if(typeSize == 8) - var.value.u64v[r * var.columns + c] = location_inputs[location + c].value.u64v[r]; - else - var.value.uv[r * var.columns + c] = location_inputs[location + c].value.uv[r]; - } - } + copyComp(var, r * var.columns + c, location_inputs[location + c], r, var.type); } return; } @@ -471,7 +468,7 @@ public: } virtual DerivativeDeltas GetDerivative(ShaderBuiltin builtin, uint32_t location, - uint32_t component) override + uint32_t component, VarType type) override { if(builtin != ShaderBuiltin::Undefined) { @@ -495,10 +492,10 @@ public: for(uint32_t src = component, dst = 0; src < 4; src++, dst++) { - ret.ddxcoarse.fv[dst] = deriv.ddxcoarse.fv[src]; - ret.ddxfine.fv[dst] = deriv.ddxfine.fv[src]; - ret.ddycoarse.fv[dst] = deriv.ddycoarse.fv[src]; - ret.ddyfine.fv[dst] = deriv.ddyfine.fv[src]; + copyComp(ret.ddxcoarse, dst, deriv.ddxcoarse, src, type); + copyComp(ret.ddxfine, dst, deriv.ddxfine, src, type); + copyComp(ret.ddycoarse, dst, deriv.ddycoarse, src, type); + copyComp(ret.ddyfine, dst, deriv.ddyfine, src, type); } return ret; @@ -2841,7 +2838,8 @@ struct PSHit static void CreatePSInputFetcher(rdcarray &fragspv, uint32_t &structStride, VulkanCreationInfo::ShaderModuleReflection &shadRefl, - StorageMode storageMode, bool usePrimitiveID, bool useSampleID) + const uint32_t paramAlign, StorageMode storageMode, + bool usePrimitiveID, bool useSampleID) { rdcspv::Editor editor(fragspv); @@ -3769,7 +3767,7 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u if(Vulkan_Debug_ShaderDebugLogging()) RDCLOG("Populating location %u", attr.location); - ShaderValue &val = locations[attr.location].value; + ShaderVariable &var = locations[attr.location]; bytebuf data; @@ -3839,10 +3837,7 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u "(index %u) in instance %u.", attr.location, attr.binding, vertid, idx, instid)); - if(IsUIntFormat(attr.format) || IsSIntFormat(attr.format)) - val.u = {0, 0, 0, 1}; - else - val.f = {0.0f, 0.0f, 0.0f, 1.0f}; + set0001(var); } else { @@ -3856,31 +3851,25 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u // this is the only packed UINT format Vec4u decoded = ConvertFromR10G10B10A2UInt(*(uint32_t *)data.data()); - val.u.x = decoded.x; - val.u.y = decoded.y; - val.u.z = decoded.z; - val.u.w = decoded.w; + setUintComp(var, 0, decoded.x); + setUintComp(var, 1, decoded.y); + setUintComp(var, 2, decoded.z); + setUintComp(var, 3, decoded.w); } else { - for(uint32_t i = 0; i < fmt.compCount; i++) - { - const byte *src = data.data() + i * fmt.compByteWidth; - if(fmt.compByteWidth == 8) - memcpy(&val.u64v[i], src, fmt.compByteWidth); - else - memcpy(&val.uv[i], src, fmt.compByteWidth); - } + RDCASSERTEQUAL(fmt.compByteWidth, VarTypeByteSize(var.type)); + memcpy(var.value.u64v, data.data(), fmt.compByteWidth * fmt.compCount); } } else { FloatVector decoded = DecodeFormattedComponents(fmt, data.data()); - val.f.x = decoded.x; - val.f.y = decoded.y; - val.f.z = decoded.z; - val.f.w = decoded.w; + setFloatComp(var, 0, decoded.x); + setFloatComp(var, 1, decoded.y); + setFloatComp(var, 2, decoded.z); + setFloatComp(var, 3, decoded.w); } } } @@ -4053,8 +4042,17 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ if(!Vulkan_Debug_PSDebugDumpDirPath().empty()) FileIO::WriteAll(Vulkan_Debug_PSDebugDumpDirPath() + "/debug_psinput_before.spv", fragspv); + uint32_t paramAlign = 16; + + for(const SigParameter &sig : shadRefl.refl.inputSignature) + { + if(VarTypeByteSize(sig.varType) * sig.compCount > paramAlign) + paramAlign = 32; + } + uint32_t structStride = 0; - CreatePSInputFetcher(fragspv, structStride, shadRefl, storageMode, usePrimitiveID, useSampleID); + CreatePSInputFetcher(fragspv, structStride, shadRefl, paramAlign, storageMode, usePrimitiveID, + useSampleID); if(!Vulkan_Debug_PSDebugDumpDirPath().empty()) FileIO::WriteAll(Vulkan_Debug_PSDebugDumpDirPath() + "/debug_psinput_after.spv", fragspv); @@ -4486,14 +4484,15 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ rdcspv::Debugger *debugger = new rdcspv::Debugger; debugger->Parse(shader.spirv.GetSPIRV()); - // the data immediately follows the PSHit header. Every piece of data is vec4 aligned, and the - // output is in input signature order. + // the data immediately follows the PSHit header. Every piece of data is uniformly aligned, + // either 16-byte by default or 32-byte if larger components exist. The output is in input + // signature order. byte *PSInputs = (byte *)(winner + 1); - Vec4f *value = (Vec4f *)(PSInputs + 0 * structStride); - Vec4f *ddxcoarse = (Vec4f *)(PSInputs + 1 * structStride); - Vec4f *ddycoarse = (Vec4f *)(PSInputs + 2 * structStride); - Vec4f *ddxfine = (Vec4f *)(PSInputs + 3 * structStride); - Vec4f *ddyfine = (Vec4f *)(PSInputs + 4 * structStride); + byte *value = (byte *)(PSInputs + 0 * structStride); + byte *ddxcoarse = (byte *)(PSInputs + 1 * structStride); + byte *ddycoarse = (byte *)(PSInputs + 2 * structStride); + byte *ddxfine = (byte *)(PSInputs + 3 * structStride); + byte *ddyfine = (byte *)(PSInputs + 4 * structStride); for(size_t i = 0; i < shadRefl.refl.inputSignature.size(); i++) { @@ -4515,15 +4514,16 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ builtin ? apiWrapper->builtin_derivatives[param.systemValue] : apiWrapper->location_derivatives[param.regIndex]; - uint32_t comp = Bits::CountTrailingZeroes(uint32_t(param.regChannelMask)); + const uint32_t comp = Bits::CountTrailingZeroes(uint32_t(param.regChannelMask)); + const uint32_t elemSize = VarTypeByteSize(param.varType); - const size_t sz = sizeof(Vec4f) - sizeof(uint32_t) * comp; + const size_t sz = elemSize * param.compCount; - memcpy(&var.value.uv[comp], &value[i], sz); - memcpy(&deriv.ddxcoarse.fv[comp], &ddxcoarse[i], sz); - memcpy(&deriv.ddycoarse.fv[comp], &ddycoarse[i], sz); - memcpy(&deriv.ddxfine.fv[comp], &ddxfine[i], sz); - memcpy(&deriv.ddyfine.fv[comp], &ddyfine[i], sz); + memcpy(((byte *)var.value.u64v) + elemSize * comp, value + i * paramAlign, sz); + memcpy(((byte *)deriv.ddxcoarse.value.u64v) + elemSize * comp, ddxcoarse + i * paramAlign, sz); + memcpy(((byte *)deriv.ddycoarse.value.u64v) + elemSize * comp, ddycoarse + i * paramAlign, sz); + memcpy(((byte *)deriv.ddxfine.value.u64v) + elemSize * comp, ddxfine + i * paramAlign, sz); + memcpy(((byte *)deriv.ddyfine.value.u64v) + elemSize * comp, ddyfine + i * paramAlign, sz); } ret = debugger->BeginDebug(apiWrapper, ShaderStage::Pixel, entryPoint, spec,