Commit 52b09c2f by Jamie Madill Committed by Commit Bot

Re-re-land "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. Re-land with a fix for the start vertex offset. Re-re-land with a fix for using XFB with deleted buffers. BUG=angleproject:1327 Change-Id: I0fba49515375c149bbf54d933f8d1f747fbb8158 Reviewed-on: https://chromium-review.googlesource.com/338003Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 8c15c574
...@@ -29,9 +29,7 @@ VertexArray::Data::~Data() ...@@ -29,9 +29,7 @@ VertexArray::Data::~Data()
} }
VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs) VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs)
: mId(id), : mId(id), mData(maxAttribs), mVertexArray(factory->createVertexArray(mData))
mVertexArray(factory->createVertexArray(mData)),
mData(maxAttribs)
{ {
} }
......
...@@ -114,10 +114,10 @@ class VertexArray final : public LabeledObject ...@@ -114,10 +114,10 @@ class VertexArray final : public LabeledObject
private: private:
GLuint mId; GLuint mId;
rx::VertexArrayImpl *mVertexArray;
Data mData; Data mData;
DirtyBits mDirtyBits; DirtyBits mDirtyBits;
rx::VertexArrayImpl *mVertexArray;
}; };
} }
......
...@@ -161,13 +161,13 @@ void BufferD3D::invalidateStaticData() ...@@ -161,13 +161,13 @@ void BufferD3D::invalidateStaticData()
// Creates static buffers if sufficient used data has been left unmodified // Creates static buffers if sufficient used data has been left unmodified
void BufferD3D::promoteStaticUsage(int dataSize) void BufferD3D::promoteStaticUsage(int dataSize)
{ {
if (mStaticVertexBuffers.empty() && !mStaticIndexBuffer) if (mUsage == D3DBufferUsage::DYNAMIC)
{ {
mUnmodifiedDataUse += dataSize; mUnmodifiedDataUse += dataSize;
if (mUnmodifiedDataUse > 3 * getSize()) if (mUnmodifiedDataUse > 3 * getSize())
{ {
initializeStaticData(); updateD3DBufferUsage(GL_STATIC_DRAW);
} }
} }
} }
......
...@@ -43,8 +43,8 @@ class BufferD3D : public BufferImpl ...@@ -43,8 +43,8 @@ class BufferD3D : public BufferImpl
StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute); StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute);
StaticIndexBufferInterface *getStaticIndexBuffer(); StaticIndexBufferInterface *getStaticIndexBuffer();
void initializeStaticData(); virtual void initializeStaticData();
void invalidateStaticData(); virtual void invalidateStaticData();
void promoteStaticUsage(int dataSize); void promoteStaticUsage(int dataSize);
......
...@@ -55,7 +55,6 @@ RendererD3D::~RendererD3D() ...@@ -55,7 +55,6 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup() void RendererD3D::cleanup()
{ {
mTranslatedAttribCache.clear();
mScratchMemoryBuffer.resize(0); mScratchMemoryBuffer.resize(0);
for (auto &incompleteTexture : mIncompleteTextures) for (auto &incompleteTexture : mIncompleteTextures)
{ {
...@@ -199,7 +198,7 @@ gl::Error RendererD3D::genericDrawArrays(const gl::Data &data, ...@@ -199,7 +198,7 @@ gl::Error RendererD3D::genericDrawArrays(const gl::Data &data,
if (!skipDraw(data, mode)) if (!skipDraw(data, mode))
{ {
ANGLE_TRY(drawArraysImpl(data, mode, count, instances)); ANGLE_TRY(drawArraysImpl(data, mode, first, count, instances));
if (data.state->isTransformFeedbackActiveUnpaused()) if (data.state->isTransformFeedbackActiveUnpaused())
{ {
......
...@@ -285,8 +285,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D ...@@ -285,8 +285,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
void initializeDebugAnnotator(); void initializeDebugAnnotator();
gl::DebugAnnotator *mAnnotator; gl::DebugAnnotator *mAnnotator;
std::vector<TranslatedAttribute> mTranslatedAttribCache;
bool mPresentPathFastEnabled; bool mPresentPathFastEnabled;
private: private:
...@@ -306,6 +304,7 @@ class RendererD3D : public Renderer, public BufferFactoryD3D ...@@ -306,6 +304,7 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
virtual gl::Error drawArraysImpl(const gl::Data &data, virtual gl::Error drawArraysImpl(const gl::Data &data,
GLenum mode, GLenum mode,
GLint startVertex,
GLsizei count, GLsizei count,
GLsizei instances) = 0; GLsizei instances) = 0;
virtual gl::Error drawElementsImpl(const gl::Data &data, virtual gl::Error drawElementsImpl(const gl::Data &data,
......
...@@ -80,7 +80,7 @@ class VertexBufferInterface : angle::NonCopyable ...@@ -80,7 +80,7 @@ class VertexBufferInterface : angle::NonCopyable
unsigned int getSerial() const; unsigned int getSerial() const;
VertexBuffer* getVertexBuffer() const; VertexBuffer *getVertexBuffer() const;
protected: protected:
gl::Error discard(); gl::Error discard();
......
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
#ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ #ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_
#define 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/Constants.h"
#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexAttribute.h"
#include "common/angleutils.h"
namespace gl namespace gl
{ {
...@@ -47,11 +48,16 @@ struct TranslatedAttribute ...@@ -47,11 +48,16 @@ struct TranslatedAttribute
{ {
TranslatedAttribute(); TranslatedAttribute();
// Computes the correct offset from baseOffset, usesFirstVertexOffset, stride and startVertex.
// Can throw an error on integer overflow.
gl::ErrorOrResult<unsigned int> computeOffset(GLint startVertex) const;
bool active; bool active;
const gl::VertexAttribute *attribute; const gl::VertexAttribute *attribute;
GLenum currentValueType; GLenum currentValueType;
unsigned int offset; unsigned int baseOffset;
bool usesFirstVertexOffset;
unsigned int stride; // 0 means not to advance the read pointer at all unsigned int stride; // 0 means not to advance the read pointer at all
VertexBufferBinding vertexBuffer; VertexBufferBinding vertexBuffer;
...@@ -84,19 +90,23 @@ class VertexDataManager : angle::NonCopyable ...@@ -84,19 +90,23 @@ class VertexDataManager : angle::NonCopyable
std::vector<TranslatedAttribute> *translatedAttribs, std::vector<TranslatedAttribute> *translatedAttribs,
GLsizei instances); GLsizei instances);
static void StoreDirectAttrib(TranslatedAttribute *directAttrib, GLint start); static void StoreDirectAttrib(TranslatedAttribute *directAttrib);
static gl::Error StoreStaticAttrib(TranslatedAttribute *translated, static gl::Error StoreStaticAttrib(TranslatedAttribute *translated,
GLint start,
GLsizei count, GLsizei count,
GLsizei instances); GLsizei instances);
gl::Error storeDynamicAttribs(std::vector<TranslatedAttribute> *translatedAttribs, gl::Error storeDynamicAttribs(std::vector<TranslatedAttribute> *translatedAttribs,
const std::vector<size_t> &dynamicAttribIndexes, const gl::AttributesMask &dynamicAttribsMask,
GLint start, GLint start,
GLsizei count, GLsizei count,
GLsizei instances); GLsizei instances);
// Promote static usage of dynamic buffers.
static void PromoteDynamicAttribs(const std::vector<TranslatedAttribute> &translatedAttribs,
const gl::AttributesMask &dynamicAttribsMask,
GLsizei count);
gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData &currentValue, gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData &currentValue,
TranslatedAttribute *translated, TranslatedAttribute *translated,
size_t attribIndex); size_t attribIndex);
...@@ -121,13 +131,11 @@ class VertexDataManager : angle::NonCopyable ...@@ -121,13 +131,11 @@ class VertexDataManager : angle::NonCopyable
GLsizei count, GLsizei count,
GLsizei instances); GLsizei instances);
void unmapStreamingBuffer();
BufferFactoryD3D *const mFactory; BufferFactoryD3D *const mFactory;
StreamingVertexBufferInterface *mStreamingBuffer; StreamingVertexBufferInterface *mStreamingBuffer;
std::vector<CurrentValueState> mCurrentValueCache; std::vector<CurrentValueState> mCurrentValueCache;
std::vector<size_t> mDynamicAttributeIndexesCache; gl::AttributesMask mDynamicAttribsMaskCache;
}; };
} // namespace rx } // namespace rx
......
...@@ -138,7 +138,7 @@ class Buffer11::BufferStorage : angle::NonCopyable ...@@ -138,7 +138,7 @@ class Buffer11::BufferStorage : angle::NonCopyable
class Buffer11::NativeStorage : public Buffer11::BufferStorage class Buffer11::NativeStorage : public Buffer11::BufferStorage
{ {
public: public:
NativeStorage(Renderer11 *renderer, BufferUsage usage); NativeStorage(Renderer11 *renderer, BufferUsage usage, const NotificationSet *onStorageChanged);
~NativeStorage() override; ~NativeStorage() override;
bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; }
...@@ -163,6 +163,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage ...@@ -163,6 +163,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
unsigned int bufferSize); unsigned int bufferSize);
ID3D11Buffer *mNativeStorage; ID3D11Buffer *mNativeStorage;
const NotificationSet *mOnStorageChanged;
}; };
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data // A emulated indexed buffer storage represents an underlying D3D11 buffer for data
...@@ -177,7 +178,8 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage ...@@ -177,7 +178,8 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
bool isMappable() const override { return true; } bool isMappable() const override { return true; }
gl::ErrorOrResult<ID3D11Buffer *> getNativeStorage(SourceIndexData *indexInfo, gl::ErrorOrResult<ID3D11Buffer *> getNativeStorage(SourceIndexData *indexInfo,
const TranslatedAttribute &attribute); const TranslatedAttribute &attribute,
GLint startVertex);
gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source, gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source,
size_t sourceOffset, size_t sourceOffset,
...@@ -521,7 +523,8 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getBuffer(BufferUsage usage) ...@@ -521,7 +523,8 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getBuffer(BufferUsage usage)
gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer( gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer(
SourceIndexData *indexInfo, SourceIndexData *indexInfo,
const TranslatedAttribute &attribute) const TranslatedAttribute &attribute,
GLint startVertex)
{ {
ASSERT(indexInfo); ASSERT(indexInfo);
...@@ -533,7 +536,8 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer( ...@@ -533,7 +536,8 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer(
EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(untypedStorage); EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(untypedStorage);
ID3D11Buffer *nativeStorage = nullptr; ID3D11Buffer *nativeStorage = nullptr;
ANGLE_TRY_RESULT(emulatedStorage->getNativeStorage(indexInfo, attribute), nativeStorage); ANGLE_TRY_RESULT(emulatedStorage->getNativeStorage(indexInfo, attribute, startVertex),
nativeStorage);
return nativeStorage; return nativeStorage;
} }
...@@ -634,23 +638,7 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs ...@@ -634,23 +638,7 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs
if (!newStorage) if (!newStorage)
{ {
if (usage == BUFFER_USAGE_PIXEL_PACK) newStorage = allocateStorage(usage);
{
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);
}
} }
// resize buffer // resize buffer
...@@ -664,6 +652,23 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs ...@@ -664,6 +652,23 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs
return newStorage; 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);
}
}
gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeStorage( gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeStorage(
GLintptr offset, GLintptr offset,
GLsizeiptr size) GLsizeiptr size)
...@@ -677,7 +682,7 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeSto ...@@ -677,7 +682,7 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeSto
if (!cacheEntry->storage) if (!cacheEntry->storage)
{ {
cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM); cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM);
cacheEntry->lruCount = ++mMaxConstantBufferLruCount; cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
} }
...@@ -806,8 +811,43 @@ bool Buffer11::supportsDirectBinding() const ...@@ -806,8 +811,43 @@ bool Buffer11::supportsDirectBinding() const
{ {
// Do not support direct buffers for dynamic data. The streaming buffer // Do not support direct buffers for dynamic data. The streaming buffer
// offers better performance for data which changes every frame. // offers better performance for data which changes every frame.
// Check for absence of static buffer interfaces to detect dynamic data. return (mUsage == D3DBufferUsage::STATIC);
return (!mStaticVertexBuffers.empty() && mStaticIndexBuffer); }
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) Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
...@@ -829,8 +869,10 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s ...@@ -829,8 +869,10 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
return gl::NoError(); return gl::NoError();
} }
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
: BufferStorage(renderer, usage), mNativeStorage(nullptr) BufferUsage usage,
const NotificationSet *onStorageChanged)
: BufferStorage(renderer, usage), mNativeStorage(nullptr), mOnStorageChanged(onStorageChanged)
{ {
} }
...@@ -945,6 +987,12 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) ...@@ -945,6 +987,12 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
mBufferSize = bufferDesc.ByteWidth; mBufferSize = bufferDesc.ByteWidth;
// Notify that the storage has changed.
if (mOnStorageChanged)
{
mOnStorageChanged->signal();
}
return gl::NoError(); return gl::NoError();
} }
...@@ -1050,7 +1098,8 @@ Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() ...@@ -1050,7 +1098,8 @@ Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage()
gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeStorage( gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeStorage(
SourceIndexData *indexInfo, SourceIndexData *indexInfo,
const TranslatedAttribute &attribute) const TranslatedAttribute &attribute,
GLint startVertex)
{ {
// If a change in the indices applied from the last draw call is detected, then the emulated // If a change in the indices applied from the last draw call is detected, then the emulated
// indexed buffer needs to be invalidated. After invalidation, the change detected flag should // indexed buffer needs to be invalidated. After invalidation, the change detected flag should
...@@ -1092,9 +1141,12 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeSto ...@@ -1092,9 +1141,12 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeSto
if (!mNativeStorage) if (!mNativeStorage)
{ {
unsigned int offset = 0;
ANGLE_TRY_RESULT(attribute.computeOffset(startVertex), offset);
// Expand the memory storage upon request and cache the results. // Expand the memory storage upon request and cache the results.
unsigned int expandedDataSize = unsigned int expandedDataSize =
static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + attribute.offset); static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset);
MemoryBuffer expandedData; MemoryBuffer expandedData;
if (!expandedData.resize(expandedDataSize)) if (!expandedData.resize(expandedDataSize))
{ {
...@@ -1111,7 +1163,7 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeSto ...@@ -1111,7 +1163,7 @@ gl::ErrorOrResult<ID3D11Buffer *> Buffer11::EmulatedIndexedStorage::getNativeSto
// Ensure that we start in the correct place for the emulated data copy operation to // Ensure that we start in the correct place for the emulated data copy operation to
// maintain offset behaviors. // maintain offset behaviors.
curr += attribute.offset; curr += offset;
ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>; ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace gl namespace gl
{ {
...@@ -63,9 +64,9 @@ class Buffer11 : public BufferD3D ...@@ -63,9 +64,9 @@ class Buffer11 : public BufferD3D
virtual ~Buffer11(); virtual ~Buffer11();
gl::ErrorOrResult<ID3D11Buffer *> getBuffer(BufferUsage usage); gl::ErrorOrResult<ID3D11Buffer *> getBuffer(BufferUsage usage);
gl::ErrorOrResult<ID3D11Buffer *> getEmulatedIndexedBuffer( gl::ErrorOrResult<ID3D11Buffer *> getEmulatedIndexedBuffer(SourceIndexData *indexInfo,
SourceIndexData *indexInfo, const TranslatedAttribute &attribute,
const TranslatedAttribute &attribute); GLint startVertex);
gl::ErrorOrResult<ID3D11Buffer *> getConstantBufferRange(GLintptr offset, GLsizeiptr size); gl::ErrorOrResult<ID3D11Buffer *> getConstantBufferRange(GLintptr offset, GLsizeiptr size);
gl::ErrorOrResult<ID3D11ShaderResourceView *> getSRV(DXGI_FORMAT srvFormat); gl::ErrorOrResult<ID3D11ShaderResourceView *> getSRV(DXGI_FORMAT srvFormat);
bool isMapped() const { return mMappedStorage != nullptr; } bool isMapped() const { return mMappedStorage != nullptr; }
...@@ -74,18 +75,32 @@ class Buffer11 : public BufferD3D ...@@ -74,18 +75,32 @@ class Buffer11 : public BufferD3D
size_t getTotalCPUBufferMemoryBytes() const; size_t getTotalCPUBufferMemoryBytes() const;
// BufferD3D implementation // BufferD3D implementation
virtual size_t getSize() const { return mSize; } size_t getSize() const override { return mSize; }
virtual bool supportsDirectBinding() const; bool supportsDirectBinding() const override;
gl::Error getData(const uint8_t **outData) override; gl::Error getData(const uint8_t **outData) override;
void initializeStaticData() override;
void invalidateStaticData() override;
// BufferImpl implementation // BufferImpl implementation
virtual gl::Error setData(const void* data, size_t size, GLenum usage); gl::Error setData(const void *data, size_t size, GLenum usage) override;
virtual gl::Error setSubData(const void* data, size_t size, size_t offset); gl::Error setSubData(const void *data, size_t size, size_t offset) override;
virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); gl::Error copySubData(BufferImpl *source,
virtual gl::Error map(GLenum access, GLvoid **mapPtr); GLintptr sourceOffset,
virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); GLintptr destOffset,
virtual gl::Error unmap(GLboolean *result); GLsizeiptr size) override;
virtual gl::Error markTransformFeedbackUsage(); 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;
gl::Error 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: private:
class BufferStorage; class BufferStorage;
...@@ -94,13 +109,6 @@ class Buffer11 : public BufferD3D ...@@ -94,13 +109,6 @@ class Buffer11 : public BufferD3D
class PackStorage; class PackStorage;
class SystemMemoryStorage; class SystemMemoryStorage;
Renderer11 *mRenderer;
size_t mSize;
BufferStorage *mMappedStorage;
std::vector<BufferStorage*> mBufferStorages;
struct ConstantBufferCacheEntry struct ConstantBufferCacheEntry
{ {
ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { } ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { }
...@@ -109,6 +117,27 @@ class Buffer11 : public BufferD3D ...@@ -109,6 +117,27 @@ class Buffer11 : public BufferD3D
unsigned int lruCount; unsigned int lruCount;
}; };
gl::Error markBufferUsage();
gl::ErrorOrResult<NativeStorage *> getStagingStorage();
gl::ErrorOrResult<PackStorage *> getPackStorage();
gl::ErrorOrResult<SystemMemoryStorage *> getSystemMemoryStorage();
gl::Error updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize);
gl::ErrorOrResult<BufferStorage *> getBufferStorage(BufferUsage usage);
gl::ErrorOrResult<BufferStorage *> getLatestBufferStorage() const;
gl::ErrorOrResult<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. // Cache of D3D11 constant buffer for specific ranges of buffer data.
// This is used to emulate UBO ranges on 11.0 devices. // This is used to emulate UBO ranges on 11.0 devices.
// Constant buffers are indexed by there start offset. // Constant buffers are indexed by there start offset.
...@@ -122,17 +151,8 @@ class Buffer11 : public BufferD3D ...@@ -122,17 +151,8 @@ class Buffer11 : public BufferD3D
unsigned int mReadUsageCount; unsigned int mReadUsageCount;
gl::Error markBufferUsage(); NotificationSet mStaticBufferDirtyCallbacks;
gl::ErrorOrResult<NativeStorage *> getStagingStorage(); NotificationSet mDirectBufferDirtyCallbacks;
gl::ErrorOrResult<PackStorage *> getPackStorage();
gl::ErrorOrResult<SystemMemoryStorage *> getSystemMemoryStorage();
gl::Error updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize);
gl::ErrorOrResult<BufferStorage *> getBufferStorage(BufferUsage usage);
gl::ErrorOrResult<BufferStorage *> getLatestBufferStorage() const;
gl::ErrorOrResult<BufferStorage *> getConstantBufferRangeStorage(GLintptr offset,
GLsizeiptr size);
}; };
} // namespace rx } // namespace rx
......
...@@ -94,7 +94,8 @@ Optional<size_t> FindFirstNonInstanced( ...@@ -94,7 +94,8 @@ Optional<size_t> FindFirstNonInstanced(
} }
void SortAttributesByLayout(const gl::Program *program, void SortAttributesByLayout(const gl::Program *program,
const std::vector<TranslatedAttribute> &unsortedAttributes, const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
AttribIndexArray *sortedD3DSemanticsOut, AttribIndexArray *sortedD3DSemanticsOut,
std::vector<const TranslatedAttribute *> *sortedAttributesOut) std::vector<const TranslatedAttribute *> *sortedAttributesOut)
{ {
...@@ -112,7 +113,17 @@ void SortAttributesByLayout(const gl::Program *program, ...@@ -112,7 +113,17 @@ void SortAttributesByLayout(const gl::Program *program,
} }
(*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic; (*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,8 +220,10 @@ void InputLayoutCache::markDirty() ...@@ -209,8 +220,10 @@ void InputLayoutCache::markDirty()
gl::Error InputLayoutCache::applyVertexBuffers( gl::Error InputLayoutCache::applyVertexBuffers(
const gl::State &state, const gl::State &state,
const std::vector<TranslatedAttribute> &unsortedAttributes, const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode, GLenum mode,
GLint start,
TranslatedIndexData *indexInfo, TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance) GLsizei numIndicesPerInstance)
{ {
...@@ -223,7 +236,7 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -223,7 +236,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
AttribIndexArray sortedSemanticIndices; AttribIndexArray sortedSemanticIndices;
SortAttributesByLayout(program, unsortedAttributes, &sortedSemanticIndices, SortAttributesByLayout(program, vertexArrayAttribs, currentValueAttribs, &sortedSemanticIndices,
&mCurrentAttributes); &mCurrentAttributes);
// If we are using FL 9_3, make sure the first attribute is not instanced // If we are using FL 9_3, make sure the first attribute is not instanced
...@@ -285,9 +298,9 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -285,9 +298,9 @@ gl::Error InputLayoutCache::applyVertexBuffers(
indexInfo->srcIndexData.srcIndices = bufferData + offset; indexInfo->srcIndexData.srcIndices = bufferData + offset;
} }
ANGLE_TRY_RESULT( ANGLE_TRY_RESULT(bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData,
bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData, attrib), attrib, start),
buffer); buffer);
} }
else else
{ {
...@@ -296,7 +309,7 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -296,7 +309,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(
} }
vertexStride = attrib.stride; vertexStride = attrib.stride;
vertexOffset = attrib.offset; ANGLE_TRY_RESULT(attrib.computeOffset(start), vertexOffset);
} }
size_t bufferIndex = reservedBuffers + attribIndex; size_t bufferIndex = reservedBuffers + attribIndex;
...@@ -414,7 +427,8 @@ gl::Error InputLayoutCache::applyVertexBuffers( ...@@ -414,7 +427,8 @@ gl::Error InputLayoutCache::applyVertexBuffers(
return gl::NoError(); return gl::NoError();
} }
gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId) gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId)
{ {
size_t reservedBuffers = GetReservedBufferCount(true); size_t reservedBuffers = GetReservedBufferCount(true);
for (size_t attribIndex = 0; attribIndex < mCurrentAttributes.size(); ++attribIndex) for (size_t attribIndex = 0; attribIndex < mCurrentAttributes.size(); ++attribIndex)
...@@ -424,8 +438,10 @@ gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei ...@@ -424,8 +438,10 @@ gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei
if (attrib.divisor > 0) if (attrib.divisor > 0)
{ {
unsigned int offset = 0;
ANGLE_TRY_RESULT(attrib.computeOffset(startVertex), offset);
mCurrentVertexOffsets[bufferIndex] = mCurrentVertexOffsets[bufferIndex] =
attrib.offset + (attrib.stride * (emulatedInstanceId / attrib.divisor)); offset + (attrib.stride * (emulatedInstanceId / attrib.divisor));
} }
} }
......
...@@ -46,12 +46,15 @@ class InputLayoutCache : angle::NonCopyable ...@@ -46,12 +46,15 @@ class InputLayoutCache : angle::NonCopyable
void markDirty(); void markDirty();
gl::Error applyVertexBuffers(const gl::State &state, gl::Error applyVertexBuffers(const gl::State &state,
const std::vector<TranslatedAttribute> &attributes, const std::vector<TranslatedAttribute> &vertexArrayAttribs,
const std::vector<TranslatedAttribute> &currentValueAttribs,
GLenum mode, GLenum mode,
GLint start,
TranslatedIndexData *indexInfo, TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance); GLsizei numIndicesPerInstance);
gl::Error updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId); gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId);
// Useful for testing // Useful for testing
void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; } void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; }
......
...@@ -189,23 +189,17 @@ RenderTarget11::~RenderTarget11() ...@@ -189,23 +189,17 @@ RenderTarget11::~RenderTarget11()
void RenderTarget11::addDirtyCallback(const NotificationCallback *callback) void RenderTarget11::addDirtyCallback(const NotificationCallback *callback)
{ {
mDirtyCallbacks.insert(callback); mDirtyCallbacks.add(callback);
} }
void RenderTarget11::removeDirtyCallback(const NotificationCallback *callback) void RenderTarget11::removeDirtyCallback(const NotificationCallback *callback)
{ {
mDirtyCallbacks.erase(callback); mDirtyCallbacks.remove(callback);
} }
void RenderTarget11::signalDirty() void RenderTarget11::signalDirty()
{ {
if (mDirtyCallbacks.empty()) mDirtyCallbacks.signal();
return;
for (const auto &callback : mDirtyCallbacks)
{
(*callback)();
}
// Clear the signal list. We can't do this in the callback because it mutates the iterator. // Clear the signal list. We can't do this in the callback because it mutates the iterator.
mDirtyCallbacks.clear(); mDirtyCallbacks.clear();
......
...@@ -41,8 +41,7 @@ class RenderTarget11 : public RenderTargetD3D ...@@ -41,8 +41,7 @@ class RenderTarget11 : public RenderTargetD3D
d3d11::ANGLEFormat getANGLEFormat() const { return mANGLEFormat; } d3d11::ANGLEFormat getANGLEFormat() const { return mANGLEFormat; }
protected: protected:
std::set<const NotificationCallback *> mDirtyCallbacks; NotificationSet mDirtyCallbacks;
d3d11::ANGLEFormat mANGLEFormat; d3d11::ANGLEFormat mANGLEFormat;
}; };
......
...@@ -835,9 +835,6 @@ void Renderer11::initializeDevice() ...@@ -835,9 +835,6 @@ void Renderer11::initializeDevice()
ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel",
angleFeatureLevel, angleFeatureLevel,
NUM_ANGLE_FEATURE_LEVELS); NUM_ANGLE_FEATURE_LEVELS);
// TODO(jmadill): use context caps, and place in common D3D location
mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
} }
void Renderer11::populateRenderer11DeviceCaps() void Renderer11::populateRenderer11DeviceCaps()
...@@ -1524,7 +1521,17 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state, ...@@ -1524,7 +1521,17 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
GLsizei instances, GLsizei instances,
TranslatedIndexData *indexInfo) 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()) if (error.isError())
{ {
return error; return error;
...@@ -1541,8 +1548,21 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state, ...@@ -1541,8 +1548,21 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
{ {
numIndicesPerInstance = count; numIndicesPerInstance = count;
} }
return mInputLayoutCache.applyVertexBuffers(state, mTranslatedAttribCache, mode, indexInfo, const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
numIndicesPerInstance); const auto &currentValueAttribs = mStateManager.getCurrentValueAttribs();
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(state, vertexArrayAttribs, currentValueAttribs,
mode, first, indexInfo, numIndicesPerInstance));
// InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex
// buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger
// allocation. This in turn will signal that the buffer is dirty. Since we just resolved the
// dirty-ness in VertexArray11::updateDirtyAndDynamicAttribs, this can make us do a needless
// update on the second draw call.
// Hence we clear the flags here, after we've applied vertex data, since we know everything
// is clean. This is a bit of a hack.
vertexArray11->clearDirtyAndPromoteDynamicAttribs(state, count);
return gl::NoError();
} }
gl::Error Renderer11::applyIndexBuffer(const gl::Data &data, gl::Error Renderer11::applyIndexBuffer(const gl::Data &data,
...@@ -1669,6 +1689,7 @@ gl::Error Renderer11::applyTransformFeedbackBuffers(const gl::State &state) ...@@ -1669,6 +1689,7 @@ gl::Error Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
gl::Error Renderer11::drawArraysImpl(const gl::Data &data, gl::Error Renderer11::drawArraysImpl(const gl::Data &data,
GLenum mode, GLenum mode,
GLint startVertex,
GLsizei count, GLsizei count,
GLsizei instances) GLsizei instances)
{ {
...@@ -1761,7 +1782,8 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data, ...@@ -1761,7 +1782,8 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data,
// offsets. // offsets.
for (GLsizei i = 0; i < instances; i++) for (GLsizei i = 0; i < instances; i++)
{ {
gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); gl::Error error =
mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(startVertex, i);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -1827,7 +1849,8 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data, ...@@ -1827,7 +1849,8 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data,
// offsets. // offsets.
for (GLsizei i = 0; i < instances; i++) for (GLsizei i = 0; i < instances; i++)
{ {
gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); gl::Error error =
mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(minIndex, i);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -2505,6 +2528,7 @@ void Renderer11::markAllStateDirty() ...@@ -2505,6 +2528,7 @@ void Renderer11::markAllStateDirty()
void Renderer11::releaseDeviceResources() void Renderer11::releaseDeviceResources()
{ {
mStateManager.deinitialize();
mStateCache.clear(); mStateCache.clear();
mInputLayoutCache.clear(); mInputLayoutCache.clear();
...@@ -4340,4 +4364,5 @@ egl::Error Renderer11::getEGLDevice(DeviceImpl **device) ...@@ -4340,4 +4364,5 @@ egl::Error Renderer11::getEGLDevice(DeviceImpl **device)
*device = static_cast<DeviceImpl *>(mEGLDevice); *device = static_cast<DeviceImpl *>(mEGLDevice);
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
}
} // namespace rx
...@@ -306,6 +306,7 @@ class Renderer11 : public RendererD3D ...@@ -306,6 +306,7 @@ class Renderer11 : public RendererD3D
private: private:
gl::Error drawArraysImpl(const gl::Data &data, gl::Error drawArraysImpl(const gl::Data &data,
GLenum mode, GLenum mode,
GLint startVertex,
GLsizei count, GLsizei count,
GLsizei instances) override; GLsizei instances) override;
gl::Error drawElementsImpl(const gl::Data &data, gl::Error drawElementsImpl(const gl::Data &data,
......
...@@ -150,7 +150,9 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -150,7 +150,9 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurNear(0.0f), mCurNear(0.0f),
mCurFar(0.0f), mCurFar(0.0f),
mViewportBounds(), mViewportBounds(),
mRenderTargetIsDirty(false) mRenderTargetIsDirty(false),
mDirtyCurrentValueAttribs(),
mCurrentValueAttribs()
{ {
mCurBlendState.blend = false; mCurBlendState.blend = false;
mCurBlendState.sourceBlendRGB = GL_ONE; mCurBlendState.sourceBlendRGB = GL_ONE;
...@@ -191,6 +193,9 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -191,6 +193,9 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurRasterState.polygonOffsetUnits = 0.0f; mCurRasterState.polygonOffsetUnits = 0.0f;
mCurRasterState.pointDrawMode = false; mCurRasterState.pointDrawMode = false;
mCurRasterState.multiSample = false; mCurRasterState.multiSample = false;
// Initially all current value attributes must be updated on first use.
mDirtyCurrentValueAttribs.flip();
} }
StateManager11::~StateManager11() StateManager11::~StateManager11()
...@@ -241,7 +246,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit ...@@ -241,7 +246,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
return; return;
} }
for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits)) for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
{ {
switch (dirtyBit) switch (dirtyBit)
{ {
...@@ -461,6 +466,13 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit ...@@ -461,6 +466,13 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
mRenderTargetIsDirty = true; mRenderTargetIsDirty = true;
break; break;
default: 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; break;
} }
} }
...@@ -958,6 +970,13 @@ void StateManager11::initialize(const gl::Caps &caps) ...@@ -958,6 +970,13 @@ void StateManager11::initialize(const gl::Caps &caps)
// Initialize cached NULL SRV block // Initialize cached NULL SRV block
mNullSRVs.resize(caps.maxTextureImageUnits, nullptr); mNullSRVs.resize(caps.maxTextureImageUnits, nullptr);
mCurrentValueAttribs.resize(caps.maxVertexAttributes);
}
void StateManager11::deinitialize()
{
mCurrentValueAttribs.clear();
} }
gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer) gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
...@@ -1078,4 +1097,40 @@ 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); 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 } // namespace rx
...@@ -48,6 +48,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -48,6 +48,7 @@ class StateManager11 final : angle::NonCopyable
~StateManager11(); ~StateManager11();
void initialize(const gl::Caps &caps); void initialize(const gl::Caps &caps);
void deinitialize();
void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits); void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
gl::Error setBlendState(const gl::Framebuffer *framebuffer, gl::Error setBlendState(const gl::Framebuffer *framebuffer,
...@@ -91,6 +92,11 @@ class StateManager11 final : angle::NonCopyable ...@@ -91,6 +92,11 @@ class StateManager11 final : angle::NonCopyable
void onDeleteQueryObject(Query11 *query); void onDeleteQueryObject(Query11 *query);
gl::Error onMakeCurrent(const gl::Data &data); gl::Error onMakeCurrent(const gl::Data &data);
gl::Error updateCurrentValueAttribs(const gl::State &state,
VertexDataManager *vertexDataManager);
const std::vector<TranslatedAttribute> &getCurrentValueAttribs() const;
private: private:
void setViewportBounds(const int width, const int height); void setViewportBounds(const int width, const int height);
void unsetConflictingSRVs(gl::SamplerType shaderType, void unsetConflictingSRVs(gl::SamplerType shaderType,
...@@ -186,6 +192,10 @@ class StateManager11 final : angle::NonCopyable ...@@ -186,6 +192,10 @@ class StateManager11 final : angle::NonCopyable
// A block of NULL pointers, cached so we don't re-allocate every draw call // A block of NULL pointers, cached so we don't re-allocate every draw call
std::vector<ID3D11ShaderResourceView *> mNullSRVs; std::vector<ID3D11ShaderResourceView *> mNullSRVs;
// Current translations of "Current-Value" data - owned by Context, not VertexArray.
gl::AttributesMask mDirtyCurrentValueAttribs;
std::vector<TranslatedAttribute> mCurrentValueAttribs;
}; };
} // namespace rx } // 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)
: VertexArrayImpl(data),
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 (size_t attribIndex = 0; attribIndex < mCurrentBuffers.size(); ++attribIndex)
{
if (mCurrentBuffers[attribIndex].get())
{
unlinkBuffer(attribIndex, mAttributeStorageTypes[attribIndex]);
mCurrentBuffers[attribIndex].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)
{
unlinkBuffer(attribIndex, oldStorageType);
}
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);
break;
case VertexStorageType::STATIC:
{
auto error =
VertexDataManager::StoreStaticAttrib(translatedAttrib, 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);
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::State &state, GLsizei count)
{
const gl::Program *program = state.getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
mAttribsToUpdate &= ~activeLocations;
// Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness.
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
VertexDataManager::PromoteDynamicAttribs(mTranslatedAttribs, activeDynamicAttribs, count);
}
void VertexArray11::unlinkBuffer(size_t attribIndex, VertexStorageType storageType)
{
Buffer11 *buffer = GetImplAs<Buffer11>(mCurrentBuffers[attribIndex].get());
if (storageType == VertexStorageType::DIRECT)
{
buffer->removeDirectBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
else if (storageType == VertexStorageType::STATIC || storageType == VertexStorageType::DYNAMIC)
{
buffer->removeStaticBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
}
} // namespace rx
...@@ -19,13 +19,42 @@ class Renderer11; ...@@ -19,13 +19,42 @@ class Renderer11;
class VertexArray11 : public VertexArrayImpl class VertexArray11 : public VertexArrayImpl
{ {
public: public:
VertexArray11(const gl::VertexArray::Data &data) VertexArray11(const gl::VertexArray::Data &data);
: VertexArrayImpl(data) ~VertexArray11() override;
{
} void syncState(const gl::VertexArray::DirtyBits &dirtyBits) override;
virtual ~VertexArray11() {} gl::Error updateDirtyAndDynamicAttribs(VertexDataManager *vertexDataManager,
const gl::State &state,
GLint start,
GLsizei count,
GLsizei instances);
void clearDirtyAndPromoteDynamicAttribs(const gl::State &state, GLsizei count);
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
private:
void updateVertexAttribStorage(size_t attribIndex);
void markBufferDataDirty(size_t attribIndex);
void unlinkBuffer(size_t attribIndex, VertexStorageType storageType);
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_ #endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_
...@@ -1716,4 +1716,40 @@ bool UsePresentPathFast(const Renderer11 *renderer, ...@@ -1716,4 +1716,40 @@ bool UsePresentPathFast(const Renderer11 *renderer,
renderer->presentPathFastEnabled()); 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 } // namespace rx
...@@ -406,6 +406,21 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm ...@@ -406,6 +406,21 @@ bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachm
using NotificationCallback = std::function<void()>; 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 } // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
...@@ -154,6 +154,8 @@ void Renderer9::release() ...@@ -154,6 +154,8 @@ void Renderer9::release()
{ {
RendererD3D::cleanup(); RendererD3D::cleanup();
mTranslatedAttribCache.clear();
releaseDeviceResources(); releaseDeviceResources();
SafeDelete(mEGLDevice); SafeDelete(mEGLDevice);
...@@ -364,7 +366,6 @@ void Renderer9::initializeDevice() ...@@ -364,7 +366,6 @@ void Renderer9::initializeDevice()
mVertexDataManager = new VertexDataManager(this); mVertexDataManager = new VertexDataManager(this);
mIndexDataManager = new IndexDataManager(this, getRendererClass()); mIndexDataManager = new IndexDataManager(this, getRendererClass());
// TODO(jmadill): use context caps, and place in common D3D location
mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes); mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
} }
...@@ -1191,7 +1192,8 @@ gl::Error Renderer9::applyVertexBuffer(const gl::State &state, ...@@ -1191,7 +1192,8 @@ gl::Error Renderer9::applyVertexBuffer(const gl::State &state,
return error; return error;
} }
return mVertexDeclarationCache.applyDeclaration(mDevice, mTranslatedAttribCache, state.getProgram(), instances, &mRepeatDraw); return mVertexDeclarationCache.applyDeclaration(
mDevice, mTranslatedAttribCache, state.getProgram(), first, instances, &mRepeatDraw);
} }
// Applies the indices and element array bindings to the Direct3D 9 device // Applies the indices and element array bindings to the Direct3D 9 device
...@@ -1233,6 +1235,7 @@ gl::Error Renderer9::applyTransformFeedbackBuffers(const gl::State &state) ...@@ -1233,6 +1235,7 @@ gl::Error Renderer9::applyTransformFeedbackBuffers(const gl::State &state)
gl::Error Renderer9::drawArraysImpl(const gl::Data &data, gl::Error Renderer9::drawArraysImpl(const gl::Data &data,
GLenum mode, GLenum mode,
GLint startVertex,
GLsizei count, GLsizei count,
GLsizei instances) GLsizei instances)
{ {
......
...@@ -275,6 +275,7 @@ class Renderer9 : public RendererD3D ...@@ -275,6 +275,7 @@ class Renderer9 : public RendererD3D
private: private:
gl::Error drawArraysImpl(const gl::Data &data, gl::Error drawArraysImpl(const gl::Data &data,
GLenum mode, GLenum mode,
GLint startVertex,
GLsizei count, GLsizei count,
GLsizei instances) override; GLsizei instances) override;
gl::Error drawElementsImpl(const gl::Data &data, gl::Error drawElementsImpl(const gl::Data &data,
...@@ -396,6 +397,7 @@ class Renderer9 : public RendererD3D ...@@ -396,6 +397,7 @@ class Renderer9 : public RendererD3D
UINT mMaxNullColorbufferLRU; UINT mMaxNullColorbufferLRU;
DeviceD3D *mEGLDevice; DeviceD3D *mEGLDevice;
std::vector<TranslatedAttribute> mTranslatedAttribCache;
}; };
} }
......
...@@ -42,11 +42,13 @@ VertexDeclarationCache::~VertexDeclarationCache() ...@@ -42,11 +42,13 @@ VertexDeclarationCache::~VertexDeclarationCache()
} }
} }
gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, gl::Error VertexDeclarationCache::applyDeclaration(
const std::vector<TranslatedAttribute> &attributes, IDirect3DDevice9 *device,
gl::Program *program, const std::vector<TranslatedAttribute> &attributes,
GLsizei instances, gl::Program *program,
GLsizei *repeatDraw) GLint start,
GLsizei instances,
GLsizei *repeatDraw)
{ {
ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size()); ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size());
...@@ -149,14 +151,18 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, ...@@ -149,14 +151,18 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device,
VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get()); VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get());
unsigned int offset = 0;
ANGLE_TRY_RESULT(attributes[i].computeOffset(start), offset);
if (mAppliedVBs[stream].serial != attributes[i].serial || if (mAppliedVBs[stream].serial != attributes[i].serial ||
mAppliedVBs[stream].stride != attributes[i].stride || mAppliedVBs[stream].stride != attributes[i].stride ||
mAppliedVBs[stream].offset != attributes[i].offset) mAppliedVBs[stream].offset != offset)
{ {
device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset,
attributes[i].stride);
mAppliedVBs[stream].serial = attributes[i].serial; mAppliedVBs[stream].serial = attributes[i].serial;
mAppliedVBs[stream].stride = attributes[i].stride; mAppliedVBs[stream].stride = attributes[i].stride;
mAppliedVBs[stream].offset = attributes[i].offset; mAppliedVBs[stream].offset = offset;
} }
gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT);
......
...@@ -30,6 +30,7 @@ class VertexDeclarationCache ...@@ -30,6 +30,7 @@ class VertexDeclarationCache
gl::Error applyDeclaration(IDirect3DDevice9 *device, gl::Error applyDeclaration(IDirect3DDevice9 *device,
const std::vector<TranslatedAttribute> &attributes, const std::vector<TranslatedAttribute> &attributes,
gl::Program *program, gl::Program *program,
GLint start,
GLsizei instances, GLsizei instances,
GLsizei *repeatDraw); GLsizei *repeatDraw);
......
...@@ -392,6 +392,7 @@ ...@@ -392,6 +392,7 @@
'libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp', '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_autogen.h',
'libANGLE/renderer/d3d/d3d11/texture_format_table.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/VertexArray11.h',
'libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp', 'libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp',
'libANGLE/renderer/d3d/d3d11/VertexBuffer11.h', 'libANGLE/renderer/d3d/d3d11/VertexBuffer11.h',
......
...@@ -207,6 +207,31 @@ TEST_P(BufferDataTest, DISABLED_HugeSetDataShouldNotCrash) ...@@ -207,6 +207,31 @@ TEST_P(BufferDataTest, DISABLED_HugeSetDataShouldNotCrash)
delete[] data; 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 class IndexedBufferCopyTest : public ANGLETest
{ {
protected: protected:
......
...@@ -82,7 +82,7 @@ class CopyTexImageTest : public ANGLETest ...@@ -82,7 +82,7 @@ class CopyTexImageTest : public ANGLETest
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, w, h); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, w, h);
} }
virtual void SetUp() void SetUp() override
{ {
ANGLETest::SetUp(); ANGLETest::SetUp();
...@@ -119,14 +119,14 @@ class CopyTexImageTest : public ANGLETest ...@@ -119,14 +119,14 @@ class CopyTexImageTest : public ANGLETest
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
virtual void TearDown() void TearDown() override
{ {
glDeleteProgram(mTextureProgram); glDeleteProgram(mTextureProgram);
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
void verifyResults(GLuint texture, GLubyte data[4], GLint x, GLint y) const void verifyResults(GLuint texture, GLubyte data[4], GLint x, GLint y)
{ {
glViewport(0, 0, 16, 16); glViewport(0, 0, 16, 16);
......
...@@ -38,7 +38,8 @@ class D3D11EmulatedIndexedBufferTest : public ANGLETest ...@@ -38,7 +38,8 @@ class D3D11EmulatedIndexedBufferTest : public ANGLETest
gl::Error error = mSourceBuffer->setData(testData, sizeof(testData), GL_STATIC_DRAW); gl::Error error = mSourceBuffer->setData(testData, sizeof(testData), GL_STATIC_DRAW);
ASSERT_FALSE(error.isError()); ASSERT_FALSE(error.isError());
mTranslatedAttribute.offset = 0; mTranslatedAttribute.baseOffset = 0;
mTranslatedAttribute.usesFirstVertexOffset = false;
mTranslatedAttribute.stride = sizeof(GLfloat); mTranslatedAttribute.stride = sizeof(GLfloat);
GLubyte indices[] = {0, 0, 3, 4, 2, 1, 1}; GLubyte indices[] = {0, 0, 3, 4, 2, 1, 1};
...@@ -107,7 +108,8 @@ class D3D11EmulatedIndexedBufferTest : public ANGLETest ...@@ -107,7 +108,8 @@ class D3D11EmulatedIndexedBufferTest : public ANGLETest
void emulateAndCompare(rx::SourceIndexData *srcData) void emulateAndCompare(rx::SourceIndexData *srcData)
{ {
auto bufferOrError = mSourceBuffer->getEmulatedIndexedBuffer(srcData, mTranslatedAttribute); auto bufferOrError =
mSourceBuffer->getEmulatedIndexedBuffer(srcData, mTranslatedAttribute, 0);
ASSERT_FALSE(bufferOrError.isError()); ASSERT_FALSE(bufferOrError.isError());
ID3D11Buffer *emulatedBuffer = bufferOrError.getResult(); ID3D11Buffer *emulatedBuffer = bufferOrError.getResult();
ASSERT_TRUE(emulatedBuffer != nullptr); ASSERT_TRUE(emulatedBuffer != nullptr);
......
...@@ -707,7 +707,90 @@ TEST_P(TransformFeedbackTest, PackingBug) ...@@ -707,7 +707,90 @@ TEST_P(TransformFeedbackTest, PackingBug)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
class TransformFeedbackLifetimeTest : public TransformFeedbackTest
{
protected:
TransformFeedbackLifetimeTest() : mVertexArray(0) {}
void SetUp() override
{
ANGLETest::SetUp();
glGenVertexArrays(1, &mVertexArray);
glBindVertexArray(mVertexArray);
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_SEPARATE_ATTRIBS);
glGenBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBufferSize = 1 << 24; // ~16MB
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, NULL,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
glGenTransformFeedbacks(1, &mTransformFeedback);
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
glDeleteVertexArrays(1, &mVertexArray);
TransformFeedbackTest::TearDown();
}
GLuint mVertexArray;
};
// Tests a bug with state syncing and deleted transform feedback buffers.
TEST_P(TransformFeedbackLifetimeTest, DeletedBuffer)
{
// First stream vertex data to mTransformFeedbackBuffer.
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glUseProgram(mProgram);
glBeginTransformFeedback(GL_TRIANGLES);
drawQuad(mProgram, "position", 0.5f, 1.0f, true);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
// TODO(jmadill): Remove this when http://anglebug.com/1351 is fixed.
glBindVertexArray(0);
drawQuad(mProgram, "position", 0.5f);
glBindVertexArray(1);
// Next, draw vertices with mTransformFeedbackBuffer. This will link to mVertexArray.
glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
GLint loc = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, loc);
glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
glEnableVertexAttribArray(loc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
// Delete resources, making a stranded pointer to mVertexArray in mTransformFeedbackBuffer.
glDeleteBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBuffer = 0;
glDeleteVertexArrays(1, &mVertexArray);
mVertexArray = 0;
// Then draw again with transform feedback, dereferencing the stranded pointer.
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glBeginTransformFeedback(GL_TRIANGLES);
drawQuad(mProgram, "position", 0.5f, 1.0f, true);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
} // anonymous namespace } // anonymous namespace
...@@ -50,7 +50,8 @@ GLfloat Normalize(T value) ...@@ -50,7 +50,8 @@ GLfloat Normalize(T value)
class VertexAttributeTest : public ANGLETest class VertexAttributeTest : public ANGLETest
{ {
protected: protected:
VertexAttributeTest() : mProgram(0), mTestAttrib(-1), mExpectedAttrib(-1), mBuffer(0) VertexAttributeTest()
: mProgram(0), mTestAttrib(-1), mExpectedAttrib(-1), mBuffer(0), mQuadBuffer(0)
{ {
setWindowWidth(128); setWindowWidth(128);
setWindowHeight(128); setWindowHeight(128);
...@@ -122,6 +123,23 @@ class VertexAttributeTest : public ANGLETest ...@@ -122,6 +123,23 @@ class VertexAttributeTest : public ANGLETest
glEnableVertexAttribArray(mExpectedAttrib); glEnableVertexAttribArray(mExpectedAttrib);
} }
void checkPixels()
{
GLint viewportSize[4];
glGetIntegerv(GL_VIEWPORT, viewportSize);
GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
// We need to offset our checks from triangle edges to ensure we don't fall on a single tri
// Avoid making assumptions of drawQuad with four checks to check the four possible tri
// regions
EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
}
void runTest(const TestData &test) void runTest(const TestData &test)
{ {
// TODO(geofflang): Figure out why this is broken on AMD OpenGL // TODO(geofflang): Figure out why this is broken on AMD OpenGL
...@@ -131,17 +149,6 @@ class VertexAttributeTest : public ANGLETest ...@@ -131,17 +149,6 @@ class VertexAttributeTest : public ANGLETest
return; return;
} }
if (mProgram == 0)
{
initBasicProgram();
}
GLint viewportSize[4];
glGetIntegerv(GL_VIEWPORT, viewportSize);
GLint midPixelX = (viewportSize[0] + viewportSize[2]) / 2;
GLint midPixelY = (viewportSize[1] + viewportSize[3]) / 2;
for (GLint i = 0; i < 4; i++) for (GLint i = 0; i < 4; i++)
{ {
GLint typeSize = i + 1; GLint typeSize = i + 1;
...@@ -152,12 +159,7 @@ class VertexAttributeTest : public ANGLETest ...@@ -152,12 +159,7 @@ class VertexAttributeTest : public ANGLETest
glDisableVertexAttribArray(mTestAttrib); glDisableVertexAttribArray(mTestAttrib);
glDisableVertexAttribArray(mExpectedAttrib); glDisableVertexAttribArray(mExpectedAttrib);
// We need to offset our checks from triangle edges to ensure we don't fall on a single tri checkPixels();
// Avoid making assumptions of drawQuad with four checks to check the four possible tri regions
EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
} }
} }
...@@ -178,6 +180,7 @@ class VertexAttributeTest : public ANGLETest ...@@ -178,6 +180,7 @@ class VertexAttributeTest : public ANGLETest
{ {
glDeleteProgram(mProgram); glDeleteProgram(mProgram);
glDeleteBuffers(1, &mBuffer); glDeleteBuffers(1, &mBuffer);
glDeleteBuffers(1, &mQuadBuffer);
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
...@@ -262,6 +265,7 @@ class VertexAttributeTest : public ANGLETest ...@@ -262,6 +265,7 @@ class VertexAttributeTest : public ANGLETest
GLint mTestAttrib; GLint mTestAttrib;
GLint mExpectedAttrib; GLint mExpectedAttrib;
GLuint mBuffer; GLuint mBuffer;
GLuint mQuadBuffer;
}; };
TEST_P(VertexAttributeTest, UnsignedByteUnnormalized) TEST_P(VertexAttributeTest, UnsignedByteUnnormalized)
...@@ -545,6 +549,69 @@ TEST_P(VertexAttributeTest, DrawElementsBufferTooSmall) ...@@ -545,6 +549,69 @@ TEST_P(VertexAttributeTest, DrawElementsBufferTooSmall)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Verify that using a different start vertex doesn't mess up the draw.
TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
{
// TODO(jmadill): Diagnose this failure.
if (IsD3D11_FL93())
{
std::cout << "Test disabled on D3D11 FL 9_3" << std::endl;
return;
}
// TODO(geofflang): Figure out why this is broken on AMD OpenGL
if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
std::cout << "Test skipped on AMD OpenGL." << std::endl;
return;
}
initBasicProgram();
glUseProgram(mProgram);
GLfloat inputData[mVertexCount];
GLfloat expectedData[mVertexCount];
for (size_t count = 0; count < mVertexCount; ++count)
{
inputData[count] = static_cast<GLfloat>(count);
expectedData[count] = inputData[count];
}
auto quadVertices = GetQuadVertices();
GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
GLsizei dataSize = mVertexCount * TypeStride(GL_FLOAT);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize + TypeStride(GL_FLOAT), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, inputData);
glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData);
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
class VertexAttributeCachingTest : public VertexAttributeTest class VertexAttributeCachingTest : public VertexAttributeTest
{ {
protected: protected:
......
...@@ -154,6 +154,39 @@ void ANGLETest::swapBuffers() ...@@ -154,6 +154,39 @@ void ANGLETest::swapBuffers()
} }
} }
// static
std::array<Vector3, 6> ANGLETest::GetQuadVertices()
{
std::array<Vector3, 6> vertices;
vertices[0] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[1] = Vector3(-1.0f, -1.0f, 0.5f);
vertices[2] = Vector3(1.0f, -1.0f, 0.5f);
vertices[3] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[4] = Vector3(1.0f, -1.0f, 0.5f);
vertices[5] = Vector3(1.0f, 1.0f, 0.5f);
return vertices;
}
void ANGLETest::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale)
{
if (mQuadVertexBuffer == 0)
{
glGenBuffers(1, &mQuadVertexBuffer);
}
auto quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.x *= positionAttribXYScale;
vertex.y *= positionAttribXYScale;
vertex.z = positionAttribZ;
}
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
}
// static
void ANGLETest::drawQuad(GLuint program, void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ) GLfloat positionAttribZ)
...@@ -161,11 +194,21 @@ void ANGLETest::drawQuad(GLuint program, ...@@ -161,11 +194,21 @@ void ANGLETest::drawQuad(GLuint program,
drawQuad(program, positionAttribName, positionAttribZ, 1.0f); drawQuad(program, positionAttribName, positionAttribZ, 1.0f);
} }
// static
void ANGLETest::drawQuad(GLuint program, void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ, GLfloat positionAttribZ,
GLfloat positionAttribXYScale) GLfloat positionAttribXYScale)
{ {
drawQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, false);
}
void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer)
{
GLint previousProgram = 0; GLint previousProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgram); glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgram);
if (previousProgram != static_cast<GLint>(program)) if (previousProgram != static_cast<GLint>(program))
...@@ -175,17 +218,24 @@ void ANGLETest::drawQuad(GLuint program, ...@@ -175,17 +218,24 @@ void ANGLETest::drawQuad(GLuint program,
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str()); GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
const GLfloat vertices[] = { if (useVertexBuffer)
-1.0f * positionAttribXYScale, 1.0f * positionAttribXYScale, positionAttribZ, {
-1.0f * positionAttribXYScale, -1.0f * positionAttribXYScale, positionAttribZ, setupQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
1.0f * positionAttribXYScale, -1.0f * positionAttribXYScale, positionAttribZ, glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
-1.0f * positionAttribXYScale, 1.0f * positionAttribXYScale, positionAttribZ, }
1.0f * positionAttribXYScale, -1.0f * positionAttribXYScale, positionAttribZ, else
1.0f * positionAttribXYScale, 1.0f * positionAttribXYScale, positionAttribZ, {
}; auto quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.x *= positionAttribXYScale;
vertex.y *= positionAttribXYScale;
vertex.z = positionAttribZ;
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
}
glEnableVertexAttribArray(positionLocation); glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
...@@ -213,27 +263,17 @@ void ANGLETest::drawIndexedQuad(GLuint program, ...@@ -213,27 +263,17 @@ void ANGLETest::drawIndexedQuad(GLuint program,
{ {
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str()); GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
glUseProgram(program); GLint activeProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(program);
}
GLuint prevBinding = 0; GLuint prevBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevBinding)); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevBinding));
if (mQuadVertexBuffer == 0) setupQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
{
glGenBuffers(1, &mQuadVertexBuffer);
const GLfloat vertices[] = {
-1.0f * positionAttribXYScale, 1.0f * positionAttribXYScale, positionAttribZ,
-1.0f * positionAttribXYScale, -1.0f * positionAttribXYScale, positionAttribZ,
1.0f * positionAttribXYScale, -1.0f * positionAttribXYScale, positionAttribZ,
1.0f * positionAttribXYScale, 1.0f * positionAttribXYScale, positionAttribZ,
};
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 4, vertices, GL_STATIC_DRAW);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation); glEnableVertexAttribArray(positionLocation);
...@@ -248,7 +288,10 @@ void ANGLETest::drawIndexedQuad(GLuint program, ...@@ -248,7 +288,10 @@ void ANGLETest::drawIndexedQuad(GLuint program,
glDisableVertexAttribArray(positionLocation); glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL); glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glUseProgram(0); if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(static_cast<GLuint>(activeProgram));
}
} }
GLuint ANGLETest::compileShader(GLenum type, const std::string &source) GLuint ANGLETest::compileShader(GLenum type, const std::string &source)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <algorithm> #include <algorithm>
#include <array>
#include "angle_gl.h" #include "angle_gl.h"
#include "angle_test_configs.h" #include "angle_test_configs.h"
...@@ -107,13 +108,19 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters> ...@@ -107,13 +108,19 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
virtual void swapBuffers(); virtual void swapBuffers();
static void drawQuad(GLuint program, void setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
const std::string &positionAttribName,
GLfloat positionAttribZ); void drawQuad(GLuint program, const std::string &positionAttribName, GLfloat positionAttribZ);
static void drawQuad(GLuint program, void drawQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ, GLfloat positionAttribZ,
GLfloat positionAttribXYScale); GLfloat positionAttribXYScale);
void drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer);
static std::array<Vector3, 6> GetQuadVertices();
void drawIndexedQuad(GLuint program, void drawIndexedQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ); GLfloat positionAttribZ);
......
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