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
// We can work around this by expanding the pow into a series of multiplies if we're running
// under the affected compiler.
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
......
......@@ -123,7 +123,7 @@ FenceSyncImpl *Context11::createFenceSync()
TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedback11(state);
return new TransformFeedback11(state, mRenderer);
}
SamplerImpl *Context11::createSampler()
......
......@@ -10,12 +10,15 @@
#include "libANGLE/Buffer.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
namespace rx
{
TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state)
TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state,
Renderer11 *renderer)
: TransformFeedbackImpl(state),
mRenderer(renderer),
mIsDirty(true),
mBuffers(state.getIndexedBuffers().size(), nullptr),
mBufferOffsets(state.getIndexedBuffers().size(), 0)
......@@ -32,6 +35,10 @@ void TransformFeedback11::begin(GLenum primitiveMode)
void TransformFeedback11::end()
{
if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback)
{
mRenderer->getDeviceContext()->Flush();
}
}
void TransformFeedback11::pause()
......
......@@ -18,10 +18,12 @@
namespace rx
{
class Renderer11;
class TransformFeedback11 : public TransformFeedbackImpl
{
public:
TransformFeedback11(const gl::TransformFeedbackState &state);
TransformFeedback11(const gl::TransformFeedbackState &state, Renderer11 *renderer);
~TransformFeedback11() override;
void begin(GLenum primitiveMode) override;
......@@ -41,6 +43,8 @@ class TransformFeedback11 : public TransformFeedbackImpl
const std::vector<UINT> &getSOBufferOffsets() const;
private:
Renderer11 *mRenderer;
bool mIsDirty;
std::vector<ID3D11Buffer *> mBuffers;
std::vector<UINT> mBufferOffsets;
......
......@@ -1537,6 +1537,8 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
// TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
workarounds.expandIntegerPowExpressions = true;
workarounds.flushAfterEndingTransformFeedback = (adapterDesc.VendorId == VENDOR_ID_NVIDIA);
return workarounds;
}
......
......@@ -5,6 +5,7 @@
//
#include "test_utils/ANGLETest.h"
#include "random_utils.h"
#include "Vector.h"
using namespace angle;
......@@ -145,13 +146,6 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
// old position)
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);
// Set the program's transform feedback varyings (just gl_Position)
......@@ -167,29 +161,31 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
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
GLuint primitivesWrittenQuery = 0;
glGenQueries(1, &primitivesWrittenQuery);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
float originalZ = 0.5f;
drawQuad(mProgram, "position", originalZ);
const float finalZ = 0.95f;
// stop, reset the buffer and resume
glEndTransformFeedback();
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_TRIANGLES);
RNG rng;
const size_t loopCount = 64;
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;
drawQuad(mProgram, "position", updatedZ);
float z = (loopIdx + 1 == loopCount) ? finalZ : rng.randomFloatBetween(0.1f, 0.5f);
drawQuad(mProgram, "position", z);
glEndTransformFeedback();
}
// End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
glUseProgram(0);
......@@ -199,7 +195,7 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(4u, primitivesWritten);
EXPECT_EQ(loopCount * 2, primitivesWritten);
// Check the buffer data
const float *bufferData = static_cast<float *>(glMapBufferRange(
......@@ -207,9 +203,9 @@ TEST_P(TransformFeedbackTest, BufferRebinding)
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
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++)
......
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