Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1076)

Unified Diff: src/gpu/instanced/GLInstancedRendering.cpp

Issue 2066993003: Begin instanced rendering for simple shapes (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: get mixed samples and base instance paths working again Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/gpu/instanced/GLInstancedRendering.cpp
diff --git a/src/gpu/instanced/GLInstancedRendering.cpp b/src/gpu/instanced/GLInstancedRendering.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1cb640cd5c2bb82793af9afe3004d645e0317d78
--- /dev/null
+++ b/src/gpu/instanced/GLInstancedRendering.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GLInstancedRendering.h"
+
+#include "GrResourceProvider.h"
+#include "gl/GrGLGpu.h"
+#include "instanced/InstanceProcessor.h"
+
+#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
+
+namespace gr_instanced {
+
+class GLInstancedRendering::GLBatch : public InstancedRendering::Batch {
+public:
+ DEFINE_BATCH_CLASS_ID
+
+ GLBatch(GLInstancedRendering* instRendering, int instanceIdx)
+ : INHERITED(ClassID(), instRendering, instanceIdx) {
+ }
+
+private:
+ int fEmulatedBaseInstance;
+ int fGLDrawCmdsIdx;
+ int fNumGLDrawCmds;
+
+ friend class GLInstancedRendering;
+
+ typedef Batch INHERITED;
+};
+
+GLInstancedRendering* GLInstancedRendering::CreateIfSupported(GrGLGpu* gpu) {
+ const GrGLCaps& caps = gpu->glCaps();
+ AntialiasMode lastSupportedAAMode;
+ if (!caps.vertexArrayObjectSupport() ||
+ !caps.drawIndirectSupport() ||
+ !InstanceProcessor::IsSupported(*caps.glslCaps(), caps, &lastSupportedAAMode)) {
+ return nullptr;
+ }
+ return new GLInstancedRendering(gpu, lastSupportedAAMode);
+}
+
+GLInstancedRendering::GLInstancedRendering(GrGLGpu* gpu, AntialiasMode lastSupportedAAMode)
+ : INHERITED(gpu, lastSupportedAAMode),
+ fVertexArrayID(0),
+ fInstanceAttribsBufferUniqueId(SK_InvalidUniqueID) {
+}
+
+GLInstancedRendering::~GLInstancedRendering() {
+ if (fVertexArrayID) {
+ GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
+ this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
+ }
+}
+
+inline GrGLGpu* GLInstancedRendering::glGpu() const {
+ return static_cast<GrGLGpu*>(this->gpu());
+}
+
+InstancedRendering::Batch* GLInstancedRendering::createBatch(int instanceIdx) {
+ return new GLBatch(this, instanceIdx);
+}
+
+void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
+ // Count what there is to draw.
+ BatchList::Iter iter;
+ iter.init(this->batchList(), BatchList::Iter::kHead_IterStart);
+ int numGLInstances = 0;
+ int numGLDrawCmds = 0;
+ while (Batch* b = iter.get()) {
+ GLBatch* batch = static_cast<GLBatch*>(b);
+ iter.next();
+
+ const auto& drawCmds = batch->fDrawCmds;
+ for (int c = 0; c < drawCmds.count(); ++c) {
+ numGLInstances += drawCmds[c].fInstanceRange.fCount;
+ if (c > 0 && drawCmds[c].fGeometry == drawCmds[c - 1].fGeometry) {
+ // When two adjacent draw commands have the same geometry, we will rearrange the
+ // instances for the GL buffer and combine them into a single command.
+ continue;
+ }
+ ++numGLDrawCmds;
+ }
+ }
+ if (!numGLDrawCmds) {
+ return;
+ }
+ SkASSERT(numGLInstances);
+
+ // Lazily create a vertex array object.
+ if (!fVertexArrayID) {
+ GL_CALL(GenVertexArrays(1, &fVertexArrayID));
+ if (!fVertexArrayID) {
+ return;
+ }
+ this->glGpu()->bindVertexArray(fVertexArrayID);
+
+ // Attach our index buffer to the vertex array.
+ GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
+ static_cast<const GrGLBuffer*>(this->indexBuffer())->bufferID()));
+
+ // Set up the non-instanced attribs.
+ this->glGpu()->bindBuffer(kVertex_GrBufferType,
+ static_cast<const GrGLBuffer*>(this->vertexBuffer()));
+ GL_CALL(EnableVertexAttribArray(kShapeCoords_AttribIdx));
+ GL_CALL(VertexAttribPointer(kShapeCoords_AttribIdx, 2, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fX)));
+ GL_CALL(EnableVertexAttribArray(kVertexAttrs_AttribIdx));
+ GL_CALL(VertexAttribIPointer(kVertexAttrs_AttribIdx, 1, GR_GL_INT, sizeof(ShapeVertex),
+ (void*) offsetof(ShapeVertex, fAttrs)));
+
+ SkASSERT(SK_InvalidUniqueID == fInstanceAttribsBufferUniqueId);
+ }
+
+ // Create and map instance and draw-indirect buffers.
+ SkASSERT(!fInstanceBuffer);
+ fInstanceBuffer.reset(static_cast<GrGLBuffer*>(
+ rp->createBuffer(sizeof(Instance) * numGLInstances, kVertex_GrBufferType,
+ kDynamic_GrAccessPattern, GrResourceProvider::kNoPendingIO_Flag)));
+ if (!fInstanceBuffer) {
+ return;
+ }
+
+ SkASSERT(!fDrawIndirectBuffer);
+ fDrawIndirectBuffer.reset(static_cast<GrGLBuffer*>(
+ rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds,
+ kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern,
+ GrResourceProvider::kNoPendingIO_Flag)));
+ if (!fDrawIndirectBuffer) {
+ return;
+ }
+
+ Instance* glMappedInstances = static_cast<Instance*>(fInstanceBuffer->map());
+ int glInstancesIdx = 0;
+
+ auto* glMappedCmds = static_cast<GrGLDrawElementsIndirectCommand*>(fDrawIndirectBuffer->map());
+ int glDrawCmdsIdx = 0;
+
+ bool baseInstanceSupport = this->glGpu()->glCaps().baseInstanceSupport();
+
+ if (!baseInstanceSupport) {
+ fGLDrawCmdsInfo.reset(numGLDrawCmds);
+ }
+
+ // Generate the instance and draw-indirect buffer contents based on the batches in existence.
+ iter.init(this->batchList(), BatchList::Iter::kHead_IterStart);
+ while (Batch* b = iter.get()) {
+ GLBatch* batch = static_cast<GLBatch*>(b);
+ iter.next();
+
+ batch->fEmulatedBaseInstance = baseInstanceSupport ? 0 : glInstancesIdx;
+ batch->fGLDrawCmdsIdx = glDrawCmdsIdx;
+ batch->fNumGLDrawCmds = 0;
+
+ const auto& drawCmds = batch->fDrawCmds;
+ int cidx = 0;
+ SkASSERT(!drawCmds.empty());
+ do {
+ IndexRange geometry = drawCmds[cidx].fGeometry;
+ int instanceCount = 0;
+
+ do {
+ SkASSERT(drawCmds[cidx].isValid());
+ InstanceRange range = drawCmds[cidx].fInstanceRange;
+ memcpy(&glMappedInstances[glInstancesIdx + instanceCount],
+ &this->instance(range.fStart), range.fCount * sizeof(Instance));
+ instanceCount += range.fCount;
+ } while (++cidx < drawCmds.count() && drawCmds[cidx].fGeometry == geometry);
+
+ GrGLDrawElementsIndirectCommand& glCmd = glMappedCmds[glDrawCmdsIdx];
+ glCmd.fCount = geometry.fCount;
+ glCmd.fInstanceCount = instanceCount;
+ glCmd.fFirstIndex = geometry.fStart;
+ glCmd.fBaseVertex = 0;
+ glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0;
+
+ if (!baseInstanceSupport) {
+ fGLDrawCmdsInfo[glDrawCmdsIdx].fInstanceCount = instanceCount;
+ }
+
+ glInstancesIdx += instanceCount;
+ ++glDrawCmdsIdx;
+ ++batch->fNumGLDrawCmds;
+ } while (cidx < drawCmds.count());
+ }
+
+ SkASSERT(glDrawCmdsIdx == numGLDrawCmds);
+ fDrawIndirectBuffer->unmap();
+
+ SkASSERT(glInstancesIdx == numGLInstances);
+ fInstanceBuffer->unmap();
+}
+
+void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProcessor& instProc,
+ const Batch* baseBatch) {
+ if (!fDrawIndirectBuffer) {
+ return; // beginFlush was not successful.
+ }
+ if (!this->glGpu()->flushGLState(pipeline, instProc)) {
+ return;
+ }
+
+ this->glGpu()->bindBuffer(kDrawIndirect_GrBufferType, fDrawIndirectBuffer.get());
+
+ const GrGLCaps& glCaps = this->glGpu()->glCaps();
+ const GLBatch* batch = static_cast<const GLBatch*>(baseBatch);
+ int numCommands = batch->fNumGLDrawCmds;
+
+#if 0
+ SkDebugf("Instanced batch: [");
+ for (int i = 0; i < numCommands; ++i) {
+ SkDebugf("%s%i * %s", (i ? ", " : ""), batch->fDrawCmds[i].fInstanceRange.fCount,
+ InstanceProcessor::GetNameOfIndexRange(batch->fDrawCmds[i].fGeometry));
+ }
+ SkDebugf("]\n");
+#endif
+
+ if (1 == numCommands || !glCaps.baseInstanceSupport() || !glCaps.multiDrawIndirectSupport()) {
+ int emulatedBaseInstance = batch->fEmulatedBaseInstance;
+ for (int i = 0; i < numCommands; ++i) {
+ int glCmdIdx = batch->fGLDrawCmdsIdx + i;
+ this->flushInstanceAttribs(emulatedBaseInstance);
+ GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
+ (GrGLDrawElementsIndirectCommand*) nullptr + glCmdIdx));
+ if (!glCaps.baseInstanceSupport()) {
+ emulatedBaseInstance += fGLDrawCmdsInfo[glCmdIdx].fInstanceCount;
+ }
+ }
+ } else {
+ int glCmdsIdx = batch->fGLDrawCmdsIdx;
+ this->flushInstanceAttribs(batch->fEmulatedBaseInstance);
+ GL_CALL(MultiDrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
+ (GrGLDrawElementsIndirectCommand*) nullptr + glCmdsIdx,
+ numCommands, 0));
+ }
+}
+
+void GLInstancedRendering::flushInstanceAttribs(int baseInstance) {
+ SkASSERT(fVertexArrayID);
+ this->glGpu()->bindVertexArray(fVertexArrayID);
+
+ SkASSERT(fInstanceBuffer);
+ if (fInstanceAttribsBufferUniqueId != fInstanceBuffer->getUniqueID() ||
+ fInstanceAttribsBaseInstance != baseInstance) {
+ Instance* offsetInBuffer = (Instance*) nullptr + baseInstance;
+
+ this->glGpu()->bindBuffer(kVertex_GrBufferType, fInstanceBuffer.get());
+
+ // Info attrib.
+ GL_CALL(EnableVertexAttribArray(kInstanceInfo_AttribIdx));
+ GL_CALL(VertexAttribIPointer(kInstanceInfo_AttribIdx, 1, GR_GL_UNSIGNED_INT,
+ sizeof(Instance), &offsetInBuffer->fInfo));
+ GL_CALL(VertexAttribDivisor(kInstanceInfo_AttribIdx, 1));
+
+ // Shape matrix attrib.
+ GL_CALL(EnableVertexAttribArray(kShapeMatrixX_AttribIdx));
+ GL_CALL(EnableVertexAttribArray(kShapeMatrixY_AttribIdx));
+ GL_CALL(VertexAttribPointer(kShapeMatrixX_AttribIdx, 3, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[0]));
+ GL_CALL(VertexAttribPointer(kShapeMatrixY_AttribIdx, 3, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[3]));
+ GL_CALL(VertexAttribDivisor(kShapeMatrixX_AttribIdx, 1));
+ GL_CALL(VertexAttribDivisor(kShapeMatrixY_AttribIdx, 1));
+
+ // Color attrib.
+ GL_CALL(EnableVertexAttribArray(kColor_AttribIdx));
+ GL_CALL(VertexAttribPointer(kColor_AttribIdx, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE,
+ sizeof(Instance), &offsetInBuffer->fColor));
+ GL_CALL(VertexAttribDivisor(kColor_AttribIdx, 1));
+
+ // Local rect attrib.
+ GL_CALL(EnableVertexAttribArray(kLocalRect_AttribIdx));
+ GL_CALL(VertexAttribPointer(kLocalRect_AttribIdx, 4, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fLocalRect));
+ GL_CALL(VertexAttribDivisor(kLocalRect_AttribIdx, 1));
+
+ fInstanceAttribsBufferUniqueId = fInstanceBuffer->getUniqueID();
+ fInstanceAttribsBaseInstance = baseInstance;
+ }
+}
+
+void GLInstancedRendering::onEndFlush() {
+ fInstanceBuffer.reset();
+ fDrawIndirectBuffer.reset();
+ fGLDrawCmdsInfo.reset(0);
+}
+
+void GLInstancedRendering::onResetGpuResources(ResetType resetType) {
+ if (fVertexArrayID && ResetType::kDestroy == resetType) {
+ GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
+ this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
+ }
+ fVertexArrayID = 0;
+ fInstanceBuffer.reset();
+ fDrawIndirectBuffer.reset();
+ fInstanceAttribsBufferUniqueId = SK_InvalidUniqueID;
+}
+
+}

Powered by Google App Engine
This is Rietveld 408576698