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