From 351c75e006a1f06c207abcdb73d8859505282e60 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 6 Feb 2019 16:24:22 +0000 Subject: [PATCH] Fix some cases handling arrays of matrices * We also pick the output pixel in the CBuffer_Zoo tests to ensure the API agrees with our interpretation of the data. * Follow-up commit will tidy D3D cbuffer code that needs it. --- renderdoc/api/replay/shader_types.h | 7 +- renderdoc/driver/d3d11/d3d11_debug.cpp | 54 +++--- renderdoc/driver/d3d12/d3d12_debug.cpp | 54 +++--- renderdoc/driver/gl/gl_replay.cpp | 15 +- renderdoc/driver/gl/gl_shader_refl.cpp | 15 +- .../driver/shaders/dxbc/dxbc_reflect.cpp | 18 +- .../driver/shaders/spirv/spirv_common.cpp | 13 +- .../shaders/spirv/spirv_disassemble.cpp | 26 ++- renderdoc/replay/renderdoc_serialise.inl | 1 + util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp | 77 ++++++++- util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp | 94 ++++++++++- util/test/demos/gl/gl_cbuffer_zoo.cpp | 130 +++++++++++---- util/test/demos/vk/vk_cbuffer_zoo.cpp | 153 ++++++++++++++++- util/test/rdtest/testcase.py | 10 ++ util/test/tests/D3D11/D3D11_CBuffer_Zoo.py | 91 +++++++++- util/test/tests/D3D12/D3D12_CBuffer_Zoo.py | 91 +++++++++- util/test/tests/GL/GL_CBuffer_Zoo.py | 138 +++++++++++++--- util/test/tests/Vulkan/VK_CBuffer_Zoo.py | 155 +++++++++++++++++- 18 files changed, 970 insertions(+), 172 deletions(-) diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 8fb90bada..a7c7267ae 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -609,7 +609,8 @@ struct ShaderVariableDescriptor { return type == o.type && rows == o.rows && columns == o.columns && rowMajorStorage == o.rowMajorStorage && elements == o.elements && - arrayByteStride == o.arrayByteStride && name == o.name; + arrayByteStride == o.arrayByteStride && matrixByteStride == o.matrixByteStride && + name == o.name; } bool operator<(const ShaderVariableDescriptor &o) const { @@ -625,6 +626,8 @@ struct ShaderVariableDescriptor return elements < o.elements; if(!(arrayByteStride == o.arrayByteStride)) return arrayByteStride < o.arrayByteStride; + if(!(matrixByteStride == o.matrixByteStride)) + return matrixByteStride < o.matrixByteStride; if(!(name == o.name)) return name < o.name; return false; @@ -635,6 +638,8 @@ struct ShaderVariableDescriptor uint8_t rows; DOCUMENT("The number of columns in this matrix."); uint8_t columns; + DOCUMENT("The number of bytes between the start of one column/row in a matrix and the next."); + uint8_t matrixByteStride; DOCUMENT("``True`` if the matrix is stored as row major instead of column major."); bool rowMajorStorage; DOCUMENT("The number of elements in the array, or 1 if it's not an array."); diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 63964e15e..d595dc0f7 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -605,6 +605,7 @@ void D3D11DebugManager::FillCBufferVariables(const std::string &prefix, size_t & ShaderVariable &var = outvars[outIdx]; bool isArray = invars[v].type.descriptor.elements > 1; + bool isMatrix = rows > 1 && cols > 1; if(rows * elems == 1) { @@ -667,7 +668,7 @@ void D3D11DebugManager::FillCBufferVariables(const std::string &prefix, size_t & std::vector varmembers; std::vector *out = &outvars; - size_t rowCopy = 1; + uint32_t rowCopy = 1; uint32_t registers = rows; uint32_t regLen = cols; @@ -683,8 +684,13 @@ void D3D11DebugManager::FillCBufferVariables(const std::string &prefix, size_t & out = &varmembers; varmembers.resize(elems); rowCopy = rows; - rows = 1; registers = 1; + + if(columnMajor) + { + regLen = rows; + rowCopy = cols; + } } else { @@ -708,38 +714,22 @@ void D3D11DebugManager::FillCBufferVariables(const std::string &prefix, size_t & StringFormat::snprintf(buf, 63, "[%d]", r); (*out)[outIdx + r].name = base + buf; - (*out)[outIdx + r].rows = (uint32_t)rowCopy; + (*out)[outIdx + r].rows = flattenVec4s ? rowCopy : rows; (*out)[outIdx + r].type = type; (*out)[outIdx + r].isStruct = false; - (*out)[outIdx + r].columns = regLen; + (*out)[outIdx + r].columns = flattenVec4s ? regLen : cols; (*out)[outIdx + r].rowMajor = !columnMajor; - size_t totalSize = 0; - - if(flattenVec4s) - { - totalSize = elemByteSize * regLen; - } - else - { - // in a matrix, each major element before the last takes up a full - // vec4 at least - size_t vecSize = elemByteSize * 4; - - if(columnMajor) - totalSize = vecSize * (cols - 1) + elemByteSize * rowCopy; - else - totalSize = vecSize * (rowCopy - 1) + elemByteSize * cols; - } + size_t regSize = elemByteSize * regLen; if((rowDataOffset % sizeof(Vec4f) != 0) && - (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + totalSize) / sizeof(Vec4f))) + (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + regSize) / sizeof(Vec4f))) { rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); } - // arrays are also aligned to the nearest Vec4f for each element - if(!flattenVec4s && isArray) + // arrays/matrices are also aligned to the nearest Vec4f for each element + if(!flattenVec4s && (isArray || isMatrix)) { rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); } @@ -748,19 +738,23 @@ void D3D11DebugManager::FillCBufferVariables(const std::string &prefix, size_t & { const byte *d = &data[rowDataOffset]; - memcpy(&((*out)[outIdx + r].value.uv[0]), d, - RDCMIN(data.size() - rowDataOffset, totalSize)); + for(uint32_t reg = 0; reg < rowCopy; reg++) + { + if(rowDataOffset + reg * sizeof(Vec4f) + regSize <= data.size()) + { + memcpy(&((*out)[outIdx + r].value.uv[reg * regLen]), d + reg * sizeof(Vec4f), + regSize); + } + } if(!flattenVec4s && columnMajor) { ShaderVariable tmp = (*out)[outIdx + r]; - size_t transposeRows = rowCopy > 1 ? 4 : 1; - // transpose - for(size_t ri = 0; ri < transposeRows; ri++) + for(size_t ri = 0; ri < rows; ri++) for(size_t ci = 0; ci < cols; ci++) - (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * transposeRows + ri]; + (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * rows + ri]; } } diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 9850ea200..0af083c58 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -822,6 +822,7 @@ void D3D12DebugManager::FillCBufferVariables(const std::string &prefix, size_t & ShaderVariable &var = outvars[outIdx]; bool isArray = invars[v].type.descriptor.elements > 1; + bool isMatrix = rows > 1 && cols > 1; if(rows * elems == 1) { @@ -884,7 +885,7 @@ void D3D12DebugManager::FillCBufferVariables(const std::string &prefix, size_t & vector varmembers; vector *out = &outvars; - size_t rowCopy = 1; + uint32_t rowCopy = 1; uint32_t registers = rows; uint32_t regLen = cols; @@ -900,8 +901,13 @@ void D3D12DebugManager::FillCBufferVariables(const std::string &prefix, size_t & out = &varmembers; varmembers.resize(elems); rowCopy = rows; - rows = 1; registers = 1; + + if(columnMajor) + { + regLen = rows; + rowCopy = cols; + } } else { @@ -925,38 +931,22 @@ void D3D12DebugManager::FillCBufferVariables(const std::string &prefix, size_t & StringFormat::snprintf(buf, 63, "[%d]", r); (*out)[outIdx + r].name = base + buf; - (*out)[outIdx + r].rows = (uint32_t)rowCopy; + (*out)[outIdx + r].rows = flatten ? rowCopy : rows; (*out)[outIdx + r].type = type; (*out)[outIdx + r].isStruct = false; - (*out)[outIdx + r].columns = regLen; + (*out)[outIdx + r].columns = flatten ? regLen : cols; (*out)[outIdx + r].rowMajor = !columnMajor; - size_t totalSize = 0; - - if(flatten) - { - totalSize = elemByteSize * regLen; - } - else - { - // in a matrix, each major element before the last takes up a full - // vec4 at least - size_t vecSize = elemByteSize * 4; - - if(columnMajor) - totalSize = vecSize * (cols - 1) + elemByteSize * rowCopy; - else - totalSize = vecSize * (rowCopy - 1) + elemByteSize * cols; - } + size_t regSize = elemByteSize * regLen; if((rowDataOffset % sizeof(Vec4f) != 0) && - (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + totalSize) / sizeof(Vec4f))) + (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + regSize) / sizeof(Vec4f))) { rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); } - // arrays are also aligned to the nearest Vec4f for each element - if(!flatten && isArray) + // arrays/matrices are also aligned to the nearest Vec4f for each element + if(!flatten && (isArray || isMatrix)) { rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); } @@ -965,19 +955,23 @@ void D3D12DebugManager::FillCBufferVariables(const std::string &prefix, size_t & { const byte *d = &data[rowDataOffset]; - memcpy(&((*out)[outIdx + r].value.uv[0]), d, - RDCMIN(data.size() - rowDataOffset, totalSize)); + for(uint32_t reg = 0; reg < rowCopy; reg++) + { + if(rowDataOffset + reg * sizeof(Vec4f) + regSize <= data.size()) + { + memcpy(&((*out)[outIdx + r].value.uv[reg * regLen]), d + reg * sizeof(Vec4f), + regSize); + } + } if(!flatten && columnMajor) { ShaderVariable tmp = (*out)[outIdx + r]; - size_t transposeRows = rowCopy > 1 ? 4 : 1; - // transpose - for(size_t ri = 0; ri < transposeRows; ri++) + for(size_t ri = 0; ri < rows; ri++) for(size_t ci = 0; ci < cols; ci++) - (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * transposeRows + ri]; + (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * rows + ri]; } } diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 38f66f26e..ea499faae 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2043,21 +2043,15 @@ void GLReplay::FillCBufferVariables(GLuint prog, bool bufferBacked, std::string } else { - GLenum props[] = {eGL_OFFSET, eGL_MATRIX_STRIDE, eGL_ARRAY_STRIDE, eGL_LOCATION}; - GLint values[] = {0, 0, 0, 0}; + GLenum props[] = {bufferBacked ? eGL_OFFSET : eGL_LOCATION}; + GLint values[] = {0}; GL.glGetProgramResourceiv(prog, eGL_UNIFORM, idx, ARRAY_COUNT(props), props, ARRAY_COUNT(props), NULL, values); - if(!bufferBacked) - { - values[0] = values[3]; - values[2] = 1; - } - if(desc.elements == 0) { - FillCBufferValue(prog, bufferBacked, values[0], values[1], data, var); + FillCBufferValue(prog, bufferBacked, values[0], desc.matrixByteStride, data, var); } else { @@ -2072,7 +2066,8 @@ void GLReplay::FillCBufferVariables(GLuint prog, bool bufferBacked, std::string else el.name = StringFormat::Fmt("[%u]", a); - FillCBufferValue(prog, bufferBacked, values[0] + values[2] * a, values[1], data, el); + FillCBufferValue(prog, bufferBacked, values[0] + desc.arrayByteStride * a, + desc.matrixByteStride, data, el); el.isStruct = false; diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 86a7ab345..dab7de182 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -526,14 +526,14 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa rdcarray *parentBlocks, rdcarray *defaultBlock) { - const size_t numProps = 8; + const size_t numProps = 9; - GLenum resProps[numProps] = {eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, - eGL_ARRAY_SIZE, eGL_OFFSET, eGL_IS_ROW_MAJOR, eGL_ARRAY_STRIDE}; + GLenum resProps[numProps] = {eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, + eGL_BLOCK_INDEX, eGL_ARRAY_SIZE, eGL_OFFSET, + eGL_IS_ROW_MAJOR, eGL_ARRAY_STRIDE, eGL_MATRIX_STRIDE}; // GL_LOCATION not valid for buffer variables (it's only used if offset comes back -1, which will - // never - // happen for buffer variables) + // never happen for buffer variables) if(query == eGL_BUFFER_VARIABLE) resProps[2] = eGL_OFFSET; @@ -723,6 +723,7 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa var.type.descriptor.rowMajorStorage = (values[6] > 0); var.type.descriptor.arrayByteStride = values[7]; + var.type.descriptor.matrixByteStride = (uint8_t)values[8]; var.name.resize(values[1] - 1); GL.glGetProgramResourceName(sepProg, query, varIdx, values[1], NULL, &var.name[0]); @@ -816,6 +817,7 @@ void ReconstructVarTree(GLenum query, GLuint sepProg, GLuint varIdx, GLint numPa parentVar.type.descriptor.elements = isarray && !multiDimArray ? RDCMAX(1U, uint32_t(arrayIdx + 1)) : 0; parentVar.type.descriptor.arrayByteStride = topLevelStride; + parentVar.type.descriptor.matrixByteStride = 0; bool found = false; @@ -982,6 +984,7 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref res.variableType.descriptor.elements = 0; res.variableType.descriptor.rowMajorStorage = false; res.variableType.descriptor.arrayByteStride = 0; + res.variableType.descriptor.matrixByteStride = 0; // float samplers if(values[0] == eGL_SAMPLER_BUFFER) @@ -1525,6 +1528,7 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref res.variableType.descriptor.elements = len; res.variableType.descriptor.rowMajorStorage = false; res.variableType.descriptor.arrayByteStride = 0; + res.variableType.descriptor.matrixByteStride = 0; res.variableType.descriptor.name = "buffer"; res.variableType.descriptor.type = VarType::UInt; res.bindPoint = (int32_t)rwresources.size(); @@ -1598,6 +1602,7 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref paddingVar.type.descriptor.elements = 1; paddingVar.type.descriptor.rowMajorStorage = false; paddingVar.type.descriptor.arrayByteStride = 0; + paddingVar.type.descriptor.matrixByteStride = 0; paddingVar.type.descriptor.name = StringFormat::Fmt("uint%u", padding); members[ssbo][0].type.members.push_back(paddingVar); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index fe11bd287..d8e334ec0 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -55,20 +55,14 @@ static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, ret.descriptor.rowMajorStorage = (type.descriptor.varClass == DXBC::CLASS_MATRIX_ROWS); uint32_t baseElemSize = (ret.descriptor.type == VarType::Double) ? 8 : 4; + + // in D3D matrices always take up a float4 per row/column + ret.descriptor.matrixByteStride = uint8_t(baseElemSize * 4); + if(ret.descriptor.rowMajorStorage) - { - uint32_t primary = ret.descriptor.rows; - if(primary == 3) - primary = 4; - ret.descriptor.arrayByteStride = baseElemSize * primary * ret.descriptor.columns; - } + ret.descriptor.arrayByteStride = ret.descriptor.matrixByteStride * ret.descriptor.rows; else - { - uint32_t primary = ret.descriptor.columns; - if(primary == 3) - primary = 4; - ret.descriptor.arrayByteStride = baseElemSize * primary * ret.descriptor.rows; - } + ret.descriptor.arrayByteStride = ret.descriptor.matrixByteStride * ret.descriptor.columns; uint32_t o = offset; diff --git a/renderdoc/driver/shaders/spirv/spirv_common.cpp b/renderdoc/driver/shaders/spirv/spirv_common.cpp index c2f0b30f5..5beeacc21 100644 --- a/renderdoc/driver/shaders/spirv/spirv_common.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_common.cpp @@ -145,6 +145,8 @@ void SPIRVFillCBufferVariables(const rdcarray &invars, ShaderVariable &var = outvars[outIdx]; + const uint32_t matStride = invars[v].type.descriptor.matrixByteStride; + if(!isArray) { outvars[outIdx].rows = rows; @@ -161,7 +163,7 @@ void SPIRVFillCBufferVariables(const rdcarray &invars, for(uint32_t c = 0; c < cols; c++) { - size_t srcoffs = 4 * elemByteSize * c; + size_t srcoffs = matStride * c; size_t dstoffs = rows * elemByteSize * c; memcpy((byte *)(tmp) + dstoffs, d + srcoffs, RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows)); @@ -176,7 +178,7 @@ void SPIRVFillCBufferVariables(const rdcarray &invars, { for(uint32_t r = 0; r < rows; r++) { - size_t srcoffs = 4 * elemByteSize * r; + size_t srcoffs = matStride * r; size_t dstoffs = cols * elemByteSize * r; memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs, RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols)); @@ -201,7 +203,7 @@ void SPIRVFillCBufferVariables(const rdcarray &invars, // so we copy secondaryDim number of primaryDim-sized elements uint32_t primaryDim = cols; uint32_t secondaryDim = rows; - if(isMatrix && rowMajor) + if(isMatrix && !rowMajor) { primaryDim = rows; secondaryDim = cols; @@ -229,10 +231,7 @@ void SPIRVFillCBufferVariables(const rdcarray &invars, // when we transpose for(uint32_t s = 0; s < secondaryDim; s++) { - uint32_t matStride = primaryDim; - if(matStride == 3) - matStride = 4; - memcpy(&(varmembers[e].value.uv[primaryDim * s]), d + matStride * elemByteSize * s, + memcpy(&(varmembers[e].value.uv[primaryDim * s]), d + matStride * s, RDCMIN(data.size() - rowDataOffset, elemByteSize * primaryDim)); } diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index f40b3b07c..a85a5db8b 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -3514,6 +3514,7 @@ void MakeConstantBlockVariable(ShaderConstant &outConst, SPVTypeData *type, cons outConst.type.descriptor.elements = 1; outConst.type.descriptor.arrayByteStride = 0; + outConst.type.descriptor.matrixByteStride = 0; if(type->type == SPVTypeData::eArray) { @@ -3526,7 +3527,7 @@ void MakeConstantBlockVariable(ShaderConstant &outConst, SPVTypeData *type, cons outConst.type.descriptor.elements = type->arraySize; } - bool foundArrayStride = false; + bool foundArrayStride = false, foundMatrixStride = false; for(size_t d = 0; d < decorations.size(); d++) { @@ -3534,8 +3535,15 @@ void MakeConstantBlockVariable(ShaderConstant &outConst, SPVTypeData *type, cons { outConst.type.descriptor.arrayByteStride = decorations[d].val; foundArrayStride = true; - break; } + if(decorations[d].decoration == spv::DecorationMatrixStride) + { + outConst.type.descriptor.matrixByteStride = (uint8_t)decorations[d].val; + foundMatrixStride = true; + } + + if(foundMatrixStride && foundArrayStride) + break; } for(size_t d = 0; !foundArrayStride && type->decorations && d < type->decorations->size(); d++) @@ -3547,6 +3555,15 @@ void MakeConstantBlockVariable(ShaderConstant &outConst, SPVTypeData *type, cons } } + for(size_t d = 0; !foundMatrixStride && type->decorations && d < type->decorations->size(); d++) + { + if((*type->decorations)[d].decoration == spv::DecorationMatrixStride) + { + outConst.type.descriptor.matrixByteStride = (uint8_t)(*type->decorations)[d].val; + break; + } + } + type = type->baseType; } @@ -3566,10 +3583,9 @@ void MakeConstantBlockVariable(ShaderConstant &outConst, SPVTypeData *type, cons for(size_t d = 0; d < decorations.size(); d++) { if(decorations[d].decoration == spv::DecorationRowMajor) - { outConst.type.descriptor.rowMajorStorage = true; - break; - } + if(decorations[d].decoration == spv::DecorationMatrixStride) + outConst.type.descriptor.matrixByteStride = (uint8_t)decorations[d].val; } if(type->type == SPVTypeData::eMatrix) diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index ebb2f1fd5..106094cc3 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -176,6 +176,7 @@ void DoSerialise(SerialiserType &ser, ShaderVariableDescriptor &el) SERIALISE_MEMBER(type); SERIALISE_MEMBER(rows); SERIALISE_MEMBER(columns); + SERIALISE_MEMBER(matrixByteStride); SERIALISE_MEMBER(rowMajorStorage); SERIALISE_MEMBER(elements); SERIALISE_MEMBER(arrayByteStride); diff --git a/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp b/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp index 404f11cc0..2811ca175 100644 --- a/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp +++ b/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp @@ -153,12 +153,85 @@ cbuffer consts : register(b0) // .c[3] = { { 320, 321, 322 }, 323 } // } - float4 test; // {324, 325, 326, 327} + column_major float3x2 ac; // covers 2 float4s with padding at end of each column (but not row) + // row0: {324, 328} + // row1: {325, 329} + // row2: {326, 330} + // <327, 331> + row_major float3x2 ad; // covers 3 float4s with padding at end of each row (but not column) + // row0: {332, 333}, <334, 335> + // row1: {336, 337}, <338, 339> + // row2: {340, 341}, <342, 343> + + column_major float3x2 ae[2]; // covers 2 float4s with padding at end of each column (but not row) + // [0] = { + // row0: {344, 348} + // row1: {345, 349} + // row2: {346, 350} + // <347, 351> + // } + // [1] = { + // row0: {352, 356} + // row1: {353, 357} + // row2: {354, 358} + // <355, 359> + // } + row_major float3x2 af[2]; // covers 3 float4s with padding at end of each row (but not column) + // [0] = { + // row0: {360, 361}, <362, 363> + // row1: {364, 365}, <366, 367> + // row2: {368, 369}, <370, 371> + // } + // [1] = { + // row0: {372, 373}, <374, 375> + // row1: {376, 377}, <378, 379> + // row2: {380, 381}, + // } + + float2 dummy9; // consumes leftovers from above array = {382, 383} + + float2 dummy10; // should have padding at the end = {384, 385}, <386, 387> + + row_major float2x2 ag; // each row is aligned to float4: + // row0: {388, 389}, <390, 391> + // row1: {392, 393}, + + float2 dummy11; // consumes leftovers from above matrix = {394, 395} + float2 dummy12; // should have padding at the end = {396, 397}, <398, 399> + + column_major float2x2 ah; // each column is aligned to float4: + // row0: {400, 404} + // row1: {401, 405} + // <402, 406> + // <403, 407> + + row_major float2x2 ai[2]; // [0] = { + // row0: {408, 409}, <410, 411> + // row1: {412, 413}, <414, 415> + // } + // [1] = { + // row0: {416, 417}, <418, 419> + // row1: {420, 421}, <422, 423> + // } + column_major float2x2 aj[2]; // [0] = { + // row0: {424, 428} + // row1: {425, 429} + // <426, 430> + // <427, 431> + // } + // [1] = { + // row0: {432, 436} + // row1: {433, 437} + // <434, 438> + // <435, 439> + // } + + float4 test; // {440, 441, 442, 443} }; float4 main() : SV_Target0 { - return test; + return test + float4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; diff --git a/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp b/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp index d284e67d3..10b49defa 100644 --- a/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp +++ b/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp @@ -153,12 +153,85 @@ cbuffer consts : register(b0) // .c[3] = { { 320, 321, 322 }, 323 } // } - float4 test; // {324, 325, 326, 327} + column_major float3x2 ac; // covers 2 float4s with padding at end of each column (but not row) + // row0: {324, 328} + // row1: {325, 329} + // row2: {326, 330} + // <327, 331> + row_major float3x2 ad; // covers 3 float4s with padding at end of each row (but not column) + // row0: {332, 333}, <334, 335> + // row1: {336, 337}, <338, 339> + // row2: {340, 341}, <342, 343> + + column_major float3x2 ae[2]; // covers 2 float4s with padding at end of each column (but not row) + // [0] = { + // row0: {344, 348} + // row1: {345, 349} + // row2: {346, 350} + // <347, 351> + // } + // [1] = { + // row0: {352, 356} + // row1: {353, 357} + // row2: {354, 358} + // <355, 359> + // } + row_major float3x2 af[2]; // covers 3 float4s with padding at end of each row (but not column) + // [0] = { + // row0: {360, 361}, <362, 363> + // row1: {364, 365}, <366, 367> + // row2: {368, 369}, <370, 371> + // } + // [1] = { + // row0: {372, 373}, <374, 375> + // row1: {376, 377}, <378, 379> + // row2: {380, 381}, + // } + + float2 dummy9; // consumes leftovers from above array = {382, 383} + + float2 dummy10; // should have padding at the end = {384, 385}, <386, 387> + + row_major float2x2 ag; // each row is aligned to float4: + // row0: {388, 389}, <390, 391> + // row1: {392, 393}, + + float2 dummy11; // consumes leftovers from above matrix = {394, 395} + float2 dummy12; // should have padding at the end = {396, 397}, <398, 399> + + column_major float2x2 ah; // each column is aligned to float4: + // row0: {400, 404} + // row1: {401, 405} + // <402, 406> + // <403, 407> + + row_major float2x2 ai[2]; // [0] = { + // row0: {408, 409}, <410, 411> + // row1: {412, 413}, <414, 415> + // } + // [1] = { + // row0: {416, 417}, <418, 419> + // row1: {420, 421}, <422, 423> + // } + column_major float2x2 aj[2]; // [0] = { + // row0: {424, 428} + // row1: {425, 429} + // <426, 430> + // <427, 431> + // } + // [1] = { + // row0: {432, 436} + // row1: {433, 437} + // <434, 438> + // <435, 439> + // } + + float4 test; // {440, 441, 442, 443} }; float4 main() : SV_Target0 { - return test; + return test + float4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; @@ -184,11 +257,16 @@ float4 main() : SV_Target0 cbvParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0), }); - ID3D12PipelineStatePtr pso = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob); + ID3D12PipelineStatePtr pso = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob).RTVs( + {DXGI_FORMAT_R32G32B32A32_FLOAT}); ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); ResourceBarrier(cb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + ID3D12ResourcePtr rtvtex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, screenWidth, screenHeight) + .RTV() + .InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET); + while(Running()) { ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); @@ -197,10 +275,14 @@ float4 main() : SV_Target0 ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D12_CPU_DESCRIPTOR_HANDLE rtv = + D3D12_CPU_DESCRIPTOR_HANDLE bbrtv = MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0); - ClearRenderTargetView(cmd, rtv, {0.4f, 0.5f, 0.6f, 1.0f}); + ClearRenderTargetView(cmd, bbrtv, {0.4f, 0.5f, 0.6f, 1.0f}); + + D3D12_CPU_DESCRIPTOR_HANDLE offrtv = MakeRTV(rtvtex).CreateCPU(0); + + ClearRenderTargetView(cmd, offrtv, {0.4f, 0.5f, 0.6f, 1.0f}); cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -212,7 +294,7 @@ float4 main() : SV_Target0 RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight}); - OMSetRenderTargets(cmd, {rtv}, {}); + OMSetRenderTargets(cmd, {offrtv}, {}); cmd->DrawInstanced(3, 1, 0, 0); diff --git a/util/test/demos/gl/gl_cbuffer_zoo.cpp b/util/test/demos/gl/gl_cbuffer_zoo.cpp index f8a33200d..446fc56b8 100644 --- a/util/test/demos/gl/gl_cbuffer_zoo.cpp +++ b/util/test/demos/gl/gl_cbuffer_zoo.cpp @@ -187,35 +187,105 @@ layout(binding = 0, std140) uniform constsbuf // .c[3] = { { 320, 321, 322 }, 323 } // } - vec4 test; // {324, 325, 326, 327} + layout(column_major) mat2x3 ac; // covers 2 vec4s with padding at end of each column (but not row) + // row0: {324, 328} + // row1: {325, 329} + // row2: {326, 330} + // <327, 331> + layout(row_major) mat2x3 ad; // covers 3 vec4s with padding at end of each row (but not column) + // row0: {332, 333}, <334, 335> + // row1: {336, 337}, <338, 339> + // row2: {340, 341}, <342, 343> + + layout(column_major) mat2x3 ae[2]; // covers 2 vec4s with padding at end of each column (but not row) + // [0] = { + // row0: {344, 348} + // row1: {345, 349} + // row2: {346, 350} + // <347, 351> + // } + // [1] = { + // row0: {352, 356} + // row1: {353, 357} + // row2: {354, 358} + // <355, 359> + // } + layout(row_major) mat2x3 af[2]; // covers 3 vec4s with padding at end of each row (but not column) + // [0] = { + // row0: {360, 361}, <362, 363> + // row1: {364, 365}, <366, 367> + // row2: {368, 369}, <370, 371> + // } + // [1] = { + // row0: {372, 373}, <374, 375> + // row1: {376, 377}, <378, 379> + // row2: {380, 381}, <382, 383> + // } + + vec2 dummy10; // should have padding at the end = {384, 385}, <386, 387> + + layout(row_major) mat2x2 ag; // each row is aligned to float4: + // row0: {388, 389}, <390, 391> + // row1: {392, 393}, <394, 395> + + vec2 dummy11; // should have padding at the end = {396, 397}, <398, 399> + + layout(column_major) mat2x2 ah; // each column is aligned to float4: + // row0: {400, 404} + // row1: {401, 405} + // <402, 406> + // <403, 407> + + layout(row_major) mat2x2 ai[2]; // [0] = { + // row0: {408, 409}, <410, 411> + // row1: {412, 413}, <414, 415> + // } + // [1] = { + // row0: {416, 417}, <418, 419> + // row1: {420, 421}, <422, 423> + // } + layout(column_major) mat2x2 aj[2]; // [0] = { + // row0: {424, 428} + // row1: {425, 429} + // <426, 430> + // <427, 431> + // } + // [1] = { + // row0: {432, 436} + // row1: {433, 437} + // <434, 438> + // <435, 439> + // } + + vec4 test; // {440, 441, 442, 443} // because GL has worse handling of multidimensional arrays than other APIs, we add an extra test // here with more than 2 dimensions - vec4 multiarray2[4][3][2]; // [0][0][0] = {328, 329, 330, 331} - // [0][0][1] = {332, 333, 334, 335} - // [0][1][0] = {336, 337, 338, 339} - // [0][1][1] = {340, 341, 342, 343} - // [0][2][0] = {344, 345, 346, 347} - // [0][2][1] = {348, 349, 350, 351} - // [1][0][0] = {352, 353, 354, 355} - // [1][0][1] = {356, 357, 358, 359} - // [1][1][0] = {360, 361, 362, 363} - // [1][1][1] = {364, 365, 366, 367} - // [1][2][0] = {368, 369, 370, 371} - // [1][2][1] = {372, 373, 374, 375} - // [2][0][0] = {376, 377, 378, 379} - // [2][0][1] = {380, 381, 382, 383} - // [2][1][0] = {384, 385, 386, 387} - // [2][1][1] = {388, 389, 390, 391} - // [2][2][0] = {392, 393, 394, 395} - // [2][2][1] = {396, 397, 398, 399} - // [3][0][0] = {400, 401, 402, 403} - // [3][0][1] = {404, 405, 406, 407} - // [3][1][0] = {408, 409, 410, 411} - // [3][1][1] = {412, 413, 414, 415} - // [3][2][0] = {416, 417, 418, 419} - // [3][2][1] = {420, 421, 422, 423} + vec4 multiarray2[4][3][2]; // [0][0][0] = {444, 445, 446, 447} + // [0][0][1] = {448, 449, 450, 451} + // [0][1][0] = {452, ..., ..., ...} + // [0][1][1] = {..., ..., ..., ...} + // [0][2][0] = {..., ..., ..., ...} + // [0][2][1] = {..., ..., ..., ...} + // [1][0][0] = {..., ..., ..., ...} + // [1][0][1] = {..., ..., ..., ...} + // [1][1][0] = {..., ..., ..., ...} + // [1][1][1] = {..., ..., ..., ...} + // [1][2][0] = {..., ..., ..., ...} + // [1][2][1] = {..., ..., ..., ...} + // [2][0][0] = {..., ..., ..., ...} + // [2][0][1] = {..., ..., ..., ...} + // [2][1][0] = {..., ..., ..., ...} + // [2][1][1] = {..., ..., ..., ...} + // [2][2][0] = {..., ..., ..., ...} + // [2][2][1] = {..., ..., ..., ...} + // [3][0][0] = {..., ..., ..., ...} + // [3][0][1] = {..., ..., ..., ...} + // [3][1][0] = {..., ..., ..., ...} + // [3][1][1] = {..., ..., ..., ...} + // [3][2][0] = {..., ..., ..., ...} + // [3][2][1] = {..., ..., ..., ...} }; void main() @@ -224,9 +294,9 @@ void main() float blah = a.x + b.x + c.x + d.x + e.x + f.x + j.x + k.x + l.x + m.x; blah += n[0] + o[0] + p.x; blah += q[0].x + r[0].x + s[0].x + t[0].x + u[0].x + v[0].x + w[0].x + x[0].x + y[0].x + z; - blah += multiarray[0][0].x; - blah *= 0.0000001f; - Color = blah + test; + blah += multiarray[0][0].x + ac[0][0] + ad[0][0] + ae[0][0][0] + af[0][0][0]; + blah *= vertIn.uv.z; + Color = blah + test + vec4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; @@ -256,9 +326,9 @@ void main() GLuint program = MakeProgram(common + vertex, common + pixel); glObjectLabel(GL_PROGRAM, program, -1, "Full program"); - Vec4f cbufferdata[512]; + Vec4f cbufferdata[684]; - for(int i = 0; i < 512; i++) + for(int i = 0; i < 684; i++) cbufferdata[i] = Vec4f(float(i * 4 + 0), float(i * 4 + 1), float(i * 4 + 2), float(i * 4 + 3)); GLuint cb = MakeBuffer(); diff --git a/util/test/demos/vk/vk_cbuffer_zoo.cpp b/util/test/demos/vk/vk_cbuffer_zoo.cpp index 3364f11b0..91b7559ca 100644 --- a/util/test/demos/vk/vk_cbuffer_zoo.cpp +++ b/util/test/demos/vk/vk_cbuffer_zoo.cpp @@ -186,12 +186,82 @@ layout(set = 0, binding = 0, std140) uniform constsbuf // .c[3] = { { 320, 321, 322 }, 323 } // } - vec4 test; // {324, 325, 326, 327} + layout(column_major) mat2x3 ac; // covers 2 vec4s with padding at end of each column (but not row) + // row0: {324, 328} + // row1: {325, 329} + // row2: {326, 330} + // <327, 331> + layout(row_major) mat2x3 ad; // covers 3 vec4s with padding at end of each row (but not column) + // row0: {332, 333}, <334, 335> + // row1: {336, 337}, <338, 339> + // row2: {340, 341}, <342, 343> + + layout(column_major) mat2x3 ae[2]; // covers 2 vec4s with padding at end of each column (but not row) + // [0] = { + // row0: {344, 348} + // row1: {345, 349} + // row2: {346, 350} + // <347, 351> + // } + // [1] = { + // row0: {352, 356} + // row1: {353, 357} + // row2: {354, 358} + // <355, 359> + // } + layout(row_major) mat2x3 af[2]; // covers 3 vec4s with padding at end of each row (but not column) + // [0] = { + // row0: {360, 361}, <362, 363> + // row1: {364, 365}, <366, 367> + // row2: {368, 369}, <370, 371> + // } + // [1] = { + // row0: {372, 373}, <374, 375> + // row1: {376, 377}, <378, 379> + // row2: {380, 381}, <382, 383> + // } + + vec2 dummy10; // should have padding at the end = {384, 385}, <386, 387> + + layout(row_major) mat2x2 ag; // each row is aligned to float4: + // row0: {388, 389}, <390, 391> + // row1: {392, 393}, <394, 395> + + vec2 dummy11; // should have padding at the end = {396, 397}, <398, 399> + + layout(column_major) mat2x2 ah; // each column is aligned to float4: + // row0: {400, 404} + // row1: {401, 405} + // <402, 406> + // <403, 407> + + layout(row_major) mat2x2 ai[2]; // [0] = { + // row0: {408, 409}, <410, 411> + // row1: {412, 413}, <414, 415> + // } + // [1] = { + // row0: {416, 417}, <418, 419> + // row1: {420, 421}, <422, 423> + // } + layout(column_major) mat2x2 aj[2]; // [0] = { + // row0: {424, 428} + // row1: {425, 429} + // <426, 430> + // <427, 431> + // } + // [1] = { + // row0: {432, 436} + // row1: {433, 437} + // <434, 438> + // <435, 439> + // } + + vec4 test; // {440, 441, 442, 443} }; void main() { - Color = test; + Color = test + vec4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; @@ -284,7 +354,7 @@ layout(set = 0, binding = 0) cbuffer consts // SPIR-V can't represent single-dimension matrices properly at the moment /* - row_major float4x1 aa; // covers 4 vec4s with maximum padding + row_major float4x1 aa; // covers 4 float4s with maximum padding // row0: {208, 212, 216, 220} // <209, 213, 217, 221> // <210, 214, 218, 222> @@ -325,12 +395,85 @@ layout(set = 0, binding = 0) cbuffer consts // .c[3] = { { 320, 321, 322 }, 323 } // } - float4 test; // {324, 325, 326, 327} + column_major float3x2 ac; // covers 2 float4s with padding at end of each column (but not row) + // row0: {324, 328} + // row1: {325, 329} + // row2: {326, 330} + // <327, 331> + row_major float3x2 ad; // covers 3 float4s with padding at end of each row (but not column) + // row0: {332, 333}, <334, 335> + // row1: {336, 337}, <338, 339> + // row2: {340, 341}, <342, 343> + + column_major float3x2 ae[2]; // covers 2 float4s with padding at end of each column (but not row) + // [0] = { + // row0: {344, 348} + // row1: {345, 349} + // row2: {346, 350} + // <347, 351> + // } + // [1] = { + // row0: {352, 356} + // row1: {353, 357} + // row2: {354, 358} + // <355, 359> + // } + row_major float3x2 af[2]; // covers 3 float4s with padding at end of each row (but not column) + // [0] = { + // row0: {360, 361}, <362, 363> + // row1: {364, 365}, <366, 367> + // row2: {368, 369}, <370, 371> + // } + // [1] = { + // row0: {372, 373}, <374, 375> + // row1: {376, 377}, <378, 379> + // row2: {380, 381}, + // } + + float2 dummy10; // consumes leftovers from above array = {382, 383} + + float2 dummy11; // should have padding at the end = {384, 385}, <386, 387> + + row_major float2x2 ag; // each row is aligned to float4: + // row0: {388, 389}, <390, 391> + // row1: {392, 393}, + + float2 dummy12; // consumes leftovers from above matrix = {394, 395} + float2 dummy13; // should have padding at the end = {396, 397}, <398, 399> + + column_major float2x2 ah; // each column is aligned to float4: + // row0: {400, 404} + // row1: {401, 405} + // <402, 406> + // <403, 407> + + row_major float2x2 ai[2]; // [0] = { + // row0: {408, 409}, <410, 411> + // row1: {412, 413}, <414, 415> + // } + // [1] = { + // row0: {416, 417}, <418, 419> + // row1: {420, 421}, <422, 423> + // } + column_major float2x2 aj[2]; // [0] = { + // row0: {424, 428} + // row1: {425, 429} + // <426, 430> + // <427, 431> + // } + // [1] = { + // row0: {432, 436} + // row1: {433, 437} + // <434, 438> + // <435, 439> + // } + + float4 test; // {440, 441, 442, 443} }; float4 main() : SV_Target0 { - return test; + return test + float4(0.1f, 0.0f, 0.0f, 0.0f); } )EOSHADER"; diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index e9eeb45d1..242046399 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -235,6 +235,16 @@ class TestCase: return first_draw + def get_texture(self, id: rd.ResourceId): + texs = self.controller.GetTextures() + + for t in texs: + t: rd.TextureDescription + if t.resourceId == id: + return t + + return None + def get_last_draw(self): last_draw: rd.DrawcallDescription = self.controller.GetDrawcalls()[-1] diff --git a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py index 1a7c45588..0ce62eb23 100644 --- a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py +++ b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py @@ -15,6 +15,13 @@ class D3D11_CBuffer_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) + # Make an output so we can pick pixels + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) + + self.check(out is not None) + + out.SetDimensions(100, 100) + pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel @@ -236,9 +243,91 @@ class D3D11_CBuffer_Zoo(rdtest.TestCase): }), }) + # column_major float3x2 ac; + var_check.check('ac').rows(3).cols(2).column_major().value([324.0, 328.0, + 325.0, 329.0, + 326.0, 330.0]) + + # row_major float3x2 ad; + var_check.check('ad').rows(3).cols(2).row_major().value([332.0, 333.0, + 336.0, 337.0, + 340.0, 341.0]) + + # column_major float3x2 ae[2]; + var_check.check('ae').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(3).cols(2).column_major().value([344.0, 348.0, + 345.0, 349.0, + 346.0, 350.0]), + 1: lambda x: x.rows(3).cols(2).column_major().value([352.0, 356.0, + 353.0, 357.0, + 354.0, 358.0]), + }) + + # row_major float3x2 af[2]; + var_check.check('af').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(3).cols(2).row_major().value([360.0, 361.0, + 364.0, 365.0, + 368.0, 369.0]), + 1: lambda x: x.rows(3).cols(2).row_major().value([372.0, 373.0, + 376.0, 377.0, + 380.0, 381.0]), + }) + + # float2 dummy9; + var_check.check('dummy9') + + # float2 dummy10; + var_check.check('dummy10') + + # row_major float2x2 ag; + var_check.check('ag').rows(2).cols(2).row_major().value([388.0, 389.0, + 392.0, 393.0]) + + # float2 dummy11; + var_check.check('dummy11') + + # float2 dummy12; + var_check.check('dummy12') + + # column_major float2x2 ah; + var_check.check('ah').rows(2).cols(2).column_major().value([400.0, 404.0, + 401.0, 405.0]) + + # row_major float2x2 ai[2]; + var_check.check('ai').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).row_major().value([408.0, 409.0, + 412.0, 413.0]), + 1: lambda x: x.rows(2).cols(2).row_major().value([416.0, 417.0, + 420.0, 421.0]), + }) + + # column_major float2x2 aj[2]; + var_check.check('aj').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).column_major().value([424.0, 428.0, + 425.0, 429.0]), + 1: lambda x: x.rows(2).cols(2).column_major().value([432.0, 436.0, + 433.0, 437.0]), + }) + # float4 test; - var_check.check('test').rows(1).cols(4).value([324.0, 325.0, 326.0, 327.0]) + var_check.check('test').rows(1).cols(4).value([440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("CBuffer variables are as expected") + + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + out.SetTextureDisplay(tex) + + texdetails = self.get_texture(tex.resourceId) + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("Picked value is as expected") + + out.Shutdown() diff --git a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py index 31a9e2fe8..865b99155 100644 --- a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py +++ b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py @@ -16,6 +16,13 @@ class D3D12_CBuffer_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) + # Make an output so we can pick pixels + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) + + self.check(out is not None) + + out.SetDimensions(100, 100) + pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel @@ -237,9 +244,91 @@ class D3D12_CBuffer_Zoo(rdtest.TestCase): }), }) + # column_major float3x2 ac; + var_check.check('ac').rows(3).cols(2).column_major().value([324.0, 328.0, + 325.0, 329.0, + 326.0, 330.0]) + + # row_major float3x2 ad; + var_check.check('ad').rows(3).cols(2).row_major().value([332.0, 333.0, + 336.0, 337.0, + 340.0, 341.0]) + + # column_major float3x2 ae[2]; + var_check.check('ae').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(3).cols(2).column_major().value([344.0, 348.0, + 345.0, 349.0, + 346.0, 350.0]), + 1: lambda x: x.rows(3).cols(2).column_major().value([352.0, 356.0, + 353.0, 357.0, + 354.0, 358.0]), + }) + + # row_major float3x2 af[2]; + var_check.check('af').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(3).cols(2).row_major().value([360.0, 361.0, + 364.0, 365.0, + 368.0, 369.0]), + 1: lambda x: x.rows(3).cols(2).row_major().value([372.0, 373.0, + 376.0, 377.0, + 380.0, 381.0]), + }) + + # float2 dummy9; + var_check.check('dummy9') + + # float2 dummy10; + var_check.check('dummy10') + + # row_major float2x2 ag; + var_check.check('ag').rows(2).cols(2).row_major().value([388.0, 389.0, + 392.0, 393.0]) + + # float2 dummy11; + var_check.check('dummy11') + + # float2 dummy12; + var_check.check('dummy12') + + # column_major float2x2 ah; + var_check.check('ah').rows(2).cols(2).column_major().value([400.0, 404.0, + 401.0, 405.0]) + + # row_major float2x2 ai[2]; + var_check.check('ai').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).row_major().value([408.0, 409.0, + 412.0, 413.0]), + 1: lambda x: x.rows(2).cols(2).row_major().value([416.0, 417.0, + 420.0, 421.0]), + }) + + # column_major float2x2 aj[2]; + var_check.check('aj').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).column_major().value([424.0, 428.0, + 425.0, 429.0]), + 1: lambda x: x.rows(2).cols(2).column_major().value([432.0, 436.0, + 433.0, 437.0]), + }) + # float4 test; - var_check.check('test').rows(1).cols(4).value([324.0, 325.0, 326.0, 327.0]) + var_check.check('test').rows(1).cols(4).value([440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("CBuffer variables are as expected") + + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + out.SetTextureDisplay(tex) + + texdetails = self.get_texture(tex.resourceId) + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("Picked value is as expected") + + out.Shutdown() diff --git a/util/test/tests/GL/GL_CBuffer_Zoo.py b/util/test/tests/GL/GL_CBuffer_Zoo.py index 3752af448..73b605fe7 100644 --- a/util/test/tests/GL/GL_CBuffer_Zoo.py +++ b/util/test/tests/GL/GL_CBuffer_Zoo.py @@ -13,6 +13,13 @@ class GL_CBuffer_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) + # Make an output so we can pick pixels + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) + + self.check(out is not None) + + out.SetDimensions(100, 100) + pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel @@ -225,65 +232,130 @@ class GL_CBuffer_Zoo(rdtest.TestCase): }), }) + # column_major mat2x3 ac; + var_check.check('ac').cols(2).rows(3).column_major().value([324.0, 328.0, + 325.0, 329.0, + 326.0, 330.0]) + + # row_major mat2x3 ad; + var_check.check('ad').cols(2).rows(3).row_major().value([332.0, 333.0, + 336.0, 337.0, + 340.0, 341.0]) + + # column_major mat2x3 ae[2]; + var_check.check('ae').cols(0).rows(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(3).column_major().value([344.0, 348.0, + 345.0, 349.0, + 346.0, 350.0]), + 1: lambda x: x.cols(2).rows(3).column_major().value([352.0, 356.0, + 353.0, 357.0, + 354.0, 358.0]), + }) + + # row_major mat2x3 af[2]; + var_check.check('af').cols(0).rows(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(3).row_major().value([360.0, 361.0, + 364.0, 365.0, + 368.0, 369.0]), + 1: lambda x: x.cols(2).rows(3).row_major().value([372.0, 373.0, + 376.0, 377.0, + 380.0, 381.0]), + }) + + # vec2 dummy10; + var_check.check('dummy10') + + # row_major mat2x2 ag; + var_check.check('ag').cols(2).rows(2).row_major().value([388.0, 389.0, + 392.0, 393.0]) + + # vec2 dummy12; + var_check.check('dummy11') + + # column_major float2x2 ah; + var_check.check('ah').cols(2).rows(2).column_major().value([400.0, 404.0, + 401.0, 405.0]) + + # row_major mat2x2 ai[2]; + var_check.check('ai').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(2).row_major().value([408.0, 409.0, + 412.0, 413.0]), + 1: lambda x: x.cols(2).rows(2).row_major().value([416.0, 417.0, + 420.0, 421.0]), + }) + + # column_major mat2x2 aj[2]; + var_check.check('aj').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(2).column_major().value([424.0, 428.0, + 425.0, 429.0]), + 1: lambda x: x.cols(2).rows(2).column_major().value([432.0, 436.0, + 433.0, 437.0]), + }) + # vec4 test; - var_check.check('test').cols(4).rows(1).value([324.0, 325.0, 326.0, 327.0]) + var_check.check('test').rows(1).cols(4).value([440.0, 441.0, 442.0, 443.0]) + + # to save duplicating if this array changes, we calculate out from the start, as the array is tightly packed + base = 444.0 + + exp_vals = lambda wi,yi,xi: [base + wi * 24.0 + yi * 8.0 + xi * 4.0 + c * 1.0 for c in range(0,4)] # vec4 multiarray2[4][3][2]; var_check.check('multiarray2').cols(0).rows(0).arraySize(4).members({ 0: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([328.0, 329.0, 330.0, 331.0]), - 1: lambda y: y.cols(4).rows(1).value([332.0, 333.0, 334.0, 335.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 0, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([336.0, 337.0, 338.0, 339.0]), - 1: lambda y: y.cols(4).rows(1).value([340.0, 341.0, 342.0, 343.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 1, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([344.0, 345.0, 346.0, 347.0]), - 1: lambda y: y.cols(4).rows(1).value([348.0, 349.0, 350.0, 351.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(0, 2, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(0, 2, 1)), }), }), 1: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([352.0, 353.0, 354.0, 355.0]), - 1: lambda y: y.cols(4).rows(1).value([356.0, 357.0, 358.0, 359.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 0, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([360.0, 361.0, 362.0, 363.0]), - 1: lambda y: y.cols(4).rows(1).value([364.0, 365.0, 366.0, 367.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 1, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([368.0, 369.0, 370.0, 371.0]), - 1: lambda y: y.cols(4).rows(1).value([372.0, 373.0, 374.0, 375.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(1, 2, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(1, 2, 1)), }), }), 2: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([376.0, 377.0, 378.0, 379.0]), - 1: lambda y: y.cols(4).rows(1).value([380.0, 381.0, 382.0, 383.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 0, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([384.0, 385.0, 386.0, 387.0]), - 1: lambda y: y.cols(4).rows(1).value([388.0, 389.0, 390.0, 391.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 1, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([392.0, 393.0, 394.0, 395.0]), - 1: lambda y: y.cols(4).rows(1).value([396.0, 397.0, 398.0, 399.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(2, 2, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(2, 2, 1)), }), }), 3: lambda w: w.cols(0).rows(0).arraySize(3).members({ 0: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([400.0, 401.0, 402.0, 403.0]), - 1: lambda y: y.cols(4).rows(1).value([404.0, 405.0, 406.0, 407.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 0, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 0, 1)), }), 1: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([408.0, 409.0, 410.0, 411.0]), - 1: lambda y: y.cols(4).rows(1).value([412.0, 413.0, 414.0, 415.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 1, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 1, 1)), }), 2: lambda x: x.cols(0).rows(0).arraySize(2).members({ - 0: lambda y: y.cols(4).rows(1).value([416.0, 417.0, 418.0, 419.0]), - 1: lambda y: y.cols(4).rows(1).value([420.0, 421.0, 422.0, 423.0]), + 0: lambda y: y.cols(4).rows(1).value(exp_vals(3, 2, 0)), + 1: lambda y: y.cols(4).rows(1).value(exp_vals(3, 2, 1)), }), }), }) @@ -291,3 +363,19 @@ class GL_CBuffer_Zoo(rdtest.TestCase): var_check.done() rdtest.log.success("CBuffer variables are as expected") + + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + out.SetTextureDisplay(tex) + + texdetails = self.get_texture(tex.resourceId) + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("Picked value is as expected") + + out.Shutdown() diff --git a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py index 5ef22a5ad..190840cc7 100644 --- a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py +++ b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py @@ -13,6 +13,13 @@ class VK_CBuffer_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) + # Make an output so we can pick pixels + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(), rd.ReplayOutputType.Texture) + + self.check(out is not None) + + out.SetDimensions(100, 100) + pipe: rd.PipeState = self.controller.GetPipelineState() stage = rd.ShaderStage.Pixel @@ -232,13 +239,87 @@ class VK_CBuffer_Zoo(rdtest.TestCase): }), }) + # column_major mat2x3 ac; + var_check.check('ac').cols(2).rows(3).column_major().value([324.0, 328.0, + 325.0, 329.0, + 326.0, 330.0]) + + # row_major mat2x3 ad; + var_check.check('ad').cols(2).rows(3).row_major().value([332.0, 333.0, + 336.0, 337.0, + 340.0, 341.0]) + + # column_major mat2x3 ae[2]; + var_check.check('ae').cols(0).rows(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(3).column_major().value([344.0, 348.0, + 345.0, 349.0, + 346.0, 350.0]), + 1: lambda x: x.cols(2).rows(3).column_major().value([352.0, 356.0, + 353.0, 357.0, + 354.0, 358.0]), + }) + + # row_major mat2x3 af[2]; + var_check.check('af').cols(0).rows(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(3).row_major().value([360.0, 361.0, + 364.0, 365.0, + 368.0, 369.0]), + 1: lambda x: x.cols(2).rows(3).row_major().value([372.0, 373.0, + 376.0, 377.0, + 380.0, 381.0]), + }) + + # vec2 dummy10; + var_check.check('dummy10') + + # row_major mat2x2 ag; + var_check.check('ag').cols(2).rows(2).row_major().value([388.0, 389.0, + 392.0, 393.0]) + + # vec2 dummy11; + var_check.check('dummy11') + + # column_major mat2x2 ah; + var_check.check('ah').cols(2).rows(2).column_major().value([400.0, 404.0, + 401.0, 405.0]) + + # row_major mat2x2 ai[2]; + var_check.check('ai').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(2).row_major().value([408.0, 409.0, + 412.0, 413.0]), + 1: lambda x: x.cols(2).rows(2).row_major().value([416.0, 417.0, + 420.0, 421.0]), + }) + + # column_major mat2x2 aj[2]; + var_check.check('aj').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.cols(2).rows(2).column_major().value([424.0, 428.0, + 425.0, 429.0]), + 1: lambda x: x.cols(2).rows(2).column_major().value([432.0, 436.0, + 433.0, 437.0]), + }) + # vec4 test; - var_check.check('test').cols(4).rows(1).value([324.0, 325.0, 326.0, 327.0]) + var_check.check('test').rows(1).cols(4).value([440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("GLSL CBuffer variables are as expected") + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + out.SetTextureDisplay(tex) + + texdetails = self.get_texture(tex.resourceId) + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("GLSL picked value is as expected") + # Move to the HLSL draw draw = draw.next @@ -484,9 +565,79 @@ class VK_CBuffer_Zoo(rdtest.TestCase): }), }) + # column_major float3x2 ac; + var_check.check('ac').rows(2).cols(3).row_major().value([324.0, 325.0, 326.0, + 328.0, 329.0, 330.0]) + + # row_major float3x2 ad; + var_check.check('ad').rows(2).cols(3).column_major().value([332.0, 336.0, 340.0, + 333.0, 337.0, 341.0]) + + # column_major float3x2 ae[2]; + var_check.check('ae').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(3).row_major().value([344.0, 345.0, 346.0, + 348.0, 349.0, 350.0]), + 1: lambda x: x.rows(2).cols(3).row_major().value([352.0, 353.0, 354.0, + 356.0, 357.0, 358.0]), + }) + + # row_major float3x2 af[2]; + var_check.check('af').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(3).column_major().value([360.0, 364.0, 368.0, + 361.0, 365.0, 369.0]), + 1: lambda x: x.rows(2).cols(3).column_major().value([372.0, 376.0, 380.0, + 373.0, 377.0, 381.0]), + }) + + # float2 dummy10; + var_check.check('dummy10') + + # float2 dummy11; + var_check.check('dummy11') + + # row_major float2x2 ag; + var_check.check('ag').rows(2).cols(2).column_major().value([388.0, 392.0, + 389.0, 393.0]) + + # float2 dummy12; + var_check.check('dummy12') + + # float2 dummy13; + var_check.check('dummy13') + + # column_major float2x2 ah; + var_check.check('ah').rows(2).cols(2).row_major().value([400.0, 401.0, + 404.0, 405.0]) + + # row_major float2x2 ai[2]; + var_check.check('ai').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).column_major().value([408.0, 412.0, + 409.0, 413.0]), + 1: lambda x: x.rows(2).cols(2).column_major().value([416.0, 420.0, + 417.0, 421.0]), + }) + + # column_major float2x2 aj[2]; + var_check.check('aj').rows(0).cols(0).arraySize(2).members({ + 0: lambda x: x.rows(2).cols(2).row_major().value([424.0, 425.0, + 428.0, 429.0]), + 1: lambda x: x.rows(2).cols(2).row_major().value([432.0, 433.0, + 436.0, 437.0]), + }) + # float4 test; - var_check.check('test').rows(1).cols(4).value([324.0, 325.0, 326.0, 327.0]) + var_check.check('test').rows(1).cols(4).value([440.0, 441.0, 442.0, 443.0]) var_check.done() rdtest.log.success("HLSL CBuffer variables are as expected") + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [440.1, 441.0, 442.0, 443.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("HLSL picked value is as expected") + + out.Shutdown()