Commit 558f2b5a by Cooper Partin Committed by Jamie Madill

Added emulated indexed pointsprite rendering support.

This emulation is for renderers that do not support Geometry Shaders. BUG=angleproject:949 Change-Id: I7acf003e83ea6661f10a703486e6d07eb28786f8 Reviewed-on: https://chromium-review.googlesource.com/274851Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarCooper Partin <coopp@microsoft.com>
parent ccda698b
......@@ -39,6 +39,7 @@ struct Data;
namespace rx
{
struct TranslatedIndexData;
struct SourceIndexData;
struct Workarounds;
class DisplayImpl;
......
......@@ -69,7 +69,7 @@ IndexDataManager::~IndexDataManager()
SafeDelete(mStreamingBufferInt);
}
gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated, SourceIndexData *sourceData)
{
const gl::Type &typeInfo = gl::GetTypeInfo(type);
......@@ -222,7 +222,13 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf
translated->startIndex = (streamOffset >> destTypeInfo.bytesShift);
translated->startOffset = streamOffset;
translated->indexType = destinationIndexType;
if (sourceData)
{
// Update pretranslated source index data
sourceData->srcIndices = indices;
sourceData->srcIndexType = type;
sourceData->srcCount = count;
}
if (storage)
{
storage->promoteStaticUsage(count << typeInfo.bytesShift);
......
......@@ -48,13 +48,21 @@ struct TranslatedIndexData
unsigned int serial;
};
struct SourceIndexData
{
const GLvoid *srcIndices;
unsigned int srcCount;
GLenum srcIndexType;
bool srcIndicesChanged;
};
class IndexDataManager : angle::NonCopyable
{
public:
explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass);
virtual ~IndexDataManager();
gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated);
gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated, SourceIndexData *sourceData);
private:
gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer);
......
......@@ -106,7 +106,10 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
gl::VertexArray *vao = data.state->getVertexArray();
TranslatedIndexData indexInfo;
indexInfo.indexRange = indexRange;
error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
SourceIndexData sourceIndexInfo;
error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo, &sourceIndexInfo);
if (error.isError())
{
return error;
......@@ -118,7 +121,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
ASSERT(!data.state->isTransformFeedbackActiveUnpaused());
GLsizei vertexCount = indexInfo.indexRange.length() + 1;
error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances);
error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances, &sourceIndexInfo);
if (error.isError())
{
return error;
......@@ -144,7 +147,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
if (!skipDraw(data, mode))
{
error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances);
error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances, program->usesPointSize());
if (error.isError())
{
return error;
......@@ -188,7 +191,7 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
applyTransformFeedbackBuffers(*data.state);
error = applyVertexBuffer(*data.state, mode, first, count, instances);
error = applyVertexBuffer(*data.state, mode, first, count, instances, nullptr);
if (error.isError())
{
return error;
......
......@@ -134,8 +134,8 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
bool rasterizerDiscard, bool transformFeedbackActive) = 0;
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) = 0;
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo) = 0;
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo) = 0;
virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
virtual void markAllStateDirty() = 0;
......@@ -206,7 +206,8 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
protected:
virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) = 0;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances,
bool usesPointSize) = 0;
virtual bool getLUID(LUID *adapterLuid) const = 0;
......
......@@ -9,10 +9,24 @@
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "common/MemoryBuffer.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
namespace
{
template <typename T>
GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index)
{
return reinterpret_cast<const T*>(data)[index];
}
typedef GLuint(*ReadIndexValueFunction)(const uint8_t *data, size_t index);
}
namespace rx
{
......@@ -20,7 +34,7 @@ PackPixelsParams::PackPixelsParams()
: format(GL_NONE),
type(GL_NONE),
outputPitch(0),
packBuffer(NULL),
packBuffer(nullptr),
offset(0)
{}
......@@ -129,6 +143,37 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
ID3D11Buffer *mNativeStorage;
};
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
// that has been expanded to match the indices list used. This storage is only
// used for FL9_3 pointsprite rendering emulation.
class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
{
public:
EmulatedIndexedStorage(Renderer11 *renderer);
~EmulatedIndexedStorage() override;
bool isMappable() const override { return true; }
ID3D11Buffer *getNativeStorage();
bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
size_t size, size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
void unmap() override;
bool update(SourceIndexData *indexInfo, const TranslatedAttribute *attribute);
private:
ID3D11Buffer *mNativeStorage; // contains expanded data for use by D3D
MemoryBuffer mMemoryBuffer; // original data (not expanded)
MemoryBuffer mIndicesMemoryBuffer; // indices data
SourceIndexData mIndexInfo; // indices information
size_t mAttributeStride; // per element stride in bytes
size_t mAttributeOffset; // starting offset
};
// Pack storage represents internal storage for pack buffers. We implement pack buffers
// as CPU memory, tied to a staging texture, for asynchronous texture readback.
class Buffer11::PackStorage : public Buffer11::BufferStorage
......@@ -188,7 +233,7 @@ Buffer11::Buffer11(Renderer11 *renderer)
: BufferD3D(renderer),
mRenderer(renderer),
mSize(0),
mMappedStorage(NULL),
mMappedStorage(nullptr),
mConstantBufferStorageAdditionalSize(0),
mMaxConstantBufferLruCount(0),
mReadUsageCount(0),
......@@ -314,7 +359,7 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset)
gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
{
Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
ASSERT(sourceBuffer != NULL);
ASSERT(sourceBuffer != nullptr);
BufferStorage *copyDest = getLatestBufferStorage();
if (!copyDest)
......@@ -416,7 +461,7 @@ gl::Error Buffer11::unmap(GLboolean *result)
{
ASSERT(mMappedStorage);
mMappedStorage->unmap();
mMappedStorage = NULL;
mMappedStorage = nullptr;
// TODO: detect if we had corruption. if so, return false.
*result = GL_TRUE;
......@@ -466,12 +511,36 @@ ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage)
if (!bufferStorage)
{
// Storage out-of-memory
return NULL;
return nullptr;
}
return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
}
ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo, const TranslatedAttribute *attribute)
{
markBufferUsage();
assert(indexInfo != nullptr);
assert(attribute != nullptr);
BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX);
if (!bufferStorage)
{
// Storage out-of-memory
return nullptr;
}
EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(bufferStorage);
if (!emulatedStorage->update(indexInfo, attribute))
{
// Storage out-of-memory
return nullptr;
}
return emulatedStorage->getNativeStorage();
}
ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size)
{
markBufferUsage();
......@@ -490,7 +559,7 @@ ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size)
if (!bufferStorage)
{
// Storage out-of-memory
return NULL;
return nullptr;
}
return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
......@@ -503,7 +572,7 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
if (!storage)
{
// Storage out-of-memory
return NULL;
return nullptr;
}
ID3D11Buffer *buffer = GetAs<NativeStorage>(storage)->getNativeStorage();
......@@ -524,7 +593,7 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
}
ID3D11Device *device = mRenderer->getDevice();
ID3D11ShaderResourceView *bufferSRV = NULL;
ID3D11ShaderResourceView *bufferSRV = nullptr;
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat);
......@@ -563,7 +632,7 @@ gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource,
Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
{
BufferStorage *newStorage = NULL;
BufferStorage *newStorage = nullptr;
auto directBufferIt = mBufferStorages.find(usage);
if (directBufferIt != mBufferStorages.end())
{
......@@ -581,6 +650,10 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
newStorage = new SystemMemoryStorage(mRenderer);
mHasSystemMemoryStorage = true;
}
else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX)
{
newStorage = new EmulatedIndexedStorage(mRenderer);
}
else
{
// buffer is not allocated, create it
......@@ -596,7 +669,7 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
if (newStorage->resize(mSize, true).isError())
{
// Out of memory error
return NULL;
return nullptr;
}
}
......@@ -697,7 +770,7 @@ Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const
{
// Even though we iterate over all the direct buffers, it is expected that only
// 1 or 2 will be present.
BufferStorage *latestStorage = NULL;
BufferStorage *latestStorage = nullptr;
DataRevision latestRevision = 0;
for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
{
......@@ -715,7 +788,7 @@ Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const
if (latestStorage->resize(mSize, true).isError())
{
// Out of memory error
return NULL;
return nullptr;
}
}
......@@ -729,7 +802,7 @@ Buffer11::NativeStorage *Buffer11::getStagingStorage()
if (!stagingStorage)
{
// Out-of-memory
return NULL;
return nullptr;
}
return GetAs<NativeStorage>(stagingStorage);
......@@ -742,7 +815,7 @@ Buffer11::PackStorage *Buffer11::getPackStorage()
if (!packStorage)
{
// Out-of-memory
return NULL;
return nullptr;
}
return GetAs<PackStorage>(packStorage);
......@@ -783,7 +856,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage)
: BufferStorage(renderer, usage),
mNativeStorage(NULL)
mNativeStorage(nullptr)
{
}
......@@ -860,7 +933,7 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
fillBufferDesc(&bufferDesc, mRenderer, mUsage, size);
ID3D11Buffer *newBuffer;
HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
HRESULT result = device->CreateBuffer(&bufferDesc, nullptr, &newBuffer);
if (FAILED(result))
{
......@@ -974,11 +1047,164 @@ void Buffer11::NativeStorage::unmap()
context->Unmap(mNativeStorage, 0);
}
Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
: BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX),
mNativeStorage(nullptr)
{
}
Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage()
{
SafeRelease(mNativeStorage);
}
ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage()
{
if (!mNativeStorage)
{
// Expand the memory storage upon request and cache the results.
unsigned int expandedDataSize = (mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset;
MemoryBuffer expandedData;
if (!expandedData.resize(expandedDataSize))
{
return nullptr;
}
// Clear the contents of the allocated buffer
ZeroMemory(expandedData.data(), expandedDataSize);
uint8_t *curr = expandedData.data();
const uint8_t *ptr = static_cast<const uint8_t*>(mIndexInfo.srcIndices);
// Ensure that we start in the correct place for the emulated data copy operation to maintain
// offset behaviors.
curr += mAttributeOffset;
ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
switch (mIndexInfo.srcIndexType)
{
case GL_UNSIGNED_INT: readIndexValue = ReadIndexValueFromIndices<GLuint>; break;
case GL_UNSIGNED_SHORT: readIndexValue = ReadIndexValueFromIndices<GLushort>; break;
case GL_UNSIGNED_BYTE: readIndexValue = ReadIndexValueFromIndices<GLubyte>; break;
}
// Iterate over the cached index data and copy entries indicated into the emulated buffer.
for (GLuint i = 0; i < mIndexInfo.srcCount; i++)
{
GLuint idx = readIndexValue(ptr, i);
memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride);
curr += mAttributeStride;
}
// Finally, initialize the emulated indexed native storage object with the newly copied data and free
// the temporary buffers used.
ID3D11Device *device = mRenderer->getDevice();
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = expandedDataSize;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA subResourceData = { expandedData.data(), 0, 0 };
HRESULT result = device->CreateBuffer(&bufferDesc, &subResourceData, &mNativeStorage);
if (FAILED(result))
{
ERR("Could not create emulated index data buffer: %08lX", result);
return nullptr;
}
d3d11::SetDebugName(mNativeStorage, "Buffer11::EmulatedIndexedStorage");
}
return mNativeStorage;
}
bool Buffer11::EmulatedIndexedStorage::update(SourceIndexData *indexInfo, const TranslatedAttribute *attribute)
{
// 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
// be cleared to avoid unnecessary recreation of the buffer.
if (mNativeStorage == nullptr || indexInfo->srcIndicesChanged)
{
SafeRelease(mNativeStorage);
// Copy attribute offset and stride information
mAttributeStride = attribute->stride;
mAttributeOffset = attribute->offset;
// Copy the source index data. This ensures that the lifetime of the indices pointer
// stays with this storage until the next time we invalidate.
size_t indicesDataSize = 0;
switch (indexInfo->srcIndexType)
{
case GL_UNSIGNED_INT: indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; break;
case GL_UNSIGNED_SHORT: indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; break;
case GL_UNSIGNED_BYTE: indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; break;
default: indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; break;
}
if (!mIndicesMemoryBuffer.resize(indicesDataSize))
{
return false;
}
memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize);
// Copy the source index data description and update the srcIndices pointer to point
// to our cached index data.
mIndexInfo = *indexInfo;
mIndexInfo.srcIndices = mIndicesMemoryBuffer.data();
indexInfo->srcIndicesChanged = false;
}
return true;
}
bool Buffer11::EmulatedIndexedStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset,
size_t size, size_t destOffset)
{
ASSERT(source->isMappable());
const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT);
ASSERT(destOffset + size <= mMemoryBuffer.size());
memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
source->unmap();
return true;
}
gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData)
{
if (mMemoryBuffer.size() < size)
{
if (!mMemoryBuffer.resize(size))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage");
}
mBufferSize = size;
}
return gl::Error(GL_NO_ERROR);
}
uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access)
{
ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
return mMemoryBuffer.data() + offset;
}
void Buffer11::EmulatedIndexedStorage::unmap()
{
// No-op
}
Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
: BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK),
mStagingTexture(NULL),
mStagingTexture(nullptr),
mTextureFormat(DXGI_FORMAT_UNKNOWN),
mQueuedPackCommand(NULL),
mQueuedPackCommand(nullptr),
mDataModified(false)
{
}
......@@ -1023,7 +1249,7 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc
gl::Error error = flushQueuedPackCommand();
if (error.isError())
{
return NULL;
return nullptr;
}
mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
......@@ -1049,7 +1275,7 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
D3D11_TEXTURE2D_DESC textureDesc;
srcTexure->GetDesc(&textureDesc);
if (mStagingTexture != NULL &&
if (mStagingTexture != nullptr &&
(mTextureFormat != textureDesc.Format ||
mTextureSize.width != params.area.width ||
mTextureSize.height != params.area.height))
......@@ -1060,7 +1286,7 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
mTextureFormat = DXGI_FORMAT_UNKNOWN;
}
if (mStagingTexture == NULL)
if (mStagingTexture == nullptr)
{
ID3D11Device *device = mRenderer->getDevice();
HRESULT hr;
......@@ -1082,7 +1308,7 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture);
hr = device->CreateTexture2D(&stagingDesc, nullptr, &mStagingTexture);
if (FAILED(hr))
{
ASSERT(hr == E_OUTOFMEMORY);
......
......@@ -17,6 +17,8 @@
namespace rx
{
class Renderer11;
struct SourceIndexData;
struct TranslatedAttribute;
enum BufferUsage
{
......@@ -27,6 +29,7 @@ enum BufferUsage
BUFFER_USAGE_PIXEL_PACK,
BUFFER_USAGE_UNIFORM,
BUFFER_USAGE_SYSTEM_MEMORY,
BUFFER_USAGE_EMULATED_INDEXED_VERTEX,
};
struct PackPixelsParams
......@@ -53,6 +56,7 @@ class Buffer11 : public BufferD3D
virtual ~Buffer11();
ID3D11Buffer *getBuffer(BufferUsage usage);
ID3D11Buffer *getEmulatedIndexedBuffer(SourceIndexData *indexInfo, const TranslatedAttribute *attribute);
ID3D11Buffer *getConstantBufferRange(GLintptr offset, GLsizeiptr size);
ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat);
bool isMapped() const { return mMappedStorage != NULL; }
......@@ -74,6 +78,7 @@ class Buffer11 : public BufferD3D
private:
class BufferStorage;
class EmulatedIndexedStorage;
class NativeStorage;
class PackStorage;
class SystemMemoryStorage;
......@@ -117,6 +122,8 @@ class Buffer11 : public BufferD3D
BufferStorage *getLatestBufferStorage() const;
BufferStorage *getContantBufferRangeStorage(GLintptr offset, GLsizeiptr size);
void invalidateEmulatedIndexedBuffer();
};
}
......
......@@ -14,6 +14,7 @@
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/Program.h"
#include "libANGLE/VertexAttribute.h"
......@@ -98,7 +99,7 @@ void InputLayoutCache::markDirty()
}
gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttribute> &unsortedAttributes,
GLenum mode, gl::Program *program)
GLenum mode, gl::Program *program, SourceIndexData *sourceInfo)
{
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
......@@ -107,6 +108,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
programD3D->sortAttributesByLayout(unsortedAttributes, sortedSemanticIndices, sortedAttributes);
bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
bool indexedPointSpriteEmulationActive = instancedPointSpritesActive && (sourceInfo != nullptr);
if (!mDevice || !mDeviceContext)
{
......@@ -293,8 +295,22 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
VertexBuffer11 *vertexBuffer = GetAs<VertexBuffer11>(sortedAttributes[i]->vertexBuffer);
Buffer11 *bufferStorage = sortedAttributes[i]->storage ? GetAs<Buffer11>(sortedAttributes[i]->storage) : NULL;
buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
: vertexBuffer->getBuffer();
// If indexed pointsprite emulation is active, then we need to take a less efficent code path.
// Emulated indexed pointsprite rendering requires that the vertex buffers match exactly to
// the indices passed by the caller. This could expand or shrink the vertex buffer depending
// on the number of points indicated by the index list or how many duplicates are found on the index list.
if (bufferStorage == nullptr)
{
buffer = vertexBuffer->getBuffer();
}
else if (indexedPointSpriteEmulationActive)
{
buffer = bufferStorage->getEmulatedIndexedBuffer(sourceInfo, sortedAttributes[i]);
}
else
{
buffer = bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
}
vertexStride = sortedAttributes[i]->stride;
vertexOffset = sortedAttributes[i]->offset;
......@@ -322,7 +338,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
}
// Instanced PointSprite emulation requires two additional ID3D11Buffers.
// A vertex buffer needs to be created and added to the list of current buffers,
// A vertex buffer needs to be created and added to the list of current buffers,
// strides and offsets collections. This buffer contains the vertices for a single
// PointSprite quad.
// An index buffer also needs to be created and applied because rendering instanced
......
......@@ -27,6 +27,8 @@ class Program;
namespace rx
{
struct TranslatedAttribute;
struct TranslatedIndexData;
struct SourceIndexData;
class InputLayoutCache : angle::NonCopyable
{
......@@ -39,7 +41,7 @@ class InputLayoutCache : angle::NonCopyable
void markDirty();
gl::Error applyVertexBuffers(const std::vector<TranslatedAttribute> &attributes,
GLenum mode, gl::Program *program);
GLenum mode, gl::Program *program, SourceIndexData *sourceInfo);
private:
struct InputLayoutElement
......
......@@ -237,6 +237,7 @@ Renderer11::Renderer11(egl::Display *display)
mLineLoopIB = NULL;
mTriangleFanIB = NULL;
mAppliedIBChanged = false;
mBlit = NULL;
mPixelTransfer = NULL;
......@@ -1515,7 +1516,7 @@ gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer)
return gl::Error(GL_NO_ERROR);
}
gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances)
gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo)
{
gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
......@@ -1523,12 +1524,18 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLi
return error;
}
return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram());
// If index information is passed, mark it with the current changed status.
if (sourceInfo)
{
sourceInfo->srcIndicesChanged = mAppliedIBChanged;
}
return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(), sourceInfo);
}
gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo)
{
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo, sourceIndexInfo);
if (error.isError())
{
return error;
......@@ -1548,6 +1555,7 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen
buffer = indexBuffer->getBuffer();
}
mAppliedIBChanged = false;
if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset)
{
mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset);
......@@ -1555,6 +1563,7 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen
mAppliedIB = buffer;
mAppliedIBFormat = bufferFormat;
mAppliedIBOffset = indexInfo->startOffset;
mAppliedIBChanged = true;
}
return gl::Error(GL_NO_ERROR);
......@@ -1690,9 +1699,9 @@ gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei coun
}
else
{
// If gl_PointSize is used and GL_POINTS is specified, then it is expected to render pointsprites.
// If instanced pointsprite emulation is being used the topology is expexted to be
// D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced must be used.
// If the shader is writing to gl_PointSize, then pointsprites are being rendered.
// Emulating instanced point sprites for FL9_3 requires the topology to be
// D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
{
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
......@@ -1706,8 +1715,10 @@ gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei coun
}
gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances)
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances,
bool usesPointSize)
{
bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation;
int minIndex = static_cast<int>(indexInfo.indexRange.start);
if (mode == GL_LINE_LOOP)
......@@ -1725,8 +1736,27 @@ gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, cons
}
else
{
mDeviceContext->DrawIndexed(count, 0, -minIndex);
return gl::Error(GL_NO_ERROR);
// If the shader is writing to gl_PointSize, then pointsprites are being rendered.
// Emulating instanced point sprites for FL9_3 requires the topology to be
// D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
{
// The count parameter passed to drawElements represents the total number of instances
// to be rendered. Each instance is referenced by the bound index buffer from the
// the caller.
//
// Indexed pointsprite emulation replicates data for duplicate entries found
// in the index buffer.
// This is not an efficent rendering mechanism and is only used on downlevel renderers
// that do not support geometry shaders.
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
return gl::Error(GL_NO_ERROR);
}
else
{
mDeviceContext->DrawIndexed(count, 0, -minIndex);
return gl::Error(GL_NO_ERROR);
}
}
}
......
......@@ -134,13 +134,14 @@ class Renderer11 : public RendererD3D
bool rasterizerDiscard, bool transformFeedbackActive);
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
void applyTransformFeedbackBuffers(const gl::State &state) override;
gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances,
bool usesPointSize);
virtual void markAllStateDirty();
......@@ -391,6 +392,7 @@ class Renderer11 : public RendererD3D
ID3D11Buffer *mAppliedIB;
DXGI_FORMAT mAppliedIBFormat;
unsigned int mAppliedIBOffset;
bool mAppliedIBChanged;
// Currently applied transform feedback buffers
size_t mAppliedNumXFBBindings;
......
......@@ -1416,7 +1416,7 @@ gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer)
return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer());
}
gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances)
gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData * /*sourceInfo*/)
{
gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
......@@ -1428,9 +1428,9 @@ gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLin
}
// Applies the indices and element array bindings to the Direct3D 9 device
gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo)
{
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo, sourceIndexInfo);
if (error.isError())
{
return error;
......@@ -1497,7 +1497,8 @@ gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count
}
gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/)
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/,
bool /*usesPointSize*/)
{
startScene();
......
......@@ -110,14 +110,15 @@ class Renderer9 : public RendererD3D
bool rasterizerDiscard, bool transformFeedbackActive);
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
void applyTransformFeedbackBuffers(const gl::State &state) override;
gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances,
bool usesPointSize);
gl::Error clear(const ClearParameters &clearParams,
const gl::FramebufferAttachment *colorBuffer,
......
......@@ -67,6 +67,7 @@
],
'angle_end2end_tests_win_sources':
[
'<(angle_path)/src/tests/gl_tests/D3D11EmulatedIndexedBufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/D3D11FormatTablesTest.cpp',
'<(angle_path)/src/tests/gl_tests/QueryDisplayAttribTest.cpp',
# TODO(cwallez) for Linux, requires a portable implementation of threads
......
//
// Copyright 2015 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.
//
// D3D11EmulatedIndexedBufferTest:
// Tests to validate our D3D11 support for emulating an indexed
// vertex buffer.
//
#include "libANGLE/angletypes.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_instantiate.h"
using namespace angle;
namespace
{
class D3D11EmulatedIndexedBufferTest : public ANGLETest
{
protected:
void SetUp() override
{
ANGLETest::SetUp();
ASSERT_EQ(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, GetParam().getRenderer());
gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
mRenderer = rx::GetAs<rx::Renderer11>(context->getRenderer());
mSourceBuffer = new rx::Buffer11(mRenderer);
GLfloat testData[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
gl::Error error = mSourceBuffer->setData(testData, sizeof(testData), GL_STATIC_DRAW);
ASSERT_FALSE(error.isError());
mTranslatedAttribute.offset = 0;
mTranslatedAttribute.stride = sizeof(GLfloat);
GLubyte indices[] = {0, 0, 3, 4, 2, 1, 1};
for (size_t i = 0; i < _countof(indices); i++)
{
mExpectedExpandedData.push_back(testData[indices[i]]);
mubyteIndices.push_back(indices[i]);
muintIndices.push_back(indices[i]);
mushortIndices.push_back(indices[i]);
}
}
void TearDown() override
{
SafeDelete(mSourceBuffer);
ANGLETest::TearDown();
}
void createMappableCompareBufferFromEmulatedBuffer(ID3D11Buffer *sourceBuffer, GLuint size, ID3D11Buffer **mappableBuffer)
{
*mappableBuffer = nullptr;
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = size;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
bufferDesc.Usage = D3D11_USAGE_STAGING;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
HRESULT hr = mRenderer->getDevice()->CreateBuffer(&bufferDesc, nullptr, mappableBuffer);
ASSERT_TRUE(SUCCEEDED(hr));
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
mRenderer->getDeviceContext()->CopySubresourceRegion(*mappableBuffer, 0, 0, 0, 0, sourceBuffer, 0, &srcBox);
}
void compareContents(ID3D11Buffer *actual)
{
ID3D11Buffer *compareBuffer = nullptr;
createMappableCompareBufferFromEmulatedBuffer(actual, sizeof(GLfloat) * mExpectedExpandedData.size(), &compareBuffer);
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = mRenderer->getDeviceContext()->Map(compareBuffer, 0, D3D11_MAP_READ, 0, &mappedResource);
ASSERT_TRUE(SUCCEEDED(hr));
GLfloat* compareData = static_cast<GLfloat*>(mappedResource.pData);
for (size_t i = 0; i < mExpectedExpandedData.size(); i++)
{
EXPECT_EQ(mExpectedExpandedData[i], compareData[i]);
}
mRenderer->getDeviceContext()->Unmap(compareBuffer, 0);
SafeRelease(compareBuffer);
}
void emulateAndCompare(rx::SourceIndexData *srcData)
{
ID3D11Buffer* emulatedBuffer = mSourceBuffer->getEmulatedIndexedBuffer(srcData, &mTranslatedAttribute);
ASSERT_TRUE(emulatedBuffer != nullptr);
compareContents(emulatedBuffer);
}
protected:
rx::Buffer11 *mSourceBuffer;
rx::Renderer11 *mRenderer;
rx::TranslatedAttribute mTranslatedAttribute;
std::vector<GLfloat> mExpectedExpandedData;
std::vector<GLubyte> mubyteIndices;
std::vector<GLuint> muintIndices;
std::vector<GLushort> mushortIndices;
};
// This tests that a GL_UNSIGNED_BYTE indices list can be successfully expanded
// into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLubyteIndices)
{
rx::SourceIndexData srcData = {mubyteIndices.data(), mubyteIndices.size(), GL_UNSIGNED_BYTE, false};
emulateAndCompare(&srcData);
}
// This tests that a GL_UNSIGNED_SHORT indices list can be successfully expanded
// into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLushortIndices)
{
rx::SourceIndexData srcData = {mushortIndices.data(), mushortIndices.size(), GL_UNSIGNED_SHORT, false};
emulateAndCompare(&srcData);
}
// This tests that a GL_UNSIGNED_INT indices list can be successfully expanded
// into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLuintIndices)
{
rx::SourceIndexData srcData = {muintIndices.data(), muintIndices.size(), GL_UNSIGNED_INT, false};
emulateAndCompare(&srcData);
}
// This tests verifies that a Buffer11 contents remain unchanged after calling getEmulatedIndexedBuffer
TEST_P(D3D11EmulatedIndexedBufferTest, TestSourceBufferRemainsUntouchedAfterExpandOperation)
{
// Copy the original source buffer before any expand calls have been made
rx::Buffer11 *cleanSourceBuffer = new rx::Buffer11(mRenderer);
cleanSourceBuffer->copySubData(mSourceBuffer, 0, 0, mSourceBuffer->getSize());
// Do a basic exanded and compare test.
rx::SourceIndexData srcData = {muintIndices.data(), muintIndices.size(), GL_UNSIGNED_INT, false};
emulateAndCompare(&srcData);
const uint8_t *sourceBufferMem = nullptr;
const uint8_t *cleanBufferMem = nullptr;
gl::Error error = mSourceBuffer->getData(&sourceBufferMem);
ASSERT_FALSE(error.isError());
error = cleanSourceBuffer->getData(&cleanBufferMem);
ASSERT_FALSE(error.isError());
int result = memcmp(sourceBufferMem, cleanBufferMem, cleanSourceBuffer->getSize());
ASSERT_EQ(result, 0);
SafeDelete(cleanSourceBuffer);
}
ANGLE_INSTANTIATE_TEST(D3D11EmulatedIndexedBufferTest,
ES2_D3D11());
} // anonymous namespace
......@@ -60,23 +60,64 @@ class IndexedPointsTest : public ANGLETest
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
if (mProgram == 0)
ASSERT_NE(0u, mProgram);
const std::string vertexShaderSource2 = SHADER_SOURCE
(
precision highp float;
attribute vec2 position;
attribute vec4 color;
varying vec4 vcolor;
void main()
{
gl_PointSize = 5.0;
gl_Position = vec4(position, 0.0, 1.0);
vcolor = color;
}
);
const std::string fragmentShaderSource2 = SHADER_SOURCE
(
precision highp float;
varying vec4 vcolor;
void main()
{
gl_FragColor = vec4(vcolor.xyz, 1.0);
}
);
mVertexWithColorBufferProgram = CompileProgram(vertexShaderSource2, fragmentShaderSource2);
ASSERT_NE(0u, mVertexWithColorBufferProgram);
// Construct a vertex buffer of position values and color values
// contained in a single structure
const float verticesWithColor[] =
{
FAIL() << "shader compilation failed.";
}
getIndexPositionX(0), getIndexPositionY(0), 0.0f, 1.0f, 0.0f,
getIndexPositionX(2), getIndexPositionY(2), 0.0f, 1.0f, 0.0f,
getIndexPositionX(1), getIndexPositionY(1), 0.0f, 1.0f, 0.0f,
getIndexPositionX(3), getIndexPositionY(3), 0.0f, 1.0f, 0.0f,
};
glGenBuffers(1, &mVertexWithColorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexWithColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesWithColor), &verticesWithColor[0], GL_STATIC_DRAW);
// Construct a vertex buffer of position values only
const GLfloat vertices[] =
{
getIndexPositionX(0), getIndexPositionY(0),
getIndexPositionX(1), getIndexPositionY(1),
getIndexPositionX(2), getIndexPositionY(2),
getIndexPositionX(1), getIndexPositionY(1),
getIndexPositionX(3), getIndexPositionY(3),
};
glGenBuffers(1, &mVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
const IndexType indices[] = { 0, 1, 2, 3 };
// The indices buffer is shared between both variations of tests
const IndexType indices[] = { 0, 2, 1, 3 };
glGenBuffers(1, &mIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW);
......@@ -84,12 +125,16 @@ class IndexedPointsTest : public ANGLETest
virtual void TearDown()
{
glDeleteBuffers(1, &mVertexBuffer);
glDeleteBuffers(1, &mIndexBuffer);
glDeleteProgram(mProgram);
glDeleteBuffers(1, &mVertexWithColorBuffer);
glDeleteProgram(mVertexWithColorBufferProgram);
ANGLETest::TearDown();
}
void runTest(GLuint firstIndex)
void runTest(GLuint firstIndex, bool useVertexBufferWithColor = false)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
......@@ -97,14 +142,30 @@ class IndexedPointsTest : public ANGLETest
GLint viewportSize[4];
glGetIntegerv(GL_VIEWPORT, viewportSize);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
GLint vertexLocation = glGetAttribLocation(mProgram, "position");
glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertexLocation);
// Choose appropriate program to apply for the test
GLuint program = useVertexBufferWithColor ? mVertexWithColorBufferProgram : mProgram;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
if (useVertexBufferWithColor)
{
glBindBuffer(GL_ARRAY_BUFFER, mVertexWithColorBuffer);
GLint vertexLocation = glGetAttribLocation(program, "position");
glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, VertexWithColorSize, 0);
glEnableVertexAttribArray(vertexLocation);
GLint vertexColorLocation = glGetAttribLocation(program, "color");
glVertexAttribPointer(vertexColorLocation, 3, GL_FLOAT, GL_FALSE, VertexWithColorSize, (GLvoid*)((sizeof(float) * 2)));
glEnableVertexAttribArray(vertexColorLocation);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
GLint vertexLocation = glGetAttribLocation(program, "position");
glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertexLocation);
}
glUseProgram(mProgram);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glUseProgram(program);
glDrawElements(GL_POINTS, mPointCount - firstIndex, IndexTypeName, reinterpret_cast<void*>(firstIndex * sizeof(IndexType)));
......@@ -119,15 +180,32 @@ class IndexedPointsTest : public ANGLETest
}
else
{
EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
if (useVertexBufferWithColor)
{
// Pixel data is assumed to be GREEN
EXPECT_PIXEL_EQ(x, y, 0, 255, 0, 255);
}
else
{
// Pixel data is assumed to be RED
EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
}
}
}
swapBuffers();
}
GLuint mProgram;
GLuint mVertexBuffer;
GLuint mIndexBuffer;
GLuint mVertexWithColorBufferProgram;
GLuint mVertexWithColorBuffer;
static const GLuint mPointCount = 4;
private:
const size_t VertexWithColorSize = sizeof(float) * 5;
};
typedef IndexedPointsTest<GLubyte, GL_UNSIGNED_BYTE> IndexedPointsTestUByte;
......@@ -152,6 +230,26 @@ TEST_P(IndexedPointsTestUByte, UnsignedByteOffset3)
runTest(3);
}
TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset0)
{
runTest(0, true);
}
TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset1)
{
runTest(1, true);
}
TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset2)
{
runTest(2, true);
}
TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset3)
{
runTest(3, true);
}
typedef IndexedPointsTest<GLushort, GL_UNSIGNED_SHORT> IndexedPointsTestUShort;
TEST_P(IndexedPointsTestUShort, UnsignedShortOffset0)
......@@ -174,6 +272,34 @@ TEST_P(IndexedPointsTestUShort, UnsignedShortOffset3)
runTest(3);
}
TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset0)
{
runTest(0, true);
}
TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset1)
{
runTest(1, true);
}
TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset2)
{
runTest(2, true);
}
TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset3)
{
runTest(3, true);
}
TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffsetChangingIndices)
{
runTest(3, true);
runTest(1, true);
runTest(0, true);
runTest(2, true);
}
typedef IndexedPointsTest<GLuint, GL_UNSIGNED_INT> IndexedPointsTestUInt;
TEST_P(IndexedPointsTestUInt, UnsignedIntOffset0)
......@@ -216,7 +342,47 @@ TEST_P(IndexedPointsTestUInt, UnsignedIntOffset3)
runTest(3);
}
TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset0)
{
if (getClientVersion() < 3 && !extensionEnabled("GL_OES_element_index_uint"))
{
return;
}
runTest(0, false);
}
TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset1)
{
if (getClientVersion() < 3 && !extensionEnabled("GL_OES_element_index_uint"))
{
return;
}
runTest(1, false);
}
TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset2)
{
if (getClientVersion() < 3 && !extensionEnabled("GL_OES_element_index_uint"))
{
return;
}
runTest(2, false);
}
TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset3)
{
if (getClientVersion() < 3 && !extensionEnabled("GL_OES_element_index_uint"))
{
return;
}
runTest(3, false);
}
// TODO(geofflang): Figure out why this test fails on Intel OpenGL
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUByte, ES2_D3D11());
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUShort, ES2_D3D11());
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUInt, ES2_D3D11());
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUByte, ES2_D3D11(), ES2_D3D11_FL9_3());
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUShort, ES2_D3D11(), ES2_D3D11_FL9_3());
ANGLE_INSTANTIATE_TEST(IndexedPointsTestUInt, ES2_D3D11(), ES2_D3D11_FL9_3());
......@@ -154,10 +154,11 @@ IndexDataManagerPerfTest::IndexDataManagerPerfTest()
void IndexDataManagerPerfTest::step(float dt, double totalTime)
{
rx::TranslatedIndexData translatedIndexData;
rx::SourceIndexData sourceIndexData;
for (unsigned int iteration = 0; iteration < 100; ++iteration)
{
mIndexBuffer.getIndexRange(GL_UNSIGNED_SHORT, 0, mIndexCount, &translatedIndexData.indexRange);
mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr, &translatedIndexData);
mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr, &translatedIndexData, &sourceIndexData);
}
if (mTimer->getElapsedTime() >= 5.0)
......
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