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,
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
bool IsOffsetAligned(GLenum elementType, unsigned int offset)
{
return (offset % ElementTypeSize(elementType) == 0);
}
// IndexDataManager implementation.
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory)
: mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt()
{
......@@ -170,7 +192,7 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context,
unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
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
if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
......@@ -182,10 +204,8 @@ gl::Error IndexDataManager::prepareIndexData(const gl::Context *context,
translated->startOffset = offset;
return gl::NoError();
}
else
{
translated->storage = nullptr;
}
translated->storage = nullptr;
// Case 2b: use a static translated copy or fall back to streaming
StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
......
......@@ -98,6 +98,8 @@ GLenum GetIndexTranslationDestType(GLenum srcType,
const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround);
bool IsOffsetAligned(GLenum elementType, unsigned int offset);
} // namespace rx
#endif // LIBANGLE_INDEXDATAMANAGER_H_
......@@ -473,6 +473,9 @@ gl::Error Buffer11::copySubData(const gl::Context *context,
mSize = std::max<size_t>(mSize, destOffset + size);
invalidateStaticData(context);
// Also notify that direct buffers are dirty.
mDirectBroadcastChannel.signal(context);
return gl::NoError();
}
......@@ -755,6 +758,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
return new SystemMemoryStorage(mRenderer);
case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_INDEX:
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel);
default:
......
......@@ -22,6 +22,7 @@
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.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/formatutils11.h"
......@@ -126,7 +127,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
GLint start,
TranslatedIndexData *indexInfo)
bool isIndexedRendering)
{
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
const gl::State &state = context->getGLState();
......@@ -161,8 +162,11 @@ gl::Error InputLayoutCache::applyVertexBuffers(
ASSERT(attrib.vertexBuffer.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)
{
const uint8_t *bufferData = nullptr;
......
......@@ -90,7 +90,7 @@ class InputLayoutCache : angle::NonCopyable
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
GLint start,
TranslatedIndexData *indexInfo);
bool isIndexedRendering);
gl::Error updateVertexOffsetsForPointSpritesEmulation(
Renderer11 *renderer,
......
......@@ -1514,7 +1514,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
}
DrawCallVertexParams vertexParams(startVertex, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
if (glState.isTransformFeedbackActiveUnpaused())
{
......@@ -1651,10 +1651,9 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances);
TranslatedIndexData indexInfo;
ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
usePrimitiveRestartWorkaround, &indexInfo));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
int startVertex = static_cast<int>(vertexParams.firstVertex());
int baseVertex = -startVertex;
......@@ -1742,7 +1741,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
if (!DrawCallNeedsTranslation(context, mode))
{
DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, nullptr));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
......@@ -1759,7 +1758,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
GLuint first = args->first;
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)
{
......@@ -1796,13 +1795,12 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
TranslatedIndexData indexInfo;
if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type))
{
ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(),
usePrimitiveRestartWorkaround, &indexInfo));
usePrimitiveRestartWorkaround));
DrawCallVertexParams vertexParams(0, 0, 0);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, &indexInfo));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
......@@ -1827,11 +1825,11 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
gl::HasIndexRange lazyIndexRange(const_cast<gl::Context *>(context), count, type, indices);
ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
usePrimitiveRestartWorkaround, &indexInfo));
usePrimitiveRestartWorkaround));
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);
......
......@@ -562,6 +562,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mAppliedIB(nullptr),
mAppliedIBFormat(DXGI_FORMAT_UNKNOWN),
mAppliedIBOffset(0),
mIndexBufferIsDirty(false),
mVertexDataManager(renderer),
mIndexDataManager(renderer),
mIsMultiviewEnabled(false),
......@@ -952,6 +953,8 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
// internal cache of TranslatedAttributes, and they CurrentValue attributes are
// owned by the StateManager11/Context.
mDirtyCurrentValueAttribs.set();
// Invalidate the cached index buffer.
mIndexBufferIsDirty = true;
break;
case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
invalidateTexturesAndSamplers();
......@@ -2486,7 +2489,7 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
GLenum mode,
const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo)
bool isIndexedRendering)
{
const auto &state = context->getGLState();
const gl::VertexArray *vertexArray = state.getVertexArray();
......@@ -2544,7 +2547,7 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// Update the applied vertex buffers.
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
// buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger
......@@ -2564,18 +2567,27 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context,
GLsizei count,
GLenum type,
const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround,
TranslatedIndexData *indexInfo)
bool usePrimitiveRestartWorkaround)
{
const auto &glState = context->getGLState();
gl::VertexArray *vao = glState.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
const auto &glState = context->getGLState();
gl::VertexArray *vao = glState.getVertexArray();
VertexArray11 *vao11 = GetImplAs<VertexArray11>(vao);
GLenum dstType =
GLenum destElementType =
GetIndexTranslationDestType(type, lazyIndexRange, usePrimitiveRestartWorkaround);
ANGLE_TRY(mIndexDataManager.prepareIndexData(context, type, dstType, count, elementArrayBuffer,
indices, indexInfo));
if (!vao11->updateElementArrayStorage(context, type, destElementType, indices) &&
!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;
DXGI_FORMAT bufferFormat =
......@@ -2594,15 +2606,28 @@ gl::Error StateManager11::applyIndexBuffer(const gl::Context *context,
// Track dirty indices in the index range cache.
indexInfo->srcIndexData.srcIndicesChanged =
setIndexBuffer(buffer, bufferFormat, indexInfo->startOffset);
syncIndexBuffer(buffer, bufferFormat, indexInfo->startOffset);
mIndexBufferIsDirty = false;
vao11->setCachedIndexInfoValid();
return gl::NoError();
}
bool StateManager11::setIndexBuffer(ID3D11Buffer *buffer,
void StateManager11::setIndexBuffer(ID3D11Buffer *buffer,
DXGI_FORMAT indexFormat,
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)
{
mRenderer->getDeviceContext()->IASetIndexBuffer(buffer, indexFormat, offset);
......
......@@ -267,17 +267,16 @@ class StateManager11 final : angle::NonCopyable
gl::Error applyVertexBuffer(const gl::Context *context,
GLenum mode,
const DrawCallVertexParams &vertexParams,
TranslatedIndexData *indexInfo);
bool isIndexedRendering);
gl::Error applyIndexBuffer(const gl::Context *context,
const void *indices,
GLsizei count,
GLenum type,
const gl::HasIndexRange &lazyIndexRange,
bool usePrimitiveRestartWorkaround,
TranslatedIndexData *indexInfo);
bool usePrimitiveRestartWorkaround);
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,
GLsizei emulatedInstanceId);
......@@ -359,6 +358,8 @@ class StateManager11 final : angle::NonCopyable
// Called by the Framebuffer11 directly.
void processFramebufferInvalidation(const gl::Context *context);
bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
enum DirtyBitType
{
DIRTY_BIT_RENDER_TARGET,
......@@ -508,6 +509,7 @@ class StateManager11 final : angle::NonCopyable
ID3D11Buffer *mAppliedIB;
DXGI_FORMAT mAppliedIBFormat;
unsigned int mAppliedIBOffset;
bool mIndexBufferIsDirty;
// Vertex, index and input layouts
VertexDataManager mVertexDataManager;
......
......@@ -19,16 +19,43 @@ using namespace angle;
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)
: VertexArrayImpl(data),
mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE),
mTranslatedAttribs(data.getMaxAttribs()),
mCurrentBuffers(data.getMaxAttribs()),
mAppliedNumViewsToDivisor(1)
mCurrentArrayBuffers(data.getMaxAttribs()),
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()
void VertexArray11::destroy(const gl::Context *context)
{
for (auto &buffer : mCurrentBuffers)
for (auto &buffer : mCurrentArrayBuffers)
{
if (buffer.get())
{
buffer.set(context, nullptr);
}
}
mCurrentElementArrayBuffer.set(context, nullptr);
}
void VertexArray11::syncState(const gl::Context *context,
......@@ -63,12 +92,17 @@ void VertexArray11::syncState(const gl::Context *context,
for (auto dirtyBit : dirtyBits)
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
continue;
size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
// TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
ASSERT(index == mState.getBindingIndexFromAttribIndex(index));
mAttribsToUpdate.set(index);
{
mCachedIndexInfoValid = false;
mLastElementType = GL_NONE;
}
else
{
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)
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)
{
const auto &attrib = mState.getVertexAttribute(attribIndex);
......@@ -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();
Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr;
Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr;
......@@ -160,8 +247,8 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
}
}
mOnBufferDataDirty[attribIndex].bind(newChannel);
mCurrentBuffers[attribIndex].set(context, binding.getBuffer().get());
mOnArrayBufferDataDirty[attribIndex].bind(newChannel);
mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get());
}
}
......@@ -263,14 +350,23 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co
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.
mAttribsToUpdate.set(channelID);
// This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(channelID);
// Changing the vertex attribute state can affect the vertex shader.
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
renderer->getStateManager()->invalidateShaders();
// Changing the vertex attribute state can affect the vertex shader.
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
renderer->getStateManager()->invalidateShaders();
}
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
......@@ -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
......@@ -12,6 +12,7 @@
#include "libANGLE/Framebuffer.h"
#include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/signal_utils.h"
namespace rx
......@@ -48,6 +49,16 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
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:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
......@@ -64,14 +75,23 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
gl::AttributesMask mAttribsToTranslate;
// 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;
// The numViews value used to adjust the divisor.
int mAppliedNumViewsToDivisor;
// If the index buffer needs re-streaming.
GLenum mLastElementType;
unsigned int mLastDrawElementsOffset;
IndexStorageType mCurrentElementArrayStorage;
TranslatedIndexData mCachedIndexInfo;
bool mCachedIndexInfoValid;
};
} // namespace rx
......
......@@ -2381,4 +2381,41 @@ bool IsStreamingIndexData(const gl::Context *context, GLenum srcType)
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
......@@ -392,6 +392,30 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm
bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type);
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.
using OnBufferDataDirtyBinding = angle::ChannelBinding<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