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

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: Rix perf regressions Created 4 years, 5 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
« no previous file with comments | « src/gpu/instanced/GLInstancedRendering.h ('k') | src/gpu/instanced/InstanceProcessor.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..7df39f07df15de889149110bb2889a9019764181
--- /dev/null
+++ b/src/gpu/instanced/GLInstancedRendering.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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) : INHERITED(ClassID(), instRendering) {}
+ int numGLCommands() const { return 1 + fNumChangesInGeometry; }
+
+private:
+ int fEmulatedBaseInstance;
+ int fGLDrawCmdsIdx;
+
+ friend class GLInstancedRendering;
+
+ typedef Batch INHERITED;
+};
+
+GLInstancedRendering* GLInstancedRendering::CreateIfSupported(GrGLGpu* gpu) {
+#ifndef SK_BUILD_FOR_MAC
+ // Only whitelisting on Mac for now. Once we've been able to work through the various issues on
+ // other platforms we can enable more generally.
+ return nullptr;
+#endif
+ const GrGLCaps& glCaps = gpu->glCaps();
+ AntialiasMode lastSupportedAAMode;
+ if (!glCaps.vertexArrayObjectSupport() ||
+ !glCaps.drawIndirectSupport() ||
+ !InstanceProcessor::IsSupported(*glCaps.glslCaps(), glCaps, &lastSupportedAAMode)) {
+ return nullptr;
+ }
+ return new GLInstancedRendering(gpu, lastSupportedAAMode);
+}
+
+GLInstancedRendering::GLInstancedRendering(GrGLGpu* gpu, AntialiasMode lastSupportedAAMode)
+ : INHERITED(gpu, lastSupportedAAMode, gpu->glCaps().canDrawIndirectToFloat()),
+ fVertexArrayID(0),
+ fGLDrawCmdsInfo(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() {
+ return new GLBatch(this);
+}
+
+void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
+ // Count what there is to draw.
+ BatchList::Iter iter;
+ iter.init(this->trackedBatches(), BatchList::Iter::kHead_IterStart);
+ int numGLInstances = 0;
+ int numGLDrawCmds = 0;
+ while (Batch* b = iter.get()) {
+ GLBatch* batch = static_cast<GLBatch*>(b);
+ iter.next();
+
+ numGLInstances += batch->fNumDraws;
+ numGLDrawCmds += batch->numGLCommands();
+ }
+ 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((int)Attrib::kShapeCoords));
+ GL_CALL(VertexAttribPointer((int)Attrib::kShapeCoords, 2, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fX)));
+ GL_CALL(EnableVertexAttribArray((int)Attrib::kVertexAttrs));
+ GL_CALL(VertexAttribIPointer((int)Attrib::kVertexAttrs, 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 (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) {
+ fGLDrawCmdsInfo.reset(numGLDrawCmds);
+ }
+
+ // Generate the instance and draw-indirect buffer contents based on the tracked batches.
+ iter.init(this->trackedBatches(), 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;
+
+ const Batch::Draw* draw = batch->fHeadDraw;
+ SkASSERT(draw);
+ do {
+ int instanceCount = 0;
+ IndexRange geometry = draw->fGeometry;
+ SkASSERT(!geometry.isEmpty());
+
+ do {
+ glMappedInstances[glInstancesIdx + instanceCount++] = draw->fInstance;
+ draw = draw->fNext;
+ } while (draw && draw->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 (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) {
+ fGLDrawCmdsInfo[glDrawCmdsIdx].fInstanceCount = instanceCount;
+#if GR_GL_LOG_INSTANCED_BATCHES
+ fGLDrawCmdsInfo[glDrawCmdsIdx].fGeometry = geometry;
+#endif
+ }
+
+ glInstancesIdx += instanceCount;
+ ++glDrawCmdsIdx;
+ } while (draw);
+ }
+
+ 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->numGLCommands();
+
+#if GR_GL_LOG_INSTANCED_BATCHES
+ SkASSERT(fGLDrawCmdsInfo);
+ SkDebugf("Instanced batch: [");
+ for (int i = 0; i < numCommands; ++i) {
+ int glCmdIdx = batch->fGLDrawCmdsIdx + i;
+ SkDebugf("%s%i * %s", (i ? ", " : ""), fGLDrawCmdsInfo[glCmdIdx].fInstanceCount,
+ InstanceProcessor::GetNameOfIndexRange(fGLDrawCmdsInfo[glCmdIdx].fGeometry));
+ }
+ SkDebugf("]\n");
+#else
+ SkASSERT(SkToBool(fGLDrawCmdsInfo) == !glCaps.baseInstanceSupport());
+#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((int)Attrib::kInstanceInfo));
+ GL_CALL(VertexAttribIPointer((int)Attrib::kInstanceInfo, 1, GR_GL_UNSIGNED_INT,
+ sizeof(Instance), &offsetInBuffer->fInfo));
+ GL_CALL(VertexAttribDivisor((int)Attrib::kInstanceInfo, 1));
+
+ // Shape matrix attrib.
+ GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixX));
+ GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixY));
+ GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixX, 3, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[0]));
+ GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixY, 3, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[3]));
+ GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixX, 1));
+ GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixY, 1));
+
+ // Color attrib.
+ GL_CALL(EnableVertexAttribArray((int)Attrib::kColor));
+ GL_CALL(VertexAttribPointer((int)Attrib::kColor, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE,
+ sizeof(Instance), &offsetInBuffer->fColor));
+ GL_CALL(VertexAttribDivisor((int)Attrib::kColor, 1));
+
+ // Local rect attrib.
+ GL_CALL(EnableVertexAttribArray((int)Attrib::kLocalRect));
+ GL_CALL(VertexAttribPointer((int)Attrib::kLocalRect, 4, GR_GL_FLOAT, GR_GL_FALSE,
+ sizeof(Instance), &offsetInBuffer->fLocalRect));
+ GL_CALL(VertexAttribDivisor((int)Attrib::kLocalRect, 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;
+}
+
+}
« no previous file with comments | « src/gpu/instanced/GLInstancedRendering.h ('k') | src/gpu/instanced/InstanceProcessor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698