xref: /aosp_15_r20/external/skia/src/gpu/ganesh/gl/GrGLOpsRenderPass.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 #include "src/gpu/ganesh/gl/GrGLOpsRenderPass.h"
8 
9 #include "include/gpu/ganesh/GrDirectContext.h"
10 #include "include/gpu/ganesh/gl/GrGLFunctions.h"
11 #include "include/gpu/ganesh/gl/GrGLInterface.h"
12 #include "include/gpu/ganesh/gl/GrGLTypes.h"
13 #include "include/private/base/SkAssert.h"
14 #include "include/private/gpu/ganesh/GrTypesPriv.h"
15 #include "src/gpu/ganesh/GrBuffer.h"
16 #include "src/gpu/ganesh/GrCaps.h"
17 #include "src/gpu/ganesh/GrCpuBuffer.h"
18 #include "src/gpu/ganesh/GrDirectContextPriv.h"
19 #include "src/gpu/ganesh/GrDrawIndirectCommand.h"
20 #include "src/gpu/ganesh/GrGpuBuffer.h"
21 #include "src/gpu/ganesh/GrProgramInfo.h"
22 #include "src/gpu/ganesh/GrRenderTarget.h"
23 #include "src/gpu/ganesh/gl/GrGLCaps.h"
24 #include "src/gpu/ganesh/gl/GrGLDefines.h"
25 #include "src/gpu/ganesh/gl/GrGLProgram.h"
26 #include "src/gpu/ganesh/gl/GrGLRenderTarget.h"
27 #include "src/gpu/ganesh/gl/GrGLUtil.h"
28 #include "src/gpu/ganesh/gl/GrGLVertexArray.h"
29 
30 #include <algorithm>
31 #include <utility>
32 
33 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
34 
set(GrRenderTarget * rt,bool useMSAASurface,const SkIRect & contentBounds,GrSurfaceOrigin origin,const LoadAndStoreInfo & colorInfo,const StencilLoadAndStoreInfo & stencilInfo)35 void GrGLOpsRenderPass::set(GrRenderTarget* rt, bool useMSAASurface, const SkIRect& contentBounds,
36                             GrSurfaceOrigin origin, const LoadAndStoreInfo& colorInfo,
37                             const StencilLoadAndStoreInfo& stencilInfo) {
38     SkASSERT(fGpu);
39     SkASSERT(!fRenderTarget);
40     SkASSERT(fGpu == rt->getContext()->priv().getGpu());
41 
42     this->INHERITED::set(rt, origin);
43     fUseMultisampleFBO = useMSAASurface;
44     fContentBounds = contentBounds;
45     fColorLoadAndStoreInfo = colorInfo;
46     fStencilLoadAndStoreInfo = stencilInfo;
47 }
48 
dmsaaLoadStoreBounds() const49 GrNativeRect GrGLOpsRenderPass::dmsaaLoadStoreBounds() const {
50     if (fGpu->glCaps().framebufferResolvesMustBeFullSize()) {
51         // If frambeffer resolves have to be full size, then resolve the entire render target during
52         // load and store both, even if we will be doing so with a draw. We do this because we will
53         // have no other choice than to do a full size resolve at the end of the render pass, so the
54         // full DMSAA attachment needs to have valid content.
55         return GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
56                                             SkIRect::MakeSize(fRenderTarget->dimensions()));
57     } else {
58         return GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(), fContentBounds);
59     }
60 }
61 
onBegin()62 void GrGLOpsRenderPass::onBegin() {
63     auto glRT = static_cast<GrGLRenderTarget*>(fRenderTarget);
64     if (fUseMultisampleFBO &&
65         fColorLoadAndStoreInfo.fLoadOp == GrLoadOp::kLoad &&
66         glRT->hasDynamicMSAAAttachment()) {
67         // Load the single sample fbo into the dmsaa attachment.
68         if (fGpu->glCaps().canResolveSingleToMSAA()) {
69             fGpu->resolveRenderFBOs(glRT, this->dmsaaLoadStoreBounds().asSkIRect(),
70                                     GrGLGpu::ResolveDirection::kSingleToMSAA);
71         } else {
72             fGpu->drawSingleIntoMSAAFBO(glRT, this->dmsaaLoadStoreBounds().asSkIRect());
73         }
74     }
75 
76     fGpu->beginCommandBuffer(glRT, fUseMultisampleFBO, fContentBounds, fOrigin,
77                              fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo);
78 }
79 
onEnd()80 void GrGLOpsRenderPass::onEnd() {
81     auto glRT = static_cast<GrGLRenderTarget*>(fRenderTarget);
82     fGpu->endCommandBuffer(glRT, fUseMultisampleFBO, fColorLoadAndStoreInfo,
83                            fStencilLoadAndStoreInfo);
84 
85     if (fUseMultisampleFBO &&
86         fColorLoadAndStoreInfo.fStoreOp == GrStoreOp::kStore &&
87         glRT->hasDynamicMSAAAttachment()) {
88         // Blit the msaa attachment into the single sample fbo.
89         fGpu->resolveRenderFBOs(glRT, this->dmsaaLoadStoreBounds().asSkIRect(),
90                                 GrGLGpu::ResolveDirection::kMSAAToSingle,
91                                 true /*invalidateReadBufferAfterBlit*/);
92     }
93 }
94 
onBindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)95 bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
96                                        const SkRect& drawBounds) {
97     fPrimitiveType = programInfo.primitiveType();
98     return fGpu->flushGLState(fRenderTarget, fUseMultisampleFBO, programInfo);
99 }
100 
onSetScissorRect(const SkIRect & scissor)101 void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
102     fGpu->flushScissorRect(scissor, fRenderTarget->height(), fOrigin);
103 }
104 
onBindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)105 bool GrGLOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc,
106                                        const GrSurfaceProxy* const geomProcTextures[],
107                                        const GrPipeline& pipeline) {
108     GrGLProgram* program = fGpu->currentProgram();
109     SkASSERT(program);
110     program->bindTextures(geomProc, geomProcTextures, pipeline);
111     return true;
112 }
113 
onBindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primitiveRestart)114 void GrGLOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer,
115                                       sk_sp<const GrBuffer> instanceBuffer,
116                                       sk_sp<const GrBuffer> vertexBuffer,
117                                       GrPrimitiveRestart primitiveRestart) {
118     SkASSERT((primitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
119     GrGLProgram* program = fGpu->currentProgram();
120     SkASSERT(program);
121 
122 #ifdef SK_DEBUG
123     fDidBindInstanceBuffer = false;
124     fDidBindVertexBuffer = false;
125 #endif
126 
127     int numAttribs = program->numVertexAttributes() + program->numInstanceAttributes();
128     fAttribArrayState = fGpu->bindInternalVertexArray(indexBuffer.get(), numAttribs,
129                                                       primitiveRestart);
130 
131     if (indexBuffer) {
132         if (indexBuffer->isCpuBuffer()) {
133             auto* cpuIndexBuffer = static_cast<const GrCpuBuffer*>(indexBuffer.get());
134             fIndexPointer = reinterpret_cast<const uint16_t*>(cpuIndexBuffer->data());
135         } else {
136             fIndexPointer = nullptr;
137         }
138     }
139 
140     // If this platform does not support baseInstance, defer binding of the instance buffer.
141     if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
142         this->bindInstanceBuffer(instanceBuffer.get(), 0);
143         SkDEBUGCODE(fDidBindInstanceBuffer = true;)
144     }
145     fActiveInstanceBuffer = std::move(instanceBuffer);
146 
147     // We differ binding the vertex buffer for one of two situations:
148     // 1) This platform does not support baseVertex with indexed draws.
149     // 2) There is a driver bug affecting glDrawArrays.
150     if ((indexBuffer && fGpu->glCaps().baseVertexBaseInstanceSupport()) ||
151         (!indexBuffer && !fGpu->glCaps().drawArraysBaseVertexIsBroken())) {
152             this->bindVertexBuffer(vertexBuffer.get(), 0);
153             SkDEBUGCODE(fDidBindVertexBuffer = true;)
154     }
155     fActiveVertexBuffer = std::move(vertexBuffer);
156     fActiveIndexBuffer = std::move(indexBuffer);
157 }
158 
bindInstanceBuffer(const GrBuffer * instanceBuffer,int baseInstance)159 void GrGLOpsRenderPass::bindInstanceBuffer(const GrBuffer* instanceBuffer, int baseInstance) {
160     GrGLProgram* program = fGpu->currentProgram();
161     SkASSERT(program);
162     if (int instanceStride = program->instanceStride()) {
163         SkASSERT(instanceBuffer);
164         SkASSERT(instanceBuffer->isCpuBuffer() ||
165                  !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
166         size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
167         int attribIdx = program->numVertexAttributes();
168         for (int i = 0; i < program->numInstanceAttributes(); ++i, ++attribIdx) {
169             const auto& attrib = program->instanceAttribute(i);
170             static constexpr int kDivisor = 1;
171             fAttribArrayState->set(fGpu, attrib.fLocation, instanceBuffer, attrib.fCPUType,
172                                    attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
173                                    kDivisor);
174         }
175     }
176 }
177 
bindVertexBuffer(const GrBuffer * vertexBuffer,int baseVertex)178 void GrGLOpsRenderPass::bindVertexBuffer(const GrBuffer* vertexBuffer, int baseVertex) {
179     GrGLProgram* program = fGpu->currentProgram();
180     SkASSERT(program);
181     if (int vertexStride = program->vertexStride()) {
182         SkASSERT(vertexBuffer);
183         SkASSERT(vertexBuffer->isCpuBuffer() ||
184                  !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
185         size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
186         for (int i = 0; i < program->numVertexAttributes(); ++i) {
187             const auto& attrib = program->vertexAttribute(i);
188             static constexpr int kDivisor = 0;
189             fAttribArrayState->set(fGpu, attrib.fLocation, vertexBuffer, attrib.fCPUType,
190                                    attrib.fGPUType, vertexStride, bufferOffset + attrib.fOffset,
191                                    kDivisor);
192         }
193     }
194 }
195 
onDraw(int vertexCount,int baseVertex)196 void GrGLOpsRenderPass::onDraw(int vertexCount, int baseVertex) {
197     SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
198     GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
199     if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
200         this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
201         baseVertex = 0;
202     }
203     GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
204     fGpu->didDrawTo(fRenderTarget);
205 }
206 
onDrawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)207 void GrGLOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
208                                       uint16_t maxIndexValue, int baseVertex) {
209     GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
210     if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
211         SkASSERT(fGpu->glCaps().drawInstancedSupport());
212         SkASSERT(fDidBindVertexBuffer);
213         if (baseVertex != 0) {
214             GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
215                     glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
216                     this->offsetForBaseIndex(baseIndex), 1, baseVertex, 0));
217             return;
218         }
219     } else {
220         this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
221     }
222 
223     if (fGpu->glCaps().drawRangeElementsSupport()) {
224         GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
225                                   GR_GL_UNSIGNED_SHORT, this->offsetForBaseIndex(baseIndex)));
226     } else {
227         GL_CALL(DrawElements(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
228                              this->offsetForBaseIndex(baseIndex)));
229     }
230     fGpu->didDrawTo(fRenderTarget);
231 }
232 
onDrawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)233 void GrGLOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
234                                         int baseVertex) {
235     SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
236     if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
237         // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
238         // affecting glDrawArrays.
239         this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
240     }
241     int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
242     for (int i = 0; i < instanceCount; i += maxInstances) {
243         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
244         int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
245         int baseInstanceForDraw = baseInstance + i;
246         if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
247             SkASSERT(fDidBindInstanceBuffer);
248             GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, baseVertex, vertexCount,
249                                                     instanceCountForDraw, baseInstanceForDraw));
250         } else {
251             this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
252             GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount, instanceCountForDraw));
253         }
254     }
255     fGpu->didDrawTo(fRenderTarget);
256 }
257 
onDrawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)258 void GrGLOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
259                                                int baseInstance, int baseVertex) {
260     int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
261     for (int i = 0; i < instanceCount; i += maxInstances) {
262         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
263         int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
264         int baseInstanceForDraw = baseInstance + i;
265         if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
266             SkASSERT(fDidBindInstanceBuffer);
267             SkASSERT(fDidBindVertexBuffer);
268             GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
269                     glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
270                     this->offsetForBaseIndex(baseIndex), instanceCountForDraw, baseVertex,
271                     baseInstanceForDraw));
272         } else {
273             this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
274             this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
275             GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
276                                         this->offsetForBaseIndex(baseIndex), instanceCountForDraw));
277         }
278     }
279     fGpu->didDrawTo(fRenderTarget);
280 }
281 
buffer_offset_to_gl_address(const GrBuffer * drawIndirectBuffer,size_t offset)282 static const void* buffer_offset_to_gl_address(const GrBuffer* drawIndirectBuffer, size_t offset) {
283     if (drawIndirectBuffer->isCpuBuffer()) {
284         return static_cast<const GrCpuBuffer*>(drawIndirectBuffer)->data() + offset;
285     } else {
286         return (offset) ? reinterpret_cast<const void*>(offset) : nullptr;
287     }
288 }
289 
onDrawIndirect(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)290 void GrGLOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
291                                        int drawCount) {
292     using MultiDrawType = GrGLCaps::MultiDrawType;
293 
294     SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
295     SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
296     SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
297 
298     if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
299         // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
300         // affecting glDrawArrays.
301         this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
302     }
303 
304     if (fGpu->glCaps().multiDrawType() == MultiDrawType::kANGLEOrWebGL) {
305         // ANGLE and WebGL don't support glDrawElementsIndirect. We draw everything as a multi draw.
306         this->multiDrawArraysANGLEOrWebGL(drawIndirectBuffer, offset, drawCount);
307         return;
308     }
309 
310     fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
311 
312     if (drawCount > 1 && fGpu->glCaps().multiDrawType() == MultiDrawType::kMultiDrawIndirect) {
313         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
314         GL_CALL(MultiDrawArraysIndirect(glPrimType,
315                                         buffer_offset_to_gl_address(drawIndirectBuffer, offset),
316                                         drawCount, sizeof(GrDrawIndirectCommand)));
317         return;
318     }
319 
320     for (int i = 0; i < drawCount; ++i) {
321         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
322         GL_CALL(DrawArraysIndirect(glPrimType,
323                                    buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
324         offset += sizeof(GrDrawIndirectCommand);
325     }
326     fGpu->didDrawTo(fRenderTarget);
327 }
328 
multiDrawArraysANGLEOrWebGL(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)329 void GrGLOpsRenderPass::multiDrawArraysANGLEOrWebGL(const GrBuffer* drawIndirectBuffer,
330                                                     size_t offset, int drawCount) {
331     SkASSERT(fGpu->glCaps().multiDrawType() == GrGLCaps::MultiDrawType::kANGLEOrWebGL);
332     SkASSERT(drawIndirectBuffer->isCpuBuffer());
333 
334     constexpr static int kMaxDrawCountPerBatch = 128;
335     GrGLint fFirsts[kMaxDrawCountPerBatch];
336     GrGLsizei fCounts[kMaxDrawCountPerBatch];
337     GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
338     GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
339 
340     GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
341     auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
342     auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(cpuBuffer->data() + offset);
343 
344     while (drawCount) {
345         int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
346         for (int i = 0; i < countInBatch; ++i) {
347             auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
348             fFirsts[i] = baseVertex;
349             fCounts[i] = vertexCount;
350             fInstanceCounts[i] = instanceCount;
351             fBaseInstances[i] = baseInstance;
352         }
353         if (countInBatch == 1) {
354             GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, fFirsts[0], fCounts[0],
355                                                     fInstanceCounts[0], fBaseInstances[0]));
356         } else {
357             GL_CALL(MultiDrawArraysInstancedBaseInstance(glPrimType, fFirsts, fCounts,
358                                                          fInstanceCounts, fBaseInstances,
359                                                          countInBatch));
360         }
361         drawCount -= countInBatch;
362         cmds += countInBatch;
363     }
364     fGpu->didDrawTo(fRenderTarget);
365 }
366 
onDrawIndexedIndirect(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)367 void GrGLOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
368                                               int drawCount) {
369     using MultiDrawType = GrGLCaps::MultiDrawType;
370 
371     SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
372     SkASSERT(!fGpu->caps()->nativeDrawIndexedIndirectIsBroken());
373     SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
374     // The vertex buffer should have already gotten bound (as opposed us stashing it away during
375     // onBindBuffers and not expecting to bind it until this point).
376     SkASSERT(fDidBindVertexBuffer);
377 
378     if (fGpu->glCaps().multiDrawType() == MultiDrawType::kANGLEOrWebGL) {
379         // ANGLE and WebGL don't support glDrawElementsIndirect. We draw everything as a multi draw.
380         this->multiDrawElementsANGLEOrWebGL(drawIndirectBuffer, offset, drawCount);
381         return;
382     }
383 
384     fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
385 
386     if (drawCount > 1 && fGpu->glCaps().multiDrawType() == MultiDrawType::kMultiDrawIndirect) {
387         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
388         GL_CALL(MultiDrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
389                                           buffer_offset_to_gl_address(drawIndirectBuffer, offset),
390                                           drawCount, sizeof(GrDrawIndexedIndirectCommand)));
391         return;
392     }
393 
394     for (int i = 0; i < drawCount; ++i) {
395         GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
396         GL_CALL(DrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
397                                      buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
398         offset += sizeof(GrDrawIndexedIndirectCommand);
399     }
400     fGpu->didDrawTo(fRenderTarget);
401 }
402 
multiDrawElementsANGLEOrWebGL(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)403 void GrGLOpsRenderPass::multiDrawElementsANGLEOrWebGL(const GrBuffer* drawIndirectBuffer,
404                                                       size_t offset, int drawCount) {
405     SkASSERT(fGpu->glCaps().multiDrawType() == GrGLCaps::MultiDrawType::kANGLEOrWebGL);
406     SkASSERT(drawIndirectBuffer->isCpuBuffer());
407 
408     constexpr static int kMaxDrawCountPerBatch = 128;
409     GrGLint fCounts[kMaxDrawCountPerBatch];
410     const void* fIndices[kMaxDrawCountPerBatch];
411     GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
412     GrGLint fBaseVertices[kMaxDrawCountPerBatch];
413     GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
414 
415     GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
416     auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
417     auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(cpuBuffer->data() + offset);
418 
419     while (drawCount) {
420         int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
421         for (int i = 0; i < countInBatch; ++i) {
422             auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
423             fCounts[i] = indexCount;
424             fIndices[i] = this->offsetForBaseIndex(baseIndex);
425             fInstanceCounts[i] = instanceCount;
426             fBaseVertices[i] = baseVertex;
427             fBaseInstances[i] = baseInstance;
428         }
429         if (countInBatch == 1) {
430             GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts[0],
431                                                                 GR_GL_UNSIGNED_SHORT, fIndices[0],
432                                                                 fInstanceCounts[0],
433                                                                 fBaseVertices[0],
434                                                                 fBaseInstances[0]));
435         } else {
436             GL_CALL(MultiDrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts,
437                                                                      GR_GL_UNSIGNED_SHORT, fIndices,
438                                                                      fInstanceCounts, fBaseVertices,
439                                                                      fBaseInstances, countInBatch));
440         }
441         drawCount -= countInBatch;
442         cmds += countInBatch;
443     }
444     fGpu->didDrawTo(fRenderTarget);
445 }
446 
onClear(const GrScissorState & scissor,std::array<float,4> color)447 void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
448     fGpu->clear(scissor, color, fRenderTarget, fUseMultisampleFBO, fOrigin);
449 }
450 
onClearStencilClip(const GrScissorState & scissor,bool insideStencilMask)451 void GrGLOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
452     fGpu->clearStencilClip(scissor, insideStencilMask, fRenderTarget, fUseMultisampleFBO, fOrigin);
453 }
454