Line data Source code
1 : /*
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 :
16 : namespace gr_instanced {
17 :
18 0 : class GLInstancedRendering::GLOp final : public InstancedRendering::Op {
19 : public:
20 0 : DEFINE_OP_CLASS_ID
21 :
22 0 : GLOp(GLInstancedRendering* instRendering, GrPaint&& paint)
23 0 : : INHERITED(ClassID(), std::move(paint), instRendering) {}
24 0 : int numGLCommands() const { return 1 + fNumChangesInGeometry; }
25 :
26 : private:
27 : int fEmulatedBaseInstance;
28 : int fGLDrawCmdsIdx;
29 :
30 : friend class GLInstancedRendering;
31 :
32 : typedef Op INHERITED;
33 : };
34 :
35 0 : GrCaps::InstancedSupport GLInstancedRendering::CheckSupport(const GrGLCaps& glCaps) {
36 : // This method is only intended to be used for initializing fInstancedSupport in the caps.
37 0 : SkASSERT(GrCaps::InstancedSupport::kNone == glCaps.instancedSupport());
38 0 : if (!glCaps.vertexArrayObjectSupport() ||
39 0 : (!glCaps.drawIndirectSupport() && !glCaps.drawInstancedSupport())) {
40 0 : return GrCaps::InstancedSupport::kNone;
41 : }
42 0 : return InstanceProcessor::CheckSupport(*glCaps.shaderCaps(), glCaps);
43 : }
44 :
45 0 : GLInstancedRendering::GLInstancedRendering(GrGLGpu* gpu)
46 : : INHERITED(gpu),
47 : fVertexArrayID(0),
48 : fGLDrawCmdsInfo(0),
49 0 : fInstanceAttribsBufferUniqueId(SK_InvalidUniqueID) {
50 0 : SkASSERT(GrCaps::InstancedSupport::kNone != this->gpu()->caps()->instancedSupport());
51 0 : }
52 :
53 0 : GLInstancedRendering::~GLInstancedRendering() {
54 0 : if (fVertexArrayID) {
55 0 : GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
56 0 : this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
57 : }
58 0 : }
59 :
60 0 : inline GrGLGpu* GLInstancedRendering::glGpu() const {
61 0 : return static_cast<GrGLGpu*>(this->gpu());
62 : }
63 :
64 0 : std::unique_ptr<InstancedRendering::Op> GLInstancedRendering::makeOp(GrPaint&& paint) {
65 0 : return std::unique_ptr<Op>(new GLOp(this, std::move(paint)));
66 : }
67 :
68 0 : void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
69 : // Count what there is to draw.
70 0 : OpList::Iter iter;
71 0 : iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart);
72 0 : int numGLInstances = 0;
73 0 : int numGLDrawCmds = 0;
74 0 : while (Op* o = iter.get()) {
75 0 : GLOp* op = static_cast<GLOp*>(o);
76 0 : iter.next();
77 :
78 0 : numGLInstances += op->fNumDraws;
79 0 : numGLDrawCmds += op->numGLCommands();
80 0 : }
81 0 : if (!numGLDrawCmds) {
82 0 : return;
83 : }
84 0 : SkASSERT(numGLInstances);
85 :
86 : // Lazily create a vertex array object.
87 0 : if (!fVertexArrayID) {
88 0 : GL_CALL(GenVertexArrays(1, &fVertexArrayID));
89 0 : if (!fVertexArrayID) {
90 0 : return;
91 : }
92 0 : this->glGpu()->bindVertexArray(fVertexArrayID);
93 :
94 : // Attach our index buffer to the vertex array.
95 0 : SkASSERT(!this->indexBuffer()->isCPUBacked());
96 0 : GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
97 : static_cast<const GrGLBuffer*>(this->indexBuffer())->bufferID()));
98 :
99 : // Set up the non-instanced attribs.
100 0 : this->glGpu()->bindBuffer(kVertex_GrBufferType, this->vertexBuffer());
101 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeCoords));
102 0 : GL_CALL(VertexAttribPointer((int)Attrib::kShapeCoords, 2, GR_GL_FLOAT, GR_GL_FALSE,
103 : sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fX)));
104 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kVertexAttrs));
105 0 : GL_CALL(VertexAttribIPointer((int)Attrib::kVertexAttrs, 1, GR_GL_INT, sizeof(ShapeVertex),
106 : (void*) offsetof(ShapeVertex, fAttrs)));
107 :
108 0 : SkASSERT(fInstanceAttribsBufferUniqueId.isInvalid());
109 : }
110 :
111 : // Create and map instance and draw-indirect buffers.
112 0 : SkASSERT(!fInstanceBuffer);
113 0 : fInstanceBuffer.reset(
114 : rp->createBuffer(sizeof(Instance) * numGLInstances, kVertex_GrBufferType,
115 : kDynamic_GrAccessPattern,
116 : GrResourceProvider::kNoPendingIO_Flag |
117 0 : GrResourceProvider::kRequireGpuMemory_Flag));
118 0 : if (!fInstanceBuffer) {
119 0 : return;
120 : }
121 :
122 0 : SkASSERT(!fDrawIndirectBuffer);
123 0 : if (this->glGpu()->glCaps().drawIndirectSupport()) {
124 0 : fDrawIndirectBuffer.reset(
125 : rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds,
126 : kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern,
127 : GrResourceProvider::kNoPendingIO_Flag |
128 0 : GrResourceProvider::kRequireGpuMemory_Flag));
129 0 : if (!fDrawIndirectBuffer) {
130 0 : return;
131 : }
132 : }
133 :
134 0 : Instance* glMappedInstances = static_cast<Instance*>(fInstanceBuffer->map());
135 0 : SkASSERT(glMappedInstances);
136 0 : int glInstancesIdx = 0;
137 :
138 0 : GrGLDrawElementsIndirectCommand* glMappedCmds = nullptr;
139 0 : int glDrawCmdsIdx = 0;
140 0 : if (fDrawIndirectBuffer) {
141 0 : glMappedCmds = static_cast<GrGLDrawElementsIndirectCommand*>(fDrawIndirectBuffer->map());
142 0 : SkASSERT(glMappedCmds);
143 : }
144 :
145 0 : bool baseInstanceSupport = this->glGpu()->glCaps().baseInstanceSupport();
146 0 : SkASSERT(!baseInstanceSupport || fDrawIndirectBuffer);
147 :
148 0 : SkASSERT(!fGLDrawCmdsInfo);
149 0 : if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) {
150 0 : fGLDrawCmdsInfo.reset(numGLDrawCmds);
151 : }
152 :
153 : // Generate the instance and draw-indirect buffer contents based on the tracked ops.
154 0 : iter.init(this->trackedOps(), OpList::Iter::kHead_IterStart);
155 0 : while (Op* o = iter.get()) {
156 0 : GLOp* op = static_cast<GLOp*>(o);
157 0 : iter.next();
158 :
159 0 : op->fEmulatedBaseInstance = baseInstanceSupport ? 0 : glInstancesIdx;
160 0 : op->fGLDrawCmdsIdx = glDrawCmdsIdx;
161 :
162 0 : const Op::Draw* draw = op->fHeadDraw;
163 0 : SkASSERT(draw);
164 0 : do {
165 0 : int instanceCount = 0;
166 0 : IndexRange geometry = draw->fGeometry;
167 0 : SkASSERT(!geometry.isEmpty());
168 :
169 0 : do {
170 0 : glMappedInstances[glInstancesIdx + instanceCount++] = draw->fInstance;
171 0 : draw = draw->fNext;
172 0 : } while (draw && draw->fGeometry == geometry);
173 :
174 0 : if (fDrawIndirectBuffer) {
175 0 : GrGLDrawElementsIndirectCommand& glCmd = glMappedCmds[glDrawCmdsIdx];
176 0 : glCmd.fCount = geometry.fCount;
177 0 : glCmd.fInstanceCount = instanceCount;
178 0 : glCmd.fFirstIndex = geometry.fStart;
179 0 : glCmd.fBaseVertex = 0;
180 0 : glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0;
181 : }
182 :
183 0 : if (GR_GL_LOG_INSTANCED_OPS || !baseInstanceSupport) {
184 0 : GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glDrawCmdsIdx];
185 0 : cmdInfo.fGeometry = geometry;
186 0 : cmdInfo.fInstanceCount = instanceCount;
187 : }
188 :
189 0 : glInstancesIdx += instanceCount;
190 0 : ++glDrawCmdsIdx;
191 0 : } while (draw);
192 0 : }
193 :
194 0 : SkASSERT(glDrawCmdsIdx == numGLDrawCmds);
195 0 : if (fDrawIndirectBuffer) {
196 0 : fDrawIndirectBuffer->unmap();
197 : }
198 :
199 0 : SkASSERT(glInstancesIdx == numGLInstances);
200 0 : fInstanceBuffer->unmap();
201 : }
202 :
203 0 : void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProcessor& instProc,
204 : const Op* baseOp) {
205 0 : if (!fDrawIndirectBuffer && !fGLDrawCmdsInfo) {
206 0 : return; // beginFlush was not successful.
207 : }
208 0 : if (!this->glGpu()->flushGLState(pipeline, instProc, false)) {
209 0 : return;
210 : }
211 :
212 0 : if (fDrawIndirectBuffer) {
213 0 : this->glGpu()->bindBuffer(kDrawIndirect_GrBufferType, fDrawIndirectBuffer.get());
214 : }
215 :
216 0 : const GrGLCaps& glCaps = this->glGpu()->glCaps();
217 0 : const GLOp* op = static_cast<const GLOp*>(baseOp);
218 0 : int numCommands = op->numGLCommands();
219 :
220 : #if GR_GL_LOG_INSTANCED_OPS
221 : SkASSERT(fGLDrawCmdsInfo);
222 : SkDebugf("Instanced op: [");
223 : for (int i = 0; i < numCommands; ++i) {
224 : int glCmdIdx = op->fGLDrawCmdsIdx + i;
225 : SkDebugf("%s%i * %s", (i ? ", " : ""), fGLDrawCmdsInfo[glCmdIdx].fInstanceCount,
226 : InstanceProcessor::GetNameOfIndexRange(fGLDrawCmdsInfo[glCmdIdx].fGeometry));
227 : }
228 : SkDebugf("]\n");
229 : #else
230 0 : SkASSERT(SkToBool(fGLDrawCmdsInfo) == !glCaps.baseInstanceSupport());
231 : #endif
232 :
233 0 : if (numCommands > 1 && glCaps.multiDrawIndirectSupport() && glCaps.baseInstanceSupport()) {
234 0 : SkASSERT(fDrawIndirectBuffer);
235 0 : int glCmdsIdx = op->fGLDrawCmdsIdx;
236 0 : this->flushInstanceAttribs(op->fEmulatedBaseInstance);
237 0 : GL_CALL(MultiDrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
238 : (GrGLDrawElementsIndirectCommand*) nullptr + glCmdsIdx,
239 : numCommands, 0));
240 0 : return;
241 : }
242 :
243 0 : int emulatedBaseInstance = op->fEmulatedBaseInstance;
244 0 : for (int i = 0; i < numCommands; ++i) {
245 0 : int glCmdIdx = op->fGLDrawCmdsIdx + i;
246 0 : this->flushInstanceAttribs(emulatedBaseInstance);
247 0 : if (fDrawIndirectBuffer) {
248 0 : GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE,
249 : (GrGLDrawElementsIndirectCommand*) nullptr + glCmdIdx));
250 : } else {
251 0 : const GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glCmdIdx];
252 0 : GL_CALL(DrawElementsInstanced(GR_GL_TRIANGLES, cmdInfo.fGeometry.fCount,
253 : GR_GL_UNSIGNED_BYTE,
254 : (GrGLubyte*) nullptr + cmdInfo.fGeometry.fStart,
255 : cmdInfo.fInstanceCount));
256 : }
257 0 : if (!glCaps.baseInstanceSupport()) {
258 0 : const GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glCmdIdx];
259 0 : emulatedBaseInstance += cmdInfo.fInstanceCount;
260 : }
261 : }
262 : }
263 :
264 0 : void GLInstancedRendering::flushInstanceAttribs(int baseInstance) {
265 0 : SkASSERT(fVertexArrayID);
266 0 : this->glGpu()->bindVertexArray(fVertexArrayID);
267 :
268 0 : SkASSERT(fInstanceBuffer);
269 0 : if (fInstanceAttribsBufferUniqueId != fInstanceBuffer->uniqueID() ||
270 0 : fInstanceAttribsBaseInstance != baseInstance) {
271 0 : Instance* offsetInBuffer = (Instance*) nullptr + baseInstance;
272 :
273 0 : this->glGpu()->bindBuffer(kVertex_GrBufferType, fInstanceBuffer.get());
274 :
275 : // Info attrib.
276 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kInstanceInfo));
277 0 : GL_CALL(VertexAttribIPointer((int)Attrib::kInstanceInfo, 1, GR_GL_UNSIGNED_INT,
278 : sizeof(Instance), &offsetInBuffer->fInfo));
279 0 : GL_CALL(VertexAttribDivisor((int)Attrib::kInstanceInfo, 1));
280 :
281 : // Shape matrix attrib.
282 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixX));
283 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeMatrixY));
284 0 : GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixX, 3, GR_GL_FLOAT, GR_GL_FALSE,
285 : sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[0]));
286 0 : GL_CALL(VertexAttribPointer((int)Attrib::kShapeMatrixY, 3, GR_GL_FLOAT, GR_GL_FALSE,
287 : sizeof(Instance), &offsetInBuffer->fShapeMatrix2x3[3]));
288 0 : GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixX, 1));
289 0 : GL_CALL(VertexAttribDivisor((int)Attrib::kShapeMatrixY, 1));
290 :
291 : // Color attrib.
292 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kColor));
293 0 : GL_CALL(VertexAttribPointer((int)Attrib::kColor, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE,
294 : sizeof(Instance), &offsetInBuffer->fColor));
295 0 : GL_CALL(VertexAttribDivisor((int)Attrib::kColor, 1));
296 :
297 : // Local rect attrib.
298 0 : GL_CALL(EnableVertexAttribArray((int)Attrib::kLocalRect));
299 0 : GL_CALL(VertexAttribPointer((int)Attrib::kLocalRect, 4, GR_GL_FLOAT, GR_GL_FALSE,
300 : sizeof(Instance), &offsetInBuffer->fLocalRect));
301 0 : GL_CALL(VertexAttribDivisor((int)Attrib::kLocalRect, 1));
302 :
303 0 : fInstanceAttribsBufferUniqueId = fInstanceBuffer->uniqueID();
304 0 : fInstanceAttribsBaseInstance = baseInstance;
305 : }
306 0 : }
307 :
308 0 : void GLInstancedRendering::onEndFlush() {
309 0 : fInstanceBuffer.reset();
310 0 : fDrawIndirectBuffer.reset();
311 0 : fGLDrawCmdsInfo.reset(0);
312 0 : }
313 :
314 0 : void GLInstancedRendering::onResetGpuResources(ResetType resetType) {
315 0 : if (fVertexArrayID && ResetType::kDestroy == resetType) {
316 0 : GL_CALL(DeleteVertexArrays(1, &fVertexArrayID));
317 0 : this->glGpu()->notifyVertexArrayDelete(fVertexArrayID);
318 : }
319 0 : fVertexArrayID = 0;
320 0 : fInstanceBuffer.reset();
321 0 : fDrawIndirectBuffer.reset();
322 0 : fInstanceAttribsBufferUniqueId.makeInvalid();
323 0 : }
324 :
325 : }
|