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
8#include "src/gpu/gl/GrGLOpsRenderPass.h"
9
10#include "src/gpu/GrContextPriv.h"
11#include "src/gpu/GrFixedClip.h"
12#include "src/gpu/GrProgramInfo.h"
13#include "src/gpu/GrRenderTargetPriv.h"
14
15#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
16
17void GrGLOpsRenderPass::set(GrRenderTarget* rt, const SkIRect& contentBounds,
18 GrSurfaceOrigin origin, const LoadAndStoreInfo& colorInfo,
19 const StencilLoadAndStoreInfo& stencilInfo) {
20 SkASSERT(fGpu);
21 SkASSERT(!fRenderTarget);
22 SkASSERT(fGpu == rt->getContext()->priv().getGpu());
23
24 this->INHERITED::set(rt, origin);
25 fContentBounds = contentBounds;
26 fColorLoadAndStoreInfo = colorInfo;
27 fStencilLoadAndStoreInfo = stencilInfo;
28}
29
30void GrGLOpsRenderPass::onBegin() {
31 fGpu->beginCommandBuffer(fRenderTarget, fContentBounds, fOrigin, fColorLoadAndStoreInfo,
32 fStencilLoadAndStoreInfo);
33}
34
35void GrGLOpsRenderPass::onEnd() {
36 fGpu->endCommandBuffer(fRenderTarget, fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo);
37}
38
39bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
40 const SkRect& drawBounds) {
41 fPrimitiveType = programInfo.primitiveType();
42 return fGpu->flushGLState(fRenderTarget, programInfo);
43}
44
45void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
46 fGpu->flushScissorRect(scissor, fRenderTarget->width(), fRenderTarget->height(), fOrigin);
47}
48
49bool GrGLOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc,
50 const GrSurfaceProxy* const primProcTextures[],
51 const GrPipeline& pipeline) {
52 GrGLProgram* program = fGpu->currentProgram();
53 SkASSERT(program);
54 program->bindTextures(primProc, primProcTextures, pipeline);
55 return true;
56}
57
58void GrGLOpsRenderPass::onBindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer,
59 const GrBuffer* vertexBuffer,
60 GrPrimitiveRestart primitiveRestart) {
61 SkASSERT((primitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
62 GrGLProgram* program = fGpu->currentProgram();
63 SkASSERT(program);
64
65 int numAttribs = program->numVertexAttributes() + program->numInstanceAttributes();
66 fAttribArrayState = fGpu->bindInternalVertexArray(indexBuffer, numAttribs, primitiveRestart);
67
68 if (indexBuffer) {
69 if (indexBuffer->isCpuBuffer()) {
70 auto* cpuIndexBuffer = static_cast<const GrCpuBuffer*>(indexBuffer);
71 fIndexPointer = reinterpret_cast<const uint16_t*>(cpuIndexBuffer->data());
72 } else {
73 fIndexPointer = nullptr;
74 }
75 }
76
77 if (!fGpu->glCaps().baseVertexBaseInstanceSupport()) {
78 // This platform does not support baseInstance. Defer binding of the instance buffer.
79 fActiveInstanceBuffer = sk_ref_sp(instanceBuffer);
80 } else {
81 this->bindInstanceBuffer(instanceBuffer, 0);
82 }
83 if (!indexBuffer && fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
84 // There is a driver bug affecting glDrawArrays. Defer binding of the vertex buffer.
85 fActiveVertexBuffer = sk_ref_sp(vertexBuffer);
86 } else if (indexBuffer && !fGpu->glCaps().baseVertexBaseInstanceSupport()) {
87 // This platform does not support baseVertex with indexed draws. Defer binding of the
88 // vertex buffer.
89 fActiveVertexBuffer = sk_ref_sp(vertexBuffer);
90 } else {
91 this->bindVertexBuffer(vertexBuffer, 0);
92 }
93}
94
95void GrGLOpsRenderPass::bindInstanceBuffer(const GrBuffer* instanceBuffer, int baseInstance) {
96 GrGLProgram* program = fGpu->currentProgram();
97 SkASSERT(program);
98 if (int instanceStride = program->instanceStride()) {
99 SkASSERT(instanceBuffer);
100 SkASSERT(instanceBuffer->isCpuBuffer() ||
101 !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
102 size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
103 int attribIdx = program->numVertexAttributes();
104 for (int i = 0; i < program->numInstanceAttributes(); ++i, ++attribIdx) {
105 const auto& attrib = program->instanceAttribute(i);
106 static constexpr int kDivisor = 1;
107 fAttribArrayState->set(fGpu, attrib.fLocation, instanceBuffer, attrib.fCPUType,
108 attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
109 kDivisor);
110 }
111 }
112}
113
114void GrGLOpsRenderPass::bindVertexBuffer(const GrBuffer* vertexBuffer, int baseVertex) {
115 GrGLProgram* program = fGpu->currentProgram();
116 SkASSERT(program);
117 if (int vertexStride = program->vertexStride()) {
118 SkASSERT(vertexBuffer);
119 SkASSERT(vertexBuffer->isCpuBuffer() ||
120 !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
121 size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
122 for (int i = 0; i < program->numVertexAttributes(); ++i) {
123 const auto& attrib = program->vertexAttribute(i);
124 static constexpr int kDivisor = 0;
125 fAttribArrayState->set(fGpu, attrib.fLocation, vertexBuffer, attrib.fCPUType,
126 attrib.fGPUType, vertexStride, bufferOffset + attrib.fOffset,
127 kDivisor);
128 }
129 }
130}
131
132void GrGLOpsRenderPass::onDraw(int vertexCount, int baseVertex) {
133 SkASSERT(!fActiveVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
134 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
135 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
136 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
137 baseVertex = 0;
138 }
139 GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
140}
141
142void GrGLOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
143 uint16_t maxIndexValue, int baseVertex) {
144 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
145 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
146 SkASSERT(fGpu->glCaps().drawInstancedSupport());
147 SkASSERT(!fActiveVertexBuffer);
148 if (baseVertex != 0) {
149 GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
150 glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
151 this->offsetForBaseIndex(baseIndex), 1, baseVertex, 0));
152 return;
153 }
154 } else {
155 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
156 }
157
158 if (fGpu->glCaps().drawRangeElementsSupport()) {
159 GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
160 GR_GL_UNSIGNED_SHORT, this->offsetForBaseIndex(baseIndex)));
161 } else {
162 GL_CALL(DrawElements(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
163 this->offsetForBaseIndex(baseIndex)));
164 }
165}
166
167void GrGLOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
168 int baseVertex) {
169 SkASSERT(!fActiveVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
170 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
171 // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
172 // affecting glDrawArrays.
173 this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
174 }
175 int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
176 for (int i = 0; i < instanceCount; i += maxInstances) {
177 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
178 int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
179 int baseInstanceForDraw = baseInstance + i;
180 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
181 SkASSERT(!fActiveInstanceBuffer);
182 GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, baseVertex, vertexCount,
183 instanceCountForDraw, baseInstanceForDraw));
184 } else {
185 this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
186 GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount, instanceCountForDraw));
187 }
188 }
189}
190
191void GrGLOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
192 int baseInstance, int baseVertex) {
193 int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
194 for (int i = 0; i < instanceCount; i += maxInstances) {
195 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
196 int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
197 int baseInstanceForDraw = baseInstance + i;
198 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
199 SkASSERT(!fActiveInstanceBuffer);
200 SkASSERT(!fActiveVertexBuffer);
201 GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
202 glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
203 this->offsetForBaseIndex(baseIndex), instanceCountForDraw, baseVertex,
204 baseInstanceForDraw));
205 } else {
206 this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
207 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
208 GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
209 this->offsetForBaseIndex(baseIndex), instanceCountForDraw));
210 }
211 }
212}
213
214static const void* buffer_offset_to_gl_address(const GrBuffer* drawIndirectBuffer, size_t offset) {
215 if (drawIndirectBuffer->isCpuBuffer()) {
216 return static_cast<const GrCpuBuffer*>(drawIndirectBuffer)->data() + offset;
217 } else {
218 return (offset) ? reinterpret_cast<const void*>(offset) : nullptr;
219 }
220}
221
222void GrGLOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
223 int drawCount) {
224 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
225
226 if (fGpu->glCaps().multiDrawIndirectSupport() && drawCount > 1) {
227 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
228 GL_CALL(MultiDrawArraysIndirect(glPrimType,
229 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
230 drawCount, sizeof(GrDrawIndirectCommand)));
231 return;
232 }
233
234 for (int i = 0; i < drawCount; ++i) {
235 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
236 GL_CALL(DrawArraysIndirect(glPrimType,
237 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
238 offset += sizeof(GrDrawIndirectCommand);
239 }
240}
241
242void GrGLOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
243 int drawCount) {
244 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
245
246 if (fGpu->glCaps().multiDrawIndirectSupport() && drawCount > 1) {
247 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
248 GL_CALL(MultiDrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
249 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
250 drawCount, sizeof(GrDrawIndexedIndirectCommand)));
251 return;
252 }
253
254 for (int i = 0; i < drawCount; ++i) {
255 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
256 GL_CALL(DrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
257 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
258 offset += sizeof(GrDrawIndexedIndirectCommand);
259 }
260}
261
262void GrGLOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
263 fGpu->clear(clip, color, fRenderTarget, fOrigin);
264}
265
266void GrGLOpsRenderPass::onClearStencilClip(const GrFixedClip& clip,
267 bool insideStencilMask) {
268 fGpu->clearStencilClip(clip, insideStencilMask, fRenderTarget, fOrigin);
269}
270
271