Commit c73475fb by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix UtilsVk dirtying driver uniforms descriptor set binding

Most UtilsVk functions bind a descriptor set to index 0 (same as driver uniforms). If that happens to close a render pass, all is well as starting a new render pass ensures all descriptor sets are rebound. However, if the render pass is not closed, or if a dispatch call is issued (which never rebinds descriptor sets if not explicitly necessary), then the driver uniforms descriptor set may end up never rebound, causing a validation error (and possible crash or corruption). This change makes sure that UtilsVk notifies the context when it binds a descriptor set. The context then dirties the driver uniforms binding as appropriate. Bug: angleproject:4272 Change-Id: Ief20c7884fbe39712f844247489812afc70b30a9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2027938 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 5de415c5
......@@ -2899,6 +2899,26 @@ void ContextVk::onTransformFeedbackStateChanged()
}
}
void ContextVk::invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet)
{
// UtilsVk currently only uses set 0
ASSERT(usedDescriptorSet == kDriverUniformsDescriptorSetIndex);
if (mDriverUniforms[PipelineType::Graphics].descriptorSet != VK_NULL_HANDLE)
{
mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
}
}
void ContextVk::invalidateComputeDescriptorSet(uint32_t usedDescriptorSet)
{
// UtilsVk currently only uses set 0
ASSERT(usedDescriptorSet == kDriverUniformsDescriptorSetIndex);
if (mDriverUniforms[PipelineType::Compute].descriptorSet != VK_NULL_HANDLE)
{
mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
}
}
angle::Result ContextVk::dispatchCompute(const gl::Context *context,
GLuint numGroupsX,
GLuint numGroupsY,
......
......@@ -403,6 +403,12 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void invalidateCurrentTransformFeedbackState();
void onTransformFeedbackStateChanged();
// When UtilsVk issues draw or dispatch calls, it binds descriptor sets that the context is not
// aware of. This function is called to make sure affected descriptor set bindings are dirtied
// for the next application draw/dispatch call.
void invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet);
void invalidateComputeDescriptorSet(uint32_t usedDescriptorSet);
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
const VkClearValue &getClearColorValue() const;
......
......@@ -751,6 +751,14 @@ angle::Result UtilsVk::setupProgram(ContextVk *contextVk,
{
commandBuffer->bindDescriptorSets(pipelineLayout.get(), pipelineBindPoint, 0, 1,
&descriptorSet, 0, nullptr);
if (isCompute)
{
contextVk->invalidateComputeDescriptorSet(0);
}
else
{
contextVk->invalidateGraphicsDescriptorSet(0);
}
}
if (pushConstants)
......
......@@ -3667,6 +3667,130 @@ void main()
EXPECT_GL_NO_ERROR();
}
// Validate that on Vulkan, compute pipeline driver uniforms descriptor set is updated after an
// internal compute-based UtilsVk function is used. The latter is achieved through a draw with a
// vertex buffer whose format is not natively supported. Atomic counters are used to make sure the
// compute pipeline uses the driver uniforms descriptor set.
TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr uint32_t kVertexCount = 6;
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
layout(binding = 0) uniform atomic_uint ac;
layout(binding=0, std140) buffer VertexData
{
uint data[];
};
void main()
{
atomicCounterIncrement(ac);
data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;
})";
constexpr char kVS[] = R"(#version 310 es
precision mediump float;
layout(location = 0) in vec4 position;
layout(location = 1) in uvec4 data;
out vec4 color;
void main() {
color = data.x < 6u && data.y == 0u && data.z == 0u && data.w == 0u
? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
precision mediump float;
in vec4 color;
out vec4 colorOut;
void main() {
colorOut = color;
})";
ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
ANGLE_GL_PROGRAM(programVSFS, kVS, kFS);
EXPECT_GL_NO_ERROR();
// Create atomic counter buffer
GLBuffer atomicCounterBuffer;
constexpr GLuint kInitialAcbData = 0;
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(kInitialAcbData), &kInitialAcbData,
GL_STATIC_DRAW);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
EXPECT_GL_NO_ERROR();
// Create vertex buffer
constexpr unsigned kVertexBufferInitData[kVertexCount] = {};
GLBuffer vertexBuffer;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vertexBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kVertexBufferInitData), kVertexBufferInitData,
GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vertexBuffer);
EXPECT_GL_NO_ERROR();
// Create position buffer
constexpr GLfloat positions[kVertexCount * 2] = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
GLBuffer positionBuffer;
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
EXPECT_GL_NO_ERROR();
// Create vertex array
GLVertexArray vao;
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_UNSIGNED_INT_10_10_10_2_OES, false, 0, 0);
EXPECT_GL_NO_ERROR();
// Fill the vertex buffer with a dispatch call
glUseProgram(programCS);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
// Draw using the vertex buffer, causing vertex format conversion in compute (in the Vulkan
// backend)
glUseProgram(programVSFS);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, kVertexCount);
EXPECT_GL_NO_ERROR();
// Issue another dispatch call. The driver uniforms descriptor set must be rebound.
glUseProgram(programCS);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
// Verify that the atomic counter has the expected value.
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
GLuint *mappedBuffer = static_cast<GLuint *>(
glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
EXPECT_EQ(kVertexCount * 2, mappedBuffer[0]);
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
}
ANGLE_INSTANTIATE_TEST_ES31(ComputeShaderTest);
ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3);
ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment