Commit e3d8628d by Jamie Madill Committed by Commit Bot

D3D11: Split input layout and VB application.

This will enable future optimizations that only update either the applied vertex buffers or the input layout independenty. It also makes debugging a bit easier since we can force an update of the vertex buffer or input layout to diagnose potential state sync bugs. BUG=angleproject:1156 Change-Id: Ib375561528da539e136ff4fd02398b03c9caabb7 Reviewed-on: https://chromium-review.googlesource.com/627077Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 96f6adfa
...@@ -67,54 +67,6 @@ struct PackedAttribute ...@@ -67,54 +67,6 @@ struct PackedAttribute
uint8_t divisor; uint8_t divisor;
}; };
Optional<size_t> FindFirstNonInstanced(
const std::vector<const TranslatedAttribute *> &currentAttributes)
{
for (size_t index = 0; index < currentAttributes.size(); ++index)
{
if (currentAttributes[index]->divisor == 0)
{
return Optional<size_t>(index);
}
}
return Optional<size_t>::Invalid();
}
void SortAttributesByLayout(const gl::Program *program,
const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
AttribIndexArray *sortedD3DSemanticsOut,
std::vector<const TranslatedAttribute *> *sortedAttributesOut)
{
sortedAttributesOut->clear();
const auto &locationToSemantic =
GetImplAs<ProgramD3D>(program)->getAttribLocationToD3DSemantics();
for (auto locationIndex : program->getActiveAttribLocationsMask())
{
int d3dSemantic = locationToSemantic[locationIndex];
if (sortedAttributesOut->size() <= static_cast<size_t>(d3dSemantic))
{
sortedAttributesOut->resize(d3dSemantic + 1);
}
(*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic;
const auto *arrayAttrib = &vertexArrayAttribs[locationIndex];
if (arrayAttrib->attribute && arrayAttrib->attribute->enabled)
{
(*sortedAttributesOut)[d3dSemantic] = arrayAttrib;
}
else
{
ASSERT(currentValueAttribs[locationIndex].attribute);
(*sortedAttributesOut)[d3dSemantic] = &currentValueAttribs[locationIndex];
}
}
}
} // anonymous namespace } // anonymous namespace
PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({}) PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({})
...@@ -153,7 +105,6 @@ bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const ...@@ -153,7 +105,6 @@ bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const
InputLayoutCache::InputLayoutCache() InputLayoutCache::InputLayoutCache()
: mLayoutCache(kDefaultCacheSize * 2), mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer() : mLayoutCache(kDefaultCacheSize * 2), mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer()
{ {
mCurrentAttributes.reserve(gl::MAX_VERTEX_ATTRIBS);
} }
InputLayoutCache::~InputLayoutCache() InputLayoutCache::~InputLayoutCache()
...@@ -170,12 +121,10 @@ void InputLayoutCache::clear() ...@@ -170,12 +121,10 @@ void InputLayoutCache::clear()
gl::Error InputLayoutCache::applyVertexBuffers( gl::Error InputLayoutCache::applyVertexBuffers(
Renderer11 *renderer, Renderer11 *renderer,
const gl::State &state, const gl::State &state,
const std::vector<TranslatedAttribute> &vertexArrayAttribs, const std::vector<const TranslatedAttribute *> &currentAttributes,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode, GLenum mode,
GLint start, GLint start,
TranslatedIndexData *indexInfo, TranslatedIndexData *indexInfo)
GLsizei numIndicesPerInstance)
{ {
ID3D11DeviceContext *deviceContext = renderer->getDeviceContext(); ID3D11DeviceContext *deviceContext = renderer->getDeviceContext();
auto *stateManager = renderer->getStateManager(); auto *stateManager = renderer->getStateManager();
...@@ -186,30 +135,6 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -186,30 +135,6 @@ gl::Error InputLayoutCache::applyVertexBuffers(
bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
AttribIndexArray sortedSemanticIndices;
SortAttributesByLayout(program, vertexArrayAttribs, currentValueAttribs, &sortedSemanticIndices,
&mCurrentAttributes);
auto featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
// If we are using FL 9_3, make sure the first attribute is not instanced
if (featureLevel <= D3D_FEATURE_LEVEL_9_3 && !mCurrentAttributes.empty())
{
if (mCurrentAttributes[0]->divisor > 0)
{
Optional<size_t> firstNonInstancedIndex = FindFirstNonInstanced(mCurrentAttributes);
if (firstNonInstancedIndex.valid())
{
size_t index = firstNonInstancedIndex.value();
std::swap(mCurrentAttributes[0], mCurrentAttributes[index]);
std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]);
}
}
}
ANGLE_TRY(
updateInputLayout(renderer, state, mode, sortedSemanticIndices, numIndicesPerInstance));
// Note that if we use instance emulation, we reserve the first buffer slot. // Note that if we use instance emulation, we reserve the first buffer slot.
size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites); size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites);
...@@ -220,9 +145,9 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -220,9 +145,9 @@ gl::Error InputLayoutCache::applyVertexBuffers(
UINT vertexStride = 0; UINT vertexStride = 0;
UINT vertexOffset = 0; UINT vertexOffset = 0;
if (attribIndex < mCurrentAttributes.size()) if (attribIndex < currentAttributes.size())
{ {
const auto &attrib = *mCurrentAttributes[attribIndex]; const auto &attrib = *currentAttributes[attribIndex];
Buffer11 *bufferStorage = attrib.storage ? GetAs<Buffer11>(attrib.storage) : nullptr; Buffer11 *bufferStorage = attrib.storage ? GetAs<Buffer11>(attrib.storage) : nullptr;
// If indexed pointsprite emulation is active, then we need to take a less efficent code path. // If indexed pointsprite emulation is active, then we need to take a less efficent code path.
...@@ -344,16 +269,18 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -344,16 +269,18 @@ gl::Error InputLayoutCache::applyVertexBuffers(
return gl::NoError(); return gl::NoError();
} }
gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(Renderer11 *renderer, gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(
GLint startVertex, Renderer11 *renderer,
GLsizei emulatedInstanceId) const std::vector<const TranslatedAttribute *> &currentAttributes,
GLint startVertex,
GLsizei emulatedInstanceId)
{ {
auto *stateManager = renderer->getStateManager(); auto *stateManager = renderer->getStateManager();
size_t reservedBuffers = GetReservedBufferCount(true); size_t reservedBuffers = GetReservedBufferCount(true);
for (size_t attribIndex = 0; attribIndex < mCurrentAttributes.size(); ++attribIndex) for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex)
{ {
const auto &attrib = *mCurrentAttributes[attribIndex]; const auto &attrib = *currentAttributes[attribIndex];
size_t bufferIndex = reservedBuffers + attribIndex; size_t bufferIndex = reservedBuffers + attribIndex;
if (attrib.divisor > 0) if (attrib.divisor > 0)
...@@ -369,11 +296,13 @@ gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(Renderer ...@@ -369,11 +296,13 @@ gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(Renderer
return gl::NoError(); return gl::NoError();
} }
gl::Error InputLayoutCache::updateInputLayout(Renderer11 *renderer, gl::Error InputLayoutCache::updateInputLayout(
const gl::State &state, Renderer11 *renderer,
GLenum mode, const gl::State &state,
const AttribIndexArray &sortedSemanticIndices, const std::vector<const TranslatedAttribute *> &currentAttributes,
GLsizei numIndicesPerInstance) GLenum mode,
const AttribIndexArray &sortedSemanticIndices,
GLsizei numIndicesPerInstance)
{ {
gl::Program *program = state.getProgram(); gl::Program *program = state.getProgram();
const auto &shaderAttributes = program->getAttributes(); const auto &shaderAttributes = program->getAttributes();
...@@ -434,8 +363,8 @@ gl::Error InputLayoutCache::updateInputLayout(Renderer11 *renderer, ...@@ -434,8 +363,8 @@ gl::Error InputLayoutCache::updateInputLayout(Renderer11 *renderer,
angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache); angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache);
d3d11::InputLayout newInputLayout; d3d11::InputLayout newInputLayout;
ANGLE_TRY(createInputLayout(renderer, sortedSemanticIndices, mode, program, ANGLE_TRY(createInputLayout(renderer, sortedSemanticIndices, currentAttributes, mode,
numIndicesPerInstance, &newInputLayout)); program, numIndicesPerInstance, &newInputLayout));
auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout)); auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout));
inputLayout = &insertIt->second; inputLayout = &insertIt->second;
...@@ -446,12 +375,14 @@ gl::Error InputLayoutCache::updateInputLayout(Renderer11 *renderer, ...@@ -446,12 +375,14 @@ gl::Error InputLayoutCache::updateInputLayout(Renderer11 *renderer,
return gl::NoError(); return gl::NoError();
} }
gl::Error InputLayoutCache::createInputLayout(Renderer11 *renderer, gl::Error InputLayoutCache::createInputLayout(
const AttribIndexArray &sortedSemanticIndices, Renderer11 *renderer,
GLenum mode, const AttribIndexArray &sortedSemanticIndices,
gl::Program *program, const std::vector<const TranslatedAttribute *> &currentAttributes,
GLsizei numIndicesPerInstance, GLenum mode,
d3d11::InputLayout *inputLayoutOut) gl::Program *program,
GLsizei numIndicesPerInstance,
d3d11::InputLayout *inputLayoutOut)
{ {
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
auto featureLevel = renderer->getRenderer11DeviceCaps().featureLevel; auto featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
...@@ -462,9 +393,9 @@ gl::Error InputLayoutCache::createInputLayout(Renderer11 *renderer, ...@@ -462,9 +393,9 @@ gl::Error InputLayoutCache::createInputLayout(Renderer11 *renderer,
unsigned int inputElementCount = 0; unsigned int inputElementCount = 0;
std::array<D3D11_INPUT_ELEMENT_DESC, gl::MAX_VERTEX_ATTRIBS> inputElements; std::array<D3D11_INPUT_ELEMENT_DESC, gl::MAX_VERTEX_ATTRIBS> inputElements;
for (size_t attribIndex = 0; attribIndex < mCurrentAttributes.size(); ++attribIndex) for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex)
{ {
const auto &attrib = *mCurrentAttributes[attribIndex]; const auto &attrib = *currentAttributes[attribIndex];
const int sortedIndex = sortedSemanticIndices[attribIndex]; const int sortedIndex = sortedSemanticIndices[attribIndex];
D3D11_INPUT_CLASSIFICATION inputClass = D3D11_INPUT_CLASSIFICATION inputClass =
...@@ -507,7 +438,7 @@ gl::Error InputLayoutCache::createInputLayout(Renderer11 *renderer, ...@@ -507,7 +438,7 @@ gl::Error InputLayoutCache::createInputLayout(Renderer11 *renderer,
{ {
inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
inputElements[elementIndex].InstanceDataStepRate = 1; inputElements[elementIndex].InstanceDataStepRate = 1;
if (numIndicesPerInstance > 0 && mCurrentAttributes[elementIndex]->divisor > 0) if (numIndicesPerInstance > 0 && currentAttributes[elementIndex]->divisor > 0)
{ {
inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance; inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance;
} }
......
...@@ -87,28 +87,31 @@ class InputLayoutCache : angle::NonCopyable ...@@ -87,28 +87,31 @@ class InputLayoutCache : angle::NonCopyable
gl::Error applyVertexBuffers(Renderer11 *renderer, gl::Error applyVertexBuffers(Renderer11 *renderer,
const gl::State &state, const gl::State &state,
const std::vector<TranslatedAttribute> &vertexArrayAttribs, const std::vector<const TranslatedAttribute *> &currentAttributes,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode, GLenum mode,
GLint start, GLint start,
TranslatedIndexData *indexInfo, TranslatedIndexData *indexInfo);
GLsizei numIndicesPerInstance);
gl::Error updateVertexOffsetsForPointSpritesEmulation(Renderer11 *renderer, gl::Error updateVertexOffsetsForPointSpritesEmulation(
GLint startVertex, Renderer11 *renderer,
GLsizei emulatedInstanceId); const std::vector<const TranslatedAttribute *> &currentAttributes,
GLint startVertex,
GLsizei emulatedInstanceId);
// Useful for testing // Useful for testing
void setCacheSize(size_t newCacheSize); void setCacheSize(size_t newCacheSize);
private:
gl::Error updateInputLayout(Renderer11 *renderer, gl::Error updateInputLayout(Renderer11 *renderer,
const gl::State &state, const gl::State &state,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode, GLenum mode,
const AttribIndexArray &sortedSemanticIndices, const AttribIndexArray &sortedSemanticIndices,
GLsizei numIndicesPerInstance); GLsizei numIndicesPerInstance);
private:
gl::Error createInputLayout(Renderer11 *renderer, gl::Error createInputLayout(Renderer11 *renderer,
const AttribIndexArray &sortedSemanticIndices, const AttribIndexArray &sortedSemanticIndices,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode, GLenum mode,
gl::Program *program, gl::Program *program,
GLsizei numIndicesPerInstance, GLsizei numIndicesPerInstance,
...@@ -123,8 +126,6 @@ class InputLayoutCache : angle::NonCopyable ...@@ -123,8 +126,6 @@ class InputLayoutCache : angle::NonCopyable
using LayoutCache = angle::base::HashingMRUCache<PackedAttributeLayout, d3d11::InputLayout>; using LayoutCache = angle::base::HashingMRUCache<PackedAttributeLayout, d3d11::InputLayout>;
LayoutCache mLayoutCache; LayoutCache mLayoutCache;
std::vector<const TranslatedAttribute *> mCurrentAttributes;
d3d11::Buffer mPointSpriteVertexBuffer; d3d11::Buffer mPointSpriteVertexBuffer;
d3d11::Buffer mPointSpriteIndexBuffer; d3d11::Buffer mPointSpriteIndexBuffer;
}; };
......
...@@ -119,6 +119,54 @@ int GetWrapBits(GLenum wrap) ...@@ -119,6 +119,54 @@ int GetWrapBits(GLenum wrap)
} }
} }
Optional<size_t> FindFirstNonInstanced(
const std::vector<const TranslatedAttribute *> &currentAttributes)
{
for (size_t index = 0; index < currentAttributes.size(); ++index)
{
if (currentAttributes[index]->divisor == 0)
{
return Optional<size_t>(index);
}
}
return Optional<size_t>::Invalid();
}
void SortAttributesByLayout(const gl::Program *program,
const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
AttribIndexArray *sortedD3DSemanticsOut,
std::vector<const TranslatedAttribute *> *sortedAttributesOut)
{
sortedAttributesOut->clear();
const auto &locationToSemantic =
GetImplAs<ProgramD3D>(program)->getAttribLocationToD3DSemantics();
for (auto locationIndex : program->getActiveAttribLocationsMask())
{
int d3dSemantic = locationToSemantic[locationIndex];
if (sortedAttributesOut->size() <= static_cast<size_t>(d3dSemantic))
{
sortedAttributesOut->resize(d3dSemantic + 1);
}
(*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic;
const auto *arrayAttrib = &vertexArrayAttribs[locationIndex];
if (arrayAttrib->attribute && arrayAttrib->attribute->enabled)
{
(*sortedAttributesOut)[d3dSemantic] = arrayAttrib;
}
else
{
ASSERT(currentValueAttribs[locationIndex].attribute);
(*sortedAttributesOut)[d3dSemantic] = &currentValueAttribs[locationIndex];
}
}
}
} // anonymous namespace } // anonymous namespace
// StateManager11::SRVCache Implementation. // StateManager11::SRVCache Implementation.
...@@ -1190,6 +1238,9 @@ gl::Error StateManager11::initialize(const gl::Caps &caps) ...@@ -1190,6 +1238,9 @@ gl::Error StateManager11::initialize(const gl::Caps &caps)
mSamplerMetadataCS.initData(caps.maxComputeTextureImageUnits); mSamplerMetadataCS.initData(caps.maxComputeTextureImageUnits);
ANGLE_TRY(mVertexDataManager.initialize()); ANGLE_TRY(mVertexDataManager.initialize());
mCurrentAttributes.reserve(gl::MAX_VERTEX_ATTRIBS);
return gl::NoError(); return gl::NoError();
} }
...@@ -1835,9 +1886,37 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context, ...@@ -1835,9 +1886,37 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
numIndicesPerInstance = count; numIndicesPerInstance = count;
} }
const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs(); const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(mRenderer, state, vertexArrayAttribs, gl::Program *program = state.getProgram();
mCurrentValueAttribs, mode, first, indexInfo,
numIndicesPerInstance)); // Sort the attributes according to ensure we re-use similar input layouts.
AttribIndexArray sortedSemanticIndices;
SortAttributesByLayout(program, vertexArrayAttribs, mCurrentValueAttribs,
&sortedSemanticIndices, &mCurrentAttributes);
auto featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel;
// If we are using FL 9_3, make sure the first attribute is not instanced
if (featureLevel <= D3D_FEATURE_LEVEL_9_3 && !mCurrentAttributes.empty())
{
if (mCurrentAttributes[0]->divisor > 0)
{
Optional<size_t> firstNonInstancedIndex = FindFirstNonInstanced(mCurrentAttributes);
if (firstNonInstancedIndex.valid())
{
size_t index = firstNonInstancedIndex.value();
std::swap(mCurrentAttributes[0], mCurrentAttributes[index]);
std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]);
}
}
}
// Update the applied input layout by querying the cache.
ANGLE_TRY(mInputLayoutCache.updateInputLayout(mRenderer, state, mCurrentAttributes, mode,
sortedSemanticIndices, numIndicesPerInstance));
// Update the applied vertex buffers.
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(mRenderer, state, mCurrentAttributes, mode,
first, indexInfo));
// InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex // InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex
// buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger // buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger
...@@ -1907,8 +1986,8 @@ void StateManager11::setIndexBuffer(ID3D11Buffer *buffer, ...@@ -1907,8 +1986,8 @@ void StateManager11::setIndexBuffer(ID3D11Buffer *buffer,
gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId) GLsizei emulatedInstanceId)
{ {
return mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(mRenderer, startVertex, return mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(
emulatedInstanceId); mRenderer, mCurrentAttributes, startVertex, emulatedInstanceId);
} }
} // namespace rx } // namespace rx
...@@ -372,6 +372,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -372,6 +372,7 @@ class StateManager11 final : angle::NonCopyable
VertexDataManager mVertexDataManager; VertexDataManager mVertexDataManager;
IndexDataManager mIndexDataManager; IndexDataManager mIndexDataManager;
InputLayoutCache mInputLayoutCache; InputLayoutCache mInputLayoutCache;
std::vector<const TranslatedAttribute *> mCurrentAttributes;
}; };
} // namespace rx } // namespace rx
......
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