diff options
author | Stephen White <senorblanco@chromium.org> | 2022-04-19 11:35:46 -0400 |
---|---|---|
committer | Angle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-04-19 20:57:12 +0000 |
commit | 6e130d2b77b8572db98edd24f5f778e630985ac1 (patch) | |
tree | 158b6377857245f6fb1719497149f073a176692e | |
parent | 50d008a7efcab80f34eb742148d05389b2ed247e (diff) | |
download | angle-6e130d2b77b8572db98edd24f5f778e630985ac1.tar.gz |
D3D: fix SSBOs used in vertex shaders.
Use the total number of pixel shader outputs as the base
UAV register for vertex and pixel shaders. This is less fragile than
making the vertex shader depend on the number of draw-time pixel shader
outputs.
Add a test that exercises SSBOs in vertex shaders, varying the number of
draw-time pixel shader outputs (which should have no effect on register
assignment).
Bug: angleproject:7156
Change-Id: I5801d59299275ea6d2569456d53c230e7e8ee5a9
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3579501
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
-rw-r--r-- | src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 7 | ||||
-rw-r--r-- | src/libANGLE/renderer/d3d/DynamicHLSL.h | 3 | ||||
-rw-r--r-- | src/libANGLE/renderer/d3d/ProgramD3D.cpp | 5 | ||||
-rw-r--r-- | src/libANGLE/renderer/d3d/ProgramD3D.h | 1 | ||||
-rw-r--r-- | src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp | 2 | ||||
-rw-r--r-- | src/tests/gl_tests/StateChangeTest.cpp | 108 |
6 files changed, 118 insertions, 8 deletions
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp index 930e371aec..3257c00457 100644 --- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp +++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp @@ -308,7 +308,7 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( angle::ReplaceSubstring(&vertexHLSL, VERTEX_ATTRIBUTE_STUB_STRING, structStream.str()); ASSERT(success); - success = ReplaceShaderStorageDeclaration(shaderStorageBlocks, &vertexHLSL, inputLayout.size(), + success = ReplaceShaderStorageDeclaration(shaderStorageBlocks, &vertexHLSL, baseUAVRegister, gl::ShaderType::Vertex); ASSERT(success); @@ -320,7 +320,8 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( const std::vector<PixelShaderOutputVariable> &outputVariables, bool usesFragDepth, const std::vector<GLenum> &outputLayout, - const std::vector<ShaderStorageBlock> &shaderStorageBlocks) const + const std::vector<ShaderStorageBlock> &shaderStorageBlocks, + size_t baseUAVRegister) const { const int shaderModel = mRenderer->getMajorShaderModel(); std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; @@ -394,7 +395,7 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( angle::ReplaceSubstring(&pixelHLSL, PIXEL_OUTPUT_STUB_STRING, declarationStream.str()); ASSERT(success); - success = ReplaceShaderStorageDeclaration(shaderStorageBlocks, &pixelHLSL, numOutputs, + success = ReplaceShaderStorageDeclaration(shaderStorageBlocks, &pixelHLSL, baseUAVRegister, gl::ShaderType::Fragment); ASSERT(success); diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/libANGLE/renderer/d3d/DynamicHLSL.h index 4785b7b27a..63b572e27c 100644 --- a/src/libANGLE/renderer/d3d/DynamicHLSL.h +++ b/src/libANGLE/renderer/d3d/DynamicHLSL.h @@ -157,7 +157,8 @@ class DynamicHLSL : angle::NonCopyable const std::vector<PixelShaderOutputVariable> &outputVariables, bool usesFragDepth, const std::vector<GLenum> &outputLayout, - const std::vector<rx::ShaderStorageBlock> &shaderStorageBlocks) const; + const std::vector<rx::ShaderStorageBlock> &shaderStorageBlocks, + size_t baseUAVRegister) const; std::string generateShaderForImage2DBindSignature( const d3d::Context *context, ProgramD3D &programD3D, diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp index eb57441d9f..c25e355b21 100644 --- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp +++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -1544,7 +1544,8 @@ angle::Result ProgramD3D::getPixelExecutableForCachedOutputLayout( std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature( mShaderHLSL[gl::ShaderType::Fragment], mPixelShaderKey, mUsesFragDepth, - mPixelShaderOutputLayoutCache, mShaderStorageBlocks[gl::ShaderType::Fragment]); + mPixelShaderOutputLayoutCache, mShaderStorageBlocks[gl::ShaderType::Fragment], + mPixelShaderKey.size()); // Generate new pixel executable ShaderExecutableD3D *pixelExecutable = nullptr; @@ -1588,7 +1589,7 @@ angle::Result ProgramD3D::getVertexExecutableForCachedInputLayout( // Generate new dynamic layout with attribute conversions std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout( mShaderHLSL[gl::ShaderType::Vertex], mCachedInputLayout, mState.getProgramInputs(), - mShaderStorageBlocks[gl::ShaderType::Vertex], getNumPixelShaderOutputs()); + mShaderStorageBlocks[gl::ShaderType::Vertex], mPixelShaderKey.size()); // Generate new vertex executable ShaderExecutableD3D *vertexExecutable = nullptr; diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h index 113b25dd4b..29cb0b062a 100644 --- a/src/libANGLE/renderer/d3d/ProgramD3D.h +++ b/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -357,7 +357,6 @@ class ProgramD3D : public ProgramImpl bool hasNamedUniform(const std::string &name); bool usesVertexID() const { return mUsesVertexID; } - size_t getNumPixelShaderOutputs() const { return mPixelShaderOutputLayoutCache.size(); } private: // These forward-declared tasks are used for multi-thread shader compiles. diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp index 916de4c979..86068e565f 100644 --- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp +++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp @@ -841,7 +841,7 @@ void StateManager11::setUnorderedAccessViewInternal(gl::ShaderType shaderType, case gl::ShaderType::Vertex: case gl::ShaderType::Fragment: { - UINT baseUAVRegister = static_cast<UINT>(mProgramD3D->getNumPixelShaderOutputs()); + UINT baseUAVRegister = static_cast<UINT>(mProgramD3D->getPixelShaderKey().size()); deviceContext->OMSetRenderTargetsAndUnorderedAccessViews( D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, baseUAVRegister + resourceSlot, 1, &uavPtr, nullptr); diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp index 98856f7486..e31263dedf 100644 --- a/src/tests/gl_tests/StateChangeTest.cpp +++ b/src/tests/gl_tests/StateChangeTest.cpp @@ -4770,6 +4770,114 @@ void main() glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); } +// Tests that writing to an SSBO in the vertex shader before and after a change to the drawbuffers +// still works +TEST_P(SimpleStateChangeTestES31, VertWriteSSBOThenChangeDrawbuffersThenWriteSSBO) +{ + GLint maxVertexShaderStorageBlocks; + glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertexShaderStorageBlocks); + + ANGLE_SKIP_TEST_IF(maxVertexShaderStorageBlocks < 1); + + constexpr GLsizei kSize = 1; + + GLTexture color; + glBindTexture(GL_TEXTURE_2D, color); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize); + EXPECT_GL_NO_ERROR(); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); + EXPECT_GL_NO_ERROR(); + + constexpr std::array<float, 4> kBufferInitValue = {0.125f, 0.25f, 0.5f, 1.0f}; + GLBuffer buffer; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kBufferInitValue), kBufferInitValue.data(), + GL_STATIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer); + + // Create a program that writes to the SSBO in the vertex shader. + constexpr char kVS[] = R"(#version 310 es +in vec4 a_position; +uniform vec4 value; +layout(binding = 0, std430) buffer Output { + vec4 value; +} b; +void main() +{ + b.value = value; + gl_Position = a_position; +})"; + + GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS); + GLuint fs = CompileShader(GL_FRAGMENT_SHADER, essl31_shaders::fs::Green()); + + const GLuint program = glCreateProgram(); + glAttachShader(program, vs); + glAttachShader(program, fs); + glLinkProgram(program); + CheckLinkStatusAndReturnProgram(program, true); + + // Detach the shaders, so any draw-time shader rewriting won't be able to use them. + glDetachShader(program, vs); + glDetachShader(program, fs); + + glUseProgram(program); + GLint positionLoc = glGetAttribLocation(program, essl31_shaders::PositionAttrib()); + ASSERT_NE(-1, positionLoc); + GLint valueLoc = glGetUniformLocation(program, "value"); + ASSERT_NE(-1, valueLoc); + + const std::array<Vector3, 6> &quadVertices = GetQuadVertices(); + const size_t posBufferSize = quadVertices.size() * sizeof(Vector3); + + GLBuffer posBuffer; + glBindBuffer(GL_ARRAY_BUFFER, posBuffer); + glBufferData(GL_ARRAY_BUFFER, posBufferSize, quadVertices.data(), GL_STATIC_DRAW); + glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glEnableVertexAttribArray(positionLoc); + + glUseProgram(program); + constexpr float kValue1[4] = {0.1f, 0.2f, 0.3f, 0.4f}; + + glUniform4fv(valueLoc, 1, kValue1); + glDrawArrays(GL_TRIANGLES, 0, 6); + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + EXPECT_GL_NO_ERROR(); + + // Verify that the program wrote the SSBO correctly. + const float *ptr = reinterpret_cast<const float *>( + glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kBufferInitValue), GL_MAP_READ_BIT)); + + for (int i = 0; i < 4; ++i) + { + EXPECT_NEAR(ptr[i], kValue1[i], 0.001); + } + + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + + GLenum drawBuffers[] = {GL_NONE}; + glDrawBuffers(1, drawBuffers); + + constexpr float kValue2[4] = {0.5f, 0.6f, 0.7f, 0.9f}; + glUniform4fv(valueLoc, 1, kValue2); + glDrawArrays(GL_TRIANGLES, 0, 6); + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + EXPECT_GL_NO_ERROR(); + // Verify that the program wrote the SSBO correctly. + ptr = reinterpret_cast<const float *>( + glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kBufferInitValue), GL_MAP_READ_BIT)); + + for (int i = 0; i < 4; ++i) + { + EXPECT_NEAR(ptr[i], kValue2[i], 0.001); + } + + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); +} + // Tests that rendering to a texture in one draw call followed by sampling from it in a dispatch // call works correctly. This requires an implicit barrier in between the calls. TEST_P(SimpleStateChangeTestES31, DrawThenSampleWithCompute) |