Commit 8e4bb4b1 by Jamie Madill Committed by Commit Bot

D3D11: Cache element array buffer updates.

This attempts to reduce the amount of redundant validation done between indexed draw calls. It keeps the cached info in the VertexArray11 class. It also includes a fix to a missing direct buffer invalidation in CopyBufferSubData which was turning up with the new caching. Reduces overhead in the D3D11 indexed rendering perf test such that it leads to an increased score of about 20%. BUG=angleproject:2229 Change-Id: I63121bea19a9c8198e1925ed6a1460838e8f8955 Reviewed-on: https://chromium-review.googlesource.com/765262 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent c7b0cf2a
...@@ -110,8 +110,30 @@ gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, ...@@ -110,8 +110,30 @@ gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer,
return gl::NoError(); return gl::NoError();
} }
unsigned int ElementTypeSize(GLenum elementType)
{
switch (elementType)
{
case GL_UNSIGNED_BYTE:
return sizeof(GLubyte);
case GL_UNSIGNED_SHORT:
return sizeof(GLushort);
case GL_UNSIGNED_INT:
return sizeof(GLuint);
default:
UNREACHABLE();
return 0;
}
}
} // anonymous namespace } // anonymous namespace
bool IsOffsetAligned(GLenum elementType, unsigned int offset)
{
return (offset % ElementTypeSize(elementType) == 0);
}
// IndexDataManager implementation.
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory) IndexDataManager::IndexDataManager(BufferFactoryD3D *factory)
: mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt() : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt()
{ {
...@@ -170,7 +192,7 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context, ...@@ -170,7 +192,7 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context,
unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices)); unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize()); ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
bool offsetAligned = (offset % gl::ElementTypeSize(srcType) == 0); bool offsetAligned = IsOffsetAligned(srcType, offset);
// Case 2a: the buffer can be used directly // Case 2a: the buffer can be used directly
if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType) if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
...@@ -182,10 +204,8 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context, ...@@ -182,10 +204,8 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context,
translated->startOffset = offset; translated->startOffset = offset;
return gl::NoError(); return gl::NoError();
} }
else
{ translated->storage = nullptr;
translated->storage = nullptr;
}
// Case 2b: use a static translated copy or fall back to streaming // Case 2b: use a static translated copy or fall back to streaming
StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer(); StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
......
...@@ -98,6 +98,8 @@ GLenum GetIndexTranslationDestType(GLenum srcType, ...@@ -98,6 +98,8 @@ GLenum GetIndexTranslationDestType(GLenum srcType,
const gl::HasIndexRange &lazyIndexRange, const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround); bool usePrimitiveRestartWorkaround);
bool IsOffsetAligned(GLenum elementType, unsigned int offset);
} // namespace rx } // namespace rx
#endif // LIBANGLE_INDEXDATAMANAGER_H_ #endif // LIBANGLE_INDEXDATAMANAGER_H_
...@@ -473,6 +473,9 @@ gl::Error Buffer11::copySubData(const gl::Context *context, ...@@ -473,6 +473,9 @@ gl::Error Buffer11::copySubData(const gl::Context *context,
mSize = std::max<size_t>(mSize, destOffset + size); mSize = std::max<size_t>(mSize, destOffset + size);
invalidateStaticData(context); invalidateStaticData(context);
// Also notify that direct buffers are dirty.
mDirectBroadcastChannel.signal(context);
return gl::NoError(); return gl::NoError();
} }
...@@ -755,6 +758,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) ...@@ -755,6 +758,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
return new SystemMemoryStorage(mRenderer); return new SystemMemoryStorage(mRenderer);
case BUFFER_USAGE_EMULATED_INDEXED_VERTEX: case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
return new EmulatedIndexedStorage(mRenderer); return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_INDEX:
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel); return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel);
default: default:
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "libANGLE/renderer/d3d/d3d11/Context11.h" #include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
...@@ -126,7 +127,7 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -126,7 +127,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(
const std::vector<const TranslatedAttribute *> &currentAttributes, const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode, GLenum mode,
GLint start, GLint start,
TranslatedIndexData *indexInfo) bool isIndexedRendering)
{ {
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer(); Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
const gl::State &state = context->getGLState(); const gl::State &state = context->getGLState();
...@@ -161,8 +162,11 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -161,8 +162,11 @@ gl::Error InputLayoutCache::applyVertexBuffers(
ASSERT(attrib.vertexBuffer.get()); ASSERT(attrib.vertexBuffer.get());
buffer = GetAs<VertexBuffer11>(attrib.vertexBuffer.get())->getBuffer().get(); buffer = GetAs<VertexBuffer11>(attrib.vertexBuffer.get())->getBuffer().get();
} }
else if (instancedPointSpritesActive && (indexInfo != nullptr)) else if (instancedPointSpritesActive && isIndexedRendering)
{ {
VertexArray11 *vao11 = GetImplAs<VertexArray11>(state.getVertexArray());
ASSERT(vao11->isCachedIndexInfoValid());
TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo();
if (indexInfo->srcIndexData.srcBuffer != nullptr) if (indexInfo->srcIndexData.srcBuffer != nullptr)
{ {
const uint8_t *bufferData = nullptr; const uint8_t *bufferData = nullptr;
......
...@@ -90,7 +90,7 @@ class InputLayoutCache : angle::NonCopyable ...@@ -90,7 +90,7 @@ class InputLayoutCache : angle::NonCopyable
const std::vector<const TranslatedAttribute *> &currentAttributes, const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode, GLenum mode,
GLint start, GLint start,
TranslatedIndexData *indexInfo); bool isIndexedRendering);
gl::Error updateVertexOffsetsForPointSpritesEmulation( gl::Error updateVertexOffsetsForPointSpritesEmulation(
Renderer11 *renderer, Renderer11 *renderer,
......
...@@ -1514,7 +1514,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context, ...@@ -1514,7 +1514,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
} }
DrawCallVertexParams vertexParams(startVertex, count, instances); DrawCallVertexParams vertexParams(startVertex, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
if (glState.isTransformFeedbackActiveUnpaused()) if (glState.isTransformFeedbackActiveUnpaused())
{ {
...@@ -1651,10 +1651,9 @@ gl::Error Renderer11::drawElements(const gl::Context *context, ...@@ -1651,10 +1651,9 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances); DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances);
TranslatedIndexData indexInfo;
ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
usePrimitiveRestartWorkaround, &indexInfo)); usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
int startVertex = static_cast<int>(vertexParams.firstVertex()); int startVertex = static_cast<int>(vertexParams.firstVertex());
int baseVertex = -startVertex; int baseVertex = -startVertex;
...@@ -1742,7 +1741,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, ...@@ -1742,7 +1741,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
if (!DrawCallNeedsTranslation(context, mode)) if (!DrawCallNeedsTranslation(context, mode))
{ {
DrawCallVertexParams vertexParams(0, 0, 0); DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
ID3D11Buffer *buffer = nullptr; ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset)); mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
...@@ -1759,7 +1758,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, ...@@ -1759,7 +1758,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
GLuint first = args->first; GLuint first = args->first;
DrawCallVertexParams vertexParams(first, count, instances); DrawCallVertexParams vertexParams(first, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
if (mode == GL_LINE_LOOP) if (mode == GL_LINE_LOOP)
{ {
...@@ -1796,13 +1795,12 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context, ...@@ -1796,13 +1795,12 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
bool usePrimitiveRestartWorkaround = bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
TranslatedIndexData indexInfo;
if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type)) if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type))
{ {
ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(), ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(),
usePrimitiveRestartWorkaround, &indexInfo)); usePrimitiveRestartWorkaround));
DrawCallVertexParams vertexParams(0, 0, 0); DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
ID3D11Buffer *buffer = nullptr; ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset)); mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
...@@ -1827,11 +1825,11 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context, ...@@ -1827,11 +1825,11 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
gl::HasIndexRange lazyIndexRange(const_cast<gl::Context *>(context), count, type, indices); gl::HasIndexRange lazyIndexRange(const_cast<gl::Context *>(context), count, type, indices);
ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
usePrimitiveRestartWorkaround, &indexInfo)); usePrimitiveRestartWorkaround));
DrawCallVertexParams vertexParams(false, lazyIndexRange, baseVertex, instances); DrawCallVertexParams vertexParams(false, lazyIndexRange, baseVertex, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo)); ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
int baseVertexLocation = -static_cast<int>(lazyIndexRange.getIndexRange().value().start); int baseVertexLocation = -static_cast<int>(lazyIndexRange.getIndexRange().value().start);
......
...@@ -562,6 +562,7 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -562,6 +562,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mAppliedIB(nullptr), mAppliedIB(nullptr),
mAppliedIBFormat(DXGI_FORMAT_UNKNOWN), mAppliedIBFormat(DXGI_FORMAT_UNKNOWN),
mAppliedIBOffset(0), mAppliedIBOffset(0),
mIndexBufferIsDirty(false),
mVertexDataManager(renderer), mVertexDataManager(renderer),
mIndexDataManager(renderer), mIndexDataManager(renderer),
mIsMultiviewEnabled(false), mIsMultiviewEnabled(false),
...@@ -952,6 +953,8 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -952,6 +953,8 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
// internal cache of TranslatedAttributes, and they CurrentValue attributes are // internal cache of TranslatedAttributes, and they CurrentValue attributes are
// owned by the StateManager11/Context. // owned by the StateManager11/Context.
mDirtyCurrentValueAttribs.set(); mDirtyCurrentValueAttribs.set();
// Invalidate the cached index buffer.
mIndexBufferIsDirty = true;
break; break;
case gl::State::DIRTY_BIT_TEXTURE_BINDINGS: case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
invalidateTexturesAndSamplers(); invalidateTexturesAndSamplers();
...@@ -2486,7 +2489,7 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod ...@@ -2486,7 +2489,7 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
gl::Error StateManager11::applyVertexBuffer(const gl::Context *context, gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
GLenum mode, GLenum mode,
const DrawCallVertexParams &vertexParams, const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo) bool isIndexedRendering)
{ {
const auto &state = context->getGLState(); const auto &state = context->getGLState();
const gl::VertexArray *vertexArray = state.getVertexArray(); const gl::VertexArray *vertexArray = state.getVertexArray();
...@@ -2544,7 +2547,7 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context, ...@@ -2544,7 +2547,7 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// Update the applied vertex buffers. // Update the applied vertex buffers.
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode, ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode,
vertexParams.firstVertex(), indexInfo)); vertexParams.firstVertex(), isIndexedRendering));
// 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
...@@ -2564,18 +2567,27 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context, ...@@ -2564,18 +2567,27 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const gl::HasIndexRange &lazyIndexRange, const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround, bool usePrimitiveRestartWorkaround)
TranslatedIndexData *indexInfo)
{ {
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
gl::VertexArray *vao = glState.getVertexArray(); gl::VertexArray *vao = glState.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); VertexArray11 *vao11 = GetImplAs<VertexArray11>(vao);
GLenum dstType = GLenum destElementType =
GetIndexTranslationDestType(type, lazyIndexRange, usePrimitiveRestartWorkaround); GetIndexTranslationDestType(type, lazyIndexRange, usePrimitiveRestartWorkaround);
ANGLE_TRY(mIndexDataManager.prepareIndexData(context, type, dstType, count, elementArrayBuffer, if (!vao11->updateElementArrayStorage(context, type, destElementType, indices) &&
indices, indexInfo)); !mIndexBufferIsDirty)
{
// No streaming or index buffer application necessary.
return gl::NoError();
}
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo();
ANGLE_TRY(mIndexDataManager.prepareIndexData(context, type, destElementType, count,
elementArrayBuffer, indices, indexInfo));
ID3D11Buffer *buffer = nullptr; ID3D11Buffer *buffer = nullptr;
DXGI_FORMAT bufferFormat = DXGI_FORMAT bufferFormat =
...@@ -2594,15 +2606,28 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context, ...@@ -2594,15 +2606,28 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context,
// Track dirty indices in the index range cache. // Track dirty indices in the index range cache.
indexInfo->srcIndexData.srcIndicesChanged = indexInfo->srcIndexData.srcIndicesChanged =
setIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); syncIndexBuffer(buffer, bufferFormat, indexInfo->startOffset);
mIndexBufferIsDirty = false;
vao11->setCachedIndexInfoValid();
return gl::NoError(); return gl::NoError();
} }
bool StateManager11::setIndexBuffer(ID3D11Buffer *buffer, void StateManager11::setIndexBuffer(ID3D11Buffer *buffer,
DXGI_FORMAT indexFormat, DXGI_FORMAT indexFormat,
unsigned int offset) unsigned int offset)
{ {
if (syncIndexBuffer(buffer, indexFormat, offset))
{
mIndexBufferIsDirty = true;
}
}
bool StateManager11::syncIndexBuffer(ID3D11Buffer *buffer,
DXGI_FORMAT indexFormat,
unsigned int offset)
{
if (buffer != mAppliedIB || indexFormat != mAppliedIBFormat || offset != mAppliedIBOffset) if (buffer != mAppliedIB || indexFormat != mAppliedIBFormat || offset != mAppliedIBOffset)
{ {
mRenderer->getDeviceContext()->IASetIndexBuffer(buffer, indexFormat, offset); mRenderer->getDeviceContext()->IASetIndexBuffer(buffer, indexFormat, offset);
......
...@@ -267,17 +267,16 @@ class StateManager11 final : angle::NonCopyable ...@@ -267,17 +267,16 @@ class StateManager11 final : angle::NonCopyable
gl::Error applyVertexBuffer(const gl::Context *context, gl::Error applyVertexBuffer(const gl::Context *context,
GLenum mode, GLenum mode,
const DrawCallVertexParams &vertexParams, const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo); bool isIndexedRendering);
gl::Error applyIndexBuffer(const gl::Context *context, gl::Error applyIndexBuffer(const gl::Context *context,
const void *indices, const void *indices,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const gl::HasIndexRange &lazyIndexRange, const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround, bool usePrimitiveRestartWorkaround);
TranslatedIndexData *indexInfo);
bool setIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset); void setIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId); GLsizei emulatedInstanceId);
...@@ -359,6 +358,8 @@ class StateManager11 final : angle::NonCopyable ...@@ -359,6 +358,8 @@ class StateManager11 final : angle::NonCopyable
// Called by the Framebuffer11 directly. // Called by the Framebuffer11 directly.
void processFramebufferInvalidation(const gl::Context *context); void processFramebufferInvalidation(const gl::Context *context);
bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
enum DirtyBitType enum DirtyBitType
{ {
DIRTY_BIT_RENDER_TARGET, DIRTY_BIT_RENDER_TARGET,
...@@ -508,6 +509,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -508,6 +509,7 @@ class StateManager11 final : angle::NonCopyable
ID3D11Buffer *mAppliedIB; ID3D11Buffer *mAppliedIB;
DXGI_FORMAT mAppliedIBFormat; DXGI_FORMAT mAppliedIBFormat;
unsigned int mAppliedIBOffset; unsigned int mAppliedIBOffset;
bool mIndexBufferIsDirty;
// Vertex, index and input layouts // Vertex, index and input layouts
VertexDataManager mVertexDataManager; VertexDataManager mVertexDataManager;
......
...@@ -19,16 +19,43 @@ using namespace angle; ...@@ -19,16 +19,43 @@ using namespace angle;
namespace rx namespace rx
{ {
namespace
{
OnBufferDataDirtyChannel *GetBufferBroadcastChannel(Buffer11 *buffer11,
IndexStorageType storageType)
{
switch (storageType)
{
case IndexStorageType::Direct:
return buffer11->getDirectBroadcastChannel();
case IndexStorageType::Static:
return buffer11->getStaticBroadcastChannel();
case IndexStorageType::Dynamic:
return buffer11 ? buffer11->getStaticBroadcastChannel() : nullptr;
default:
UNREACHABLE();
return nullptr;
}
}
} // anonymous namespace
VertexArray11::VertexArray11(const gl::VertexArrayState &data) VertexArray11::VertexArray11(const gl::VertexArrayState &data)
: VertexArrayImpl(data), : VertexArrayImpl(data),
mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE), mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE),
mTranslatedAttribs(data.getMaxAttribs()), mTranslatedAttribs(data.getMaxAttribs()),
mCurrentBuffers(data.getMaxAttribs()), mCurrentArrayBuffers(data.getMaxAttribs()),
mAppliedNumViewsToDivisor(1) mCurrentElementArrayBuffer(),
mOnArrayBufferDataDirty(),
mOnElementArrayBufferDataDirty(this, mCurrentArrayBuffers.size()),
mAppliedNumViewsToDivisor(1),
mLastElementType(GL_NONE),
mLastDrawElementsOffset(0),
mCurrentElementArrayStorage(IndexStorageType::Invalid),
mCachedIndexInfoValid(false)
{ {
for (size_t attribIndex = 0; attribIndex < mCurrentBuffers.size(); ++attribIndex) for (size_t attribIndex = 0; attribIndex < mCurrentArrayBuffers.size(); ++attribIndex)
{ {
mOnBufferDataDirty.emplace_back(this, attribIndex); mOnArrayBufferDataDirty.emplace_back(this, attribIndex);
} }
} }
...@@ -38,13 +65,15 @@ VertexArray11::~VertexArray11() ...@@ -38,13 +65,15 @@ VertexArray11::~VertexArray11()
void VertexArray11::destroy(const gl::Context *context) void VertexArray11::destroy(const gl::Context *context)
{ {
for (auto &buffer : mCurrentBuffers) for (auto &buffer : mCurrentArrayBuffers)
{ {
if (buffer.get()) if (buffer.get())
{ {
buffer.set(context, nullptr); buffer.set(context, nullptr);
} }
} }
mCurrentElementArrayBuffer.set(context, nullptr);
} }
void VertexArray11::syncState(const gl::Context *context, void VertexArray11::syncState(const gl::Context *context,
...@@ -63,12 +92,17 @@ void VertexArray11::syncState(const gl::Context *context, ...@@ -63,12 +92,17 @@ void VertexArray11::syncState(const gl::Context *context,
for (auto dirtyBit : dirtyBits) for (auto dirtyBit : dirtyBits)
{ {
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER) if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
continue; {
mCachedIndexInfoValid = false;
size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit); mLastElementType = GL_NONE;
// TODO(jiawei.shao@intel.com): Vertex Attrib Bindings }
ASSERT(index == mState.getBindingIndexFromAttribIndex(index)); else
mAttribsToUpdate.set(index); {
size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
// TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
ASSERT(index == mState.getBindingIndexFromAttribIndex(index));
mAttribsToUpdate.set(index);
}
} }
} }
...@@ -94,6 +128,59 @@ bool VertexArray11::flushAttribUpdates(const gl::Context *context) ...@@ -94,6 +128,59 @@ bool VertexArray11::flushAttribUpdates(const gl::Context *context)
return false; return false;
} }
bool VertexArray11::updateElementArrayStorage(const gl::Context *context,
GLenum elementType,
GLenum destElementType,
const void *indices)
{
unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
if (mCachedIndexInfoValid && mLastElementType == elementType &&
offset == mLastDrawElementsOffset)
{
// Dynamic index buffers must be re-streamed every draw.
return (mCurrentElementArrayStorage == IndexStorageType::Dynamic);
}
gl::Buffer *newBuffer = mState.getElementArrayBuffer().get();
gl::Buffer *oldBuffer = mCurrentElementArrayBuffer.get();
bool needsTranslation = false;
IndexStorageType newStorageType = ClassifyIndexStorage(
context->getGLState(), newBuffer, elementType, destElementType, offset, &needsTranslation);
if (newBuffer != oldBuffer)
{
mCurrentElementArrayBuffer.set(context, newBuffer);
}
if (newStorageType != mCurrentElementArrayStorage || newBuffer != oldBuffer)
{
Buffer11 *newBuffer11 = SafeGetImplAs<Buffer11>(newBuffer);
auto *newChannel = GetBufferBroadcastChannel(newBuffer11, newStorageType);
mCurrentElementArrayStorage = newStorageType;
mOnElementArrayBufferDataDirty.bind(newChannel);
needsTranslation = true;
}
if (mLastDrawElementsOffset != offset)
{
needsTranslation = true;
mLastDrawElementsOffset = offset;
}
if (mLastElementType != elementType)
{
needsTranslation = true;
mLastElementType = elementType;
}
// TODO(jmadill): We should probably promote static usage immediately, because this can change
// the storage type for dynamic buffers.
return needsTranslation || !mCachedIndexInfoValid;
}
void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex) void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex)
{ {
const auto &attrib = mState.getVertexAttribute(attribIndex); const auto &attrib = mState.getVertexAttribute(attribIndex);
...@@ -128,7 +215,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t ...@@ -128,7 +215,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
} }
} }
gl::Buffer *oldBufferGL = mCurrentBuffers[attribIndex].get(); gl::Buffer *oldBufferGL = mCurrentArrayBuffers[attribIndex].get();
gl::Buffer *newBufferGL = binding.getBuffer().get(); gl::Buffer *newBufferGL = binding.getBuffer().get();
Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr; Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr;
Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr; Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr;
...@@ -160,8 +247,8 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t ...@@ -160,8 +247,8 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
} }
} }
mOnBufferDataDirty[attribIndex].bind(newChannel); mOnArrayBufferDataDirty[attribIndex].bind(newChannel);
mCurrentBuffers[attribIndex].set(context, binding.getBuffer().get()); mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get());
} }
} }
...@@ -263,14 +350,23 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co ...@@ -263,14 +350,23 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co
void VertexArray11::signal(size_t channelID, const gl::Context *context) void VertexArray11::signal(size_t channelID, const gl::Context *context)
{ {
ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE); if (channelID == mAttributeStorageTypes.size())
{
mCachedIndexInfoValid = false;
mLastElementType = GL_NONE;
mLastDrawElementsOffset = 0;
}
else
{
ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE);
// This can change a buffer's storage, we'll need to re-check. // This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(channelID); mAttribsToUpdate.set(channelID);
// Changing the vertex attribute state can affect the vertex shader. // Changing the vertex attribute state can affect the vertex shader.
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer(); Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
renderer->getStateManager()->invalidateShaders(); renderer->getStateManager()->invalidateShaders();
}
} }
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
...@@ -299,4 +395,19 @@ void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews) ...@@ -299,4 +395,19 @@ void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
} }
} }
TranslatedIndexData *VertexArray11::getCachedIndexInfo()
{
return &mCachedIndexInfo;
}
void VertexArray11::setCachedIndexInfoValid()
{
mCachedIndexInfoValid = true;
}
bool VertexArray11::isCachedIndexInfoValid() const
{
return mCachedIndexInfoValid;
}
} // namespace rx } // namespace rx
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
#include "libANGLE/renderer/VertexArrayImpl.h" #include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/signal_utils.h" #include "libANGLE/signal_utils.h"
namespace rx namespace rx
...@@ -48,6 +49,16 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -48,6 +49,16 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
bool flushAttribUpdates(const gl::Context *context); bool flushAttribUpdates(const gl::Context *context);
// Returns true if the element array buffer needs to be translated.
bool updateElementArrayStorage(const gl::Context *context,
GLenum elementType,
GLenum destElementType,
const void *indices);
TranslatedIndexData *getCachedIndexInfo();
void setCachedIndexInfoValid();
bool isCachedIndexInfoValid() const;
private: private:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex); void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
...@@ -64,14 +75,23 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -64,14 +75,23 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
gl::AttributesMask mAttribsToTranslate; gl::AttributesMask mAttribsToTranslate;
// We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks. // We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks.
std::vector<gl::BindingPointer<gl::Buffer>> mCurrentBuffers; std::vector<gl::BindingPointer<gl::Buffer>> mCurrentArrayBuffers;
gl::BindingPointer<gl::Buffer> mCurrentElementArrayBuffer;
std::vector<OnBufferDataDirtyBinding> mOnBufferDataDirty; std::vector<OnBufferDataDirtyBinding> mOnArrayBufferDataDirty;
OnBufferDataDirtyBinding mOnElementArrayBufferDataDirty;
Serial mCurrentStateSerial; Serial mCurrentStateSerial;
// The numViews value used to adjust the divisor. // The numViews value used to adjust the divisor.
int mAppliedNumViewsToDivisor; int mAppliedNumViewsToDivisor;
// If the index buffer needs re-streaming.
GLenum mLastElementType;
unsigned int mLastDrawElementsOffset;
IndexStorageType mCurrentElementArrayStorage;
TranslatedIndexData mCachedIndexInfo;
bool mCachedIndexInfoValid;
}; };
} // namespace rx } // namespace rx
......
...@@ -2381,4 +2381,41 @@ bool IsStreamingIndexData(const gl::Context *context, GLenum srcType) ...@@ -2381,4 +2381,41 @@ bool IsStreamingIndexData(const gl::Context *context, GLenum srcType)
return false; return false;
} }
IndexStorageType ClassifyIndexStorage(const gl::State &glState,
const gl::Buffer *elementArrayBuffer,
GLenum elementType,
GLenum destElementType,
unsigned int offset,
bool *needsTranslation)
{
// No buffer bound means we are streaming from a client pointer.
if (!elementArrayBuffer || !IsOffsetAligned(elementType, offset))
{
*needsTranslation = true;
return IndexStorageType::Dynamic;
}
// The buffer can be used directly if the storage supports it and no translation needed.
BufferD3D *bufferD3D = GetImplAs<BufferD3D>(elementArrayBuffer);
if (bufferD3D->supportsDirectBinding() && destElementType == elementType)
{
*needsTranslation = false;
return IndexStorageType::Direct;
}
// Use a static copy when available.
StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer();
if (staticBuffer != nullptr)
{
// Need to re-translate the static data if has never been used, or changed type.
*needsTranslation =
(staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != destElementType);
return IndexStorageType::Static;
}
// Static buffer not available, fall back to streaming.
*needsTranslation = true;
return IndexStorageType::Dynamic;
}
} // namespace rx } // namespace rx
...@@ -392,6 +392,30 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm ...@@ -392,6 +392,30 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm
bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type); bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type);
bool IsStreamingIndexData(const gl::Context *context, GLenum srcType); bool IsStreamingIndexData(const gl::Context *context, GLenum srcType);
enum class IndexStorageType
{
// Dynamic indexes are re-streamed every frame. They come from a client data pointer or
// from buffers that are updated frequently.
Dynamic,
// Static indexes are translated from the original storage once, and re-used multiple times.
Static,
// Direct indexes are never transated and are used directly from the source buffer. They are
// the fastest available path.
Direct,
// Not a real storage type.
Invalid,
};
IndexStorageType ClassifyIndexStorage(const gl::State &glState,
const gl::Buffer *elementArrayBuffer,
GLenum elementType,
GLenum destElementType,
unsigned int offset,
bool *needsTranslation);
// Used for state change notifications between buffers and vertex arrays. // Used for state change notifications between buffers and vertex arrays.
using OnBufferDataDirtyBinding = angle::ChannelBinding<size_t, const gl::Context *>; using OnBufferDataDirtyBinding = angle::ChannelBinding<size_t, const gl::Context *>;
using OnBufferDataDirtyChannel = angle::BroadcastChannel<size_t, const gl::Context *>; using OnBufferDataDirtyChannel = angle::BroadcastChannel<size_t, const gl::Context *>;
......
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