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 | |
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 | |
33 | void GrGLOpsRenderPass::onBegin() { |
34 | fGpu->beginCommandBuffer(fRenderTarget, fContentBounds, fOrigin, fColorLoadAndStoreInfo, |
35 | fStencilLoadAndStoreInfo); |
36 | } |
37 | |
38 | void GrGLOpsRenderPass::onEnd() { |
39 | fGpu->endCommandBuffer(fRenderTarget, fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo); |
40 | } |
41 | |
42 | bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, |
43 | const SkRect& drawBounds) { |
44 | fPrimitiveType = programInfo.primitiveType(); |
45 | return fGpu->flushGLState(fRenderTarget, programInfo); |
46 | } |
47 | |
48 | void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { |
49 | fGpu->flushScissorRect(scissor, fRenderTarget->width(), fRenderTarget->height(), fOrigin); |
50 | } |
51 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
233 | void 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 | |
268 | void 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 | |
299 | void 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 | |
331 | void 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 | |
366 | void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { |
367 | fGpu->clear(scissor, color, fRenderTarget, fOrigin); |
368 | } |
369 | |
370 | void GrGLOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { |
371 | fGpu->clearStencilClip(scissor, insideStencilMask, fRenderTarget, fOrigin); |
372 | } |
373 | |