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