Commit 1e0ea4f5 by Geoff Lang Committed by Commit Bot

Add a workaround for NVIDIA drivers with repeated transform feedback.

BUG=angleproject:1298 Change-Id: Ibfbad8eb8ec824e377d8c1746a6691d6b689f498 Reviewed-on: https://chromium-review.googlesource.com/362601Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent ee7e1e21
...@@ -59,6 +59,10 @@ struct WorkaroundsD3D ...@@ -59,6 +59,10 @@ struct WorkaroundsD3D
// We can work around this by expanding the pow into a series of multiplies if we're running // We can work around this by expanding the pow into a series of multiplies if we're running
// under the affected compiler. // under the affected compiler.
bool expandIntegerPowExpressions = false; bool expandIntegerPowExpressions = false;
// NVIDIA drivers sometimes write out-of-order results to StreamOut buffers when transform
// feedback is used to repeatedly write to the same buffer positions.
bool flushAfterEndingTransformFeedback = false;
}; };
} // namespace rx } // namespace rx
......
...@@ -123,7 +123,7 @@ FenceSyncImpl *Context11::createFenceSync() ...@@ -123,7 +123,7 @@ FenceSyncImpl *Context11::createFenceSync()
TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state) TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state)
{ {
return new TransformFeedback11(state); return new TransformFeedback11(state, mRenderer);
} }
SamplerImpl *Context11::createSampler() SamplerImpl *Context11::createSampler()
......
...@@ -10,12 +10,15 @@ ...@@ -10,12 +10,15 @@
#include "libANGLE/Buffer.h" #include "libANGLE/Buffer.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
namespace rx namespace rx
{ {
TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state) TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state,
Renderer11 *renderer)
: TransformFeedbackImpl(state), : TransformFeedbackImpl(state),
mRenderer(renderer),
mIsDirty(true), mIsDirty(true),
mBuffers(state.getIndexedBuffers().size(), nullptr), mBuffers(state.getIndexedBuffers().size(), nullptr),
mBufferOffsets(state.getIndexedBuffers().size(), 0) mBufferOffsets(state.getIndexedBuffers().size(), 0)
...@@ -32,6 +35,10 @@ void TransformFeedback11::begin(GLenum primitiveMode) ...@@ -32,6 +35,10 @@ void TransformFeedback11::begin(GLenum primitiveMode)
void TransformFeedback11::end() void TransformFeedback11::end()
{ {
if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback)
{
mRenderer->getDeviceContext()->Flush();
}
} }
void TransformFeedback11::pause() void TransformFeedback11::pause()
......
...@@ -18,10 +18,12 @@ ...@@ -18,10 +18,12 @@
namespace rx namespace rx
{ {
class Renderer11;
class TransformFeedback11 : public TransformFeedbackImpl class TransformFeedback11 : public TransformFeedbackImpl
{ {
public: public:
TransformFeedback11(const gl::TransformFeedbackState &state); TransformFeedback11(const gl::TransformFeedbackState &state, Renderer11 *renderer);
~TransformFeedback11() override; ~TransformFeedback11() override;
void begin(GLenum primitiveMode) override; void begin(GLenum primitiveMode) override;
...@@ -41,6 +43,8 @@ class TransformFeedback11 : public TransformFeedbackImpl ...@@ -41,6 +43,8 @@ class TransformFeedback11 : public TransformFeedbackImpl
const std::vector<UINT> &getSOBufferOffsets() const; const std::vector<UINT> &getSOBufferOffsets() const;
private: private:
Renderer11 *mRenderer;
bool mIsDirty; bool mIsDirty;
std::vector<ID3D11Buffer *> mBuffers; std::vector<ID3D11Buffer *> mBuffers;
std::vector<UINT> mBufferOffsets; std::vector<UINT> mBufferOffsets;
......
...@@ -1537,6 +1537,8 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, ...@@ -1537,6 +1537,8 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
// TODO(jmadill): Disable workaround when we have a fixed compiler DLL. // TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
workarounds.expandIntegerPowExpressions = true; workarounds.expandIntegerPowExpressions = true;
workarounds.flushAfterEndingTransformFeedback = (adapterDesc.VendorId == VENDOR_ID_NVIDIA);
return workarounds; return workarounds;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// //
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "random_utils.h"
#include "Vector.h" #include "Vector.h"
using namespace angle; using namespace angle;
...@@ -145,13 +146,6 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport) ...@@ -145,13 +146,6 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
// old position) // old position)
TEST_P(TransformFeedbackTest, BufferRebinding) TEST_P(TransformFeedbackTest, BufferRebinding)
{ {
if (IsWindows() && IsD3D11() && IsNVIDIA())
{
// TODO(geofflang): Diagnose driver bug in latest nvidia driver
std::cout << "Test skipped on NVIDIA due to driver bug.";
return;
}
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Set the program's transform feedback varyings (just gl_Position) // Set the program's transform feedback varyings (just gl_Position)
...@@ -167,29 +161,31 @@ TEST_P(TransformFeedbackTest, BufferRebinding) ...@@ -167,29 +161,31 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(), glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
GL_STATIC_DRAW); GL_STATIC_DRAW);
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_TRIANGLES);
// Create a query to check how many primitives were written // Create a query to check how many primitives were written
GLuint primitivesWrittenQuery = 0; GLuint primitivesWrittenQuery = 0;
glGenQueries(1, &primitivesWrittenQuery); glGenQueries(1, &primitivesWrittenQuery);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery); glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
float originalZ = 0.5f; const float finalZ = 0.95f;
drawQuad(mProgram, "position", originalZ);
// stop, reset the buffer and resume RNG rng;
glEndTransformFeedback();
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer); const size_t loopCount = 64;
glBeginTransformFeedback(GL_TRIANGLES); for (size_t loopIdx = 0; loopIdx < loopCount; loopIdx++)
{
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_TRIANGLES);
float updatedZ = 0.75f; float z = (loopIdx + 1 == loopCount) ? finalZ : rng.randomFloatBetween(0.1f, 0.5f);
drawQuad(mProgram, "position", updatedZ); drawQuad(mProgram, "position", z);
glEndTransformFeedback();
}
// End the query and transform feedback // End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
glUseProgram(0); glUseProgram(0);
...@@ -199,7 +195,7 @@ TEST_P(TransformFeedbackTest, BufferRebinding) ...@@ -199,7 +195,7 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten); glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_EQ(4u, primitivesWritten); EXPECT_EQ(loopCount * 2, primitivesWritten);
// Check the buffer data // Check the buffer data
const float *bufferData = static_cast<float *>(glMapBufferRange( const float *bufferData = static_cast<float *>(glMapBufferRange(
...@@ -207,9 +203,9 @@ TEST_P(TransformFeedbackTest, BufferRebinding) ...@@ -207,9 +203,9 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
for (size_t vertexIdx = 0; vertexIdx < 6; vertexIdx++) for (size_t vertexIdx = 0; vertexIdx < 6; vertexIdx++)
{ {
// Check the third (Z) component of each vertex written and make sure it has the updated // Check the third (Z) component of each vertex written and make sure it has the final
// value // value
EXPECT_NEAR(updatedZ, bufferData[vertexIdx * 4 + 2], 0.0001); EXPECT_NEAR(finalZ, bufferData[vertexIdx * 4 + 2], 0.0001);
} }
for (size_t dataIdx = 24; dataIdx < mTransformFeedbackBufferSize / sizeof(float); dataIdx++) for (size_t dataIdx = 24; dataIdx < mTransformFeedbackBufferSize / sizeof(float); dataIdx++)
......
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