• 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 
bindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)74 void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
75 #ifdef SK_DEBUG
76     // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
77     // place (i.e., the target renderTargetProxy) they had best agree.
78     SkASSERT(programInfo.origin() == fOrigin);
79     if (programInfo.geomProc().hasInstanceAttributes()) {
80          SkASSERT(this->gpu()->caps()->drawInstancedSupport());
81     }
82     if (programInfo.pipeline().usesConservativeRaster()) {
83         SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
84     }
85     if (programInfo.pipeline().isWireframe()) {
86          SkASSERT(this->gpu()->caps()->wireframeSupport());
87     }
88     if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
89         programInfo.isStencilEnabled()) {
90         const GrUserStencilSettings* stencil = programInfo.userStencilSettings();
91         if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
92             SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
93             SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
94             SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
95         }
96     }
97     if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
98         SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
99     }
100     programInfo.checkAllInstantiated();
101     programInfo.checkMSAAAndMIPSAreResolved();
102 #endif
103 
104     this->resetActiveBuffers();
105 
106     if (programInfo.geomProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
107         fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
108         return;
109     }
110 
111     if (!this->onBindPipeline(programInfo, drawBounds)) {
112         fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
113         return;
114     }
115 
116 #ifdef SK_DEBUG
117     fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
118             DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
119     bool hasTextures = (programInfo.geomProc().numTextureSamplers() > 0);
120     if (!hasTextures) {
121         programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
122             hasTextures = true;
123         });
124     }
125     fTextureBindingStatus = (hasTextures) ?
126             DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
127     fHasIndexBuffer = false;
128     fInstanceBufferStatus = (programInfo.geomProc().hasInstanceAttributes()) ?
129             DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
130     fVertexBufferStatus = (programInfo.geomProc().hasVertexAttributes()) ?
131             DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
132 #endif
133 
134     fDrawPipelineStatus = DrawPipelineStatus::kOk;
135     fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
136 }
137 
setScissorRect(const SkIRect & scissor)138 void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
139     if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
140         SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
141         return;
142     }
143     SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
144     this->onSetScissorRect(scissor);
145     SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
146 }
147 
bindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)148 void GrOpsRenderPass::bindTextures(const GrGeometryProcessor& geomProc,
149                                    const GrSurfaceProxy* const geomProcTextures[],
150                                    const GrPipeline& pipeline) {
151 #ifdef SK_DEBUG
152     SkASSERT((geomProc.numTextureSamplers() > 0) == SkToBool(geomProcTextures));
153     for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
154         const auto& sampler = geomProc.textureSampler(i);
155         const GrSurfaceProxy* proxy = geomProcTextures[i];
156         SkASSERT(proxy);
157         SkASSERT(proxy->backendFormat() == sampler.backendFormat());
158         SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
159 
160         const GrTexture* tex = proxy->peekTexture();
161         SkASSERT(tex);
162         if (sampler.samplerState().mipmapped() == GrMipmapped::kYes &&
163             (tex->width() != 1 || tex->height() != 1)) {
164             // There are some cases where we might be given a non-mipmapped texture with a mipmap
165             // filter. See skbug.com/7094.
166             SkASSERT(tex->mipmapped() != GrMipmapped::kYes || !tex->mipmapsAreDirty());
167         }
168     }
169 #endif
170 
171     if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
172         SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
173         return;
174     }
175 
176     // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
177     // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
178     // many clients it is easier to just always call this method.
179     if (!this->onBindTextures(geomProc, geomProcTextures, pipeline)) {
180         fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
181         return;
182     }
183 
184     SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
185 }
186 
bindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primRestart)187 void GrOpsRenderPass::bindBuffers(sk_sp<const GrBuffer> indexBuffer,
188                                   sk_sp<const GrBuffer> instanceBuffer,
189                                   sk_sp<const GrBuffer> vertexBuffer,
190                                   GrPrimitiveRestart primRestart) {
191     if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
192         SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
193         return;
194     }
195 
196 #ifdef SK_DEBUG
197     if (indexBuffer) {
198         fHasIndexBuffer = true;
199     }
200 
201     SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
202     if (instanceBuffer) {
203         fInstanceBufferStatus = DynamicStateStatus::kConfigured;
204     }
205 
206     SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
207     if (vertexBuffer) {
208         fVertexBufferStatus = DynamicStateStatus::kConfigured;
209     }
210 
211     if (GrPrimitiveRestart::kYes == primRestart) {
212         SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
213     }
214 #endif
215 
216     this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
217                         primRestart);
218 }
219 
prepareToDraw()220 bool GrOpsRenderPass::prepareToDraw() {
221     if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
222         SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
223         this->gpu()->stats()->incNumFailedDraws();
224         return false;
225     }
226     SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
227     SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
228 
229     if (kNone_GrXferBarrierType != fXferBarrierType) {
230         this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
231     }
232     return true;
233 }
234 
draw(int vertexCount,int baseVertex)235 void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
236     if (!this->prepareToDraw()) {
237         return;
238     }
239     SkASSERT(!fHasIndexBuffer);
240     SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
241     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
242     this->onDraw(vertexCount, baseVertex);
243 }
244 
drawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)245 void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
246                                   uint16_t maxIndexValue, int baseVertex) {
247     if (!this->prepareToDraw()) {
248         return;
249     }
250     SkASSERT(fHasIndexBuffer);
251     SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
252     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
253     this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
254 }
255 
drawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)256 void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
257                                     int baseVertex) {
258     SkASSERT(this->gpu()->caps()->drawInstancedSupport());
259     if (!this->prepareToDraw()) {
260         return;
261     }
262     SkASSERT(!fHasIndexBuffer);
263     SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
264     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
265     this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
266 }
267 
drawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)268 void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
269                                            int baseInstance, int baseVertex) {
270     SkASSERT(this->gpu()->caps()->drawInstancedSupport());
271     if (!this->prepareToDraw()) {
272         return;
273     }
274     SkASSERT(fHasIndexBuffer);
275     SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
276     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
277     this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
278 }
279 
drawIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)280 void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
281                                    int drawCount) {
282     SkASSERT(this->gpu()->caps()->drawInstancedSupport());
283     SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
284              !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
285     if (!this->prepareToDraw()) {
286         return;
287     }
288     SkASSERT(!fHasIndexBuffer);
289     SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
290     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
291     if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
292         // Polyfill indirect draws with looping instanced calls.
293         SkASSERT(drawIndirectBuffer->isCpuBuffer());
294         auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
295         auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(
296                 cpuIndirectBuffer->data() + bufferOffset);
297         for (int i = 0; i < drawCount; ++i) {
298             auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
299             this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
300         }
301         return;
302     }
303     this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
304 }
305 
drawIndexedIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)306 void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
307                                           int drawCount) {
308     SkASSERT(this->gpu()->caps()->drawInstancedSupport());
309     SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
310              !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
311     if (!this->prepareToDraw()) {
312         return;
313     }
314     SkASSERT(fHasIndexBuffer);
315     SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
316     SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
317     if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
318         this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
319         // Polyfill indexedIndirect draws with looping indexedInstanced calls.
320         SkASSERT(drawIndirectBuffer->isCpuBuffer());
321         auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
322         auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
323                 cpuIndirectBuffer->data() + bufferOffset);
324         for (int i = 0; i < drawCount; ++i) {
325             auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
326             this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance,
327                                          baseVertex);
328         }
329         return;
330     }
331     this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
332 }
333 
drawIndexPattern(int patternIndexCount,int patternRepeatCount,int maxPatternRepetitionsInIndexBuffer,int patternVertexCount,int baseVertex)334 void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
335                                        int maxPatternRepetitionsInIndexBuffer,
336                                        int patternVertexCount, int baseVertex) {
337     int baseRepetition = 0;
338     while (baseRepetition < patternRepeatCount) {
339         int repeatCount = std::min(patternRepeatCount - baseRepetition,
340                                    maxPatternRepetitionsInIndexBuffer);
341         int drawIndexCount = repeatCount * patternIndexCount;
342         // A patterned index buffer must contain indices in the range [0..vertexCount].
343         int minIndexValue = 0;
344         int maxIndexValue = patternVertexCount * repeatCount - 1;
345         this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
346                           patternVertexCount * baseRepetition + baseVertex);
347         baseRepetition += repeatCount;
348     }
349 }
350