Commit 5d3a4ca4 by Jamie Madill Committed by Commit Bot

Vulkan: Fix dirty state in XFB emulation on EndXFB.

This regressed in "Vulkan: Preserve RPs on XFB changes when possible." The bug manifested as incorrect fire rendering in Manhattan. The fix is to ensure we dirty the correct buffer state when we call endXFB. Also adds a regression test. Bug: b/161744596 Bug: angleproject:4622 Change-Id: If16cc22b149526950f300e74c0cc82c0fefae5bc Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2368016Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarTobin Ehlis <tobine@google.com> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 18cd3cea
...@@ -1535,16 +1535,20 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation( ...@@ -1535,16 +1535,20 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback()); TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
size_t bufferCount = executable->getTransformFeedbackBufferCount(); size_t bufferCount = executable->getTransformFeedbackBufferCount();
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
transformFeedbackVk->getBufferHelpers();
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex) if (mState.isTransformFeedbackActiveUnpaused())
{ {
vk::BufferHelper *bufferHelper = bufferHelpers[bufferIndex]; const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
ASSERT(bufferHelper); transformFeedbackVk->getBufferHelpers();
mRenderPassCommands->bufferWrite(&mResourceUseList, VK_ACCESS_SHADER_WRITE_BIT,
vk::PipelineStage::VertexShader, for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
vk::AliasingMode::Disallowed, bufferHelper); {
vk::BufferHelper *bufferHelper = bufferHelpers[bufferIndex];
ASSERT(bufferHelper);
mRenderPassCommands->bufferWrite(&mResourceUseList, VK_ACCESS_SHADER_WRITE_BIT,
vk::PipelineStage::VertexShader,
vk::AliasingMode::Disallowed, bufferHelper);
}
} }
// TODO(http://anglebug.com/3570): Need to update to handle Program Pipelines // TODO(http://anglebug.com/3570): Need to update to handle Program Pipelines
...@@ -3408,6 +3412,7 @@ void ContextVk::invalidateCurrentTransformFeedbackBuffers() ...@@ -3408,6 +3412,7 @@ void ContextVk::invalidateCurrentTransformFeedbackBuffers()
} }
else if (getFeatures().emulateTransformFeedback.enabled) else if (getFeatures().emulateTransformFeedback.enabled)
{ {
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
} }
} }
...@@ -3422,6 +3427,7 @@ void ContextVk::onTransformFeedbackStateChanged() ...@@ -3422,6 +3427,7 @@ void ContextVk::onTransformFeedbackStateChanged()
else if (getFeatures().emulateTransformFeedback.enabled) else if (getFeatures().emulateTransformFeedback.enabled)
{ {
invalidateGraphicsDriverUniforms(); invalidateGraphicsDriverUniforms();
invalidateCurrentTransformFeedbackBuffers();
} }
} }
...@@ -3482,7 +3488,7 @@ angle::Result ContextVk::onPauseTransformFeedback() ...@@ -3482,7 +3488,7 @@ angle::Result ContextVk::onPauseTransformFeedback()
} }
else if (getFeatures().emulateTransformFeedback.enabled) else if (getFeatures().emulateTransformFeedback.enabled)
{ {
onTransformFeedbackStateChanged(); return flushCommandsAndEndRenderPass();
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -1242,7 +1242,7 @@ void ProgramExecutableVk::updateTransformFeedbackDescriptorSetImpl( ...@@ -1242,7 +1242,7 @@ void ProgramExecutableVk::updateTransformFeedbackDescriptorSetImpl(
// If xfb has no output there is no need to update descriptor set. // If xfb has no output there is no need to update descriptor set.
return; return;
} }
if (!glState.isTransformFeedbackActive()) if (!glState.isTransformFeedbackActiveUnpaused())
{ {
// We set empty Buffer to xfb descriptor set because xfb descriptor set // We set empty Buffer to xfb descriptor set because xfb descriptor set
// requires valid buffer bindings, even if they are empty buffer, // requires valid buffer bindings, even if they are empty buffer,
......
...@@ -46,15 +46,8 @@ void TransformFeedbackVk::onDestroy(const gl::Context *context) ...@@ -46,15 +46,8 @@ void TransformFeedbackVk::onDestroy(const gl::Context *context)
} }
} }
angle::Result TransformFeedbackVk::begin(const gl::Context *context, void TransformFeedbackVk::initializeXFBBuffersDesc(ContextVk *contextVk, size_t xfbBufferCount)
gl::PrimitiveMode primitiveMode)
{ {
ContextVk *contextVk = vk::GetImpl(context);
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
mXFBBuffersDesc.reset(); mXFBBuffersDesc.reset();
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{ {
...@@ -78,10 +71,26 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context, ...@@ -78,10 +71,26 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context,
mBufferSizes[bufferIndex] = nullBuffer.getSize(); mBufferSizes[bufferIndex] = nullBuffer.getSize();
} }
mBufferHandles[bufferIndex] = mBufferHelpers[bufferIndex]->getBuffer().getHandle();
mXFBBuffersDesc.updateTransformFeedbackBuffer( mXFBBuffersDesc.updateTransformFeedbackBuffer(
bufferIndex, mBufferHelpers[bufferIndex]->getBufferSerial()); bufferIndex, mBufferHelpers[bufferIndex]->getBufferSerial());
}
}
angle::Result TransformFeedbackVk::begin(const gl::Context *context,
gl::PrimitiveMode primitiveMode)
{
ContextVk *contextVk = vk::GetImpl(context);
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
initializeXFBBuffersDesc(contextVk, xfbBufferCount);
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(bufferIndex);
mBufferHandles[bufferIndex] = mBufferHelpers[bufferIndex]->getBuffer().getHandle();
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled) if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{ {
if (mCounterBufferHandles[bufferIndex] == VK_NULL_HANDLE) if (mCounterBufferHandles[bufferIndex] == VK_NULL_HANDLE)
...@@ -144,6 +153,22 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context) ...@@ -144,6 +153,22 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context)
angle::Result TransformFeedbackVk::pause(const gl::Context *context) angle::Result TransformFeedbackVk::pause(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
// Bind the empty buffer until we resume.
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
const vk::BufferHelper &emptyBuffer = contextVk->getEmptyBuffer();
for (size_t xfbIndex = 0; xfbIndex < xfbBufferCount; ++xfbIndex)
{
mXFBBuffersDesc.updateTransformFeedbackBuffer(xfbIndex, emptyBuffer.getBufferSerial());
}
}
return contextVk->onPauseTransformFeedback(); return contextVk->onPauseTransformFeedback();
} }
...@@ -153,6 +178,12 @@ angle::Result TransformFeedbackVk::resume(const gl::Context *context) ...@@ -153,6 +178,12 @@ angle::Result TransformFeedbackVk::resume(const gl::Context *context)
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable(); const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable); ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount(); size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
initializeXFBBuffersDesc(contextVk, xfbBufferCount);
}
return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers); return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers);
} }
......
...@@ -98,6 +98,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -98,6 +98,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl
VkDescriptorBufferInfo *pBufferInfo, VkDescriptorBufferInfo *pBufferInfo,
VkDescriptorSet descSet) const; VkDescriptorSet descSet) const;
void initializeXFBBuffersDesc(ContextVk *contextVk, size_t xfbBufferCount);
// This member variable is set when glBindTransformFeedbackBuffers/glBeginTransformFeedback // This member variable is set when glBindTransformFeedbackBuffers/glBeginTransformFeedback
// is called and unset in dirty bit handler for transform feedback state change. If this // is called and unset in dirty bit handler for transform feedback state change. If this
// value is true, vertex shader will record transform feedback varyings from the beginning // value is true, vertex shader will record transform feedback varyings from the beginning
......
...@@ -1987,6 +1987,82 @@ TEST_P(TransformFeedbackTest, OverrunWithMultiplePauseAndResume) ...@@ -1987,6 +1987,82 @@ TEST_P(TransformFeedbackTest, OverrunWithMultiplePauseAndResume)
VerifyVertexFloats(mapPtrFloat, vertices, 3, numFloats); VerifyVertexFloats(mapPtrFloat, vertices, 3, numFloats);
} }
// Tests begin/draw/end/*bindBuffer*/begin/draw/end.
TEST_P(TransformFeedbackTest, EndThenBindNewBufferAndRestart)
{
// TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
// Set the program's transform feedback varyings (just gl_Position)
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
ASSERT_NE(-1, positionLocation);
glEnableVertexAttribArray(positionLocation);
GLBuffer secondBuffer;
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, secondBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, nullptr,
GL_STATIC_DRAW);
std::vector<GLfloat> posData1 = {0.1f, 0.0f, 0.0f, 1.0f, 0.2f, 0.0f, 0.0f, 1.0f, 0.3f, 0.0f,
0.0f, 1.0f, 0.4f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f};
std::vector<GLfloat> posData2 = {0.6f, 0.0f, 0.0f, 1.0f, 0.7f, 0.0f, 0.0f, 1.0f, 0.8f, 0.0f,
0.0f, 1.0f, 0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
size_t posBytes = posData1.size() * sizeof(posData1[0]);
ASSERT_EQ(posBytes, posData2.size() * sizeof(posData2[0]));
GLBuffer posBuffer1;
glBindBuffer(GL_ARRAY_BUFFER, posBuffer1);
glBufferData(GL_ARRAY_BUFFER, posBytes, posData1.data(), GL_STATIC_DRAW);
GLBuffer posBuffer2;
glBindBuffer(GL_ARRAY_BUFFER, posBuffer2);
glBufferData(GL_ARRAY_BUFFER, posBytes, posData2.data(), GL_STATIC_DRAW);
// Draw a first time with first buffer.
glBindBuffer(GL_ARRAY_BUFFER, posBuffer1);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 5);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Bind second buffer and draw with new data.
glBindBuffer(GL_ARRAY_BUFFER, posBuffer2);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 5);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Read back buffer datas.
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
void *posMap1 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, posBytes, GL_MAP_READ_BIT);
ASSERT_NE(posMap1, nullptr);
std::vector<GLfloat> actualData1(posData1.size());
memcpy(actualData1.data(), posMap1, posBytes);
EXPECT_EQ(posData1, actualData1);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, secondBuffer);
void *posMap2 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, posBytes, GL_MAP_READ_BIT);
ASSERT_NE(posMap2, nullptr);
std::vector<GLfloat> actualData2(posData2.size());
memcpy(actualData2.data(), posMap2, posBytes);
EXPECT_EQ(posData2, actualData2);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest); ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest);
......
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