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