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