Commit 534bf87b by Cooper Partin Committed by Commit Bot

Implemented instanced rendering for emulated point sprites

Non-instanced PointSprite emulation for lower feature levels is implemented using D3D DrawIndexedInstanced and an instanced vertex buffer containing a pointsprite quad. GL instanced rendering using glDrawArraysInstanced and glDrawElementsInstanced with pointsprite emulation is performed using a for-loop. The loop iterates over each instance to render and adjusts the buffer offsets accordingly. This is not performant and is only used and required by this chosen pointsprite emulation method. Indexed instanced (glDrawElementsInstanced), uses the same offset loop because the vertex buffer containing the data to be rendered has already been expanded using getEmulatedIndexedBuffer(). Expanding the buffer makes the two rendering operations similar enough to share code. BUG=angleproject:1279 TEST=angle_end2end_tests Change-Id: If46cc9f158e29f5518c70ad630b3228f474a9f8b Reviewed-on: https://chromium-review.googlesource.com/321407Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent cfd6b2b6
......@@ -150,7 +150,6 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
gl::Buffer *glBuffer,
const GLvoid *indices,
TranslatedIndexData *translated,
SourceIndexData *sourceData,
bool primitiveRestartFixedIndexEnabled)
{
// Avoid D3D11's primitive restart index value
......@@ -176,13 +175,10 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
translated->indexType = dstType;
if (sourceData)
{
sourceData->srcBuffer = buffer;
sourceData->srcIndices = indices;
sourceData->srcIndexType = srcType;
sourceData->srcCount = count;
}
translated->srcIndexData.srcBuffer = buffer;
translated->srcIndexData.srcIndices = indices;
translated->srcIndexData.srcIndexType = srcType;
translated->srcIndexData.srcCount = count;
// Case 1: the indices are passed by pointer, which forces the streaming of index data
if (glBuffer == nullptr)
......
......@@ -36,6 +36,15 @@ class IndexBuffer;
class BufferD3D;
class RendererD3D;
struct SourceIndexData
{
BufferD3D *srcBuffer;
const GLvoid *srcIndices;
unsigned int srcCount;
GLenum srcIndexType;
bool srcIndicesChanged;
};
struct TranslatedIndexData
{
gl::IndexRange indexRange;
......@@ -46,15 +55,8 @@ struct TranslatedIndexData
BufferD3D *storage;
GLenum indexType;
unsigned int serial;
};
struct SourceIndexData
{
BufferD3D *srcBuffer;
const GLvoid *srcIndices;
unsigned int srcCount;
GLenum srcIndexType;
bool srcIndicesChanged;
SourceIndexData srcIndexData;
};
class IndexDataManager : angle::NonCopyable
......@@ -68,7 +70,6 @@ class IndexDataManager : angle::NonCopyable
gl::Buffer *glBuffer,
const GLvoid *indices,
TranslatedIndexData *translated,
SourceIndexData *sourceData,
bool primitiveRestartFixedIndexEnabled);
private:
......
......@@ -156,9 +156,7 @@ gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
TranslatedIndexData indexInfo;
indexInfo.indexRange = indexRange;
SourceIndexData sourceIndexInfo;
error = applyIndexBuffer(data, indices, count, mode, type, &indexInfo, &sourceIndexInfo);
error = applyIndexBuffer(data, indices, count, mode, type, &indexInfo);
if (error.isError())
{
return error;
......@@ -171,7 +169,7 @@ gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
size_t vertexCount = indexInfo.indexRange.vertexCount();
error = applyVertexBuffer(*data.state, mode, static_cast<GLsizei>(indexInfo.indexRange.start),
static_cast<GLsizei>(vertexCount), instances, &sourceIndexInfo);
static_cast<GLsizei>(vertexCount), instances, &indexInfo);
if (error.isError())
{
return error;
......
......@@ -162,14 +162,18 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
GLenum drawMode,
const std::vector<D3DUniform *> &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, SourceIndexData *sourceIndexInfo) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
TranslatedIndexData *indexInfo) = 0;
virtual gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) = 0;
TranslatedIndexData *indexInfo) = 0;
virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
virtual unsigned int getReservedVertexUniformVectors() const = 0;
......
......@@ -27,6 +27,11 @@ namespace rx
namespace
{
size_t GetReservedBufferCount(bool usesPointSpriteEmulation)
{
return usesPointSpriteEmulation ? 1 : 0;
}
gl::InputLayout GetInputLayout(const SortedAttribArray &translatedAttributes, size_t attributeCount)
{
gl::InputLayout inputLayout(attributeCount, gl::VERTEX_FORMAT_INVALID);
......@@ -131,13 +136,13 @@ bool InputLayoutCache::PackedAttributeLayout::operator<(const PackedAttributeLay
return memcmp(attributeData, other.attributeData, sizeof(uint32_t) * numAttributes) < 0;
}
InputLayoutCache::InputLayoutCache()
: mCacheSize(kDefaultCacheSize)
InputLayoutCache::InputLayoutCache() : mCacheSize(kDefaultCacheSize), mUnsortedAttributesCount(0)
{
mCounter = 0;
mDevice = NULL;
mDeviceContext = NULL;
mCurrentIL = NULL;
for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
{
mCurrentBuffers[i] = NULL;
......@@ -182,10 +187,15 @@ void InputLayoutCache::markDirty()
mCurrentVertexStrides[i] = static_cast<UINT>(-1);
mCurrentVertexOffsets[i] = static_cast<UINT>(-1);
}
mUnsortedAttributesCount = 0;
}
gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttribute> &unsortedAttributes,
GLenum mode, gl::Program *program, SourceIndexData *sourceInfo)
gl::Error InputLayoutCache::applyVertexBuffers(
const std::vector<TranslatedAttribute> &unsortedAttributes,
GLenum mode,
gl::Program *program,
TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance)
{
ASSERT(mDevice && mDeviceContext);
......@@ -195,29 +205,30 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
SortedIndexArray sortedSemanticIndices;
SortedAttribArray sortedAttributes;
sortedAttributes.fill(nullptr);
mSortedAttributes.fill(nullptr);
mUnsortedAttributesCount = unsortedAttributes.size();
programD3D->sortAttributesByLayout(unsortedAttributes, sortedSemanticIndices.data(),
sortedAttributes.data());
mSortedAttributes.data());
// If we are using FL 9_3, make sure the first attribute is not instanced
if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && !unsortedAttributes.empty())
{
if (sortedAttributes[0]->divisor > 0)
if (mSortedAttributes[0]->divisor > 0)
{
Optional<size_t> firstNonInstancedIndex =
FindFirstNonInstanced(sortedAttributes, unsortedAttributes.size());
FindFirstNonInstanced(mSortedAttributes, unsortedAttributes.size());
if (firstNonInstancedIndex.valid())
{
size_t index = firstNonInstancedIndex.value();
std::swap(sortedAttributes[0], sortedAttributes[index]);
std::swap(mSortedAttributes[0], mSortedAttributes[index]);
std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]);
}
}
}
gl::Error error = updateInputLayout(program, mode, sortedAttributes, sortedSemanticIndices,
unsortedAttributes.size());
gl::Error error = updateInputLayout(program, mode, mSortedAttributes, sortedSemanticIndices,
unsortedAttributes.size(), numIndicesPerInstance);
if (error.isError())
{
return error;
......@@ -228,7 +239,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
size_t maxDiff = 0;
// Note that if we use instance emulation, we reserve the first buffer slot.
size_t reservedBuffers = programUsesInstancedPointSprites ? 1 : 0;
size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites);
for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers);
++attribIndex)
......@@ -237,7 +248,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
UINT vertexStride = 0;
UINT vertexOffset = 0;
const auto &attrib = *sortedAttributes[attribIndex];
const auto &attrib = *mSortedAttributes[attribIndex];
if (attribIndex < unsortedAttributes.size() && attrib.active)
{
......@@ -252,24 +263,25 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
{
buffer = vertexBuffer->getBuffer();
}
else if (instancedPointSpritesActive && (sourceInfo != nullptr))
else if (instancedPointSpritesActive && (indexInfo != nullptr))
{
if (sourceInfo->srcBuffer != nullptr)
if (indexInfo->srcIndexData.srcBuffer != nullptr)
{
const uint8_t *bufferData = nullptr;
error = sourceInfo->srcBuffer->getData(&bufferData);
error = indexInfo->srcIndexData.srcBuffer->getData(&bufferData);
if (error.isError())
{
return error;
}
ASSERT(bufferData != nullptr);
ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(sourceInfo->srcIndices);
sourceInfo->srcBuffer = nullptr;
sourceInfo->srcIndices = bufferData + offset;
ptrdiff_t offset =
reinterpret_cast<ptrdiff_t>(indexInfo->srcIndexData.srcIndices);
indexInfo->srcIndexData.srcBuffer = nullptr;
indexInfo->srcIndexData.srcIndices = bufferData + offset;
}
buffer = bufferStorage->getEmulatedIndexedBuffer(sourceInfo, &attrib);
buffer = bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData, &attrib);
}
else
{
......@@ -395,11 +407,33 @@ gl::Error InputLayoutCache::applyVertexBuffers(const std::vector<TranslatedAttri
return gl::Error(GL_NO_ERROR);
}
gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId)
{
size_t reservedBuffers = GetReservedBufferCount(true);
for (size_t attribIndex = 0; attribIndex < mUnsortedAttributesCount; ++attribIndex)
{
const auto &attrib = *mSortedAttributes[attribIndex];
size_t bufferIndex = reservedBuffers + attribIndex;
if (attrib.active && attrib.divisor > 0)
{
mCurrentVertexOffsets[bufferIndex] =
attrib.offset + (attrib.stride * (emulatedInstanceId / attrib.divisor));
}
}
mDeviceContext->IASetVertexBuffers(0, gl::MAX_VERTEX_ATTRIBS, mCurrentBuffers,
mCurrentVertexStrides, mCurrentVertexOffsets);
return gl::Error(GL_NO_ERROR);
}
gl::Error InputLayoutCache::updateInputLayout(gl::Program *program,
GLenum mode,
const SortedAttribArray &sortedAttributes,
const SortedIndexArray &sortedSemanticIndices,
size_t attribCount)
size_t attribCount,
GLsizei numIndicesPerInstance)
{
const std::vector<sh::Attribute> &shaderAttributes = program->getAttributes();
PackedAttributeLayout layout;
......@@ -419,6 +453,11 @@ gl::Error InputLayoutCache::updateInputLayout(gl::Program *program,
layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE;
}
if (numIndicesPerInstance > 0)
{
layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE;
}
const auto &semanticToLocation = programD3D->getAttributesByLayout();
for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
......@@ -450,8 +489,9 @@ gl::Error InputLayoutCache::updateInputLayout(gl::Program *program,
}
else
{
gl::Error error = createInputLayout(sortedAttributes, sortedSemanticIndices,
attribCount, mode, program, &inputLayout);
gl::Error error =
createInputLayout(sortedAttributes, sortedSemanticIndices, attribCount, mode,
program, numIndicesPerInstance, &inputLayout);
if (error.isError())
{
return error;
......@@ -493,6 +533,7 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt
size_t attribCount,
GLenum mode,
gl::Program *program,
GLsizei numIndicesPerInstance,
ID3D11InputLayout **inputLayoutOut)
{
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
......@@ -553,6 +594,10 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt
{
inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
inputElements[elementIndex].InstanceDataStepRate = 1;
if (numIndicesPerInstance > 0 && sortedAttributes[elementIndex]->divisor > 0)
{
inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance;
}
}
inputElements[elementIndex].InputSlot++;
}
......
......@@ -48,7 +48,12 @@ class InputLayoutCache : angle::NonCopyable
void markDirty();
gl::Error applyVertexBuffers(const std::vector<TranslatedAttribute> &attributes,
GLenum mode, gl::Program *program, SourceIndexData *sourceInfo);
GLenum mode,
gl::Program *program,
TranslatedIndexData *indexInfo,
GLsizei numIndicesPerInstance);
gl::Error updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId);
// Useful for testing
void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; }
......@@ -73,6 +78,7 @@ class InputLayoutCache : angle::NonCopyable
{
FLAG_USES_INSTANCED_SPRITES = 0x1,
FLAG_INSTANCED_SPRITES_ACTIVE = 0x2,
FLAG_INSTANCED_RENDERING_ACTIVE = 0x4,
};
size_t numAttributes;
......@@ -84,12 +90,14 @@ class InputLayoutCache : angle::NonCopyable
GLenum mode,
const SortedAttribArray &sortedAttributes,
const SortedIndexArray &sortedSemanticIndices,
size_t attribCount);
size_t attribCount,
GLsizei numIndicesPerInstance);
gl::Error createInputLayout(const SortedAttribArray &sortedAttributes,
const SortedIndexArray &sortedSemanticIndices,
size_t attribCount,
GLenum mode,
gl::Program *program,
GLsizei numIndicesPerInstance,
ID3D11InputLayout **inputLayoutOut);
std::map<PackedAttributeLayout, ID3D11InputLayout *> mLayoutMap;
......@@ -98,6 +106,8 @@ class InputLayoutCache : angle::NonCopyable
ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS];
UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS];
UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS];
SortedAttribArray mSortedAttributes;
size_t mUnsortedAttributesCount;
ID3D11Buffer *mPointSpriteVertexBuffer;
ID3D11Buffer *mPointSpriteIndexBuffer;
......
......@@ -1476,7 +1476,12 @@ gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer)
return mStateManager.syncFramebuffer(framebuffer);
}
gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo)
gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
TranslatedIndexData *indexInfo)
{
gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
......@@ -1485,12 +1490,18 @@ gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLi
}
// If index information is passed, mark it with the current changed status.
if (sourceInfo)
if (indexInfo)
{
sourceInfo->srcIndicesChanged = mAppliedIBChanged;
indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged;
}
return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(), sourceInfo);
GLsizei numIndicesPerInstance = 0;
if (instances > 0)
{
numIndicesPerInstance = count;
}
return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(),
indexInfo, numIndicesPerInstance);
}
gl::Error Renderer11::applyIndexBuffer(const gl::Data &data,
......@@ -1498,13 +1509,12 @@ gl::Error Renderer11::applyIndexBuffer(const gl::Data &data,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo)
TranslatedIndexData *indexInfo)
{
gl::VertexArray *vao = data.state->getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices,
indexInfo, sourceIndexInfo,
gl::Error error =
mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo,
data.state->isPrimitiveRestartEnabled());
if (error.isError())
{
......@@ -1676,15 +1686,39 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data,
return drawTriangleFan(data, count, GL_NONE, nullptr, 0, instances);
}
bool useInstancedPointSpriteEmulation =
programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation;
if (instances > 0)
{
if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
{
// If pointsprite emulation is used with glDrawArraysInstanced then we need to take a
// less efficent code path.
// Instanced rendering of emulated pointsprites requires a loop to draw each batch of
// points. An offset into the instanced data buffer is calculated and applied on each
// iteration to ensure all instances are rendered correctly.
// Each instance being rendered requires the inputlayout cache to reapply buffers and
// offsets.
for (GLsizei i = 0; i < instances; i++)
{
gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i);
if (error.isError())
{
return error;
}
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
}
}
else
{
mDeviceContext->DrawInstanced(count, instances, 0, 0);
}
return gl::Error(GL_NO_ERROR);
}
bool useInstancedPointSpriteEmulation =
programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation;
// 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.
......@@ -1719,16 +1753,41 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data,
return drawTriangleFan(data, count, type, indices, minIndex, instances);
}
const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
if (instances > 0)
{
if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation())
{
// If pointsprite emulation is used with glDrawElementsInstanced then we need to take a
// less efficent code path.
// Instanced rendering of emulated pointsprites requires a loop to draw each batch of
// points. An offset into the instanced data buffer is calculated and applied on each
// iteration to ensure all instances are rendered correctly.
GLsizei elementsToRender = static_cast<GLsizei>(indexInfo.indexRange.vertexCount());
// Each instance being rendered requires the inputlayout cache to reapply buffers and
// offsets.
for (GLsizei i = 0; i < instances; i++)
{
gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i);
if (error.isError())
{
return error;
}
mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0);
}
}
else
{
mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0);
}
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.
const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation())
{
// The count parameter passed to drawElements represents the total number of instances
......
......@@ -135,14 +135,18 @@ class Renderer11 : public RendererD3D
gl::Error applyUniforms(const ProgramD3D &programD3D,
GLenum drawMode,
const std::vector<D3DUniform *> &uniformArray) override;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo);
virtual gl::Error applyVertexBuffer(const gl::State &state,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
TranslatedIndexData *indexInfo);
gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) override;
TranslatedIndexData *indexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
// lost device
......
......@@ -1171,7 +1171,12 @@ 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, SourceIndexData * /*sourceInfo*/)
gl::Error Renderer9::applyVertexBuffer(const gl::State &state,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
TranslatedIndexData * /*indexInfo*/)
{
gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
......@@ -1188,13 +1193,12 @@ gl::Error Renderer9::applyIndexBuffer(const gl::Data &data,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo)
TranslatedIndexData *indexInfo)
{
gl::VertexArray *vao = data.state->getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices,
indexInfo, sourceIndexInfo, false);
indexInfo, false);
if (error.isError())
{
return error;
......
......@@ -121,14 +121,18 @@ class Renderer9 : public RendererD3D
GLenum drawMode,
const std::vector<D3DUniform *> &uniformArray) override;
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, SourceIndexData *sourceInfo);
virtual gl::Error applyVertexBuffer(const gl::State &state,
GLenum mode,
GLint first,
GLsizei count,
GLsizei instances,
TranslatedIndexData *indexInfo);
gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) override;
TranslatedIndexData *indexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
......
......@@ -11,7 +11,7 @@ using namespace angle;
class InstancingTest : public ANGLETest
{
protected:
InstancingTest()
InstancingTest() : mProgram(0), mVertexBuffer(0)
{
setWindowWidth(256);
setWindowHeight(256);
......@@ -21,7 +21,13 @@ class InstancingTest : public ANGLETest
setConfigAlphaBits(8);
}
virtual void SetUp()
~InstancingTest() override
{
glDeleteBuffers(1, &mVertexBuffer);
glDeleteProgram(mProgram);
}
void SetUp() override
{
ANGLETest::SetUp();
......@@ -93,10 +99,12 @@ class InstancingTest : public ANGLETest
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glGenBuffers(1, &mVertexBuffer);
ASSERT_GL_NO_ERROR();
}
GLuint setupDrawArraysTest(const std::string &vs)
void setupDrawArraysTest(const std::string &vs)
{
const std::string fs = SHADER_SOURCE
(
......@@ -107,11 +115,8 @@ class InstancingTest : public ANGLETest
}
);
GLuint program = CompileProgram(vs, fs);
if (program == 0)
{
return 0;
}
mProgram = CompileProgram(vs, fs);
ASSERT_NE(0u, mProgram);
// Set the viewport
glViewport(0, 0, getWindowWidth(), getWindowHeight());
......@@ -120,30 +125,69 @@ class InstancingTest : public ANGLETest
glClear(GL_COLOR_BUFFER_BIT);
// Use the program object
glUseProgram(program);
glUseProgram(mProgram);
}
return program;
void setupInstancedPointsTest()
{
mIndices.clear();
mIndices.push_back(0);
mIndices.push_back(1);
mIndices.push_back(2);
mIndices.push_back(3);
// clang-format off
const std::string vs = SHADER_SOURCE
(
attribute vec3 a_position;
attribute vec3 a_instancePos;
void main()
{
gl_Position = vec4(a_position.xyz, 1.0);
gl_Position = vec4(a_instancePos.xyz, 1.0);
gl_PointSize = 6.0;
}
);
void runDrawArraysTest(GLuint program, GLint first, GLsizei count, GLsizei instanceCount, float *offset)
const std::string fs = SHADER_SOURCE
(
precision mediump float;
void main()
{
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
gl_FragColor = vec4(1.0, 0, 0, 1.0);
}
);
// clang-format on
mProgram = CompileProgram(vs, fs);
ASSERT_NE(0u, mProgram);
// Set the viewport
glViewport(0, 0, getWindowWidth(), getWindowHeight());
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Use the program object
glUseProgram(mProgram);
}
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
void runDrawArraysTest(GLint first, GLsizei count, GLsizei instanceCount, float *offset)
{
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, mInstances.size() * sizeof(mInstances[0]), &mInstances[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Get the attribute locations
GLint positionLoc = glGetAttribLocation(program, "a_position");
GLint instancePosLoc = glGetAttribLocation(program, "a_instancePos");
GLint positionLoc = glGetAttribLocation(mProgram, "a_position");
GLint instancePosLoc = glGetAttribLocation(mProgram, "a_instancePos");
// Load the vertex position
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, mNonIndexedVertices.data());
glEnableVertexAttribArray(positionLoc);
// Load the instance position
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glVertexAttribPointer(instancePosLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(instancePosLoc);
......@@ -152,7 +196,7 @@ class InstancingTest : public ANGLETest
mVertexAttribDivisorANGLE(instancePosLoc, 1);
// Offset
GLint uniformLoc = glGetUniformLocation(program, "u_offset");
GLint uniformLoc = glGetUniformLocation(mProgram, "u_offset");
ASSERT_NE(uniformLoc, -1);
glUniform3fv(uniformLoc, 1, offset);
......@@ -240,6 +284,9 @@ class InstancingTest : public ANGLETest
std::vector<GLushort> mIndices;
const GLfloat quadRadius = 0.30f;
GLuint mProgram;
GLuint mVertexBuffer;
};
class InstancingTestAllConfigs : public InstancingTest
......@@ -254,6 +301,12 @@ class InstancingTestNo9_3 : public InstancingTest
InstancingTestNo9_3() {}
};
class InstancingTestPoints : public InstancingTest
{
protected:
InstancingTestPoints() {}
};
// This test uses a vertex shader with the first attribute (attribute zero) instanced.
// On D3D9 and D3D11 FL9_3, this triggers a special codepath that rearranges the input layout sent to D3D,
// to ensure that slot/stream zero of the input layout doesn't contain per-instance data.
......@@ -304,18 +357,100 @@ TEST_P(InstancingTestNo9_3, DrawArraysWithOffset)
}
);
GLuint program = setupDrawArraysTest(vs);
ASSERT_NE(program, 0u);
setupDrawArraysTest(vs);
float offset1[3] = { 0, 0, 0 };
runDrawArraysTest(program, 0, 6, 2, offset1);
runDrawArraysTest(0, 6, 2, offset1);
float offset2[3] = { 0.0f, 1.0f, 0 };
runDrawArraysTest(program, 6, 6, 2, offset2);
runDrawArraysTest(6, 6, 2, offset2);
checkQuads();
}
// This test verifies instancing with GL_POINTS with glDrawArraysInstanced works.
// On D3D11 FL9_3, this triggers a special codepath that emulates instanced points rendering.
TEST_P(InstancingTestPoints, DrawArrays)
{
// Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
// On Win7, the D3D SDK Layers emits a false warning for these tests.
// This doesn't occur on Windows 10 (Version 1511) though.
ignoreD3D11SDKLayersWarnings();
setupInstancedPointsTest();
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, mInstances.size() * sizeof(mInstances[0]), &mInstances[0],
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Get the attribute locations
GLint positionLoc = glGetAttribLocation(mProgram, "a_position");
GLint instancePosLoc = glGetAttribLocation(mProgram, "a_instancePos");
// Load the vertex position
GLfloat pos[3] = {0, 0, 0};
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, pos);
glEnableVertexAttribArray(positionLoc);
// Load the instance position
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glVertexAttribPointer(instancePosLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(instancePosLoc);
// Enable instancing
mVertexAttribDivisorANGLE(instancePosLoc, 1);
// Do the instanced draw
mDrawArraysInstancedANGLE(GL_POINTS, 0, 1, static_cast<GLsizei>(mInstances.size()) / 3);
ASSERT_GL_NO_ERROR();
checkQuads();
}
glDeleteProgram(program);
// This test verifies instancing with GL_POINTS with glDrawElementsInstanced works.
// On D3D11 FL9_3, this triggers a special codepath that emulates instanced points rendering.
TEST_P(InstancingTestPoints, DrawElements)
{
// Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
// On Win7, the D3D SDK Layers emits a false warning for these tests.
// This doesn't occur on Windows 10 (Version 1511) though.
ignoreD3D11SDKLayersWarnings();
setupInstancedPointsTest();
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, mInstances.size() * sizeof(mInstances[0]), &mInstances[0],
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Get the attribute locations
GLint positionLoc = glGetAttribLocation(mProgram, "a_position");
GLint instancePosLoc = glGetAttribLocation(mProgram, "a_instancePos");
// Load the vertex position
GLfloat pos[3] = {0, 0, 0};
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, pos);
glEnableVertexAttribArray(positionLoc);
// Load the instance position
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glVertexAttribPointer(instancePosLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(instancePosLoc);
// Enable instancing
mVertexAttribDivisorANGLE(instancePosLoc, 1);
// Do the instanced draw
mDrawElementsInstancedANGLE(GL_POINTS, static_cast<GLsizei>(mIndices.size()), GL_UNSIGNED_SHORT,
mIndices.data(), static_cast<GLsizei>(mInstances.size()) / 3);
ASSERT_GL_NO_ERROR();
checkQuads();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
......@@ -329,3 +464,5 @@ ANGLE_INSTANTIATE_TEST(InstancingTestAllConfigs,
// TODO(jmadill): Figure out the situation with DrawInstanced on FL 9_3
ANGLE_INSTANTIATE_TEST(InstancingTestNo9_3, ES2_D3D9(), ES2_D3D11());
ANGLE_INSTANTIATE_TEST(InstancingTestPoints, ES2_D3D11(), ES2_D3D11_FL9_3());
......@@ -154,13 +154,12 @@ IndexDataManagerPerfTest::IndexDataManagerPerfTest()
void IndexDataManagerPerfTest::step()
{
rx::TranslatedIndexData translatedIndexData;
rx::SourceIndexData sourceIndexData;
for (unsigned int iteration = 0; iteration < 100; ++iteration)
{
mIndexBuffer.getIndexRange(GL_UNSIGNED_SHORT, 0, mIndexCount, false,
&translatedIndexData.indexRange);
mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr,
&translatedIndexData, &sourceIndexData, false);
&translatedIndexData, false);
}
}
......
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