blob: da764b2d2eceaf698f511143d61a189e2b5c4b84 [file] [log] [blame]
csmartdaltona7f29642016-07-07 08:49:11 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GLInstancedRendering.h"
9
10#include "GrResourceProvider.h"
11#include "gl/GrGLGpu.h"
12#include "instanced/InstanceProcessor.h"
13
14#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
15
16namespace gr_instanced {
17
Brian Salomon99ad1642016-12-16 09:50:45 -050018class GLInstancedRendering::GLOp final : public InstancedRendering::Op {
csmartdaltona7f29642016-07-07 08:49:11 -070019public:
Brian Salomon25a88092016-12-01 09:36:50 -050020 DEFINE_OP_CLASS_ID
csmartdaltona7f29642016-07-07 08:49:11 -070021
Brian Salomon99ad1642016-12-16 09:50:45 -050022 GLOp(GLInstancedRendering* instRendering) : INHERITED(ClassID(), instRendering) {}
csmartdaltona7f29642016-07-07 08:49:11 -070023 int numGLCommands() const { return 1 + fNumChangesInGeometry; }
24
25private:
26 int fEmulatedBaseInstance;
27 int fGLDrawCmdsIdx;
28
29 friend class GLInstancedRendering;
30
Brian Salomon99ad1642016-12-16 09:50:45 -050031 typedef Op INHERITED;
csmartdaltona7f29642016-07-07 08:49:11 -070032};
33
csmartdaltone0d36292016-07-29 08:14:20 -070034GrCaps::InstancedSupport GLInstancedRendering::CheckSupport(const GrGLCaps& glCaps) {
35 // This method is only intended to be used for initializing fInstancedSupport in the caps.
36 SkASSERT(GrCaps::InstancedSupport::kNone == glCaps.instancedSupport());
csmartdalton4c18b622016-07-29 12:19:28 -070037 if (!glCaps.vertexArrayObjectSupport() ||
38 (!glCaps.drawIndirectSupport() && !glCaps.drawInstancedSupport())) {
csmartdaltone0d36292016-07-29 08:14:20 -070039 return GrCaps::InstancedSupport::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -070040 }
Brian Salomon1edc5b92016-11-29 13:43:46 -050041 return InstanceProcessor::CheckSupport(*glCaps.shaderCaps(), glCaps);
csmartdaltona7f29642016-07-07 08:49:11 -070042}
43
csmartdaltone0d36292016-07-29 08:14:20 -070044GLInstancedRendering::GLInstancedRendering(GrGLGpu* gpu)
45 : INHERITED(gpu),
csmartdaltona7f29642016-07-07 08:49:11 -070046 fVertexArrayID(0),
47 fGLDrawCmdsInfo(0),
48 fInstanceAttribsBufferUniqueId(SK_InvalidUniqueID) {
csmartdaltone0d36292016-07-29 08:14:20 -070049 SkASSERT(GrCaps::InstancedSupport::kNone != this->gpu()->caps()->instancedSupport());
csmartdaltona7f29642016-07-07 08:49:11 -070050}
51
52GLInstancedRendering::~GLInstancedRendering() {
53 if (fVertexArrayID) {
54 GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
55 this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
56 }
57}
58
59inline GrGLGpu* GLInstancedRendering::glGpu() const {
60 return static_cast<GrGLGpu*>(this->gpu());
61}
62
Brian Salomon99ad1642016-12-16 09:50:45 -050063sk_sp<InstancedRendering::Op> GLInstancedRendering::makeOp() { return sk_sp<Op>(new GLOp(this)); }
csmartdaltona7f29642016-07-07 08:49:11 -070064
65void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
66 // Count what there is to draw.
Brian Salomon99ad1642016-12-16 09:50:45 -050067 OpList::Iter iter;
68 iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart);
csmartdaltona7f29642016-07-07 08:49:11 -070069 int numGLInstances = 0;
70 int numGLDrawCmds = 0;
Brian Salomon99ad1642016-12-16 09:50:45 -050071 while (Op* o = iter.get()) {
72 GLOp* op = static_cast<GLOp*>(o);
csmartdaltona7f29642016-07-07 08:49:11 -070073 iter.next();
74
Brian Salomon99ad1642016-12-16 09:50:45 -050075 numGLInstances += op->fNumDraws;
76 numGLDrawCmds += op->numGLCommands();
csmartdaltona7f29642016-07-07 08:49:11 -070077 }
78 if (!numGLDrawCmds) {
79 return;
80 }
81 SkASSERT(numGLInstances);
82
83 // Lazily create a vertex array object.
84 if (!fVertexArrayID) {
85 GL_CALL(GenVertexArrays(1, &fVertexArrayID));
86 if (!fVertexArrayID) {
87 return;
88 }
89 this->glGpu()->bindVertexArray(fVertexArrayID);
90
91 // Attach our index buffer to the vertex array.
csmartdalton485a1202016-07-13 10:16:32 -070092 SkASSERT(!this->indexBuffer()->isCPUBacked());
csmartdaltona7f29642016-07-07 08:49:11 -070093 GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
94 static_cast<const GrGLBuffer*>(this->indexBuffer())->bufferID()));
95
96 // Set up the non-instanced attribs.
csmartdalton485a1202016-07-13 10:16:32 -070097 this->glGpu()->bindBuffer(kVertex_GrBufferType, this->vertexBuffer());
csmartdaltona7f29642016-07-07 08:49:11 -070098 GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeCoords));
99 GL_CALL(VertexAttribPointer((int)Attrib::kShapeCoords, 2, GR_GL_FLOAT, GR_GL_FALSE,
100 sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fX)));
101 GL_CALL(EnableVertexAttribArray((int)Attrib::kVertexAttrs));
102 GL_CALL(VertexAttribIPointer((int)Attrib::kVertexAttrs, 1, GR_GL_INT, sizeof(ShapeVertex),
103 (void*) offsetof(ShapeVertex, fAttrs)));
104
Robert Phillips294870f2016-11-11 12:38:40 -0500105 SkASSERT(fInstanceAttribsBufferUniqueId.isInvalid());
csmartdaltona7f29642016-07-07 08:49:11 -0700106 }
107
108 // Create and map instance and draw-indirect buffers.
109 SkASSERT(!fInstanceBuffer);
csmartdalton485a1202016-07-13 10:16:32 -0700110 fInstanceBuffer.reset(
csmartdaltona7f29642016-07-07 08:49:11 -0700111 rp->createBuffer(sizeof(Instance) * numGLInstances, kVertex_GrBufferType,
csmartdalton485a1202016-07-13 10:16:32 -0700112 kDynamic_GrAccessPattern,
113 GrResourceProvider::kNoPendingIO_Flag |
114 GrResourceProvider::kRequireGpuMemory_Flag));
csmartdaltona7f29642016-07-07 08:49:11 -0700115 if (!fInstanceBuffer) {
116 return;
117 }
118
119 SkASSERT(!fDrawIndirectBuffer);
csmartdalton4c18b622016-07-29 12:19:28 -0700120 if (this->glGpu()->glCaps().drawIndirectSupport()) {
121 fDrawIndirectBuffer.reset(
122 rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds,
123 kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern,
124 GrResourceProvider::kNoPendingIO_Flag |
125 GrResourceProvider::kRequireGpuMemory_Flag));
126 if (!fDrawIndirectBuffer) {
127 return;
128 }
csmartdaltona7f29642016-07-07 08:49:11 -0700129 }
130
131 Instance* glMappedInstances = static_cast<Instance*>(fInstanceBuffer->map());
csmartdalton4c18b622016-07-29 12:19:28 -0700132 SkASSERT(glMappedInstances);
csmartdaltona7f29642016-07-07 08:49:11 -0700133 int glInstancesIdx = 0;
134
csmartdalton4c18b622016-07-29 12:19:28 -0700135 GrGLDrawElementsIndirectCommand* glMappedCmds = nullptr;
csmartdaltona7f29642016-07-07 08:49:11 -0700136 int glDrawCmdsIdx = 0;
csmartdalton4c18b622016-07-29 12:19:28 -0700137 if (fDrawIndirectBuffer) {
138 glMappedCmds = static_cast<GrGLDrawElementsIndirectCommand*>(fDrawIndirectBuffer->map());
139 SkASSERT(glMappedCmds);
140 }
csmartdaltona7f29642016-07-07 08:49:11 -0700141
142 bool baseInstanceSupport = this->glGpu()->glCaps().baseInstanceSupport();
csmartdalton4c18b622016-07-29 12:19:28 -0700143 SkASSERT(!baseInstanceSupport || fDrawIndirectBuffer);
csmartdaltona7f29642016-07-07 08:49:11 -0700144
csmartdalton4c18b622016-07-29 12:19:28 -0700145 SkASSERT(!fGLDrawCmdsInfo);
Brian Salomon99ad1642016-12-16 09:50:45 -0500146 if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) {
csmartdaltona7f29642016-07-07 08:49:11 -0700147 fGLDrawCmdsInfo.reset(numGLDrawCmds);
148 }
149
Brian Salomon99ad1642016-12-16 09:50:45 -0500150 // Generate the instance and draw-indirect buffer contents based on the tracked ops.
151 iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart);
152 while (Op* o = iter.get()) {
153 GLOp* op = static_cast<GLOp*>(o);
csmartdaltona7f29642016-07-07 08:49:11 -0700154 iter.next();
155
Brian Salomon99ad1642016-12-16 09:50:45 -0500156 op->fEmulatedBaseInstance = baseInstanceSupport ? 0 : glInstancesIdx;
157 op->fGLDrawCmdsIdx = glDrawCmdsIdx;
csmartdaltona7f29642016-07-07 08:49:11 -0700158
Brian Salomon99ad1642016-12-16 09:50:45 -0500159 const Op::Draw* draw = op->fHeadDraw;
csmartdaltona7f29642016-07-07 08:49:11 -0700160 SkASSERT(draw);
161 do {
162 int instanceCount = 0;
163 IndexRange geometry = draw->fGeometry;
164 SkASSERT(!geometry.isEmpty());
165
166 do {
167 glMappedInstances[glInstancesIdx + instanceCount++] = draw->fInstance;
168 draw = draw->fNext;
169 } while (draw && draw->fGeometry == geometry);
170
csmartdalton4c18b622016-07-29 12:19:28 -0700171 if (fDrawIndirectBuffer) {
172 GrGLDrawElementsIndirectCommand& glCmd = glMappedCmds[glDrawCmdsIdx];
173 glCmd.fCount = geometry.fCount;
174 glCmd.fInstanceCount = instanceCount;
175 glCmd.fFirstIndex = geometry.fStart;
176 glCmd.fBaseVertex = 0;
177 glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0;
178 }
csmartdaltona7f29642016-07-07 08:49:11 -0700179
Brian Salomon99ad1642016-12-16 09:50:45 -0500180 if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) {
csmartdalton4c18b622016-07-29 12:19:28 -0700181 GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glDrawCmdsIdx];
182 cmdInfo.fGeometry = geometry;
183 cmdInfo.fInstanceCount = instanceCount;
csmartdaltona7f29642016-07-07 08:49:11 -0700184 }
185
186 glInstancesIdx += instanceCount;
187 ++glDrawCmdsIdx;
188 } while (draw);
189 }
190
191 SkASSERT(glDrawCmdsIdx == numGLDrawCmds);
csmartdalton4c18b622016-07-29 12:19:28 -0700192 if (fDrawIndirectBuffer) {
193 fDrawIndirectBuffer->unmap();
194 }
csmartdaltona7f29642016-07-07 08:49:11 -0700195
196 SkASSERT(glInstancesIdx == numGLInstances);
197 fInstanceBuffer->unmap();
198}
199
200void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProcessor& instProc,
Brian Salomon99ad1642016-12-16 09:50:45 -0500201 const Op* baseOp) {
csmartdalton4c18b622016-07-29 12:19:28 -0700202 if (!fDrawIndirectBuffer && !fGLDrawCmdsInfo) {
csmartdaltona7f29642016-07-07 08:49:11 -0700203 return; // beginFlush was not successful.
204 }
bsalomon2eda5b32016-09-21 10:53:24 -0700205 if (!this->glGpu()->flushGLState(pipeline, instProc, false)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700206 return;
207 }
208
csmartdalton4c18b622016-07-29 12:19:28 -0700209 if (fDrawIndirectBuffer) {
210 this->glGpu()->bindBuffer(kDrawIndirect_GrBufferType, fDrawIndirectBuffer.get());
211 }
csmartdaltona7f29642016-07-07 08:49:11 -0700212
213 const GrGLCaps& glCaps = this->glGpu()->glCaps();
Brian Salomon99ad1642016-12-16 09:50:45 -0500214 const GLOp* op = static_cast<const GLOp*>(baseOp);
215 int numCommands = op->numGLCommands();
csmartdaltona7f29642016-07-07 08:49:11 -0700216
Brian Salomon99ad1642016-12-16 09:50:45 -0500217#if GR_GL_LOG_INSTANCED_OPS
csmartdaltona7f29642016-07-07 08:49:11 -0700218 SkASSERT(fGLDrawCmdsInfo);
Brian Salomon99ad1642016-12-16 09:50:45 -0500219 SkDebugf("Instanced op: [");
csmartdaltona7f29642016-07-07 08:49:11 -0700220 for (int i = 0; i < numCommands; ++i) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500221 int glCmdIdx = op->fGLDrawCmdsIdx + i;
csmartdaltona7f29642016-07-07 08:49:11 -0700222 SkDebugf("%s%i * %s", (i ? ", " : ""), fGLDrawCmdsInfo[glCmdIdx].fInstanceCount,
223 InstanceProcessor::GetNameOfIndexRange(fGLDrawCmdsInfo[glCmdIdx].fGeometry));
224 }
225 SkDebugf("]\n");
226#else
227 SkASSERT(SkToBool(fGLDrawCmdsInfo) == !glCaps.baseInstanceSupport());
228#endif
229
csmartdalton4c18b622016-07-29 12:19:28 -0700230 if (numCommands > 1 && glCaps.multiDrawIndirectSupport() && glCaps.baseInstanceSupport()) {
231 SkASSERT(fDrawIndirectBuffer);
Brian Salomon99ad1642016-12-16 09:50:45 -0500232 int glCmdsIdx = op->fGLDrawCmdsIdx;
233 this->flushInstanceAttribs(op->fEmulatedBaseInstance);
csmartdaltona7f29642016-07-07 08:49:11 -0700234 GL_CALL(MultiDrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
235 (GrGLDrawElementsIndirectCommand*) nullptr + glCmdsIdx,
236 numCommands, 0));
csmartdalton4c18b622016-07-29 12:19:28 -0700237 return;
238 }
239
Brian Salomon99ad1642016-12-16 09:50:45 -0500240 int emulatedBaseInstance = op->fEmulatedBaseInstance;
csmartdalton4c18b622016-07-29 12:19:28 -0700241 for (int i = 0; i < numCommands; ++i) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500242 int glCmdIdx = op->fGLDrawCmdsIdx + i;
csmartdalton4c18b622016-07-29 12:19:28 -0700243 this->flushInstanceAttribs(emulatedBaseInstance);
244 if (fDrawIndirectBuffer) {
245 GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
246 (GrGLDrawElementsIndirectCommand*) nullptr + glCmdIdx));
247 } else {
mtklein35b26a42016-09-15 09:56:28 -0700248 const GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glCmdIdx];
csmartdalton4c18b622016-07-29 12:19:28 -0700249 GL_CALL(DrawElementsInstanced(GR_GL_TRIANGLES, cmdInfo.fGeometry.fCount,
250 GR_GL_UNSIGNED_BYTE,
251 (GrGLubyte*) nullptr + cmdInfo.fGeometry.fStart,
252 cmdInfo.fInstanceCount));
253 }
254 if (!glCaps.baseInstanceSupport()) {
mtklein35b26a42016-09-15 09:56:28 -0700255 const GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glCmdIdx];
csmartdalton4c18b622016-07-29 12:19:28 -0700256 emulatedBaseInstance += cmdInfo.fInstanceCount;
257 }
csmartdaltona7f29642016-07-07 08:49:11 -0700258 }
259}
260
261void GLInstancedRendering::flushInstanceAttribs(int baseInstance) {
262 SkASSERT(fVertexArrayID);
263 this->glGpu()->bindVertexArray(fVertexArrayID);
264
265 SkASSERT(fInstanceBuffer);
robertphillips8abb3702016-08-31 14:04:06 -0700266 if (fInstanceAttribsBufferUniqueId != fInstanceBuffer->uniqueID() ||
csmartdaltona7f29642016-07-07 08:49:11 -0700267 fInstanceAttribsBaseInstance != baseInstance) {
268 Instance* offsetInBuffer = (Instance*) nullptr + baseInstance;
269
270 this->glGpu()->bindBuffer(kVertex_GrBufferType, fInstanceBuffer.get());
271
272 // Info attrib.
273 GL_CALL(EnableVertexAttribArray((int)Attrib::kInstanceInfo));
274 GL_CALL(VertexAttribIPointer((int)Attrib::kInstanceInfo, 1, GR_GL_UNSIGNED_INT,
275 sizeof(Instance), &offsetInBuffer->fInfo));
276 GL_CALL(VertexAttribDivisor((int)Attrib::kInstanceInfo, 1));
277
278 // Shape matrix attrib.
279 GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixX));
280 GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixY));
281 GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixX, 3, GR_GL_FLOAT, GR_GL_FALSE,
282 sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[0]));
283 GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixY, 3, GR_GL_FLOAT, GR_GL_FALSE,
284 sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[3]));
285 GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixX, 1));
286 GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixY, 1));
287
288 // Color attrib.
289 GL_CALL(EnableVertexAttribArray((int)Attrib::kColor));
290 GL_CALL(VertexAttribPointer((int)Attrib::kColor, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE,
291 sizeof(Instance), &offsetInBuffer->fColor));
292 GL_CALL(VertexAttribDivisor((int)Attrib::kColor, 1));
293
294 // Local rect attrib.
295 GL_CALL(EnableVertexAttribArray((int)Attrib::kLocalRect));
296 GL_CALL(VertexAttribPointer((int)Attrib::kLocalRect, 4, GR_GL_FLOAT, GR_GL_FALSE,
297 sizeof(Instance), &offsetInBuffer->fLocalRect));
298 GL_CALL(VertexAttribDivisor((int)Attrib::kLocalRect, 1));
299
robertphillips8abb3702016-08-31 14:04:06 -0700300 fInstanceAttribsBufferUniqueId = fInstanceBuffer->uniqueID();
csmartdaltona7f29642016-07-07 08:49:11 -0700301 fInstanceAttribsBaseInstance = baseInstance;
302 }
303}
304
305void GLInstancedRendering::onEndFlush() {
306 fInstanceBuffer.reset();
307 fDrawIndirectBuffer.reset();
308 fGLDrawCmdsInfo.reset(0);
309}
310
311void GLInstancedRendering::onResetGpuResources(ResetType resetType) {
312 if (fVertexArrayID && ResetType::kDestroy == resetType) {
313 GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
314 this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
315 }
316 fVertexArrayID = 0;
317 fInstanceBuffer.reset();
318 fDrawIndirectBuffer.reset();
Robert Phillips294870f2016-11-11 12:38:40 -0500319 fInstanceAttribsBufferUniqueId.makeInvalid();
csmartdaltona7f29642016-07-07 08:49:11 -0700320}
321
322}