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/GrProgramInfo.h"
11#include "src/gpu/GrRenderTarget.h"
12
13#ifdef SK_DEBUG
14#include "include/gpu/GrDirectContext.h"
15#include "src/gpu/GrContextPriv.h"
16#endif
17
18#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
19
20void GrGLOpsRenderPass::set(GrRenderTarget* rt, const SkIRect& contentBounds,
21 GrSurfaceOrigin origin, const LoadAndStoreInfo& colorInfo,
22 const StencilLoadAndStoreInfo& stencilInfo) {
23 SkASSERT(fGpu);
24 SkASSERT(!fRenderTarget);
25 SkASSERT(fGpu == rt->getContext()->priv().getGpu());
26
27 this->INHERITED::set(rt, origin);
28 fContentBounds = contentBounds;
29 fColorLoadAndStoreInfo = colorInfo;
30 fStencilLoadAndStoreInfo = stencilInfo;
31}
32
33void GrGLOpsRenderPass::onBegin() {
34 fGpu->beginCommandBuffer(fRenderTarget, fContentBounds, fOrigin, fColorLoadAndStoreInfo,
35 fStencilLoadAndStoreInfo);
36}
37
38void GrGLOpsRenderPass::onEnd() {
39 fGpu->endCommandBuffer(fRenderTarget, fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo);
40}
41
42bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
43 const SkRect& drawBounds) {
44 fPrimitiveType = programInfo.primitiveType();
45 return fGpu->flushGLState(fRenderTarget, programInfo);
46}
47
48void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
49 fGpu->flushScissorRect(scissor, fRenderTarget->width(), fRenderTarget->height(), fOrigin);
50}
51
52bool GrGLOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc,
53 const GrSurfaceProxy* const primProcTextures[],
54 const GrPipeline& pipeline) {
55 GrGLProgram* program = fGpu->currentProgram();
56 SkASSERT(program);
57 program->bindTextures(primProc, primProcTextures, pipeline);
58 return true;
59}
60
61void GrGLOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer,
62 sk_sp<const GrBuffer> instanceBuffer,
63 sk_sp<const GrBuffer> vertexBuffer,
64 GrPrimitiveRestart primitiveRestart) {
65 SkASSERT((primitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
66 GrGLProgram* program = fGpu->currentProgram();
67 SkASSERT(program);
68
69#ifdef SK_DEBUG
70 fDidBindInstanceBuffer = false;
71 fDidBindVertexBuffer = false;
72#endif
73
74 int numAttribs = program->numVertexAttributes() + program->numInstanceAttributes();
75 fAttribArrayState = fGpu->bindInternalVertexArray(indexBuffer.get(), numAttribs,
76 primitiveRestart);
77
78 if (indexBuffer) {
79 if (indexBuffer->isCpuBuffer()) {
80 auto* cpuIndexBuffer = static_cast<const GrCpuBuffer*>(indexBuffer.get());
81 fIndexPointer = reinterpret_cast<const uint16_t*>(cpuIndexBuffer->data());
82 } else {
83 fIndexPointer = nullptr;
84 }
85 }
86
87 // If this platform does not support baseInstance, defer binding of the instance buffer.
88 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
89 this->bindInstanceBuffer(instanceBuffer.get(), 0);
90 SkDEBUGCODE(fDidBindInstanceBuffer = true;)
91 }
92 fActiveInstanceBuffer = std::move(instanceBuffer);
93
94 // We differ binding the vertex buffer for one of two situations:
95 // 1) This platform does not support baseVertex with indexed draws.
96 // 2) There is a driver bug affecting glDrawArrays.
97 if ((indexBuffer && fGpu->glCaps().baseVertexBaseInstanceSupport()) ||
98 (!indexBuffer && !fGpu->glCaps().drawArraysBaseVertexIsBroken())) {
99 this->bindVertexBuffer(vertexBuffer.get(), 0);
100 SkDEBUGCODE(fDidBindVertexBuffer = true;)
101 }
102 fActiveVertexBuffer = std::move(vertexBuffer);
103 fActiveIndexBuffer = std::move(indexBuffer);
104}
105
106void GrGLOpsRenderPass::bindInstanceBuffer(const GrBuffer* instanceBuffer, int baseInstance) {
107 GrGLProgram* program = fGpu->currentProgram();
108 SkASSERT(program);
109 if (int instanceStride = program->instanceStride()) {
110 SkASSERT(instanceBuffer);
111 SkASSERT(instanceBuffer->isCpuBuffer() ||
112 !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
113 size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
114 int attribIdx = program->numVertexAttributes();
115 for (int i = 0; i < program->numInstanceAttributes(); ++i, ++attribIdx) {
116 const auto& attrib = program->instanceAttribute(i);
117 static constexpr int kDivisor = 1;
118 fAttribArrayState->set(fGpu, attrib.fLocation, instanceBuffer, attrib.fCPUType,
119 attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
120 kDivisor);
121 }
122 }
123}
124
125void GrGLOpsRenderPass::bindVertexBuffer(const GrBuffer* vertexBuffer, int baseVertex) {
126 GrGLProgram* program = fGpu->currentProgram();
127 SkASSERT(program);
128 if (int vertexStride = program->vertexStride()) {
129 SkASSERT(vertexBuffer);
130 SkASSERT(vertexBuffer->isCpuBuffer() ||
131 !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
132 size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
133 for (int i = 0; i < program->numVertexAttributes(); ++i) {
134 const auto& attrib = program->vertexAttribute(i);
135 static constexpr int kDivisor = 0;
136 fAttribArrayState->set(fGpu, attrib.fLocation, vertexBuffer, attrib.fCPUType,
137 attrib.fGPUType, vertexStride, bufferOffset + attrib.fOffset,
138 kDivisor);
139 }
140 }
141}
142
143void GrGLOpsRenderPass::onDraw(int vertexCount, int baseVertex) {
144 SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
145 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
146 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
147 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
148 baseVertex = 0;
149 }
150 GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
151}
152
153void GrGLOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
154 uint16_t maxIndexValue, int baseVertex) {
155 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
156 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
157 SkASSERT(fGpu->glCaps().drawInstancedSupport());
158 SkASSERT(fDidBindVertexBuffer);
159 if (baseVertex != 0) {
160 GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
161 glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
162 this->offsetForBaseIndex(baseIndex), 1, baseVertex, 0));
163 return;
164 }
165 } else {
166 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
167 }
168
169 if (fGpu->glCaps().drawRangeElementsSupport()) {
170 GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
171 GR_GL_UNSIGNED_SHORT, this->offsetForBaseIndex(baseIndex)));
172 } else {
173 GL_CALL(DrawElements(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
174 this->offsetForBaseIndex(baseIndex)));
175 }
176}
177
178void GrGLOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
179 int baseVertex) {
180 SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
181 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
182 // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
183 // affecting glDrawArrays.
184 this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
185 }
186 int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
187 for (int i = 0; i < instanceCount; i += maxInstances) {
188 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
189 int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
190 int baseInstanceForDraw = baseInstance + i;
191 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
192 SkASSERT(fDidBindInstanceBuffer);
193 GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, baseVertex, vertexCount,
194 instanceCountForDraw, baseInstanceForDraw));
195 } else {
196 this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
197 GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount, instanceCountForDraw));
198 }
199 }
200}
201
202void GrGLOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
203 int baseInstance, int baseVertex) {
204 int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
205 for (int i = 0; i < instanceCount; i += maxInstances) {
206 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
207 int instanceCountForDraw = std::min(instanceCount - i, maxInstances);
208 int baseInstanceForDraw = baseInstance + i;
209 if (fGpu->glCaps().baseVertexBaseInstanceSupport()) {
210 SkASSERT(fDidBindInstanceBuffer);
211 SkASSERT(fDidBindVertexBuffer);
212 GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(
213 glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
214 this->offsetForBaseIndex(baseIndex), instanceCountForDraw, baseVertex,
215 baseInstanceForDraw));
216 } else {
217 this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw);
218 this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex);
219 GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT,
220 this->offsetForBaseIndex(baseIndex), instanceCountForDraw));
221 }
222 }
223}
224
225static const void* buffer_offset_to_gl_address(const GrBuffer* drawIndirectBuffer, size_t offset) {
226 if (drawIndirectBuffer->isCpuBuffer()) {
227 return static_cast<const GrCpuBuffer*>(drawIndirectBuffer)->data() + offset;
228 } else {
229 return (offset) ? reinterpret_cast<const void*>(offset) : nullptr;
230 }
231}
232
233void GrGLOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
234 int drawCount) {
235 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
236 SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
237 SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
238
239 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
240 // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
241 // affecting glDrawArrays.
242 this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
243 }
244
245 if (fGpu->glCaps().ANGLEMultiDrawSupport()) {
246 this->multiDrawArraysANGLE(drawIndirectBuffer, offset, drawCount);
247 return;
248 }
249
250 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
251
252 if (fGpu->glCaps().multiDrawIndirectSupport() && drawCount > 1) {
253 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
254 GL_CALL(MultiDrawArraysIndirect(glPrimType,
255 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
256 drawCount, sizeof(GrDrawIndirectCommand)));
257 return;
258 }
259
260 for (int i = 0; i < drawCount; ++i) {
261 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
262 GL_CALL(DrawArraysIndirect(glPrimType,
263 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
264 offset += sizeof(GrDrawIndirectCommand);
265 }
266}
267
268void GrGLOpsRenderPass::multiDrawArraysANGLE(const GrBuffer* drawIndirectBuffer, size_t offset,
269 int drawCount) {
270 SkASSERT(fGpu->glCaps().ANGLEMultiDrawSupport());
271 SkASSERT(drawIndirectBuffer->isCpuBuffer());
272
273 constexpr static int kMaxDrawCountPerBatch = 128;
274 GrGLint fFirsts[kMaxDrawCountPerBatch];
275 GrGLsizei fCounts[kMaxDrawCountPerBatch];
276 GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
277 GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
278
279 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
280 auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
281 auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(cpuBuffer->data() + offset);
282
283 while (drawCount) {
284 int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
285 for (int i = 0; i < countInBatch; ++i) {
286 const auto& cmd = cmds[i];
287 fFirsts[i] = cmd.fBaseVertex;
288 fCounts[i] = cmd.fVertexCount;
289 fInstanceCounts[i] = cmd.fInstanceCount;
290 fBaseInstances[i] = cmd.fBaseInstance;
291 }
292 GL_CALL(MultiDrawArraysInstancedBaseInstance(glPrimType, fFirsts, fCounts, fInstanceCounts,
293 fBaseInstances, countInBatch));
294 drawCount -= countInBatch;
295 cmds += countInBatch;
296 }
297}
298
299void GrGLOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
300 int drawCount) {
301 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
302 SkASSERT(!fGpu->caps()->nativeDrawIndexedIndirectIsBroken());
303 SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
304 // The vertex buffer should have already gotten bound (as opposed us stashing it away during
305 // onBindBuffers and not expecting to bind it until this point).
306 SkASSERT(fDidBindVertexBuffer);
307
308 if (fGpu->glCaps().ANGLEMultiDrawSupport()) {
309 this->multiDrawElementsANGLE(drawIndirectBuffer, offset, drawCount);
310 return;
311 }
312
313 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
314
315 if (fGpu->glCaps().multiDrawIndirectSupport() && drawCount > 1) {
316 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
317 GL_CALL(MultiDrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
318 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
319 drawCount, sizeof(GrDrawIndexedIndirectCommand)));
320 return;
321 }
322
323 for (int i = 0; i < drawCount; ++i) {
324 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
325 GL_CALL(DrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
326 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
327 offset += sizeof(GrDrawIndexedIndirectCommand);
328 }
329}
330
331void GrGLOpsRenderPass::multiDrawElementsANGLE(const GrBuffer* drawIndirectBuffer, size_t offset,
332 int drawCount) {
333 SkASSERT(fGpu->glCaps().ANGLEMultiDrawSupport());
334 SkASSERT(drawIndirectBuffer->isCpuBuffer());
335
336 constexpr static int kMaxDrawCountPerBatch = 128;
337 GrGLint fCounts[kMaxDrawCountPerBatch];
338 const void* fIndices[kMaxDrawCountPerBatch];
339 GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
340 GrGLint fBaseVertices[kMaxDrawCountPerBatch];
341 GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
342
343 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
344 auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
345 auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(cpuBuffer->data() + offset);
346
347 while (drawCount) {
348 int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
349 for (int i = 0; i < countInBatch; ++i) {
350 const auto& cmd = cmds[i];
351 fCounts[i] = cmd.fIndexCount;
352 fIndices[i] = this->offsetForBaseIndex(cmd.fBaseIndex);
353 fInstanceCounts[i] = cmd.fInstanceCount;
354 fBaseVertices[i] = cmd.fBaseVertex;
355 fBaseInstances[i] = cmd.fBaseInstance;
356 }
357 GL_CALL(MultiDrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts,
358 GR_GL_UNSIGNED_SHORT, fIndices,
359 fInstanceCounts, fBaseVertices,
360 fBaseInstances, countInBatch));
361 drawCount -= countInBatch;
362 cmds += countInBatch;
363 }
364}
365
366void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
367 fGpu->clear(scissor, color, fRenderTarget, fOrigin);
368}
369
370void GrGLOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
371 fGpu->clearStencilClip(scissor, insideStencilMask, fRenderTarget, fOrigin);
372}
373