Commit 7d8585b8 by Jamie Madill

D3D11: Implement dirty bits for VertexArray11.

Translated attributes are now stored in the VertexArray11 in a cache, and only updated when dirty bits change. Currently dynamic attributes must be re-translated every call, so these are stored in a list and processed repeatedly. This skips doing a lot of the VertexDataManager work for vertex attributes that don't change between draw calls. Current value attributes, which correspond to disabled attributes that the program will pulls vertex data from, are owned by the Context, so these need to be handled outside of the VertexArray11. Further changes will be necessary to reduce the redundant work we do in the InputLayoutCache. We shouldn't need to re-check the cache if nothing relevant changed. This give about a 23% performance improvement on the draw call benchmark on my machine. BUG=angleproject:1327 Change-Id: I7fb944d32ea7e6c78b9e478406bdb7e10a7fc05b Reviewed-on: https://chromium-review.googlesource.com/330173Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent aa57aa4c
......@@ -29,9 +29,7 @@ VertexArray::Data::~Data()
}
VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs)
: mId(id),
mVertexArray(factory->createVertexArray(mData)),
mData(maxAttribs)
: mId(id), mData(maxAttribs), mVertexArray(factory->createVertexArray(mData))
{
}
......
......@@ -114,10 +114,10 @@ class VertexArray final : public LabeledObject
private:
GLuint mId;
rx::VertexArrayImpl *mVertexArray;
Data mData;
DirtyBits mDirtyBits;
rx::VertexArrayImpl *mVertexArray;
};
}
......
......@@ -161,13 +161,13 @@ void BufferD3D::invalidateStaticData()
// Creates static buffers if sufficient used data has been left unmodified
void BufferD3D::promoteStaticUsage(int dataSize)
{
if (mStaticVertexBuffers.empty() && !mStaticIndexBuffer)
if (mUsage == D3DBufferUsage::DYNAMIC)
{
mUnmodifiedDataUse += dataSize;
if (mUnmodifiedDataUse > 3 * getSize())
{
initializeStaticData();
updateD3DBufferUsage(GL_STATIC_DRAW);
}
}
}
......
......@@ -43,8 +43,8 @@ class BufferD3D : public BufferImpl
StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute);
StaticIndexBufferInterface *getStaticIndexBuffer();
void initializeStaticData();
void invalidateStaticData();
virtual void initializeStaticData();
virtual void invalidateStaticData();
void promoteStaticUsage(int dataSize);
......
......@@ -55,7 +55,6 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup()
{
mTranslatedAttribCache.clear();
mScratchMemoryBuffer.resize(0);
for (auto &incompleteTexture : mIncompleteTextures)
{
......
......@@ -282,8 +282,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
void initializeDebugAnnotator();
gl::DebugAnnotator *mAnnotator;
std::vector<TranslatedAttribute> mTranslatedAttribCache;
bool mPresentPathFastEnabled;
private:
......
......@@ -80,7 +80,7 @@ class VertexBufferInterface : angle::NonCopyable
unsigned int getSerial() const;
VertexBuffer* getVertexBuffer() const;
VertexBuffer *getVertexBuffer() const;
protected:
gl::Error discard();
......
......@@ -9,6 +9,7 @@
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "common/BitSetIterator.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/Program.h"
......@@ -201,7 +202,7 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
const gl::VertexArray *vertexArray = state.getVertexArray();
const auto &vertexAttributes = vertexArray->getVertexAttributes();
mDynamicAttributeIndexesCache.clear();
mDynamicAttribsMaskCache.reset();
const gl::Program *program = state.getProgram();
translatedAttribs->clear();
......@@ -241,7 +242,7 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
}
case VertexStorageType::DYNAMIC:
// Dynamic attributes must be handled together.
mDynamicAttributeIndexesCache.push_back(attribIndex);
mDynamicAttribsMaskCache.set(attribIndex);
break;
case VertexStorageType::DIRECT:
// Update translated data for direct attributes.
......@@ -262,12 +263,12 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
}
}
if (mDynamicAttributeIndexesCache.empty())
if (mDynamicAttribsMaskCache.none())
{
gl::Error(GL_NO_ERROR);
}
return storeDynamicAttribs(translatedAttribs, mDynamicAttributeIndexesCache, start, count,
return storeDynamicAttribs(translatedAttribs, mDynamicAttribsMaskCache, start, count,
instances);
}
......@@ -365,13 +366,13 @@ gl::Error VertexDataManager::StoreStaticAttrib(TranslatedAttribute *translated,
gl::Error VertexDataManager::storeDynamicAttribs(
std::vector<TranslatedAttribute> *translatedAttribs,
const std::vector<size_t> &dynamicAttribIndexes,
const gl::AttributesMask &dynamicAttribsMask,
GLint start,
GLsizei count,
GLsizei instances)
{
// Reserve the required space for the dynamic buffers.
for (size_t attribIndex : dynamicAttribIndexes)
for (auto attribIndex : angle::IterateBitSet(dynamicAttribsMask))
{
const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
gl::Error error = reserveSpaceForAttrib(dynamicAttrib, count, instances);
......@@ -382,7 +383,7 @@ gl::Error VertexDataManager::storeDynamicAttribs(
}
// Store dynamic attributes
for (size_t attribIndex : dynamicAttribIndexes)
for (auto attribIndex : angle::IterateBitSet(dynamicAttribsMask))
{
auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
gl::Error error = storeDynamicAttrib(dynamicAttrib, start, count, instances);
......@@ -391,8 +392,14 @@ gl::Error VertexDataManager::storeDynamicAttribs(
unmapStreamingBuffer();
return error;
}
}
unmapStreamingBuffer();
// Promote static usage of dynamic buffers.
// Promote static usage of dynamic buffers.
for (auto attribIndex : angle::IterateBitSet(dynamicAttribsMask))
{
auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
gl::Buffer *buffer = dynamicAttrib->attribute->buffer.get();
if (buffer)
{
......@@ -402,7 +409,6 @@ gl::Error VertexDataManager::storeDynamicAttribs(
}
}
unmapStreamingBuffer();
return gl::Error(GL_NO_ERROR);
}
......
......@@ -10,9 +10,10 @@
#ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_
#define LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Constants.h"
#include "libANGLE/VertexAttribute.h"
#include "common/angleutils.h"
namespace gl
{
......@@ -92,7 +93,7 @@ class VertexDataManager : angle::NonCopyable
GLsizei instances);
gl::Error storeDynamicAttribs(std::vector<TranslatedAttribute> *translatedAttribs,
const std::vector<size_t> &dynamicAttribIndexes,
const gl::AttributesMask &dynamicAttribsMask,
GLint start,
GLsizei count,
GLsizei instances);
......@@ -127,7 +128,7 @@ class VertexDataManager : angle::NonCopyable
StreamingVertexBufferInterface *mStreamingBuffer;
std::vector<CurrentValueState> mCurrentValueCache;
std::vector<size_t> mDynamicAttributeIndexesCache;
gl::AttributesMask mDynamicAttribsMaskCache;
};
} // namespace rx
......
......@@ -127,7 +127,7 @@ class Buffer11::BufferStorage : angle::NonCopyable
class Buffer11::NativeStorage : public Buffer11::BufferStorage
{
public:
NativeStorage(Renderer11 *renderer, BufferUsage usage);
NativeStorage(Renderer11 *renderer, BufferUsage usage, const NotificationSet *onStorageChanged);
~NativeStorage() override;
bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; }
......@@ -149,6 +149,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
unsigned int bufferSize);
ID3D11Buffer *mNativeStorage;
const NotificationSet *mOnStorageChanged;
};
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
......@@ -664,23 +665,7 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
if (!newStorage)
{
if (usage == BUFFER_USAGE_PIXEL_PACK)
{
newStorage = new PackStorage(mRenderer);
}
else if (usage == BUFFER_USAGE_SYSTEM_MEMORY)
{
newStorage = new SystemMemoryStorage(mRenderer);
}
else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX)
{
newStorage = new EmulatedIndexedStorage(mRenderer);
}
else
{
// buffer is not allocated, create it
newStorage = new NativeStorage(mRenderer, usage);
}
newStorage = allocateStorage(usage);
}
// resize buffer
......@@ -698,6 +683,23 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
return newStorage;
}
Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) const
{
switch (usage)
{
case BUFFER_USAGE_PIXEL_PACK:
return new PackStorage(mRenderer);
case BUFFER_USAGE_SYSTEM_MEMORY:
return new SystemMemoryStorage(mRenderer);
case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
return new NativeStorage(mRenderer, usage, &mDirectBufferDirtyCallbacks);
default:
return new NativeStorage(mRenderer, usage, nullptr);
}
}
Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size)
{
BufferStorage *newStorage;
......@@ -709,7 +711,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset
if (!cacheEntry->storage)
{
cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM);
cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM);
cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
}
......@@ -848,8 +850,43 @@ bool Buffer11::supportsDirectBinding() const
{
// Do not support direct buffers for dynamic data. The streaming buffer
// offers better performance for data which changes every frame.
// Check for absence of static buffer interfaces to detect dynamic data.
return (!mStaticVertexBuffers.empty() && mStaticIndexBuffer);
return (mUsage == D3DBufferUsage::STATIC);
}
void Buffer11::initializeStaticData()
{
BufferD3D::initializeStaticData();
// Notify when static data changes.
mStaticBufferDirtyCallbacks.signal();
}
void Buffer11::invalidateStaticData()
{
BufferD3D::invalidateStaticData();
// Notify when static data changes.
mStaticBufferDirtyCallbacks.signal();
}
void Buffer11::addStaticBufferDirtyCallback(const NotificationCallback *callback)
{
mStaticBufferDirtyCallbacks.add(callback);
}
void Buffer11::removeStaticBufferDirtyCallback(const NotificationCallback *callback)
{
mStaticBufferDirtyCallbacks.remove(callback);
}
void Buffer11::addDirectBufferDirtyCallback(const NotificationCallback *callback)
{
mDirectBufferDirtyCallbacks.add(callback);
}
void Buffer11::removeDirectBufferDirtyCallback(const NotificationCallback *callback)
{
mDirectBufferDirtyCallbacks.remove(callback);
}
Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
......@@ -874,8 +911,10 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
return gl::Error(GL_NO_ERROR);
}
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage)
: BufferStorage(renderer, usage), mNativeStorage(nullptr)
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
BufferUsage usage,
const NotificationSet *onStorageChanged)
: BufferStorage(renderer, usage), mNativeStorage(nullptr), mOnStorageChanged(onStorageChanged)
{
}
......@@ -987,6 +1026,12 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
mBufferSize = bufferDesc.ByteWidth;
// Notify that the storage has changed.
if (mOnStorageChanged)
{
mOnStorageChanged->signal();
}
return gl::Error(GL_NO_ERROR);
}
......@@ -1426,4 +1471,4 @@ void Buffer11::SystemMemoryStorage::unmap()
{
// No-op
}
}
} // namespace rx
......@@ -13,6 +13,7 @@
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace gl
{
......@@ -66,24 +67,38 @@ class Buffer11 : public BufferD3D
ID3D11Buffer *getEmulatedIndexedBuffer(SourceIndexData *indexInfo, const TranslatedAttribute *attribute);
ID3D11Buffer *getConstantBufferRange(GLintptr offset, GLsizeiptr size);
ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat);
bool isMapped() const { return mMappedStorage != NULL; }
bool isMapped() const { return mMappedStorage != nullptr; }
gl::Error packPixels(const gl::FramebufferAttachment &readAttachment,
const PackPixelsParams &params);
size_t getTotalCPUBufferMemoryBytes() const;
// BufferD3D implementation
virtual size_t getSize() const { return mSize; }
virtual bool supportsDirectBinding() const;
size_t getSize() const override { return mSize; }
bool supportsDirectBinding() const override;
gl::Error getData(const uint8_t **outData) override;
void initializeStaticData() override;
void invalidateStaticData() override;
// BufferImpl implementation
virtual gl::Error setData(const void* data, size_t size, GLenum usage);
virtual gl::Error setSubData(const void* data, size_t size, size_t offset);
virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
virtual gl::Error map(GLenum access, GLvoid **mapPtr);
virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr);
virtual gl::Error unmap(GLboolean *result);
virtual void markTransformFeedbackUsage();
gl::Error setData(const void *data, size_t size, GLenum usage) override;
gl::Error setSubData(const void *data, size_t size, size_t offset) override;
gl::Error copySubData(BufferImpl *source,
GLintptr sourceOffset,
GLintptr destOffset,
GLsizeiptr size) override;
gl::Error map(GLenum access, GLvoid **mapPtr) override;
gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) override;
gl::Error unmap(GLboolean *result) override;
void markTransformFeedbackUsage() override;
// We use two set of dirty callbacks for two events. Static buffers are marked dirty whenever
// the data is changed, because they must be re-translated. Direct buffers only need to be
// updated when the underlying ID3D11Buffer pointer changes - hopefully far less often.
void addStaticBufferDirtyCallback(const NotificationCallback *callback);
void removeStaticBufferDirtyCallback(const NotificationCallback *callback);
void addDirectBufferDirtyCallback(const NotificationCallback *callback);
void removeDirectBufferDirtyCallback(const NotificationCallback *callback);
private:
class BufferStorage;
......@@ -92,13 +107,6 @@ class Buffer11 : public BufferD3D
class PackStorage;
class SystemMemoryStorage;
Renderer11 *mRenderer;
size_t mSize;
BufferStorage *mMappedStorage;
std::vector<BufferStorage*> mBufferStorages;
struct ConstantBufferCacheEntry
{
ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { }
......@@ -107,6 +115,26 @@ class Buffer11 : public BufferD3D
unsigned int lruCount;
};
void markBufferUsage();
NativeStorage *getStagingStorage();
PackStorage *getPackStorage();
gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut);
void updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize);
BufferStorage *getBufferStorage(BufferUsage usage);
BufferStorage *getLatestBufferStorage() const;
BufferStorage *getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size);
BufferStorage *allocateStorage(BufferUsage usage) const;
Renderer11 *mRenderer;
size_t mSize;
BufferStorage *mMappedStorage;
std::vector<BufferStorage *> mBufferStorages;
// Cache of D3D11 constant buffer for specific ranges of buffer data.
// This is used to emulate UBO ranges on 11.0 devices.
// Constant buffers are indexed by there start offset.
......@@ -120,20 +148,10 @@ class Buffer11 : public BufferD3D
unsigned int mReadUsageCount;
void markBufferUsage();
NativeStorage *getStagingStorage();
PackStorage *getPackStorage();
gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut);
void updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize);
BufferStorage *getBufferStorage(BufferUsage usage);
BufferStorage *getLatestBufferStorage() const;
BufferStorage *getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size);
void invalidateEmulatedIndexedBuffer();
NotificationSet mStaticBufferDirtyCallbacks;
NotificationSet mDirectBufferDirtyCallbacks;
};
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_
......@@ -94,7 +94,8 @@ Optional<size_t> FindFirstNonInstanced(
}
void SortAttributesByLayout(const gl::Program *program,
const std::vector<TranslatedAttribute> &unsortedAttributes,
const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
AttribIndexArray *sortedD3DSemanticsOut,
std::vector<const TranslatedAttribute *> *sortedAttributesOut)
{
......@@ -112,7 +113,17 @@ void SortAttributesByLayout(const gl::Program *program,
}
(*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic;
(*sortedAttributesOut)[d3dSemantic] = &unsortedAttributes[locationIndex];
const auto *arrayAttrib = &vertexArrayAttribs[locationIndex];
if (arrayAttrib->attribute && arrayAttrib->attribute->enabled)
{
(*sortedAttributesOut)[d3dSemantic] = arrayAttrib;
}
else
{
ASSERT(currentValueAttribs[locationIndex].attribute);
(*sortedAttributesOut)[d3dSemantic] = &currentValueAttribs[locationIndex];
}
}
}
......@@ -209,7 +220,8 @@ void InputLayoutCache::markDirty()
gl::Error InputLayoutCache::applyVertexBuffers(
const gl::State &state,
const std::vector<TranslatedAttribute> &unsortedAttributes,
const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode,
TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance)
......@@ -223,7 +235,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
AttribIndexArray sortedSemanticIndices;
SortAttributesByLayout(program, unsortedAttributes, &sortedSemanticIndices,
SortAttributesByLayout(program, vertexArrayAttribs, currentValueAttribs, &sortedSemanticIndices,
&mCurrentAttributes);
// If we are using FL 9_3, make sure the first attribute is not instanced
......
......@@ -46,7 +46,8 @@ class InputLayoutCache : angle::NonCopyable
void markDirty();
gl::Error applyVertexBuffers(const gl::State &state,
const std::vector<TranslatedAttribute> &attributes,
const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode,
TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance);
......
......@@ -189,23 +189,17 @@ RenderTarget11::~RenderTarget11()
void RenderTarget11::addDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.insert(callback);
mDirtyCallbacks.add(callback);
}
void RenderTarget11::removeDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.erase(callback);
mDirtyCallbacks.remove(callback);
}
void RenderTarget11::signalDirty()
{
if (mDirtyCallbacks.empty())
return;
for (const auto &callback : mDirtyCallbacks)
{
(*callback)();
}
mDirtyCallbacks.signal();
// Clear the signal list. We can't do this in the callback because it mutates the iterator.
mDirtyCallbacks.clear();
......
......@@ -40,8 +40,7 @@ class RenderTarget11 : public RenderTargetD3D
d3d11::ANGLEFormat getANGLEFormat() const { return mANGLEFormat; }
protected:
std::set<const NotificationCallback *> mDirtyCallbacks;
NotificationSet mDirtyCallbacks;
d3d11::ANGLEFormat mANGLEFormat;
};
......
......@@ -833,9 +833,6 @@ void Renderer11::initializeDevice()
ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel",
angleFeatureLevel,
NUM_ANGLE_FEATURE_LEVELS);
// TODO(jmadill): use context caps, and place in common D3D location
mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
}
void Renderer11::populateRenderer11DeviceCaps()
......@@ -1498,7 +1495,17 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
GLsizei instances,
TranslatedIndexData *indexInfo)
{
gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
const auto &vertexArray = state.getVertexArray();
auto *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
gl::Error error = vertexArray11->updateDirtyAndDynamicAttribs(mVertexDataManager, state, first,
count, instances);
if (error.isError())
{
return error;
}
error = mStateManager.updateCurrentValueAttribs(state, mVertexDataManager);
if (error.isError())
{
return error;
......@@ -1515,8 +1522,10 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
{
numIndicesPerInstance = count;
}
return mInputLayoutCache.applyVertexBuffers(state, mTranslatedAttribCache, mode, indexInfo,
numIndicesPerInstance);
const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
const auto &currentValueAttribs = mStateManager.getCurrentValueAttribs();
return mInputLayoutCache.applyVertexBuffers(state, vertexArrayAttribs, currentValueAttribs,
mode, indexInfo, numIndicesPerInstance);
}
gl::Error Renderer11::applyIndexBuffer(const gl::Data &data,
......@@ -2462,6 +2471,7 @@ void Renderer11::markAllStateDirty()
void Renderer11::releaseDeviceResources()
{
mStateManager.deinitialize();
mStateCache.clear();
mInputLayoutCache.clear();
......@@ -3404,7 +3414,7 @@ BufferImpl *Renderer11::createBuffer()
VertexArrayImpl *Renderer11::createVertexArray(const gl::VertexArray::Data &data)
{
return new VertexArray11(data);
return new VertexArray11(data, this);
}
QueryImpl *Renderer11::createQuery(GLenum type)
......@@ -4255,4 +4265,5 @@ egl::Error Renderer11::getEGLDevice(DeviceImpl **device)
*device = static_cast<DeviceImpl *>(mEGLDevice);
return egl::Error(EGL_SUCCESS);
}
}
} // namespace rx
......@@ -150,7 +150,9 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurNear(0.0f),
mCurFar(0.0f),
mViewportBounds(),
mRenderTargetIsDirty(false)
mRenderTargetIsDirty(false),
mDirtyCurrentValueAttribs(),
mCurrentValueAttribs()
{
mCurBlendState.blend = false;
mCurBlendState.sourceBlendRGB = GL_ONE;
......@@ -191,6 +193,9 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurRasterState.polygonOffsetUnits = 0.0f;
mCurRasterState.pointDrawMode = false;
mCurRasterState.multiSample = false;
// Initially all current value attributes must be updated on first use.
mDirtyCurrentValueAttribs.flip();
}
StateManager11::~StateManager11()
......@@ -241,7 +246,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
return;
}
for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
{
switch (dirtyBit)
{
......@@ -461,6 +466,13 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
mRenderTargetIsDirty = true;
break;
default:
if (dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 &&
dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX)
{
size_t attribIndex =
static_cast<size_t>(dirtyBit - gl::State::DIRTY_BIT_CURRENT_VALUE_0);
mDirtyCurrentValueAttribs.set(attribIndex);
}
break;
}
}
......@@ -958,6 +970,13 @@ void StateManager11::initialize(const gl::Caps &caps)
// Initialize cached NULL SRV block
mNullSRVs.resize(caps.maxTextureImageUnits, nullptr);
mCurrentValueAttribs.resize(caps.maxVertexAttributes);
}
void StateManager11::deinitialize()
{
mCurrentValueAttribs.clear();
}
gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
......@@ -1078,4 +1097,40 @@ gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
return gl::Error(GL_NO_ERROR);
}
gl::Error StateManager11::updateCurrentValueAttribs(const gl::State &state,
VertexDataManager *vertexDataManager)
{
const auto &activeAttribsMask = state.getProgram()->getActiveAttribLocationsMask();
const auto &dirtyActiveAttribs = (activeAttribsMask & mDirtyCurrentValueAttribs);
const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
for (auto attribIndex : angle::IterateBitSet(dirtyActiveAttribs))
{
if (vertexAttributes[attribIndex].enabled)
continue;
mDirtyCurrentValueAttribs.reset(attribIndex);
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
auto currentValueAttrib = &mCurrentValueAttribs[attribIndex];
currentValueAttrib->currentValueType = currentValue.Type;
currentValueAttrib->attribute = &vertexAttributes[attribIndex];
gl::Error error = vertexDataManager->storeCurrentValue(currentValue, currentValueAttrib,
static_cast<size_t>(attribIndex));
if (error.isError())
{
return error;
}
}
return gl::Error(GL_NO_ERROR);
}
const std::vector<TranslatedAttribute> &StateManager11::getCurrentValueAttribs() const
{
return mCurrentValueAttribs;
}
} // namespace rx
......@@ -48,6 +48,7 @@ class StateManager11 final : angle::NonCopyable
~StateManager11();
void initialize(const gl::Caps &caps);
void deinitialize();
void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
gl::Error setBlendState(const gl::Framebuffer *framebuffer,
......@@ -91,6 +92,11 @@ class StateManager11 final : angle::NonCopyable
void onDeleteQueryObject(Query11 *query);
gl::Error onMakeCurrent(const gl::Data &data);
gl::Error updateCurrentValueAttribs(const gl::State &state,
VertexDataManager *vertexDataManager);
const std::vector<TranslatedAttribute> &getCurrentValueAttribs() const;
private:
void setViewportBounds(const int width, const int height);
void unsetConflictingSRVs(gl::SamplerType shaderType,
......@@ -186,6 +192,10 @@ class StateManager11 final : angle::NonCopyable
// A block of NULL pointers, cached so we don't re-allocate every draw call
std::vector<ID3D11ShaderResourceView *> mNullSRVs;
// Current translations of "Current-Value" data - owned by Context, not VertexArray.
gl::AttributesMask mDirtyCurrentValueAttribs;
std::vector<TranslatedAttribute> mCurrentValueAttribs;
};
} // namespace rx
......
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VertexArray11:
// Implementation of rx::VertexArray11.
//
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "common/BitSetIterator.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
namespace rx
{
namespace
{
size_t GetAttribIndex(unsigned long dirtyBit)
{
if (dirtyBit >= gl::VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
dirtyBit < gl::VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
{
return dirtyBit - gl::VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED;
}
if (dirtyBit >= gl::VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
dirtyBit < gl::VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
{
return dirtyBit - gl::VertexArray::DIRTY_BIT_ATTRIB_0_POINTER;
}
ASSERT(dirtyBit >= gl::VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR &&
dirtyBit < gl::VertexArray::DIRTY_BIT_ATTRIB_MAX_DIVISOR);
return static_cast<size_t>(dirtyBit) - gl::VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR;
}
} // anonymous namespace
VertexArray11::VertexArray11(const gl::VertexArray::Data &data, Renderer11 *renderer)
: VertexArrayImpl(data),
mRenderer(renderer),
mAttributeStorageTypes(data.getVertexAttributes().size(), VertexStorageType::CURRENT_VALUE),
mTranslatedAttribs(data.getVertexAttributes().size()),
mCurrentBuffers(data.getVertexAttributes().size())
{
for (size_t attribIndex = 0; attribIndex < mCurrentBuffers.size(); ++attribIndex)
{
auto callback = [this, attribIndex]()
{
this->markBufferDataDirty(attribIndex);
};
mOnBufferDataDirty.push_back(callback);
}
}
VertexArray11::~VertexArray11()
{
for (auto &binding : mCurrentBuffers)
{
binding.set(nullptr);
}
}
void VertexArray11::syncState(const gl::VertexArray::DirtyBits &dirtyBits)
{
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
continue;
size_t attribIndex = GetAttribIndex(dirtyBit);
mAttribsToUpdate.set(attribIndex);
}
}
void VertexArray11::updateVertexAttribStorage(size_t attribIndex)
{
const auto &attrib = mData.getVertexAttribute(attribIndex);
// Note: having an unchanged storage type doesn't mean the attribute is clean.
auto oldStorageType = mAttributeStorageTypes[attribIndex];
auto newStorageType = ClassifyAttributeStorage(attrib);
mAttributeStorageTypes[attribIndex] = newStorageType;
if (newStorageType == VertexStorageType::DYNAMIC)
{
if (oldStorageType != VertexStorageType::DYNAMIC)
{
// Sync dynamic attribs in a different set.
mAttribsToTranslate.reset(attribIndex);
mDynamicAttribsMask.set(attribIndex);
}
}
else
{
mAttribsToTranslate.set(attribIndex);
if (oldStorageType == VertexStorageType::DYNAMIC)
{
ASSERT(mDynamicAttribsMask[attribIndex]);
mDynamicAttribsMask.reset(attribIndex);
}
}
gl::Buffer *oldBufferGL = mCurrentBuffers[attribIndex].get();
gl::Buffer *newBufferGL = attrib.buffer.get();
Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr;
Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr;
if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType)
{
// Note that for static callbacks, promotion to a static buffer from a dynamic buffer means
// we need to tag dynamic buffers with static callbacks.
if (oldBuffer11 != nullptr)
{
if (oldStorageType == VertexStorageType::DIRECT)
{
oldBuffer11->removeDirectBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
else if (oldStorageType == VertexStorageType::STATIC ||
oldStorageType == VertexStorageType::DYNAMIC)
{
oldBuffer11->removeStaticBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
}
if (newBuffer11 != nullptr)
{
if (newStorageType == VertexStorageType::DIRECT)
{
newBuffer11->addDirectBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
else if (newStorageType == VertexStorageType::STATIC ||
newStorageType == VertexStorageType::DYNAMIC)
{
newBuffer11->addStaticBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
}
mCurrentBuffers[attribIndex] = attrib.buffer;
}
}
gl::Error VertexArray11::updateDirtyAndDynamicAttribs(VertexDataManager *vertexDataManager,
const gl::State &state,
GLint start,
GLsizei count,
GLsizei instances)
{
const gl::Program *program = state.getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
if (mAttribsToUpdate.any())
{
// Skip attrib locations the program doesn't use.
const auto &activeToUpdate = (mAttribsToUpdate & activeLocations);
for (auto toUpdateIndex : angle::IterateBitSet(activeToUpdate))
{
mAttribsToUpdate.reset(toUpdateIndex);
updateVertexAttribStorage(toUpdateIndex);
}
}
const auto &attribs = mData.getVertexAttributes();
if (mAttribsToTranslate.any())
{
// Skip attrib locations the program doesn't use, saving for the next frame.
const auto &dirtyActiveAttribs = (mAttribsToTranslate & activeLocations);
for (auto dirtyAttribIndex : angle::IterateBitSet(dirtyActiveAttribs))
{
mAttribsToTranslate.reset(dirtyAttribIndex);
auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(dirtyAttribIndex));
// Record basic attrib info
translatedAttrib->attribute = &attribs[dirtyAttribIndex];
translatedAttrib->currentValueType = currentValue.Type;
translatedAttrib->divisor = translatedAttrib->attribute->divisor;
switch (mAttributeStorageTypes[dirtyAttribIndex])
{
case VertexStorageType::DIRECT:
VertexDataManager::StoreDirectAttrib(translatedAttrib, start);
break;
case VertexStorageType::STATIC:
{
auto error = VertexDataManager::StoreStaticAttrib(translatedAttrib, start,
count, instances);
if (error.isError())
{
return error;
}
break;
}
case VertexStorageType::CURRENT_VALUE:
// Current value attribs are managed by the StateManager11.
break;
default:
UNREACHABLE();
break;
}
}
}
if (mDynamicAttribsMask.any())
{
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
for (auto dynamicAttribIndex : angle::IterateBitSet(activeDynamicAttribs))
{
auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(dynamicAttribIndex));
// Record basic attrib info
dynamicAttrib->attribute = &attribs[dynamicAttribIndex];
dynamicAttrib->currentValueType = currentValue.Type;
dynamicAttrib->divisor = dynamicAttrib->attribute->divisor;
}
return vertexDataManager->storeDynamicAttribs(&mTranslatedAttribs, activeDynamicAttribs,
start, count, instances);
}
return gl::Error(GL_NO_ERROR);
}
const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
{
return mTranslatedAttribs;
}
void VertexArray11::markBufferDataDirty(size_t attribIndex)
{
ASSERT(mAttributeStorageTypes[attribIndex] != VertexStorageType::CURRENT_VALUE);
// This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(attribIndex);
}
} // namespace rx
......@@ -19,13 +19,41 @@ class Renderer11;
class VertexArray11 : public VertexArrayImpl
{
public:
VertexArray11(const gl::VertexArray::Data &data)
: VertexArrayImpl(data)
{
}
virtual ~VertexArray11() {}
VertexArray11(const gl::VertexArray::Data &data, Renderer11 *renderer);
~VertexArray11() override;
void syncState(const gl::VertexArray::DirtyBits &dirtyBits) override;
gl::Error updateDirtyAndDynamicAttribs(VertexDataManager *vertexDataManager,
const gl::State &state,
GLint start,
GLsizei count,
GLsizei instances);
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
private:
void updateVertexAttribStorage(size_t attribIndex);
void markBufferDataDirty(size_t attribIndex);
Renderer11 *mRenderer;
std::vector<VertexStorageType> mAttributeStorageTypes;
std::vector<TranslatedAttribute> mTranslatedAttribs;
// The mask of attributes marked as dynamic.
gl::AttributesMask mDynamicAttribsMask;
// A mask of attributes that need to be re-evaluated.
gl::AttributesMask mAttribsToUpdate;
// A set of attributes we know are dirty, and need to be re-translated.
gl::AttributesMask mAttribsToTranslate;
// We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks.
std::vector<BindingPointer<gl::Buffer>> mCurrentBuffers;
std::vector<NotificationCallback> mOnBufferDataDirty;
};
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_
......@@ -1716,4 +1716,40 @@ bool UsePresentPathFast(const Renderer11 *renderer,
renderer->presentPathFastEnabled());
}
NotificationSet::NotificationSet()
{
}
NotificationSet::~NotificationSet()
{
}
void NotificationSet::add(const NotificationCallback *callback)
{
ASSERT(mCallbacks.count(callback) == 0);
mCallbacks.insert(callback);
}
void NotificationSet::remove(const NotificationCallback *callback)
{
ASSERT(mCallbacks.count(callback) == 1);
mCallbacks.erase(callback);
}
void NotificationSet::signal() const
{
if (mCallbacks.empty())
return;
for (const auto *callback : mCallbacks)
{
(*callback)();
}
}
void NotificationSet::clear()
{
mCallbacks.clear();
}
} // namespace rx
......@@ -406,6 +406,21 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm
using NotificationCallback = std::function<void()>;
class NotificationSet final : angle::NonCopyable
{
public:
NotificationSet();
~NotificationSet();
void add(const NotificationCallback *callback);
void remove(const NotificationCallback *callback);
void signal() const;
void clear();
private:
std::set<const NotificationCallback *> mCallbacks;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
......@@ -154,6 +154,8 @@ void Renderer9::release()
{
RendererD3D::cleanup();
mTranslatedAttribCache.clear();
releaseDeviceResources();
SafeDelete(mEGLDevice);
......@@ -364,7 +366,6 @@ void Renderer9::initializeDevice()
mVertexDataManager = new VertexDataManager(this);
mIndexDataManager = new IndexDataManager(this, getRendererClass());
// TODO(jmadill): use context caps, and place in common D3D location
mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
}
......
......@@ -393,6 +393,7 @@ class Renderer9 : public RendererD3D
UINT mMaxNullColorbufferLRU;
DeviceD3D *mEGLDevice;
std::vector<TranslatedAttribute> mTranslatedAttribCache;
};
}
......
......@@ -387,6 +387,7 @@
'libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp',
'libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.h',
'libANGLE/renderer/d3d/d3d11/texture_format_table.h',
'libANGLE/renderer/d3d/d3d11/VertexArray11.cpp',
'libANGLE/renderer/d3d/d3d11/VertexArray11.h',
'libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp',
'libANGLE/renderer/d3d/d3d11/VertexBuffer11.h',
......
......@@ -207,6 +207,31 @@ TEST_P(BufferDataTest, DISABLED_HugeSetDataShouldNotCrash)
delete[] data;
}
// Internally in D3D, we promote dynamic data to static after many draw loops. This code tests
// path.
TEST_P(BufferDataTest, RepeatedDrawWithDynamic)
{
std::vector<GLfloat> data;
for (int i = 0; i < 16; ++i)
{
data.push_back(static_cast<GLfloat>(i));
}
glUseProgram(mProgram);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * data.size(), data.data(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(mAttribLocation);
for (int drawCount = 0; drawCount < 40; ++drawCount)
{
drawQuad(mProgram, "position", 0.5f);
}
EXPECT_GL_NO_ERROR();
}
class IndexedBufferCopyTest : public ANGLETest
{
protected:
......
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