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/GrDirectContextPriv.h"
16 #endif
17
18 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
19
set(GrRenderTarget * rt,const SkIRect & contentBounds,GrSurfaceOrigin origin,const LoadAndStoreInfo & colorInfo,const StencilLoadAndStoreInfo & stencilInfo)20 void 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
onBegin()33 void GrGLOpsRenderPass::onBegin() {
34 fGpu->beginCommandBuffer(fRenderTarget, fContentBounds, fOrigin, fColorLoadAndStoreInfo,
35 fStencilLoadAndStoreInfo);
36 }
37
onEnd()38 void GrGLOpsRenderPass::onEnd() {
39 fGpu->endCommandBuffer(fRenderTarget, fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo);
40 }
41
onBindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)42 bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
43 const SkRect& drawBounds) {
44 fPrimitiveType = programInfo.primitiveType();
45 return fGpu->flushGLState(fRenderTarget, programInfo);
46 }
47
onSetScissorRect(const SkIRect & scissor)48 void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
49 fGpu->flushScissorRect(scissor, fRenderTarget->width(), fRenderTarget->height(), fOrigin);
50 }
51
onBindTextures(const GrPrimitiveProcessor & primProc,const GrSurfaceProxy * const primProcTextures[],const GrPipeline & pipeline)52 bool 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
onBindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primitiveRestart)61 void 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
bindInstanceBuffer(const GrBuffer * instanceBuffer,int baseInstance)106 void 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
bindVertexBuffer(const GrBuffer * vertexBuffer,int baseVertex)125 void 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
onDraw(int vertexCount,int baseVertex)143 void 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
onDrawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)153 void 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
onDrawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)178 void 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
onDrawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)202 void 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
buffer_offset_to_gl_address(const GrBuffer * drawIndirectBuffer,size_t offset)225 static 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
onDrawIndirect(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)233 void GrGLOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
234 int drawCount) {
235 using MultiDrawType = GrGLCaps::MultiDrawType;
236
237 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
238 SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
239 SkASSERT(fDidBindVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken());
240
241 if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
242 // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug
243 // affecting glDrawArrays.
244 this->bindVertexBuffer(fActiveVertexBuffer.get(), 0);
245 }
246
247 if (fGpu->glCaps().multiDrawType() == MultiDrawType::kANGLEOrWebGL) {
248 // ANGLE and WebGL don't support glDrawElementsIndirect. We draw everything as a multi draw.
249 this->multiDrawArraysANGLEOrWebGL(drawIndirectBuffer, offset, drawCount);
250 return;
251 }
252
253 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
254
255 if (drawCount > 1 && fGpu->glCaps().multiDrawType() == MultiDrawType::kMultiDrawIndirect) {
256 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
257 GL_CALL(MultiDrawArraysIndirect(glPrimType,
258 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
259 drawCount, sizeof(GrDrawIndirectCommand)));
260 return;
261 }
262
263 for (int i = 0; i < drawCount; ++i) {
264 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
265 GL_CALL(DrawArraysIndirect(glPrimType,
266 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
267 offset += sizeof(GrDrawIndirectCommand);
268 }
269 }
270
multiDrawArraysANGLEOrWebGL(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)271 void GrGLOpsRenderPass::multiDrawArraysANGLEOrWebGL(const GrBuffer* drawIndirectBuffer,
272 size_t offset, int drawCount) {
273 SkASSERT(fGpu->glCaps().multiDrawType() == GrGLCaps::MultiDrawType::kANGLEOrWebGL);
274 SkASSERT(drawIndirectBuffer->isCpuBuffer());
275
276 constexpr static int kMaxDrawCountPerBatch = 128;
277 GrGLint fFirsts[kMaxDrawCountPerBatch];
278 GrGLsizei fCounts[kMaxDrawCountPerBatch];
279 GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
280 GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
281
282 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
283 auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
284 auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(cpuBuffer->data() + offset);
285
286 while (drawCount) {
287 int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
288 for (int i = 0; i < countInBatch; ++i) {
289 const auto& cmd = cmds[i];
290 fFirsts[i] = cmd.fBaseVertex;
291 fCounts[i] = cmd.fVertexCount;
292 fInstanceCounts[i] = cmd.fInstanceCount;
293 fBaseInstances[i] = cmd.fBaseInstance;
294 }
295 if (countInBatch == 1) {
296 GL_CALL(DrawArraysInstancedBaseInstance(glPrimType, fFirsts[0], fCounts[0],
297 fInstanceCounts[0], fBaseInstances[0]));
298 } else {
299 GL_CALL(MultiDrawArraysInstancedBaseInstance(glPrimType, fFirsts, fCounts,
300 fInstanceCounts, fBaseInstances,
301 countInBatch));
302 }
303 drawCount -= countInBatch;
304 cmds += countInBatch;
305 }
306 }
307
onDrawIndexedIndirect(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)308 void GrGLOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
309 int drawCount) {
310 using MultiDrawType = GrGLCaps::MultiDrawType;
311
312 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport());
313 SkASSERT(!fGpu->caps()->nativeDrawIndexedIndirectIsBroken());
314 SkASSERT(fGpu->glCaps().baseVertexBaseInstanceSupport());
315 // The vertex buffer should have already gotten bound (as opposed us stashing it away during
316 // onBindBuffers and not expecting to bind it until this point).
317 SkASSERT(fDidBindVertexBuffer);
318
319 if (fGpu->glCaps().multiDrawType() == MultiDrawType::kANGLEOrWebGL) {
320 // ANGLE and WebGL don't support glDrawElementsIndirect. We draw everything as a multi draw.
321 this->multiDrawElementsANGLEOrWebGL(drawIndirectBuffer, offset, drawCount);
322 return;
323 }
324
325 fGpu->bindBuffer(GrGpuBufferType::kDrawIndirect, drawIndirectBuffer);
326
327 if (drawCount > 1 && fGpu->glCaps().multiDrawType() == MultiDrawType::kMultiDrawIndirect) {
328 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
329 GL_CALL(MultiDrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
330 buffer_offset_to_gl_address(drawIndirectBuffer, offset),
331 drawCount, sizeof(GrDrawIndexedIndirectCommand)));
332 return;
333 }
334
335 for (int i = 0; i < drawCount; ++i) {
336 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
337 GL_CALL(DrawElementsIndirect(glPrimType, GR_GL_UNSIGNED_SHORT,
338 buffer_offset_to_gl_address(drawIndirectBuffer, offset)));
339 offset += sizeof(GrDrawIndexedIndirectCommand);
340 }
341 }
342
multiDrawElementsANGLEOrWebGL(const GrBuffer * drawIndirectBuffer,size_t offset,int drawCount)343 void GrGLOpsRenderPass::multiDrawElementsANGLEOrWebGL(const GrBuffer* drawIndirectBuffer,
344 size_t offset, int drawCount) {
345 SkASSERT(fGpu->glCaps().multiDrawType() == GrGLCaps::MultiDrawType::kANGLEOrWebGL);
346 SkASSERT(drawIndirectBuffer->isCpuBuffer());
347
348 constexpr static int kMaxDrawCountPerBatch = 128;
349 GrGLint fCounts[kMaxDrawCountPerBatch];
350 const void* fIndices[kMaxDrawCountPerBatch];
351 GrGLsizei fInstanceCounts[kMaxDrawCountPerBatch];
352 GrGLint fBaseVertices[kMaxDrawCountPerBatch];
353 GrGLuint fBaseInstances[kMaxDrawCountPerBatch];
354
355 GrGLenum glPrimType = fGpu->prepareToDraw(fPrimitiveType);
356 auto* cpuBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
357 auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(cpuBuffer->data() + offset);
358
359 while (drawCount) {
360 int countInBatch = std::min(drawCount, kMaxDrawCountPerBatch);
361 for (int i = 0; i < countInBatch; ++i) {
362 const auto& cmd = cmds[i];
363 fCounts[i] = cmd.fIndexCount;
364 fIndices[i] = this->offsetForBaseIndex(cmd.fBaseIndex);
365 fInstanceCounts[i] = cmd.fInstanceCount;
366 fBaseVertices[i] = cmd.fBaseVertex;
367 fBaseInstances[i] = cmd.fBaseInstance;
368 }
369 if (countInBatch == 1) {
370 GL_CALL(DrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts[0],
371 GR_GL_UNSIGNED_SHORT, fIndices[0],
372 fInstanceCounts[0],
373 fBaseVertices[0],
374 fBaseInstances[0]));
375 } else {
376 GL_CALL(MultiDrawElementsInstancedBaseVertexBaseInstance(glPrimType, fCounts,
377 GR_GL_UNSIGNED_SHORT, fIndices,
378 fInstanceCounts, fBaseVertices,
379 fBaseInstances, countInBatch));
380 }
381 drawCount -= countInBatch;
382 cmds += countInBatch;
383 }
384 }
385
onClear(const GrScissorState & scissor,const SkPMColor4f & color)386 void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
387 fGpu->clear(scissor, color, fRenderTarget, fOrigin);
388 }
389
onClearStencilClip(const GrScissorState & scissor,bool insideStencilMask)390 void GrGLOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
391 fGpu->clearStencilClip(scissor, insideStencilMask, fRenderTarget, fOrigin);
392 }
393