Implement the instanced draw calls in RendererGL.
BUG=angleproject:1136
Change-Id: I1167365618bdc3ca37ac0f4c60809de32c7a9d78
Reviewed-on: https://chromium-review.googlesource.com/295733
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/VertexAttribute.cpp b/src/libANGLE/VertexAttribute.cpp
index c164be5..13d78fd 100644
--- a/src/libANGLE/VertexAttribute.cpp
+++ b/src/libANGLE/VertexAttribute.cpp
@@ -52,4 +52,23 @@
return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib);
}
+size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib,
+ size_t drawCount,
+ size_t instanceCount)
+{
+ // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
+ //
+ // A vertex attribute with a positive divisor loads one instanced vertex for every set of
+ // non-instanced vertices, and the instanced vertex index advances once every "mDivisor"
+ // instances.
+ if (instanceCount > 0 && attrib.divisor > 0)
+ {
+ // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
+ // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced
+ // vertices.
+ return (instanceCount + attrib.divisor - 1u) / attrib.divisor;
+ }
+
+ return drawCount;
+}
}
diff --git a/src/libANGLE/VertexAttribute.h b/src/libANGLE/VertexAttribute.h
index d6a4afa..d1ee1b4 100644
--- a/src/libANGLE/VertexAttribute.h
+++ b/src/libANGLE/VertexAttribute.h
@@ -44,6 +44,9 @@
size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib);
size_t ComputeVertexAttributeStride(const VertexAttribute& attrib);
+size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib,
+ size_t drawCount,
+ size_t instanceCount);
struct VertexAttribCurrentValueData
{
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
index 4ae1e8d..254fc96 100644
--- a/src/libANGLE/renderer/d3d/VertexDataManager.cpp
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
@@ -41,22 +41,6 @@
stride;
}
-static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount)
-{
- // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
- //
- // A vertex attribute with a positive divisor loads one instanced vertex for every set of
- // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances.
- if (instanceDrawCount > 0 && attrib.divisor > 0)
- {
- // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
- // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced vertices.
- return (instanceDrawCount + attrib.divisor - 1) / attrib.divisor;
- }
-
- return vertexDrawCount;
-}
-
VertexDataManager::CurrentValueState::CurrentValueState()
: buffer(nullptr),
offset(0)
@@ -278,12 +262,13 @@
}
else
{
- int totalCount = StreamingBufferElementCount(attrib, count, instances);
+ size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);
ASSERT(!bufferImpl ||
ElementsInBuffer(attrib, static_cast<unsigned int>(bufferImpl->getSize())) >=
totalCount);
- gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances);
+ gl::Error error = mStreamingBuffer->reserveVertexSpace(
+ attrib, static_cast<GLsizei>(totalCount), instances);
if (error.isError())
{
return error;
@@ -388,20 +373,16 @@
}
else
{
- int totalCount = StreamingBufferElementCount(attrib, count, instances);
+ size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);
gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
if (error.isError())
{
return error;
}
- error = mStreamingBuffer->storeVertexAttributes(attrib,
- translated->currentValueType,
- firstVertexIndex,
- totalCount,
- instances,
- &streamOffset,
- sourceData);
+ error = mStreamingBuffer->storeVertexAttributes(
+ attrib, translated->currentValueType, firstVertexIndex,
+ static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData);
if (error.isError())
{
return error;
diff --git a/src/libANGLE/renderer/gl/FunctionsGL.cpp b/src/libANGLE/renderer/gl/FunctionsGL.cpp
index 9bc4603..d383d6f 100644
--- a/src/libANGLE/renderer/gl/FunctionsGL.cpp
+++ b/src/libANGLE/renderer/gl/FunctionsGL.cpp
@@ -71,7 +71,6 @@
{
if (std::find(extensions.begin(), extensions.end(), requiredExtension) == extensions.end())
{
- *outFunction = nullptr;
return;
}
}
@@ -798,6 +797,8 @@
profile = 0;
}
+ // clang-format off
+
// Load extensions
// Even though extensions are written against specific versions of GL, many drivers expose the extensions
// in even older versions. Always try loading the extensions regardless of GL version.
@@ -880,6 +881,17 @@
AssignGLExtensionEntryPoint(extensions, "GL_ARB_ES2_compatibility", loadProcAddress("glDepthRangef"), &depthRangef);
AssignGLExtensionEntryPoint(extensions, "GL_ARB_ES2_compatibility", loadProcAddress("glClearDepthf"), &clearDepthf);
+ // GL_ARB_instanced_arrays
+ AssignGLExtensionEntryPoint(extensions, "GL_ARB_instanced_arrays", loadProcAddress("glVertexAttribDivisorARB"), &vertexAttribDivisor);
+
+ // GL_EXT_draw_instanced
+ AssignGLExtensionEntryPoint(extensions, "GL_EXT_draw_instanced", loadProcAddress("glDrawArraysInstancedEXT"), &drawArraysInstanced);
+ AssignGLExtensionEntryPoint(extensions, "GL_EXT_draw_instanced", loadProcAddress("glDrawElementsInstancedEXT"), &drawElementsInstanced);
+
+ // GL_ARB_draw_instanced
+ AssignGLExtensionEntryPoint(extensions, "GL_ARB_draw_instanced", loadProcAddress("glDrawArraysInstancedARB"), &drawArraysInstanced);
+ AssignGLExtensionEntryPoint(extensions, "GL_ARB_draw_instanced", loadProcAddress("glDrawElementsInstancedARB"), &drawElementsInstanced);
+
// 1.0
if (isAtLeastGL(gl::Version(1, 0)))
{
@@ -1622,6 +1634,8 @@
AssignGLEntryPoint(loadProcAddress("glVertexArrayVertexBuffer"), &vertexArrayVertexBuffer);
AssignGLEntryPoint(loadProcAddress("glVertexArrayVertexBuffers"), &vertexArrayVertexBuffers);
}
+
+ // clang-format on
}
bool FunctionsGL::isAtLeastGL(const gl::Version &glVersion) const
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index cb4110d..f4db4d7 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -131,7 +131,7 @@
gl::Error RendererGL::drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count)
{
- gl::Error error = mStateManager->setDrawArraysState(data, first, count);
+ gl::Error error = mStateManager->setDrawArraysState(data, first, count, 0);
if (error.isError())
{
return error;
@@ -151,7 +151,17 @@
GLsizei count,
GLsizei instanceCount)
{
- UNIMPLEMENTED();
+ gl::Error error = mStateManager->setDrawArraysState(data, first, count, instanceCount);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!mSkipDrawCalls)
+ {
+ mFunctions->drawArraysInstanced(mode, first, count, instanceCount);
+ }
+
return gl::Error(GL_NO_ERROR);
}
@@ -163,7 +173,8 @@
const gl::RangeUI &indexRange)
{
const GLvoid *drawIndexPointer = nullptr;
- gl::Error error = mStateManager->setDrawElementsState(data, count, type, indices, &drawIndexPointer);
+ gl::Error error =
+ mStateManager->setDrawElementsState(data, count, type, indices, 0, &drawIndexPointer);
if (error.isError())
{
return error;
@@ -185,7 +196,19 @@
GLsizei instances,
const gl::RangeUI &indexRange)
{
- UNIMPLEMENTED();
+ const GLvoid *drawIndexPointer = nullptr;
+ gl::Error error = mStateManager->setDrawElementsState(data, count, type, indices, instances,
+ &drawIndexPointer);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!mSkipDrawCalls)
+ {
+ mFunctions->drawElementsInstanced(mode, count, type, drawIndexPointer, instances);
+ }
+
return gl::Error(GL_NO_ERROR);
}
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index 6514b25..adf25da 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -401,7 +401,10 @@
}
}
-gl::Error StateManagerGL::setDrawArraysState(const gl::Data &data, GLint first, GLsizei count)
+gl::Error StateManagerGL::setDrawArraysState(const gl::Data &data,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount)
{
const gl::State &state = *data.state;
@@ -410,8 +413,8 @@
const gl::VertexArray *vao = state.getVertexArray();
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
- gl::Error error =
- vaoGL->syncDrawArraysState(program->getActiveAttribLocationsMask(), first, count);
+ gl::Error error = vaoGL->syncDrawArraysState(program->getActiveAttribLocationsMask(), first,
+ count, instanceCount);
if (error.isError())
{
return error;
@@ -422,7 +425,11 @@
return setGenericDrawState(data);
}
-gl::Error StateManagerGL::setDrawElementsState(const gl::Data &data, GLsizei count, GLenum type, const GLvoid *indices,
+gl::Error StateManagerGL::setDrawElementsState(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices)
{
const gl::State &state = *data.state;
@@ -433,7 +440,7 @@
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
gl::Error error = vaoGL->syncDrawElementsState(program->getActiveAttribLocationsMask(), count,
- type, indices, outIndices);
+ type, indices, instanceCount, outIndices);
if (error.isError())
{
return error;
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.h b/src/libANGLE/renderer/gl/StateManagerGL.h
index 1502fd8..97c8666 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.h
+++ b/src/libANGLE/renderer/gl/StateManagerGL.h
@@ -105,8 +105,15 @@
void setPixelPackState(const gl::PixelPackState &pack);
void setPixelPackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels);
- gl::Error setDrawArraysState(const gl::Data &data, GLint first, GLsizei count);
- gl::Error setDrawElementsState(const gl::Data &data, GLsizei count, GLenum type, const GLvoid *indices,
+ gl::Error setDrawArraysState(const gl::Data &data,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount);
+ gl::Error setDrawElementsState(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices);
void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index 4fc9a65..1166ae2 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -77,18 +77,21 @@
gl::Error VertexArrayGL::syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
GLint first,
- GLsizei count) const
+ GLsizei count,
+ GLsizei instanceCount) const
{
- return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, nullptr);
+ return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, instanceCount,
+ nullptr);
}
gl::Error VertexArrayGL::syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
GLsizei count,
GLenum type,
const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices) const
{
- return syncDrawState(activeAttributesMask, 0, count, type, indices, outIndices);
+ return syncDrawState(activeAttributesMask, 0, count, type, indices, instanceCount, outIndices);
}
gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttributesMask,
@@ -96,6 +99,7 @@
GLsizei count,
GLenum type,
const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices) const
{
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
@@ -123,7 +127,7 @@
if (attributesNeedStreaming)
{
- Error error = streamAttributes(activeAttributesMask, indexRange);
+ Error error = streamAttributes(activeAttributesMask, instanceCount, indexRange);
if (error.isError())
{
return error;
@@ -213,6 +217,7 @@
}
void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
+ GLsizei instanceCount,
const gl::RangeUI &indexRange,
size_t *outStreamingDataSize,
size_t *outMaxAttributeDataSize) const
@@ -228,26 +233,28 @@
const auto &attrib = attribs[idx];
ASSERT(AttributeNeedsStreaming(attrib));
- const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
+ const size_t vertexCount = indexRange.end - indexRange.start + 1;
// If streaming is going to be required, compute the size of the required buffer
// and how much slack space at the beginning of the buffer will be required by determining
// the attribute with the largest data size.
size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
- *outStreamingDataSize += typeSize * streamedVertexCount;
+ *outStreamingDataSize +=
+ typeSize * ComputeVertexAttributeElementCount(attrib, vertexCount, instanceCount);
*outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
}
}
gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
+ GLsizei instanceCount,
const gl::RangeUI &indexRange) const
{
// Sync the vertex attribute state and track what data needs to be streamed
size_t streamingDataSize = 0;
size_t maxAttributeDataSize = 0;
- computeStreamingAttributeSizes(activeAttributesMask, indexRange, &streamingDataSize,
- &maxAttributeDataSize);
+ computeStreamingAttributeSizes(activeAttributesMask, instanceCount, indexRange,
+ &streamingDataSize, &maxAttributeDataSize);
if (streamingDataSize == 0)
{
@@ -282,7 +289,7 @@
uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
size_t curBufferOffset = bufferEmptySpace;
- const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
+ const size_t vertexCount = indexRange.end - indexRange.start + 1;
const auto &attribs = mData.getVertexAttributes();
for (unsigned int idx :
@@ -291,6 +298,9 @@
const auto &attrib = attribs[idx];
ASSERT(AttributeNeedsStreaming(attrib));
+ const size_t streamedVertexCount =
+ ComputeVertexAttributeElementCount(attrib, vertexCount, instanceCount);
+
const size_t sourceStride = ComputeVertexAttributeStride(attrib);
const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.h b/src/libANGLE/renderer/gl/VertexArrayGL.h
index 52c8f4e..343fd31 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.h
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.h
@@ -25,11 +25,13 @@
gl::Error syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
GLint first,
- GLsizei count) const;
+ GLsizei count,
+ GLsizei instanceCount) const;
gl::Error syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
GLsizei count,
GLenum type,
const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices) const;
GLuint getVertexArrayID() const;
@@ -43,6 +45,7 @@
GLsizei count,
GLenum type,
const GLvoid *indices,
+ GLsizei instanceCount,
const GLvoid **outIndices) const;
// Apply index data, only sets outIndexRange if attributesNeedStreaming is true
@@ -52,12 +55,14 @@
// Returns the amount of space needed to stream all attributes that need streaming
// and the data size of the largest attribute
void computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
+ GLsizei instanceCount,
const gl::RangeUI &indexRange,
size_t *outStreamingDataSize,
size_t *outMaxAttributeDataSize) const;
// Stream attributes that have client data
gl::Error streamAttributes(const gl::AttributesMask &activeAttributesMask,
+ GLsizei instanceCount,
const gl::RangeUI &indexRange) const;
void updateNeedsStreaming(size_t attribIndex);
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 527f25a..47b2797 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -532,6 +532,12 @@
functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_frag_depth");
extensions->fboRenderMipmap = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") ||
functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_fbo_render_mipmap");
+ extensions->instancedArrays = functions->isAtLeastGL(gl::Version(3, 1)) ||
+ (functions->hasGLExtension("GL_ARB_instanced_arrays") &&
+ (functions->hasGLExtension("GL_ARB_draw_instanced") ||
+ functions->hasGLExtension("GL_EXT_draw_instanced"))) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLESExtension("GL_EXT_instanced_arrays");
}
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds)