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;
......
......@@ -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