Commit 5274202f by Gregoire Payen de La Garanderie Committed by Geoff Lang

Unbind unused stream out from the D3D11 pipeline to avoid conflicts.

Also allow points drawing without gl_PointSize if transform feedback is active. Change-Id: I172d423e847b35b94ebaea102dd97b695575c828 Reviewed-on: https://chromium-review.googlesource.com/246100Tested-by: 's avatarGregoire Payen de La Garanderie <Gregory.Payen@imgtec.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent f4780c1c
......@@ -900,6 +900,12 @@ TransformFeedback *State::getCurrentTransformFeedback() const
return mTransformFeedback.get();
}
bool State::isTransformFeedbackActiveUnpaused() const
{
gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
return curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused();
}
void State::detachTransformFeedback(GLuint transformFeedback)
{
if (mTransformFeedback.id() == transformFeedback)
......
......@@ -177,6 +177,7 @@ class State
// Transform feedback object (not buffer) binding manipulation
void setTransformFeedbackBinding(TransformFeedback *transformFeedback);
TransformFeedback *getCurrentTransformFeedback() const;
bool isTransformFeedbackActiveUnpaused() const;
void detachTransformFeedback(GLuint transformFeedback);
// Query binding manipulation
......
......@@ -108,6 +108,11 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return error;
}
applyTransformFeedbackBuffers(*data.state);
// Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
// layer.
ASSERT(!data.state->isTransformFeedbackActiveUnpaused());
GLsizei vertexCount = indexInfo.indexRange.length() + 1;
error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances);
if (error.isError())
......@@ -115,12 +120,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return error;
}
bool transformFeedbackActive = applyTransformFeedbackBuffers(data);
// Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
// layer.
ASSERT(!transformFeedbackActive);
error = applyShaders(data, transformFeedbackActive);
error = applyShaders(data);
if (error.isError())
{
return error;
......@@ -182,15 +182,15 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
return error;
}
applyTransformFeedbackBuffers(*data.state);
error = applyVertexBuffer(*data.state, mode, first, count, instances);
if (error.isError())
{
return error;
}
bool transformFeedbackActive = applyTransformFeedbackBuffers(data);
error = applyShaders(data, transformFeedbackActive);
error = applyShaders(data);
if (error.isError())
{
return error;
......@@ -210,13 +210,13 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
if (!skipDraw(data, mode))
{
error = drawArrays(data, mode, count, instances, transformFeedbackActive, program->usesPointSize());
error = drawArrays(data, mode, count, instances, program->usesPointSize());
if (error.isError())
{
return error;
}
if (transformFeedbackActive)
if (data.state->isTransformFeedbackActiveUnpaused())
{
markTransformFeedbackUsage(data);
}
......@@ -356,22 +356,8 @@ gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode)
return gl::Error(GL_NO_ERROR);
}
bool RendererD3D::applyTransformFeedbackBuffers(const gl::Data &data)
{
gl::TransformFeedback *curTransformFeedback = data.state->getCurrentTransformFeedback();
if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
{
applyTransformFeedbackBuffers(*data.state);
return true;
}
else
{
return false;
}
}
// Applies the shaders and shader constants to the Direct3D device
gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedbackActive)
gl::Error RendererD3D::applyShaders(const gl::Data &data)
{
gl::Program *program = data.state->getProgram();
......@@ -380,7 +366,7 @@ gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedback
const gl::Framebuffer *fbo = data.state->getDrawFramebuffer();
gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive);
gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, data.state->isTransformFeedbackActiveUnpaused());
if (error.isError())
{
return error;
......@@ -520,7 +506,7 @@ bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
// ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
// which affects varying interpolation. Since the value of gl_PointSize is
// undefined when not written, just skip drawing to avoid unexpected results.
if (!data.state->getProgram()->usesPointSize())
if (!data.state->getProgram()->usesPointSize() && !data.state->isTransformFeedbackActiveUnpaused())
{
// This is stictly speaking not an error, but developers should be
// notified of risking undefined behavior.
......
......@@ -166,7 +166,7 @@ class RendererD3D : public Renderer
gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut);
protected:
virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize) = 0;
virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) = 0;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
......@@ -188,8 +188,7 @@ class RendererD3D : public Renderer
gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport);
gl::Error applyState(const gl::Data &data, GLenum drawMode);
bool applyTransformFeedbackBuffers(const gl::Data &data);
gl::Error applyShaders(const gl::Data &data, bool transformFeedbackActive);
gl::Error applyShaders(const gl::Data &data);
gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType,
const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount);
gl::Error applyTextures(const gl::Data &data);
......
......@@ -180,6 +180,8 @@ Renderer11::Renderer11(egl::Display *display)
mAppliedGeometryShader = NULL;
mAppliedPixelShader = NULL;
mAppliedNumXFBBindings = -1;
const auto &attributes = mDisplay->getAttributeMap();
EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
......@@ -1238,31 +1240,36 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen
return gl::Error(GL_NO_ERROR);
}
void Renderer11::applyTransformFeedbackBuffers(const gl::State& state)
void Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
{
size_t numXFBBindings = state.getTransformFeedbackBufferIndexRange();
ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
size_t numXFBBindings = 0;
bool requiresUpdate = false;
for (size_t i = 0; i < numXFBBindings; i++)
if (state.isTransformFeedbackActiveUnpaused())
{
gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
ID3D11Buffer *d3dBuffer = NULL;
if (curXFBBuffer)
{
Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
}
numXFBBindings = state.getTransformFeedbackBufferIndexRange();
ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
// TODO: mAppliedTFBuffers and friends should also be kept in a vector.
if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i])
for (size_t i = 0; i < numXFBBindings; i++)
{
requiresUpdate = true;
gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
ID3D11Buffer *d3dBuffer = NULL;
if (curXFBBuffer)
{
Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
}
// TODO: mAppliedTFBuffers and friends should also be kept in a vector.
if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i])
{
requiresUpdate = true;
}
}
}
if (requiresUpdate)
if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings)
{
for (size_t i = 0; i < numXFBBindings; ++i)
{
......@@ -1286,14 +1293,16 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State& state)
mAppliedTFOffsets[i] = curXFBOffset;
}
mAppliedNumXFBBindings = numXFBBindings;
mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets);
}
}
gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize)
gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize)
{
bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation;
if (mode == GL_POINTS && transformFeedbackActive)
if (mode == GL_POINTS && data.state->isTransformFeedbackActiveUnpaused())
{
// Since point sprites are generated with a geometry shader, too many vertices will
// be written if transform feedback is active. To work around this, draw only the points
......@@ -1321,7 +1330,7 @@ gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei coun
}
// Skip this step if we're doing rasterizer discard.
if (pixelExe && !data.state->getRasterizerState().rasterizerDiscard)
if (pixelExe && !data.state->getRasterizerState().rasterizerDiscard && usesPointSize)
{
ID3D11PixelShader *pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader();
ASSERT(reinterpret_cast<uintptr_t>(pixelShader) == mAppliedPixelShader);
......@@ -1910,6 +1919,8 @@ void Renderer11::markAllStateDirty()
mAppliedGeometryShader = DirtyPointer;
mAppliedPixelShader = DirtyPointer;
mAppliedNumXFBBindings = -1;
for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
{
mAppliedTFBuffers[i] = NULL;
......
......@@ -88,9 +88,9 @@ class Renderer11 : public RendererD3D
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual void applyTransformFeedbackBuffers(const gl::State &state);
void applyTransformFeedbackBuffers(const gl::State &state) override;
virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize);
gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
......@@ -304,6 +304,7 @@ class Renderer11 : public RendererD3D
unsigned int mAppliedIBOffset;
// Currently applied transform feedback buffers
size_t mAppliedNumXFBBindings;
ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers
// in use for streamout
GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified
......
......@@ -1425,9 +1425,9 @@ void Renderer9::applyTransformFeedbackBuffers(const gl::State& state)
UNREACHABLE();
}
gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize)
gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize)
{
ASSERT(!transformFeedbackActive);
ASSERT(!data.state->isTransformFeedbackActiveUnpaused());
startScene();
......
......@@ -90,9 +90,9 @@ class Renderer9 : public RendererD3D
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual void applyTransformFeedbackBuffers(const gl::State& state);
void applyTransformFeedbackBuffers(const gl::State &state) override;
virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize);
gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
......
......@@ -113,3 +113,84 @@ TYPED_TEST(TransformFeedbackTest, ZeroSizedViewport)
EXPECT_EQ(primitivesWritten, 2);
}
// Test that XFB can write back vertices to a buffer and that we can draw from this buffer afterward.
TYPED_TEST(TransformFeedbackTest, RecordAndDraw)
{
// Set the program's transform feedback varyings (just gl_Position)
const GLchar* transformFeedbackVaryings[] =
{
"gl_Position"
};
glTransformFeedbackVaryings(mProgram, ArraySize(transformFeedbackVaryings), transformFeedbackVaryings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(mProgram);
// Re-link the program
GLint linkStatus;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
ASSERT_NE(linkStatus, 0);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, "position");
// First pass: draw 6 points to the XFB buffer
glEnable(GL_RASTERIZER_DISCARD);
const GLfloat vertices[] =
{
-1.0f, 1.0f, 0.5f,
-1.0f, -1.0f, 0.5f,
1.0f, -1.0f, 0.5f,
-1.0f, 1.0f, 0.5f,
1.0f, -1.0f, 0.5f,
1.0f, 1.0f, 0.5f,
};
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionLocation);
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_POINTS);
// Create a query to check how many primitives were written
GLuint primitivesWrittenQuery = 0;
glGenQueries(1, &primitivesWrittenQuery);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
glDrawArrays(GL_POINTS, 0, 6);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
// End the query and transform feedkback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
glDisable(GL_RASTERIZER_DISCARD);
// Check how many primitives were written and verify that some were written even if
// no pixels were rendered
GLuint primitivesWritten = 0;
glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(primitivesWritten, 6);
// Nothing should have been drawn to the framebuffer
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 0);
// Second pass: draw from the feedback buffer
glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
EXPECT_GL_NO_ERROR();
}
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