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/ganesh/GrOpsRenderPass.h"
9
10 #include "include/core/SkRect.h"
11 #include "src/gpu/ganesh/GrCaps.h"
12 #include "src/gpu/ganesh/GrCpuBuffer.h"
13 #include "src/gpu/ganesh/GrDrawIndirectCommand.h"
14 #include "src/gpu/ganesh/GrGeometryProcessor.h"
15 #include "src/gpu/ganesh/GrGpu.h"
16 #include "src/gpu/ganesh/GrProgramInfo.h"
17 #include "src/gpu/ganesh/GrRenderTarget.h"
18 #include "src/gpu/ganesh/GrScissorState.h"
19 #include "src/gpu/ganesh/GrSimpleMesh.h"
20 #include "src/gpu/ganesh/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 programInfo.checkAllInstantiated();
86 programInfo.checkMSAAAndMIPSAreResolved();
87 #endif
88
89 this->resetActiveBuffers();
90
91 if (programInfo.geomProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
92 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
93 return;
94 }
95
96 if (!this->onBindPipeline(programInfo, drawBounds)) {
97 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
98 return;
99 }
100
101 #ifdef SK_DEBUG
102 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
103 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
104 bool hasTextures = (programInfo.geomProc().numTextureSamplers() > 0);
105 if (!hasTextures) {
106 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
107 hasTextures = true;
108 });
109 }
110 fTextureBindingStatus = (hasTextures) ?
111 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
112 fHasIndexBuffer = false;
113 fInstanceBufferStatus = (programInfo.geomProc().hasInstanceAttributes()) ?
114 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
115 fVertexBufferStatus = (programInfo.geomProc().hasVertexAttributes()) ?
116 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
117 #endif
118
119 fDrawPipelineStatus = DrawPipelineStatus::kOk;
120 fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
121 }
122
setScissorRect(const SkIRect & scissor)123 void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
124 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
125 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
126 return;
127 }
128 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
129 this->onSetScissorRect(scissor);
130 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
131 }
132
bindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)133 void GrOpsRenderPass::bindTextures(const GrGeometryProcessor& geomProc,
134 const GrSurfaceProxy* const geomProcTextures[],
135 const GrPipeline& pipeline) {
136 #ifdef SK_DEBUG
137 SkASSERT((geomProc.numTextureSamplers() > 0) == SkToBool(geomProcTextures));
138 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
139 const auto& sampler = geomProc.textureSampler(i);
140 const GrSurfaceProxy* proxy = geomProcTextures[i];
141 SkASSERT(proxy);
142 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
143 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
144
145 const GrTexture* tex = proxy->peekTexture();
146 SkASSERT(tex);
147 if (sampler.samplerState().mipmapped() == GrMipmapped::kYes &&
148 (tex->width() != 1 || tex->height() != 1)) {
149 // There are some cases where we might be given a non-mipmapped texture with a mipmap
150 // filter. See skbug.com/7094.
151 SkASSERT(tex->mipmapped() != GrMipmapped::kYes || !tex->mipmapsAreDirty());
152 }
153 }
154 #endif
155
156 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
157 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
158 return;
159 }
160
161 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
162 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
163 // many clients it is easier to just always call this method.
164 if (!this->onBindTextures(geomProc, geomProcTextures, pipeline)) {
165 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
166 return;
167 }
168
169 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
170 }
171
bindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primRestart)172 void GrOpsRenderPass::bindBuffers(sk_sp<const GrBuffer> indexBuffer,
173 sk_sp<const GrBuffer> instanceBuffer,
174 sk_sp<const GrBuffer> vertexBuffer,
175 GrPrimitiveRestart primRestart) {
176 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
177 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
178 return;
179 }
180
181 #ifdef SK_DEBUG
182 if (indexBuffer) {
183 fHasIndexBuffer = true;
184 }
185
186 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
187 if (instanceBuffer) {
188 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
189 }
190
191 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
192 if (vertexBuffer) {
193 fVertexBufferStatus = DynamicStateStatus::kConfigured;
194 }
195
196 if (GrPrimitiveRestart::kYes == primRestart) {
197 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
198 }
199 #endif
200
201 this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
202 primRestart);
203 }
204
prepareToDraw()205 bool GrOpsRenderPass::prepareToDraw() {
206 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
207 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
208 this->gpu()->stats()->incNumFailedDraws();
209 return false;
210 }
211 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
212 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
213
214 if (kNone_GrXferBarrierType != fXferBarrierType) {
215 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
216 }
217 return true;
218 }
219
draw(int vertexCount,int baseVertex)220 void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
221 if (!this->prepareToDraw()) {
222 return;
223 }
224 SkASSERT(!fHasIndexBuffer);
225 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
226 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
227 this->onDraw(vertexCount, baseVertex);
228 }
229
drawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)230 void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
231 uint16_t maxIndexValue, int baseVertex) {
232 if (!this->prepareToDraw()) {
233 return;
234 }
235 SkASSERT(fHasIndexBuffer);
236 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
237 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
238 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
239 }
240
drawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)241 void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
242 int baseVertex) {
243 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
244 if (!this->prepareToDraw()) {
245 return;
246 }
247 SkASSERT(!fHasIndexBuffer);
248 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
249 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
250 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
251 }
252
drawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)253 void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
254 int baseInstance, int baseVertex) {
255 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
256 if (!this->prepareToDraw()) {
257 return;
258 }
259 SkASSERT(fHasIndexBuffer);
260 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
261 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
262 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
263 }
264
drawIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)265 void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
266 int drawCount) {
267 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
268 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
269 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
270 if (!this->prepareToDraw()) {
271 return;
272 }
273 SkASSERT(!fHasIndexBuffer);
274 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
275 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
276 if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
277 // Polyfill indirect draws with looping instanced calls.
278 SkASSERT(drawIndirectBuffer->isCpuBuffer());
279 auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
280 auto* cmds = reinterpret_cast<const GrDrawIndirectCommand*>(
281 cpuIndirectBuffer->data() + bufferOffset);
282 for (int i = 0; i < drawCount; ++i) {
283 auto [vertexCount, instanceCount, baseVertex, baseInstance] = cmds[i];
284 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
285 }
286 return;
287 }
288 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
289 }
290
drawIndexedIndirect(const GrBuffer * drawIndirectBuffer,size_t bufferOffset,int drawCount)291 void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
292 int drawCount) {
293 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
294 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
295 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
296 if (!this->prepareToDraw()) {
297 return;
298 }
299 SkASSERT(fHasIndexBuffer);
300 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
301 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
302 if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
303 this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
304 // Polyfill indexedIndirect draws with looping indexedInstanced calls.
305 SkASSERT(drawIndirectBuffer->isCpuBuffer());
306 auto* cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
307 auto* cmds = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
308 cpuIndirectBuffer->data() + bufferOffset);
309 for (int i = 0; i < drawCount; ++i) {
310 auto [indexCount, instanceCount, baseIndex, baseVertex, baseInstance] = cmds[i];
311 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance,
312 baseVertex);
313 }
314 return;
315 }
316 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
317 }
318
drawIndexPattern(int patternIndexCount,int patternRepeatCount,int maxPatternRepetitionsInIndexBuffer,int patternVertexCount,int baseVertex)319 void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
320 int maxPatternRepetitionsInIndexBuffer,
321 int patternVertexCount, int baseVertex) {
322 int baseRepetition = 0;
323 while (baseRepetition < patternRepeatCount) {
324 int repeatCount = std::min(patternRepeatCount - baseRepetition,
325 maxPatternRepetitionsInIndexBuffer);
326 int drawIndexCount = repeatCount * patternIndexCount;
327 // A patterned index buffer must contain indices in the range [0..vertexCount].
328 int minIndexValue = 0;
329 int maxIndexValue = patternVertexCount * repeatCount - 1;
330 this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
331 patternVertexCount * baseRepetition + baseVertex);
332 baseRepetition += repeatCount;
333 }
334 }
335