1 /*
2 * Copyright 2016 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 #include "src/gpu/ganesh/GrOpsRenderPass.h"
8
9 #include "include/gpu/GpuTypes.h"
10 #include "include/gpu/ganesh/GrBackendSurface.h"
11 #include "include/private/base/SkDebug.h"
12 #include "include/private/base/SkTo.h"
13 #include "src/gpu/ganesh/GrCaps.h"
14 #include "src/gpu/ganesh/GrCpuBuffer.h"
15 #include "src/gpu/ganesh/GrDrawIndirectCommand.h"
16 #include "src/gpu/ganesh/GrGeometryProcessor.h"
17 #include "src/gpu/ganesh/GrGpu.h"
18 #include "src/gpu/ganesh/GrGpuBuffer.h"
19 #include "src/gpu/ganesh/GrPipeline.h"
20 #include "src/gpu/ganesh/GrProgramInfo.h"
21 #include "src/gpu/ganesh/GrSamplerState.h"
22 #include "src/gpu/ganesh/GrScissorState.h"
23 #include "src/gpu/ganesh/GrSurfaceProxy.h"
24 #include "src/gpu/ganesh/GrTexture.h"
25 #include "src/gpu/ganesh/GrUserStencilSettings.h"
26
27 #include <algorithm>
28 #include <functional>
29 #include <utility>
30
begin()31 void GrOpsRenderPass::begin() {
32 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
33 #ifdef SK_DEBUG
34 fScissorStatus = DynamicStateStatus::kDisabled;
35 fTextureBindingStatus = DynamicStateStatus::kDisabled;
36 fHasIndexBuffer = false;
37 fInstanceBufferStatus = DynamicStateStatus::kDisabled;
38 fVertexBufferStatus = DynamicStateStatus::kDisabled;
39 #endif
40 this->onBegin();
41 }
42
end()43 void GrOpsRenderPass::end() {
44 this->onEnd();
45 this->resetActiveBuffers();
46 }
47
clear(const GrScissorState & scissor,std::array<float,4> color)48 void GrOpsRenderPass::clear(const GrScissorState& scissor, std::array<float, 4> color) {
49 SkASSERT(fRenderTarget);
50 // A clear at this level will always be a true clear, so make sure clears were not supposed to
51 // be redirected to draws instead
52 SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws());
53 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
54 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
55 this->onClear(scissor, color);
56 }
57
clearStencilClip(const GrScissorState & scissor,bool insideStencilMask)58 void GrOpsRenderPass::clearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
59 // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings
60 SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws());
61 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
62 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
63 this->onClearStencilClip(scissor, insideStencilMask);
64 }
65
executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable)66 void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
67 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
68 this->onExecuteDrawable(std::move(drawable));
69 }
70
bindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)71 void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
72 #ifdef SK_DEBUG
73 // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
74 // place (i.e., the target renderTargetProxy) they had best agree.
75 SkASSERT(programInfo.origin() == fOrigin);
76 if (programInfo.geomProc().hasInstanceAttributes()) {
77 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
78 }
79 if (programInfo.pipeline().usesConservativeRaster()) {
80 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
81 }
82 if (programInfo.pipeline().isWireframe()) {
83 SkASSERT(this->gpu()->caps()->wireframeSupport());
84 }
85 if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
86 programInfo.isStencilEnabled()) {
87 const GrUserStencilSettings* stencil = programInfo.userStencilSettings();
88 if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
89 SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
90 SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
91 SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
92 }
93 }
94 programInfo.checkAllInstantiated();
95 programInfo.checkMSAAAndMIPSAreResolved();
96 #endif
97
98 this->resetActiveBuffers();
99
100 if (programInfo.geomProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
101 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
102 return;
103 }
104
105 if (!this->onBindPipeline(programInfo, drawBounds)) {
106 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
107 return;
108 }
109
110 #ifdef SK_DEBUG
111 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
112 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
113 bool hasTextures = (programInfo.geomProc().numTextureSamplers() > 0);
114 if (!hasTextures) {
115 programInfo.pipeline().visitProxies(
116 [&hasTextures](GrSurfaceProxy*, skgpu::Mipmapped) { hasTextures = true; });
117 }
118 fTextureBindingStatus = (hasTextures) ?
119 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
120 fHasIndexBuffer = false;
121 fInstanceBufferStatus = (programInfo.geomProc().hasInstanceAttributes()) ?
122 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
123 fVertexBufferStatus = (programInfo.geomProc().hasVertexAttributes()) ?
124 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
125 #endif
126
127 fDrawPipelineStatus = DrawPipelineStatus::kOk;
128 fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
129 }
130
setScissorRect(const SkIRect & scissor)131 void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
132 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
133 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
134 return;
135 }
136 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
137 this->onSetScissorRect(scissor);
138 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
139 }
140
bindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)141 void GrOpsRenderPass::bindTextures(const GrGeometryProcessor& geomProc,
142 const GrSurfaceProxy* const geomProcTextures[],
143 const GrPipeline& pipeline) {
144 #ifdef SK_DEBUG
145 SkASSERT((geomProc.numTextureSamplers() > 0) == SkToBool(geomProcTextures));
146 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
147 const auto& sampler = geomProc.textureSampler(i);
148 const GrSurfaceProxy* proxy = geomProcTextures[i];
149 SkASSERT(proxy);
150 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
151 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
152
153 const GrTexture* tex = proxy->peekTexture();
154 SkASSERT(tex);
155 if (sampler.samplerState().mipmapped() == skgpu::Mipmapped::kYes &&
156 (tex->width() != 1 || tex->height() != 1)) {
157 // There are some cases where we might be given a non-mipmapped texture with a mipmap
158 // filter. See skbug.com/7094.
159 SkASSERT(tex->mipmapped() != skgpu::Mipmapped::kYes || !tex->mipmapsAreDirty());
160 }
161 }
162 #endif
163
164 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
165 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
166 return;
167 }
168
169 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
170 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
171 // many clients it is easier to just always call this method.
172 if (!this->onBindTextures(geomProc, geomProcTextures, pipeline)) {
173 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
174 return;
175 }
176
177 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
178 }
179
bindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primRestart)180 void GrOpsRenderPass::bindBuffers(sk_sp<const GrBuffer> indexBuffer,
181 sk_sp<const GrBuffer> instanceBuffer,
182 sk_sp<const GrBuffer> vertexBuffer,
183 GrPrimitiveRestart primRestart) {
184 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
185 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
186 return;
187 }
188
189 #ifdef SK_DEBUG
190 if (indexBuffer) {
191 fHasIndexBuffer = true;
192 }
193
194 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
195 if (instanceBuffer) {
196 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
197 }
198
199 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
200 if (vertexBuffer) {
201 fVertexBufferStatus = DynamicStateStatus::kConfigured;
202 }
203
204 if (GrPrimitiveRestart::kYes == primRestart) {
205 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
206 }
207 #endif
208
209 this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
210 primRestart);
211 }
212
prepareToDraw()213 bool GrOpsRenderPass::prepareToDraw() {
214 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
215 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
216 this->gpu()->stats()->incNumFailedDraws();
217 return false;
218 }
219 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
220 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
221
222 if (kNone_GrXferBarrierType != fXferBarrierType) {
223 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
224 }
225 return true;
226 }
227
draw(int vertexCount,int baseVertex)228 void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
229 if (!this->prepareToDraw()) {
230 return;
231 }
232 SkASSERT(!fHasIndexBuffer);
233 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
234 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
235 this->onDraw(vertexCount, baseVertex);
236 }
237
drawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)238 void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
239 uint16_t maxIndexValue, int baseVertex) {
240 if (!this->prepareToDraw()) {
241 return;
242 }
243 SkASSERT(fHasIndexBuffer);
244 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
245 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
246 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
247 }
248
drawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)249 void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
250 int baseVertex) {
251 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
252 if (!this->prepareToDraw()) {
253 return;
254 }
255 SkASSERT(!fHasIndexBuffer);
256 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
257 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
258 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
259 }
260
drawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)261 void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
262 int baseInstance, int baseVertex) {
263 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
264 if (!this->prepareToDraw()) {
265 return;
266 }
267 SkASSERT(fHasIndexBuffer);
268 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
269 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
270 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
271 }
272
drawIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)273 void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
274 int drawCount) {
275 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
276 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
277 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
278 if (!this->prepareToDraw()) {
279 return;
280 }
281 SkASSERT(!fHasIndexBuffer);
282 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
283 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
284 if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
285 // Polyfill indirect draws with looping instanced calls.
286 SkASSERT(drawIndirectBuffer->isCpuBuffer());
287 auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
288 auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(
289 cpuIndirectBuffer->data() + bufferOffset);
290 for (int i = 0; i < drawCount; ++i) {
291 auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
292 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
293 }
294 return;
295 }
296 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
297 }
298
drawIndexedIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)299 void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
300 int drawCount) {
301 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
302 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
303 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
304 if (!this->prepareToDraw()) {
305 return;
306 }
307 SkASSERT(fHasIndexBuffer);
308 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
309 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
310 if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
311 this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
312 // Polyfill indexedIndirect draws with looping indexedInstanced calls.
313 SkASSERT(drawIndirectBuffer->isCpuBuffer());
314 auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
315 auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
316 cpuIndirectBuffer->data() + bufferOffset);
317 for (int i = 0; i < drawCount; ++i) {
318 auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
319 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance,
320 baseVertex);
321 }
322 return;
323 }
324 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
325 }
326
drawIndexPattern(int patternIndexCount,int patternRepeatCount,int maxPatternRepetitionsInIndexBuffer,int patternVertexCount,int baseVertex)327 void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
328 int maxPatternRepetitionsInIndexBuffer,
329 int patternVertexCount, int baseVertex) {
330 int baseRepetition = 0;
331 while (baseRepetition < patternRepeatCount) {
332 int repeatCount = std::min(patternRepeatCount - baseRepetition,
333 maxPatternRepetitionsInIndexBuffer);
334 int drawIndexCount = repeatCount * patternIndexCount;
335 // A patterned index buffer must contain indices in the range [0..vertexCount].
336 int minIndexValue = 0;
337 int maxIndexValue = patternVertexCount * repeatCount - 1;
338 this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
339 patternVertexCount * baseRepetition + baseVertex);
340 baseRepetition += repeatCount;
341 }
342 }
343