diff --git a/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp b/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp index a48b36a9c..e93115b91 100644 --- a/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp +++ b/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp @@ -9,45 +9,100 @@ #include "compiler/translator/ShaderStorageBlockFunctionHLSL.h" #include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" namespace sh { +namespace +{ + +unsigned int GetMatrixStride(const TType &type) +{ + sh::Std140BlockEncoder std140Encoder; + sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false); + sh::BlockLayoutEncoder *encoder = nullptr; + + if (type.getLayoutQualifier().blockStorage == EbsStd140) + { + encoder = &std140Encoder; + } + else + { + // TODO(jiajia.qin@intel.com): add std430 support. http://anglebug.com/1951 + encoder = &hlslEncoder; + } + const bool isRowMajorLayout = (type.getLayoutQualifier().matrixPacking == EmpRowMajor); + std::vector arraySizes; + auto *typeArraySizes = type.getArraySizes(); + if (typeArraySizes != nullptr) + { + arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end()); + } + const BlockMemberInfo &memberInfo = + encoder->encodeType(GLVariableType(type), arraySizes, isRowMajorLayout); + return memberInfo.matrixStride; +} + +} // anonymous namespace + // static void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody( TInfoSinkBase &out, const ShaderStorageBlockFunction &ssboFunction) { - if (ssboFunction.type.isScalar()) + const char *convertString; + switch (ssboFunction.type.getBasicType()) { - TString convertString; - switch (ssboFunction.type.getBasicType()) - { - case EbtFloat: - convertString = "asfloat("; - break; - case EbtInt: - convertString = "asint("; - break; - case EbtUInt: - convertString = "asuint("; - break; - case EbtBool: - convertString = "asint("; - break; - default: - UNREACHABLE(); - break; - } - - out << " " << ssboFunction.typeString << " result = " << convertString - << "buffer.Load(loc));\n"; - out << " return result;\n"; - return; + case EbtFloat: + convertString = "asfloat("; + break; + case EbtInt: + convertString = "asint("; + break; + case EbtUInt: + convertString = "asuint("; + break; + case EbtBool: + convertString = "asint("; + break; + default: + UNREACHABLE(); + return; } - // TODO(jiajia.qin@intel.com): Process all possible return types. - out << " return 1.0;\n"; + out << " " << ssboFunction.typeString << " result"; + if (ssboFunction.type.isScalar()) + { + out << " = " << convertString << "buffer.Load(loc));\n"; + } + else if (ssboFunction.type.isVector()) + { + out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize() + << "(loc));\n"; + } + else if (ssboFunction.type.isMatrix()) + { + unsigned int matrixStride = GetMatrixStride(ssboFunction.type); + out << " = {"; + for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) + { + out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc +" + << rowIndex * matrixStride << ")), "; + } + + out << "};\n"; + } + else + { + // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 + out << ";\n"; + } + + out << " return result;\n"; + return; } // static @@ -59,8 +114,24 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody( { out << " buffer.Store(loc, asuint(value));\n"; } - - // TODO(jiajia.qin@intel.com): Process all possible return types. + else if (ssboFunction.type.isVector()) + { + out << " buffer.Store" << ssboFunction.type.getNominalSize() + << "(loc, asuint(value));\n"; + } + else if (ssboFunction.type.isMatrix()) + { + unsigned int matrixStride = GetMatrixStride(ssboFunction.type); + for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) + { + out << " buffer.Store" << ssboFunction.type.getCols() << "(loc +" + << rowIndex * matrixStride << ", asuint(value[" << rowIndex << "]));\n"; + } + } + else + { + // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 + } } bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<( diff --git a/src/tests/gl_tests/ProgramInterfaceTest.cpp b/src/tests/gl_tests/ProgramInterfaceTest.cpp index a836edae8..1ac8807c8 100644 --- a/src/tests/gl_tests/ProgramInterfaceTest.cpp +++ b/src/tests/gl_tests/ProgramInterfaceTest.cpp @@ -253,6 +253,10 @@ TEST_P(ProgramInterfaceTestES31, GetResource) // Tests glGetProgramInterfaceiv. TEST_P(ProgramInterfaceTestES31, GetProgramInterface) { + // TODO(jiajia.qin@intel.com): Don't skip this test once SSBO are supported on render pipeline. + // http://anglebug.com/1951 + ANGLE_SKIP_TEST_IF(IsD3D11()); + const std::string &fragmentShaderSource = "#version 310 es\n" "precision highp float;\n" diff --git a/src/tests/gl_tests/ShaderStorageBufferTest.cpp b/src/tests/gl_tests/ShaderStorageBufferTest.cpp index 7ce4408d0..a546ac858 100644 --- a/src/tests/gl_tests/ShaderStorageBufferTest.cpp +++ b/src/tests/gl_tests/ShaderStorageBufferTest.cpp @@ -190,6 +190,129 @@ TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite) EXPECT_GL_NO_ERROR(); } +// Test that access/write to vector data in shader storage buffer. +TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferVector) +{ + constexpr char kComputeShaderSource[] = + R"(#version 310 es + layout(local_size_x=1, local_size_y=1, local_size_z=1) in; + layout(std140, binding = 0) buffer blockIn { + uvec2 data; + } instanceIn; + layout(std140, binding = 1) buffer blockOut { + uvec2 data; + } instanceOut; + void main() + { + instanceOut.data[0] = instanceIn.data[0]; + instanceOut.data[1] = instanceIn.data[1]; + } + )"; + + ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource); + + glUseProgram(program.get()); + + constexpr unsigned int kComponentCount = 2; + constexpr unsigned int kBytesPerComponent = sizeof(unsigned int); + constexpr unsigned int kExpectedValues[kComponentCount] = {3u, 4u}; + // Create shader storage buffer + GLBuffer shaderStorageBuffer[2]; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]); + glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kExpectedValues, + GL_STATIC_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]); + glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, nullptr, + GL_STATIC_DRAW); + + // Bind shader storage buffer + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]); + + glDispatchCompute(1, 1, 1); + + glFinish(); + + // Read back shader storage buffer + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]); + const GLuint *ptr = reinterpret_cast(glMapBufferRange( + GL_SHADER_STORAGE_BUFFER, 0, kComponentCount * kBytesPerComponent, GL_MAP_READ_BIT)); + for (unsigned int idx = 0; idx < kComponentCount; idx++) + { + EXPECT_EQ(kExpectedValues[idx], *(ptr + idx)); + } + + EXPECT_GL_NO_ERROR(); +} + +// Test that access/write to matrix data in shader storage buffer. +TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferMatrix) +{ + constexpr char kComputeShaderSource[] = + R"(#version 310 es +layout(local_size_x=1, local_size_y=1, local_size_z=1) in; +layout(std140, binding = 0) buffer blockIn { + mat2x3 data; +} instanceIn; +layout(std140, binding = 1) buffer blockOut { + mat2x3 data; +} instanceOut; +void main() +{ + instanceOut.data[0][0] = instanceIn.data[0][0]; + instanceOut.data[0][1] = instanceIn.data[0][1]; + instanceOut.data[0][2] = instanceIn.data[0][2]; + instanceOut.data[1][0] = instanceIn.data[1][0]; + instanceOut.data[1][1] = instanceIn.data[1][1]; + instanceOut.data[1][2] = instanceIn.data[1][2]; +} +)"; + + ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource); + + glUseProgram(program.get()); + + constexpr unsigned int kColumns = 2; + constexpr unsigned int kRows = 3; + constexpr unsigned int kBytesPerComponent = sizeof(float); + constexpr unsigned int kVectorStride = 16; + // kVectorStride / kBytesPerComponent is used instead of kRows is because std140 layout requires + // that base alignment and stride of arrays of scalars and vectors are rounded up a multiple of + // the base alignment of a vec4. + constexpr float kInputDada[kColumns][kVectorStride / kBytesPerComponent] = { + {0.1, 0.2, 0.3, 0.0}, {0.4, 0.5, 0.6, 0.0}}; + // Create shader storage buffer + GLBuffer shaderStorageBuffer[2]; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]); + glBufferData(GL_SHADER_STORAGE_BUFFER, kColumns * kVectorStride, kInputDada, GL_STATIC_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]); + glBufferData(GL_SHADER_STORAGE_BUFFER, kColumns * kVectorStride, nullptr, GL_STATIC_DRAW); + + // Bind shader storage buffer + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]); + + glDispatchCompute(1, 1, 1); + + glFinish(); + + // Read back shader storage buffer + constexpr float kExpectedValues[kColumns][kRows] = {{0.1, 0.2, 0.3}, {0.4, 0.5, 0.6}}; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]); + const GLfloat *ptr = reinterpret_cast( + glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kColumns * kVectorStride, GL_MAP_READ_BIT)); + for (unsigned int idx = 0; idx < kColumns; idx++) + { + for (unsigned int idy = 0; idy < kRows; idy++) + { + EXPECT_EQ(kExpectedValues[idx][idy], + *(ptr + idx * (kVectorStride / kBytesPerComponent) + idy)); + } + } + + EXPECT_GL_NO_ERROR(); +} + // Test atomic memory functions. TEST_P(ShaderStorageBufferTest31, AtomicMemoryFunctions) {