Commit dfebe9b2 by Jamie Madill Committed by Commit Bot

D3D11: Add dirty bits for Transform Feedback.

After testing, it seems practially impossible to trigger a dependent state change in a Buffer that would affect XFB. Any buffer change would have to happen between a pause or begin/end of XFB, which would trigger a state update. Bug: angleproject:1155 Bug: angleproject:2389 Change-Id: Ic3c1dc7cec661a826909bb5647ddabda1d6fb7fc Reviewed-on: https://chromium-review.googlesource.com/948795Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 2fe36e45
...@@ -587,8 +587,7 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -587,8 +587,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mVertexDataManager(renderer), mVertexDataManager(renderer),
mIndexDataManager(renderer), mIndexDataManager(renderer),
mIsMultiviewEnabled(false), mIsMultiviewEnabled(false),
mEmptySerial(mRenderer->generateSerial()), mEmptySerial(mRenderer->generateSerial())
mIsTransformFeedbackCurrentlyActiveUnpaused(false)
{ {
mCurBlendState.blend = false; mCurBlendState.blend = false;
mCurBlendState.sourceBlendRGB = GL_ONE; mCurBlendState.sourceBlendRGB = GL_ONE;
...@@ -764,9 +763,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -764,9 +763,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
return; return;
} }
const auto &state = context->getGLState(); const gl::State &state = context->getGLState();
for (auto dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyBits)
{ {
switch (dirtyBit) switch (dirtyBit)
{ {
...@@ -1010,6 +1009,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -1010,6 +1009,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_SAMPLER_BINDINGS: case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
invalidateTexturesAndSamplers(); invalidateTexturesAndSamplers();
break; break;
case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
invalidateTransformFeedback();
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE: case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{ {
mInternalDirtyBits.set(DIRTY_BIT_SHADERS); mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
...@@ -1497,6 +1499,13 @@ void StateManager11::invalidateShaders() ...@@ -1497,6 +1499,13 @@ void StateManager11::invalidateShaders()
mInternalDirtyBits.set(DIRTY_BIT_SHADERS); mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
} }
void StateManager11::invalidateTransformFeedback()
{
// Transform feedback affects the stream-out geometry shader.
invalidateShaders();
mInternalDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK);
}
void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv) void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv)
{ {
if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv))) if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv)))
...@@ -1971,14 +1980,6 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod ...@@ -1971,14 +1980,6 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS); mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS);
} }
// Transform feedback affects the stream-out geometry shader.
// TODO(jmadill): Use dirty bits.
if (glState.isTransformFeedbackActiveUnpaused() != mIsTransformFeedbackCurrentlyActiveUnpaused)
{
mIsTransformFeedbackCurrentlyActiveUnpaused = glState.isTransformFeedbackActiveUnpaused();
invalidateShaders();
}
// Swizzling can cause internal state changes with blit shaders. // Swizzling can cause internal state changes with blit shaders.
if (mDirtySwizzles) if (mDirtySwizzles)
{ {
...@@ -2063,14 +2064,15 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod ...@@ -2063,14 +2064,15 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
case DIRTY_BIT_CURRENT_VALUE_ATTRIBS: case DIRTY_BIT_CURRENT_VALUE_ATTRIBS:
ANGLE_TRY(syncCurrentValueAttribs(glState)); ANGLE_TRY(syncCurrentValueAttribs(glState));
break; break;
case DIRTY_BIT_TRANSFORM_FEEDBACK:
ANGLE_TRY(syncTransformFeedbackBuffers(context));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
} }
} }
ANGLE_TRY(syncTransformFeedbackBuffers(context));
// Check that we haven't set any dirty bits in the flushing of the dirty bits loop. // Check that we haven't set any dirty bits in the flushing of the dirty bits loop.
ASSERT(mInternalDirtyBits.none()); ASSERT(mInternalDirtyBits.none());
......
...@@ -189,6 +189,9 @@ class StateManager11 final : angle::NonCopyable ...@@ -189,6 +189,9 @@ class StateManager11 final : angle::NonCopyable
// Called by the Program on Uniform Buffer change. Also called internally. // Called by the Program on Uniform Buffer change. Also called internally.
void invalidateProgramUniformBuffers(); void invalidateProgramUniformBuffers();
// Called by TransformFeedback11.
void invalidateTransformFeedback();
void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv); void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv);
void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv); void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv);
...@@ -353,6 +356,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -353,6 +356,7 @@ class StateManager11 final : angle::NonCopyable
DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS, DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS,
DIRTY_BIT_SHADERS, DIRTY_BIT_SHADERS,
DIRTY_BIT_CURRENT_VALUE_ATTRIBS, DIRTY_BIT_CURRENT_VALUE_ATTRIBS,
DIRTY_BIT_TRANSFORM_FEEDBACK,
DIRTY_BIT_INVALID, DIRTY_BIT_INVALID,
DIRTY_BIT_MAX = DIRTY_BIT_INVALID, DIRTY_BIT_MAX = DIRTY_BIT_INVALID,
}; };
...@@ -556,8 +560,6 @@ class StateManager11 final : angle::NonCopyable ...@@ -556,8 +560,6 @@ class StateManager11 final : angle::NonCopyable
Serial mAppliedTFSerial; Serial mAppliedTFSerial;
Serial mEmptySerial; Serial mEmptySerial;
bool mIsTransformFeedbackCurrentlyActiveUnpaused;
}; };
} // namespace rx } // namespace rx
......
...@@ -46,10 +46,12 @@ void TransformFeedback11::begin(GLenum primitiveMode) ...@@ -46,10 +46,12 @@ void TransformFeedback11::begin(GLenum primitiveMode)
mBufferOffsets[bindingIdx] = 0; mBufferOffsets[bindingIdx] = 0;
} }
} }
mRenderer->getStateManager()->invalidateTransformFeedback();
} }
void TransformFeedback11::end() void TransformFeedback11::end()
{ {
mRenderer->getStateManager()->invalidateTransformFeedback();
if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback) if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback)
{ {
mRenderer->getDeviceContext()->Flush(); mRenderer->getDeviceContext()->Flush();
...@@ -58,14 +60,17 @@ void TransformFeedback11::end() ...@@ -58,14 +60,17 @@ void TransformFeedback11::end()
void TransformFeedback11::pause() void TransformFeedback11::pause()
{ {
mRenderer->getStateManager()->invalidateTransformFeedback();
} }
void TransformFeedback11::resume() void TransformFeedback11::resume()
{ {
mRenderer->getStateManager()->invalidateTransformFeedback();
} }
void TransformFeedback11::bindGenericBuffer(const gl::BindingPointer<gl::Buffer> &binding) void TransformFeedback11::bindGenericBuffer(const gl::BindingPointer<gl::Buffer> &binding)
{ {
mRenderer->getStateManager()->invalidateTransformFeedback();
} }
void TransformFeedback11::bindIndexedBuffer(size_t index, void TransformFeedback11::bindIndexedBuffer(size_t index,
...@@ -73,6 +78,7 @@ void TransformFeedback11::bindIndexedBuffer(size_t index, ...@@ -73,6 +78,7 @@ void TransformFeedback11::bindIndexedBuffer(size_t index,
{ {
mIsDirty = true; mIsDirty = true;
mBufferOffsets[index] = static_cast<UINT>(binding.getOffset()); mBufferOffsets[index] = static_cast<UINT>(binding.getOffset());
mRenderer->getStateManager()->invalidateTransformFeedback();
} }
void TransformFeedback11::onApply() void TransformFeedback11::onApply()
......
...@@ -801,6 +801,92 @@ TEST_P(StateChangeTestES3, SamplerMetadataUpdateOnSetProgram) ...@@ -801,6 +801,92 @@ TEST_P(StateChangeTestES3, SamplerMetadataUpdateOnSetProgram)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests that redefining Buffer storage syncs with the Transform Feedback object.
TEST_P(StateChangeTestES3, RedefineTransformFeedbackBuffer)
{
// Create the most simple program possible - simple a passthrough for a float attribute.
constexpr char kVertexShader[] = R"(#version 300 es
in float valueIn;
out float valueOut;
void main()
{
gl_Position = vec4(0, 0, 0, 0);
valueOut = valueIn;
})";
constexpr char kFragmentShader[] = R"(#version 300 es
out mediump float dummy;
void main()
{
dummy = 1.0;
})";
std::vector<std::string> tfVaryings = {"valueOut"};
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVertexShader, kFragmentShader, tfVaryings,
GL_SEPARATE_ATTRIBS);
glUseProgram(program);
GLint attribLoc = glGetAttribLocation(program, "valueIn");
ASSERT_NE(-1, attribLoc);
// Disable rasterization - we're not interested in the framebuffer.
glEnable(GL_RASTERIZER_DISCARD);
// Initialize a float vertex buffer with 1.0.
std::vector<GLfloat> data1(16, 1.0);
GLsizei size1 = static_cast<GLsizei>(sizeof(GLfloat) * data1.size());
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, size1, data1.data(), GL_STATIC_DRAW);
glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(attribLoc);
ASSERT_GL_NO_ERROR();
// Initialize a same-sized XFB buffer.
GLBuffer xfbBuffer;
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size1, nullptr, GL_STATIC_DRAW);
// Draw with XFB enabled.
GLTransformFeedback xfb;
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 16);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Verify the XFB stage caught the 1.0 attribute values.
void *mapped1 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, size1, GL_MAP_READ_BIT);
GLfloat *asFloat1 = reinterpret_cast<GLfloat *>(mapped1);
std::vector<GLfloat> actualData1(asFloat1, asFloat1 + data1.size());
EXPECT_EQ(data1, actualData1);
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
// Now, reinitialize the XFB buffer to a larger size, and draw with 2.0.
std::vector<GLfloat> data2(128, 2.0);
const GLsizei size2 = static_cast<GLsizei>(sizeof(GLfloat) * data2.size());
glBufferData(GL_ARRAY_BUFFER, size2, data2.data(), GL_STATIC_DRAW);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size2, nullptr, GL_STATIC_DRAW);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 128);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Verify the XFB stage caught the 2.0 attribute values.
void *mapped2 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, size2, GL_MAP_READ_BIT);
GLfloat *asFloat2 = reinterpret_cast<GLfloat *>(mapped2);
std::vector<GLfloat> actualData2(asFloat2, asFloat2 + data2.size());
EXPECT_EQ(data2, actualData2);
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
}
// Simple state change tests, primarily focused on basic object lifetime and dependency management // Simple state change tests, primarily focused on basic object lifetime and dependency management
// with back-ends that don't support that automatically (i.e. Vulkan). // with back-ends that don't support that automatically (i.e. Vulkan).
class SimpleStateChangeTest : public ANGLETest class SimpleStateChangeTest : public ANGLETest
......
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