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