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(
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
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];
ASSERT(bufferHelper);
mRenderPassCommands->bufferWrite(&mResourceUseList, VK_ACCESS_SHADER_WRITE_BIT,
vk::PipelineStage::VertexShader,
vk::AliasingMode::Disallowed, bufferHelper);
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
transformFeedbackVk->getBufferHelpers();
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
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
......@@ -3408,6 +3412,7 @@ void ContextVk::invalidateCurrentTransformFeedbackBuffers()
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
}
......@@ -3422,6 +3427,7 @@ void ContextVk::onTransformFeedbackStateChanged()
else if (getFeatures().emulateTransformFeedback.enabled)
{
invalidateGraphicsDriverUniforms();
invalidateCurrentTransformFeedbackBuffers();
}
}
......@@ -3482,7 +3488,7 @@ angle::Result ContextVk::onPauseTransformFeedback()
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
onTransformFeedbackStateChanged();
return flushCommandsAndEndRenderPass();
}
return angle::Result::Continue;
}
......
......@@ -1242,7 +1242,7 @@ void ProgramExecutableVk::updateTransformFeedbackDescriptorSetImpl(
// If xfb has no output there is no need to update descriptor set.
return;
}
if (!glState.isTransformFeedbackActive())
if (!glState.isTransformFeedbackActiveUnpaused())
{
// We set empty Buffer to xfb descriptor set because xfb descriptor set
// requires valid buffer bindings, even if they are empty buffer,
......
......@@ -46,15 +46,8 @@ void TransformFeedbackVk::onDestroy(const gl::Context *context)
}
}
angle::Result TransformFeedbackVk::begin(const gl::Context *context,
gl::PrimitiveMode primitiveMode)
void TransformFeedbackVk::initializeXFBBuffersDesc(ContextVk *contextVk, size_t xfbBufferCount)
{
ContextVk *contextVk = vk::GetImpl(context);
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
mXFBBuffersDesc.reset();
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
......@@ -78,10 +71,26 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context,
mBufferSizes[bufferIndex] = nullBuffer.getSize();
}
mBufferHandles[bufferIndex] = mBufferHelpers[bufferIndex]->getBuffer().getHandle();
mXFBBuffersDesc.updateTransformFeedbackBuffer(
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 (mCounterBufferHandles[bufferIndex] == VK_NULL_HANDLE)
......@@ -144,6 +153,22 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context)
angle::Result TransformFeedbackVk::pause(const gl::Context *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();
}
......@@ -153,6 +178,12 @@ angle::Result TransformFeedbackVk::resume(const gl::Context *context)
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
initializeXFBBuffersDesc(contextVk, xfbBufferCount);
}
return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers);
}
......
......@@ -98,6 +98,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl
VkDescriptorBufferInfo *pBufferInfo,
VkDescriptorSet descSet) const;
void initializeXFBBuffersDesc(ContextVk *contextVk, size_t xfbBufferCount);
// This member variable is set when glBindTransformFeedbackBuffers/glBeginTransformFeedback
// 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
......
......@@ -1987,6 +1987,82 @@ TEST_P(TransformFeedbackTest, OverrunWithMultiplePauseAndResume)
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
// tests should be run against.
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