Flutter Engine
The Flutter Engine
GrOpsRenderPass.cpp
Go to the documentation of this file.
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*/
8
26
27#include <algorithm>
28#include <functional>
29#include <utility>
30
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
44 this->onEnd();
45 this->resetActiveBuffers();
46}
47
48void GrOpsRenderPass::clear(const GrScissorState& scissor, std::array<float, 4> color) {
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
58void 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
66void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
67 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
68 this->onExecuteDrawable(std::move(drawable));
69}
70
71void 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
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
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.
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
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
213bool 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
228void 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
238void 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
249void 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
261void 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
273void 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
299void 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
327void 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}
GrPrimitiveRestart
Definition: GrTypesPriv.h:56
@ kNone_GrXferBarrierType
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
GrTextureType textureType() const
virtual bool isCpuBuffer() const =0
const TextureSampler & textureSampler(int index) const
bool hasInstanceAttributes() const
bool hasVertexAttributes() const
bool isMapped() const
Definition: GrGpuBuffer.cpp:47
void incNumFailedDraws()
Definition: GrGpu.h:542
Stats * stats()
Definition: GrGpu.h:551
const GrCaps * caps() const
Definition: GrGpu.h:73
virtual void xferBarrier(GrRenderTarget *, GrXferBarrierType)=0
virtual void onBegin()
void bindTextures(const GrGeometryProcessor &, const GrSurfaceProxy *const geomProcTextures[], const GrPipeline &)
virtual void onSetScissorRect(const SkIRect &)=0
virtual void onEnd()
virtual void onExecuteDrawable(std::unique_ptr< SkDrawable::GpuDrawHandler >)
void bindPipeline(const GrProgramInfo &, const SkRect &drawBounds)
void draw(int vertexCount, int baseVertex)
virtual bool onBindTextures(const GrGeometryProcessor &, const GrSurfaceProxy *const geomProcTextures[], const GrPipeline &)=0
void clear(const GrScissorState &scissor, std::array< float, 4 > color)
void drawInstanced(int instanceCount, int baseInstance, int vertexCount, int baseVertex)
void drawIndexPattern(int patternIndexCount, int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer, int patternVertexCount, int baseVertex)
virtual void onClearStencilClip(const GrScissorState &, bool insideStencilMask)=0
virtual void onDrawIndexedIndirect(const GrBuffer *, size_t offset, int drawCount)
virtual GrGpu * gpu()=0
virtual void onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue, int baseVertex)=0
virtual void onBindBuffers(sk_sp< const GrBuffer > indexBuffer, sk_sp< const GrBuffer > instanceBuffer, sk_sp< const GrBuffer > vertexBuffer, GrPrimitiveRestart)=0
virtual void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex)=0
void executeDrawable(std::unique_ptr< SkDrawable::GpuDrawHandler >)
void bindBuffers(sk_sp< const GrBuffer > indexBuffer, sk_sp< const GrBuffer > instanceBuffer, sk_sp< const GrBuffer > vertexBuffer, GrPrimitiveRestart=GrPrimitiveRestart::kNo)
void setScissorRect(const SkIRect &)
virtual void onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, int baseVertex)=0
void drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue, int baseVertex)
virtual void onDrawIndirect(const GrBuffer *, size_t offset, int drawCount)
void drawIndexedIndirect(const GrBuffer *drawIndirectBuffer, size_t bufferOffset, int drawCount)
virtual bool onBindPipeline(const GrProgramInfo &, const SkRect &drawBounds)=0
virtual void onClear(const GrScissorState &, std::array< float, 4 > color)=0
void drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex)
GrSurfaceOrigin fOrigin
void drawIndirect(const GrBuffer *drawIndirectBuffer, size_t bufferOffset, int drawCount)
void clearStencilClip(const GrScissorState &scissor, bool insideStencilMask)
virtual void onDraw(int vertexCount, int baseVertex)=0
GrRenderTarget * fRenderTarget
bool hasStencilClip() const
Definition: GrPipeline.h:174
void visitProxies(const GrVisitProxyFunc &) const
Definition: GrPipeline.cpp:105
bool isScissorTestEnabled() const
Definition: GrPipeline.h:163
bool isWireframe() const
Definition: GrPipeline.h:170
bool usesConservativeRaster() const
Definition: GrPipeline.h:169
GrXferBarrierType xferBarrierType(const GrCaps &) const
Definition: GrPipeline.cpp:59
GrSurfaceOrigin origin() const
Definition: GrProgramInfo.h:38
const GrPipeline & pipeline() const
Definition: GrProgramInfo.h:39
const GrGeometryProcessor & geomProc() const
Definition: GrProgramInfo.h:40
const GrUserStencilSettings * userStencilSettings() const
Definition: GrProgramInfo.h:35
bool isStencilEnabled() const
Definition: GrProgramInfo.h:31
bool enabled() const
const GrBackendFormat & backendFormat() const
GrTexture * peekTexture() const
int height() const
Definition: GrSurface.h:37
int width() const
Definition: GrSurface.h:32
skgpu::Mipmapped mipmapped() const
Definition: GrTexture.h:62
bool mipmapsAreDirty() const
Definition: GrTexture.h:65
DlColor color
static float min(float r, float g, float b)
Definition: hsl.cpp:48
Mipmapped
Definition: GpuTypes.h:53
bool isTwoSided(bool hasStencilClip) const
Definition: SkRect.h:32