xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrOpsRenderPass.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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