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
drawBlurImage(const GrSurfaceProxyView& proxyView, SkBlurArg& blurArg)62 void GrOpsRenderPass::drawBlurImage(const GrSurfaceProxyView& proxyView, SkBlurArg& blurArg)
63 {
64 this->onDrawBlurImage(proxyView, blurArg);
65 }
66
bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds)67 void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
68 #ifdef SK_DEBUG
69 // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
70 // place (i.e., the target renderTargetProxy) they had best agree.
71 SkASSERT(programInfo.origin() == fOrigin);
72 if (programInfo.geomProc().hasInstanceAttributes()) {
73 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
74 }
75 if (programInfo.pipeline().usesConservativeRaster()) {
76 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
77 }
78 if (programInfo.pipeline().isWireframe()) {
79 SkASSERT(this->gpu()->caps()->wireframeSupport());
80 }
81 if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
82 programInfo.isStencilEnabled()) {
83 const GrUserStencilSettings* stencil = programInfo.userStencilSettings();
84 if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
85 SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
86 SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
87 SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
88 }
89 }
90 if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
91 SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
92 }
93 programInfo.checkAllInstantiated();
94 programInfo.checkMSAAAndMIPSAreResolved();
95 #endif
96
97 this->resetActiveBuffers();
98
99 if (programInfo.geomProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
100 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
101 return;
102 }
103
104 if (!this->onBindPipeline(programInfo, drawBounds)) {
105 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
106 return;
107 }
108
109 #ifdef SK_DEBUG
110 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
111 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
112 bool hasTextures = (programInfo.geomProc().numTextureSamplers() > 0);
113 if (!hasTextures) {
114 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
115 hasTextures = true;
116 });
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() == GrMipmapped::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() != GrMipmapped::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