aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen White <senorblanco@chromium.org>2022-04-19 11:35:46 -0400
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-19 20:57:12 +0000
commit6e130d2b77b8572db98edd24f5f778e630985ac1 (patch)
tree158b6377857245f6fb1719497149f073a176692e
parent50d008a7efcab80f34eb742148d05389b2ed247e (diff)
downloadangle-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.cpp7
-rw-r--r--src/libANGLE/renderer/d3d/DynamicHLSL.h3
-rw-r--r--src/libANGLE/renderer/d3d/ProgramD3D.cpp5
-rw-r--r--src/libANGLE/renderer/d3d/ProgramD3D.h1
-rw-r--r--src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp2
-rw-r--r--src/tests/gl_tests/StateChangeTest.cpp108
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)