Commit 3cf12ce6 by Geoff Lang

Implement the instanced draw calls in RendererGL.

BUG=angleproject:1136 Change-Id: I1167365618bdc3ca37ac0f4c60809de32c7a9d78 Reviewed-on: https://chromium-review.googlesource.com/295733Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 5b49bb83
......@@ -52,4 +52,23 @@ size_t ComputeVertexAttributeStride(const VertexAttribute& attrib)
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;
}
}
......@@ -44,6 +44,9 @@ T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pnam
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
{
......
......@@ -41,22 +41,6 @@ static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size
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 @@ gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &tr
}
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 @@ gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated,
}
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;
......
......@@ -71,7 +71,6 @@ static void AssignGLExtensionEntryPoint(const std::vector<std::string> &extensio
{
if (std::find(extensions.begin(), extensions.end(), requiredExtension) == extensions.end())
{
*outFunction = nullptr;
return;
}
}
......@@ -798,6 +797,8 @@ void FunctionsGL::initialize()
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 @@ void FunctionsGL::initialize()
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 @@ void FunctionsGL::initialize()
AssignGLEntryPoint(loadProcAddress("glVertexArrayVertexBuffer"), &vertexArrayVertexBuffer);
AssignGLEntryPoint(loadProcAddress("glVertexArrayVertexBuffers"), &vertexArrayVertexBuffers);
}
// clang-format on
}
bool FunctionsGL::isAtLeastGL(const gl::Version &glVersion) const
......
......@@ -131,7 +131,7 @@ gl::Error RendererGL::finish()
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 @@ gl::Error RendererGL::drawArraysInstanced(const gl::Data &data,
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 @@ gl::Error RendererGL::drawElements(const gl::Data &data,
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 @@ gl::Error RendererGL::drawElementsInstanced(const gl::Data &data,
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);
}
......
......@@ -401,7 +401,10 @@ void StateManagerGL::bindRenderbuffer(GLenum type, GLuint renderbuffer)
}
}
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 @@ gl::Error StateManagerGL::setDrawArraysState(const gl::Data &data, GLint first,
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 @@ gl::Error StateManagerGL::setDrawArraysState(const gl::Data &data, GLint first,
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 @@ gl::Error StateManagerGL::setDrawElementsState(const gl::Data &data, GLsizei cou
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;
......
......@@ -105,8 +105,15 @@ class StateManagerGL final : angle::NonCopyable
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);
......
......@@ -77,18 +77,21 @@ VertexArrayGL::~VertexArrayGL()
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 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute
GLsizei count,
GLenum type,
const GLvoid *indices,
GLsizei instanceCount,
const GLvoid **outIndices) const
{
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
......@@ -123,7 +127,7 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute
if (attributesNeedStreaming)
{
Error error = streamAttributes(activeAttributesMask, indexRange);
Error error = streamAttributes(activeAttributesMask, instanceCount, indexRange);
if (error.isError())
{
return error;
......@@ -213,6 +217,7 @@ Error VertexArrayGL::syncIndexData(GLsizei count,
}
void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
GLsizei instanceCount,
const gl::RangeUI &indexRange,
size_t *outStreamingDataSize,
size_t *outMaxAttributeDataSize) const
......@@ -228,26 +233,28 @@ void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &act
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 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
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 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
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);
......
......@@ -25,11 +25,13 @@ class VertexArrayGL : public VertexArrayImpl
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 @@ class VertexArrayGL : public VertexArrayImpl
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 @@ class VertexArrayGL : public VertexArrayImpl
// 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);
......
......@@ -532,6 +532,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
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)
......
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