Commit 378734c5 by Jamie Madill Committed by Commit Bot

D3D11: Lazy evaluation for draw call vertex params.

The vertex params are the 'start' vertex index and the number of vertices in the draw call. For indexed draws, they sometimes mean we need to compute the index range. In other cases, we don't. Defer computing the index range as long as possible so we don't end up computing the index range when we don't have to. BUG=angleproject:2229 Change-Id: I8e125416ef6767787a14509b322efa8dcd8e4a34 Reviewed-on: https://chromium-review.googlesource.com/764676 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 39f74df5
......@@ -303,7 +303,7 @@ gl::Error InputLayoutCache::updateInputLayout(
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
const AttribIndexArray &sortedSemanticIndices,
GLsizei numIndicesPerInstance)
const DrawCallVertexParams &vertexParams)
{
gl::Program *program = state.getProgram();
const auto &shaderAttributes = program->getAttributes();
......@@ -324,7 +324,7 @@ gl::Error InputLayoutCache::updateInputLayout(
layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE;
}
if (numIndicesPerInstance > 0)
if (vertexParams.instances() > 0)
{
layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE;
}
......@@ -366,7 +366,7 @@ gl::Error InputLayoutCache::updateInputLayout(
d3d11::InputLayout newInputLayout;
ANGLE_TRY(createInputLayout(renderer, sortedSemanticIndices, currentAttributes, mode,
program, numIndicesPerInstance, &newInputLayout));
program, vertexParams, &newInputLayout));
auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout));
inputLayout = &insertIt->second;
......@@ -383,7 +383,7 @@ gl::Error InputLayoutCache::createInputLayout(
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
gl::Program *program,
GLsizei numIndicesPerInstance,
const DrawCallVertexParams &vertexParams,
d3d11::InputLayout *inputLayoutOut)
{
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
......@@ -432,6 +432,14 @@ gl::Error InputLayoutCache::createInputLayout(
// doesn't support OpenGL ES 3.0.
// As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced
// simultaneously, so a non-instanced element must exist.
GLsizei numIndicesPerInstance = 0;
if (vertexParams.instances() > 0)
{
// This may trigger an evaluation of the index range.
numIndicesPerInstance = vertexParams.vertexCount();
}
for (size_t elementIndex = 0; elementIndex < inputElementCount; ++elementIndex)
{
// If rendering points and instanced pointsprite emulation is being used, the
......
......@@ -27,6 +27,7 @@
namespace rx
{
class DrawCallVertexParams;
struct PackedAttributeLayout;
} // namespace rx
......@@ -105,7 +106,7 @@ class InputLayoutCache : angle::NonCopyable
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
const AttribIndexArray &sortedSemanticIndices,
GLsizei numIndicesPerInstance);
const DrawCallVertexParams &vertexParams);
private:
gl::Error createInputLayout(Renderer11 *renderer,
......@@ -113,7 +114,7 @@ class InputLayoutCache : angle::NonCopyable
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
gl::Program *program,
GLsizei numIndicesPerInstance,
const DrawCallVertexParams &vertexParams,
d3d11::InputLayout *inputLayoutOut);
// Starting cache size.
......
......@@ -1511,8 +1511,8 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
return gl::NoError();
}
ANGLE_TRY(
mStateManager.applyVertexBuffer(context, mode, startVertex, count, instances, nullptr));
DrawCallVertexParams vertexParams(startVertex, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr));
if (glState.isTransformFeedbackActiveUnpaused())
{
......@@ -1655,7 +1655,8 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
&indexInfo));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, 0, 0, 0, &indexInfo));
DrawCallVertexParams vertexParams(0, 0, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
if (adjustedInstanceCount > 0)
{
mDeviceContext->DrawIndexedInstanced(count, adjustedInstanceCount, 0, 0, 0);
......@@ -1670,13 +1671,11 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
ANGLE_TRY(
mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, &indexInfo));
const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value();
size_t vertexCount = indexRange.vertexCount();
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, static_cast<GLsizei>(indexRange.start),
static_cast<GLsizei>(vertexCount), instances,
&indexInfo));
DrawCallVertexParams vertexParams(lazyIndexRange, 0, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
int startVertex = static_cast<int>(indexRange.start);
int startVertex = static_cast<int>(vertexParams.firstVertex());
int baseVertex = -startVertex;
if (mode == GL_LINE_LOOP)
......@@ -1727,7 +1726,7 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
// efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each
// batch of points. An offset into the instanced data buffer is calculated and applied on each
// iteration to ensure all instances are rendered correctly.
GLsizei elementsToRender = static_cast<GLsizei>(indexRange.vertexCount());
GLsizei elementsToRender = vertexParams.vertexCount();
// Each instance being rendered requires the inputlayout cache to reapply buffers and offsets.
for (GLsizei i = 0; i < instances; i++)
......@@ -1758,7 +1757,8 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
if (!DrawCallNeedsTranslation(context, mode))
{
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, 0, 0, 0, nullptr));
DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
......@@ -1774,7 +1774,8 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
GLuint instances = args->instanceCount;
GLuint first = args->first;
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, first, count, instances, nullptr));
DrawCallVertexParams vertexParams(first, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr));
if (mode == GL_LINE_LOOP)
{
......@@ -1812,7 +1813,8 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
{
ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(),
&indexInfo));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, 0, 0, 0, &indexInfo));
DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
......@@ -1838,13 +1840,12 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
ANGLE_TRY(
mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, &indexInfo));
const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value();
size_t vertexCount = indexRange.vertexCount();
ANGLE_TRY(mStateManager.applyVertexBuffer(
context, mode, static_cast<GLsizei>(indexRange.start) + baseVertex,
static_cast<GLsizei>(vertexCount), instances, &indexInfo));
DrawCallVertexParams vertexParams(lazyIndexRange, baseVertex, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
int baseVertexLocation = -static_cast<int>(lazyIndexRange.getIndexRange().value().start);
int baseVertexLocation = -static_cast<int>(indexRange.start);
if (mode == GL_LINE_LOOP)
{
return drawLineLoop(context, count, type, indices, baseVertexLocation, instances);
......
......@@ -2473,9 +2473,7 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo)
{
const auto &state = context->getGLState();
......@@ -2484,17 +2482,17 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
if (mVertexAttribsNeedTranslation)
{
ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager, first,
count, instances));
ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager,
vertexParams));
mInputLayoutIsDirty = true;
// Determine if we need to update attribs on the next draw.
mVertexAttribsNeedTranslation = (vertexArray11->hasActiveDynamicAttrib(context));
}
if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != first)
if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != vertexParams.firstVertex())
{
mLastFirstVertex = first;
mLastFirstVertex = vertexParams.firstVertex();
mInputLayoutIsDirty = true;
}
......@@ -2503,12 +2501,6 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
return gl::NoError();
}
GLsizei numIndicesPerInstance = 0;
if (instances > 0)
{
numIndicesPerInstance = count;
}
const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
gl::Program *program = state.getProgram();
......@@ -2536,11 +2528,11 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// Update the applied input layout by querying the cache.
ANGLE_TRY(mInputLayoutCache.updateInputLayout(mRenderer, state, mCurrentAttributes, mode,
sortedSemanticIndices, numIndicesPerInstance));
sortedSemanticIndices, vertexParams));
// Update the applied vertex buffers.
ANGLE_TRY(
mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode, first, indexInfo));
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode,
vertexParams.firstVertex(), indexInfo));
// InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex
// buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger
......@@ -2549,7 +2541,7 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// update on the second draw call.
// Hence we clear the flags here, after we've applied vertex data, since we know everything
// is clean. This is a bit of a hack.
vertexArray11->clearDirtyAndPromoteDynamicAttribs(context, count);
vertexArray11->clearDirtyAndPromoteDynamicAttribs(context, vertexParams);
mInputLayoutIsDirty = false;
return gl::NoError();
......@@ -2981,4 +2973,55 @@ gl::Error StateManager11::syncTransformFeedbackBuffers(const gl::Context *contex
return gl::NoError();
}
// DrawCallVertexParams implementation.
DrawCallVertexParams::DrawCallVertexParams(GLint firstVertex,
GLsizei vertexCount,
GLsizei instances)
: mHasIndexRange(nullptr),
mFirstVertex(firstVertex),
mVertexCount(vertexCount),
mInstances(instances)
{
}
// Use when in a drawElements call.
DrawCallVertexParams::DrawCallVertexParams(const gl::HasIndexRange &hasIndexRange,
GLint baseVertex,
GLsizei instances)
: mHasIndexRange(&hasIndexRange),
mFirstVertex(baseVertex),
mVertexCount(0),
mInstances(instances)
{
}
GLint DrawCallVertexParams::firstVertex() const
{
ensureResolved();
return mFirstVertex;
}
GLsizei DrawCallVertexParams::vertexCount() const
{
ensureResolved();
return mVertexCount;
}
GLsizei DrawCallVertexParams::instances() const
{
return mInstances;
}
void DrawCallVertexParams::ensureResolved() const
{
if (mHasIndexRange)
{
// Resolve the index range now if we need to.
const gl::IndexRange &indexRange = mHasIndexRange->getIndexRange().value();
mFirstVertex += static_cast<GLint>(indexRange.start);
mVertexCount = static_cast<GLsizei>(indexRange.vertexCount());
mHasIndexRange = nullptr;
}
}
} // namespace rx
......@@ -140,6 +140,30 @@ class ShaderConstants11 : angle::NonCopyable
bool mSamplerMetadataCSDirty;
};
class DrawCallVertexParams final : angle::NonCopyable
{
public:
// Use when in a drawArrays call.
DrawCallVertexParams(GLint firstVertex, GLsizei vertexCount, GLsizei instances);
// Use when in a drawElements call.
DrawCallVertexParams(const gl::HasIndexRange &hasIndexRange,
GLint baseVertex,
GLsizei instances);
GLint firstVertex() const;
GLsizei vertexCount() const;
GLsizei instances() const;
private:
void ensureResolved() const;
mutable const gl::HasIndexRange *mHasIndexRange;
mutable GLint mFirstVertex;
mutable GLsizei mVertexCount;
GLsizei mInstances;
};
class StateManager11 final : angle::NonCopyable
{
public:
......@@ -236,9 +260,7 @@ class StateManager11 final : angle::NonCopyable
// Not handled by an internal dirty bit because of the extra draw parameters.
gl::Error applyVertexBuffer(const gl::Context *context,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo);
gl::Error applyIndexBuffer(const gl::Context *context,
......
......@@ -172,9 +172,7 @@ bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
GLint start,
GLsizei count,
GLsizei instances)
const DrawCallVertexParams &vertexParams)
{
flushAttribUpdates(context);
......@@ -247,7 +245,8 @@ gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context
}
ANGLE_TRY(vertexDataManager->storeDynamicAttribs(
context, &mTranslatedAttribs, activeDynamicAttribs, start, count, instances));
context, &mTranslatedAttribs, activeDynamicAttribs, vertexParams.firstVertex(),
vertexParams.vertexCount(), vertexParams.instances()));
}
return gl::NoError();
......@@ -270,7 +269,8 @@ void VertexArray11::signal(size_t channelID, const gl::Context *context)
renderer->getStateManager()->invalidateShaders();
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, GLsizei count)
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
const DrawCallVertexParams &vertexParams)
{
const gl::State &state = context->getGLState();
const gl::Program *program = state.getProgram();
......@@ -279,8 +279,11 @@ void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *contex
// Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness.
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
count);
if (activeDynamicAttribs.any())
{
VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
vertexParams.vertexCount());
}
}
void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
......
......@@ -30,10 +30,9 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
bool hasActiveDynamicAttrib(const gl::Context *context);
gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
GLint start,
GLsizei count,
GLsizei instances);
void clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, GLsizei count);
const DrawCallVertexParams &vertexParams);
void clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
const DrawCallVertexParams &vertexParams);
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
......
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