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