Commit abf66fb3 by Jamie Madill Committed by Commit Bot

D3D11: Use dirty bits for applyVertexBuffers.

If the vertex array has any dirty or dynamic attribs, we must do an update. Similarly, if a prior state change has left the vertex state invalidated, we do an update. For instance, a program change means we need a new input layout. If there was no such invalidation or dirtyness we can skip the call to InputLayoutCache. This improves the performance of the draw call benchmark (with no state changes) by about 50% on the D3D11 null driver. Increases the frames per second count of the aquarium demo with the passthrough command buffer by about 25% on a test machine. BUG=angleproject:1156 Change-Id: I8381999029f5b1912030a3342e96285a58f95e82 Reviewed-on: https://chromium-review.googlesource.com/616784 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent e3d8628d
......@@ -1720,6 +1720,9 @@ gl::Error Renderer11::drawArraysImpl(const gl::Context *context,
ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
}
// This required by updateVertexOffsets... above but is outside of the loop for speed.
mStateManager.invalidateVertexBuffer();
return gl::NoError();
}
......@@ -1817,6 +1820,7 @@ gl::Error Renderer11::drawElementsImpl(const gl::Context *context,
ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0);
}
mStateManager.invalidateVertexBuffer();
return gl::NoError();
}
......
......@@ -678,6 +678,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
invalidateRenderTarget(context);
break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
invalidateVertexBuffer();
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
invalidateVertexBuffer();
invalidateRenderTarget(context);
......@@ -1056,6 +1059,8 @@ void StateManager11::invalidateEverything(const gl::Context *context)
mAppliedIB = nullptr;
mAppliedIBFormat = DXGI_FORMAT_UNKNOWN;
mAppliedIBOffset = 0;
mLastFirstVertex.reset();
}
void StateManager11::invalidateVertexBuffer()
......@@ -1383,12 +1388,14 @@ void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout)
{
deviceContext->IASetInputLayout(nullptr);
mCurrentInputLayout = 0;
mInputLayoutIsDirty = true;
}
}
else if (inputLayout->getSerial() != mCurrentInputLayout)
{
deviceContext->IASetInputLayout(inputLayout->get());
mCurrentInputLayout = inputLayout->getSerial();
mInputLayoutIsDirty = true;
}
}
......@@ -1401,6 +1408,7 @@ bool StateManager11::queueVertexBufferChange(size_t bufferIndex,
stride != mCurrentVertexStrides[bufferIndex] ||
offset != mCurrentVertexOffsets[bufferIndex])
{
mInputLayoutIsDirty = true;
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(bufferIndex));
mCurrentVertexBuffers[bufferIndex] = buffer;
......@@ -1416,6 +1424,7 @@ bool StateManager11::queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly
{
if (offsetOnly != mCurrentVertexOffsets[bufferIndex])
{
mInputLayoutIsDirty = true;
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(bufferIndex));
mCurrentVertexOffsets[bufferIndex] = offsetOnly;
return true;
......@@ -1869,8 +1878,12 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
const auto &vertexArray = state.getVertexArray();
auto *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager, first,
count, instances));
if (vertexArray11->hasDirtyOrDynamicAttrib(context))
{
ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager, first,
count, instances));
invalidateVertexBuffer();
}
ANGLE_TRY(syncCurrentValueAttribs(state));
......@@ -1880,11 +1893,23 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged;
}
if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != first)
{
mLastFirstVertex = first;
mInputLayoutIsDirty = true;
}
if (!mInputLayoutIsDirty)
{
return gl::NoError();
}
GLsizei numIndicesPerInstance = 0;
if (instances > 0)
{
numIndicesPerInstance = count;
}
const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
gl::Program *program = state.getProgram();
......@@ -1927,6 +1952,7 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// is clean. This is a bit of a hack.
vertexArray11->clearDirtyAndPromoteDynamicAttribs(state, count);
mInputLayoutIsDirty = false;
return gl::NoError();
}
......@@ -1983,6 +2009,7 @@ void StateManager11::setIndexBuffer(ID3D11Buffer *buffer,
}
}
// Vertex buffer is invalidated outside this function.
gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId)
{
......
......@@ -373,6 +373,7 @@ class StateManager11 final : angle::NonCopyable
IndexDataManager mIndexDataManager;
InputLayoutCache mInputLayoutCache;
std::vector<const TranslatedAttribute *> mCurrentAttributes;
Optional<GLint> mLastFirstVertex;
};
} // namespace rx
......
......@@ -161,6 +161,12 @@ bool VertexArray11::hasDynamicAttrib(const gl::Context *context)
return mDynamicAttribsMask.any();
}
bool VertexArray11::hasDirtyOrDynamicAttrib(const gl::Context *context)
{
flushAttribUpdates(context);
return mAttribsToTranslate.any() || mDynamicAttribsMask.any();
}
gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
GLint start,
......@@ -229,8 +235,8 @@ gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context
dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor();
}
return vertexDataManager->storeDynamicAttribs(&mTranslatedAttribs, activeDynamicAttribs,
start, count, instances);
ANGLE_TRY(vertexDataManager->storeDynamicAttribs(&mTranslatedAttribs, activeDynamicAttribs,
start, count, instances));
}
return gl::NoError();
......
......@@ -28,6 +28,7 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
const gl::VertexArray::DirtyBits &dirtyBits) override;
// This will flush any pending attrib updates and then check the dynamic attribs mask.
bool hasDynamicAttrib(const gl::Context *context);
bool hasDirtyOrDynamicAttrib(const gl::Context *context);
gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
GLint start,
......
......@@ -622,6 +622,80 @@ TEST_P(VertexAttributeTestES3, UnsignedIntNormalized)
runTest(data);
}
void SetupColorsForUnitQuad(GLint location, const GLColor32F &color, GLenum usage, GLBuffer *vbo)
{
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
std::vector<GLColor32F> vertices(6, color);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLColor32F), vertices.data(), usage);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
// Tests that rendering works as expected with VAOs.
TEST_P(VertexAttributeTestES3, VertexArrayObjectRendering)
{
const std::string kVertexShader =
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_Position = a_position;\n"
" v_color = a_color;\n"
"}";
const std::string kFragmentShader =
"precision mediump float;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}";
ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader);
GLint positionLoc = glGetAttribLocation(program, "a_position");
ASSERT_NE(-1, positionLoc);
GLint colorLoc = glGetAttribLocation(program, "a_color");
ASSERT_NE(-1, colorLoc);
GLVertexArray vaos[2];
GLBuffer positionBuffer;
GLBuffer colorBuffers[2];
const auto &quadVertices = GetQuadVertices();
glBindVertexArrayOES(vaos[0]);
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVertices.size() * sizeof(Vector3), quadVertices.data(),
GL_STATIC_DRAW);
glEnableVertexAttribArray(positionLoc);
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
SetupColorsForUnitQuad(colorLoc, kFloatRed, GL_STREAM_DRAW, &colorBuffers[0]);
glBindVertexArrayOES(vaos[1]);
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glEnableVertexAttribArray(positionLoc);
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
SetupColorsForUnitQuad(colorLoc, kFloatGreen, GL_STATIC_DRAW, &colorBuffers[1]);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
for (int ii = 0; ii < 2; ++ii)
{
glBindVertexArrayOES(vaos[0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glBindVertexArrayOES(vaos[1]);
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
ASSERT_GL_NO_ERROR();
}
// Validate that we can support GL_MAX_ATTRIBS attribs
TEST_P(VertexAttributeTest, MaxAttribs)
{
......
......@@ -132,14 +132,6 @@ angle::Vector4 GLColor::toNormalizedVector() const
return angle::Vector4(ColorNorm(R), ColorNorm(G), ColorNorm(B), ColorNorm(A));
}
GLColor32F::GLColor32F() : GLColor32F(0.0f, 0.0f, 0.0f, 0.0f)
{
}
GLColor32F::GLColor32F(GLfloat r, GLfloat g, GLfloat b, GLfloat a) : R(r), G(g), B(b), A(a)
{
}
GLColor ReadColor(GLint x, GLint y)
{
GLColor actual;
......
......@@ -93,12 +93,16 @@ struct GLColor
struct GLColor32F
{
GLColor32F();
GLColor32F(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
constexpr GLColor32F() : GLColor32F(0.0f, 0.0f, 0.0f, 0.0f) {}
constexpr GLColor32F(GLfloat r, GLfloat g, GLfloat b, GLfloat a) : R(r), G(g), B(b), A(a) {}
GLfloat R, G, B, A;
};
static constexpr GLColor32F kFloatRed = {1.0f, 0.0f, 0.0f, 1.0f};
static constexpr GLColor32F kFloatGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static constexpr GLColor32F kFloatBlue = {0.0f, 0.0f, 1.0f, 1.0f};
struct WorkaroundsD3D;
// Useful to cast any type to GLubyte.
......
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