blob: 07b4eeebe3a14caa22c5b7a024b691c4212dc10d [file] [log] [blame]
egdaniel9cb63402016-06-23 08:37:05 -07001/*
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
Greg Daniel2d41d0d2019-08-26 11:08:51 -04008#include "src/gpu/GrOpsRenderPass.h"
egdaniel9cb63402016-06-23 08:37:05 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkRect.h"
11#include "include/gpu/GrContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/gpu/GrCaps.h"
13#include "src/gpu/GrContextPriv.h"
Michael Ludwig1e632792020-05-21 12:45:31 -040014#include "src/gpu/GrCpuBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrGpu.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrPrimitiveProcessor.h"
Robert Phillips901aff02019-10-08 12:32:56 -040017#include "src/gpu/GrProgramInfo.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040018#include "src/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrRenderTargetPriv.h"
Michael Ludwig1e632792020-05-21 12:45:31 -040020#include "src/gpu/GrScissorState.h"
Chris Daltoneb694b72020-03-16 09:25:50 -060021#include "src/gpu/GrSimpleMesh.h"
Chris Dalton4ece96d2019-08-30 11:26:39 -060022#include "src/gpu/GrTexturePriv.h"
egdaniel9cb63402016-06-23 08:37:05 -070023
Chris Dalton2c3e1692020-03-20 12:32:55 -060024void GrOpsRenderPass::begin() {
25 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
26#ifdef SK_DEBUG
27 fScissorStatus = DynamicStateStatus::kDisabled;
28 fTextureBindingStatus = DynamicStateStatus::kDisabled;
29 fHasIndexBuffer = false;
30 fInstanceBufferStatus = DynamicStateStatus::kDisabled;
31 fVertexBufferStatus = DynamicStateStatus::kDisabled;
32#endif
33 this->onBegin();
34}
35
36void GrOpsRenderPass::end() {
37 this->onEnd();
Chris Daltonb60c8a22020-03-31 17:24:22 -060038 this->resetActiveBuffers();
Chris Dalton2c3e1692020-03-20 12:32:55 -060039}
40
Michael Ludwig1e632792020-05-21 12:45:31 -040041void GrOpsRenderPass::clear(const GrScissorState& scissor, const SkPMColor4f& color) {
Robert Phillips4912d902018-04-27 12:09:35 -040042 SkASSERT(fRenderTarget);
Michael Ludwigc39d0c82019-01-15 10:03:43 -050043 // A clear at this level will always be a true clear, so make sure clears were not supposed to
44 // be redirected to draws instead
45 SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws());
Michael Ludwig1e632792020-05-21 12:45:31 -040046 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070047 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Michael Ludwig1e632792020-05-21 12:45:31 -040048 this->onClear(scissor, color);
egdaniel9cb63402016-06-23 08:37:05 -070049}
50
Michael Ludwig1e632792020-05-21 12:45:31 -040051void GrOpsRenderPass::clearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
Michael Ludwigc39d0c82019-01-15 10:03:43 -050052 // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings
53 SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws());
Michael Ludwig1e632792020-05-21 12:45:31 -040054 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070055 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Michael Ludwig1e632792020-05-21 12:45:31 -040056 this->onClearStencilClip(scissor, insideStencilMask);
egdaniel9cb63402016-06-23 08:37:05 -070057}
58
Chris Dalton4386ad12020-02-19 16:42:06 -070059void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
60 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
61 this->onExecuteDrawable(std::move(drawable));
62}
Robert Phillips901aff02019-10-08 12:32:56 -040063
Chris Daltonaa0e45c2020-03-16 10:05:11 -060064void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
Chris Daltonbca46e22017-05-15 11:03:26 -060065#ifdef SK_DEBUG
Chris Dalton56c09f02020-03-13 17:30:03 -060066 // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
67 // place (i.e., the target renderTargetProxy) they had best agree.
68 SkASSERT(programInfo.origin() == fOrigin);
Chris Dalton4386ad12020-02-19 16:42:06 -070069 if (programInfo.primProc().hasInstanceAttributes()) {
Chris Daltona77cdee2020-04-03 14:50:43 -060070 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton4386ad12020-02-19 16:42:06 -070071 }
72 if (programInfo.pipeline().usesConservativeRaster()) {
73 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
74 // Conservative raster, by default, only supports triangles. Implementations can
75 // optionally indicate that they also support points and lines, but we don't currently
76 // query or track that info.
77 SkASSERT(GrIsPrimTypeTris(programInfo.primitiveType()));
78 }
79 if (programInfo.pipeline().isWireframe()) {
80 SkASSERT(this->gpu()->caps()->wireframeSupport());
81 }
Chris Dalton3d28b6a2020-04-13 11:12:28 -060082 if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
83 programInfo.pipeline().isStencilEnabled()) {
84 const GrUserStencilSettings* stencil = programInfo.pipeline().getUserStencil();
85 if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
86 SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
87 SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
88 SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
89 }
90 }
Chris Dalton4386ad12020-02-19 16:42:06 -070091 if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
92 SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
93 }
Robert Phillips2d8a95e2019-10-10 12:50:22 -040094 programInfo.checkAllInstantiated();
95 programInfo.checkMSAAAndMIPSAreResolved();
Robert Phillips12c46292019-04-23 07:36:17 -040096#endif
Robert Phillipsa91e0b72017-05-01 13:12:20 -040097
Chris Daltonb60c8a22020-03-31 17:24:22 -060098 this->resetActiveBuffers();
99
Robert Phillips901aff02019-10-08 12:32:56 -0400100 if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
Chris Dalton4386ad12020-02-19 16:42:06 -0700101 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
102 return;
egdaniel9cb63402016-06-23 08:37:05 -0700103 }
Chris Dalton4386ad12020-02-19 16:42:06 -0700104
105 if (!this->onBindPipeline(programInfo, drawBounds)) {
106 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
107 return;
108 }
Robert Phillips901aff02019-10-08 12:32:56 -0400109
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600110#ifdef SK_DEBUG
Robert Phillips901aff02019-10-08 12:32:56 -0400111 GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600112 if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) {
113 // Verify we always have the same sample pattern key, regardless of graphics state.
114 SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget)
115 == fRenderTarget->renderTargetPriv().getSamplePatternKey());
116 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700117 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
118 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
119 bool hasTextures = (programInfo.primProc().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;
Chris Daltonded43702020-03-02 11:45:27 -0700127 fHasIndexBuffer = false;
128 fInstanceBufferStatus = (programInfo.primProc().hasInstanceAttributes()) ?
129 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
130 fVertexBufferStatus = (programInfo.primProc().hasVertexAttributes()) ?
131 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600132#endif
Chris Dalton4386ad12020-02-19 16:42:06 -0700133
134 fDrawPipelineStatus = DrawPipelineStatus::kOk;
Chris Dalton2e7ed262020-02-21 15:17:59 -0700135 fXferBarrierType = programInfo.pipeline().xferBarrierType(fRenderTarget->asTexture(),
136 *this->gpu()->caps());
137}
138
139void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
140 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
141 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
142 return;
143 }
144 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
145 this->onSetScissorRect(scissor);
146 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
147}
148
Chris Daltondb20afc2020-03-05 12:13:53 -0700149void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
150 const GrSurfaceProxy* const primProcTextures[],
151 const GrPipeline& pipeline) {
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700152#ifdef SK_DEBUG
153 SkASSERT((primProc.numTextureSamplers() > 0) == SkToBool(primProcTextures));
154 for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600155 const auto& sampler = primProc.textureSampler(i);
156 const GrSurfaceProxy* proxy = primProcTextures[i];
157 SkASSERT(proxy);
158 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
159 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
160
161 const GrTexture* tex = proxy->peekTexture();
162 SkASSERT(tex);
163 if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter() &&
164 (tex->width() != 1 || tex->height() != 1)) {
165 // There are some cases where we might be given a non-mipmapped texture with a mipmap
166 // filter. See skbug.com/7094.
167 SkASSERT(tex->texturePriv().mipMapped() != GrMipMapped::kYes ||
168 !tex->texturePriv().mipMapsAreDirty());
169 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700170 }
171#endif
172
Chris Dalton2e7ed262020-02-21 15:17:59 -0700173 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
174 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
175 return;
176 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700177
Chris Dalton2e7ed262020-02-21 15:17:59 -0700178 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
179 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
180 // many clients it is easier to just always call this method.
Chris Daltondb20afc2020-03-05 12:13:53 -0700181 if (!this->onBindTextures(primProc, primProcTextures, pipeline)) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700182 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
183 return;
184 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700185
Chris Dalton2e7ed262020-02-21 15:17:59 -0700186 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
Chris Dalton4386ad12020-02-19 16:42:06 -0700187}
188
Chris Daltonded43702020-03-02 11:45:27 -0700189void GrOpsRenderPass::bindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer,
190 const GrBuffer* vertexBuffer, 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(indexBuffer, instanceBuffer, vertexBuffer, primRestart);
217}
218
Chris Dalton33db9fc2020-02-25 18:52:12 -0700219bool GrOpsRenderPass::prepareToDraw() {
Chris Dalton4386ad12020-02-19 16:42:06 -0700220 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
221 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
222 this->gpu()->stats()->incNumFailedDraws();
Chris Dalton33db9fc2020-02-25 18:52:12 -0700223 return false;
Chris Dalton4386ad12020-02-19 16:42:06 -0700224 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700225 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
226 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
Chris Dalton4386ad12020-02-19 16:42:06 -0700227
Chris Dalton2e7ed262020-02-21 15:17:59 -0700228 if (kNone_GrXferBarrierType != fXferBarrierType) {
229 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
Chris Dalton4386ad12020-02-19 16:42:06 -0700230 }
Chris Dalton33db9fc2020-02-25 18:52:12 -0700231 return true;
232}
233
Chris Daltonded43702020-03-02 11:45:27 -0700234void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700235 if (!this->prepareToDraw()) {
236 return;
237 }
Chris Daltonded43702020-03-02 11:45:27 -0700238 SkASSERT(!fHasIndexBuffer);
239 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
240 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
241 this->onDraw(vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700242}
243
Chris Daltonded43702020-03-02 11:45:27 -0700244void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
245 uint16_t maxIndexValue, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700246 if (!this->prepareToDraw()) {
247 return;
248 }
Chris Daltonded43702020-03-02 11:45:27 -0700249 SkASSERT(fHasIndexBuffer);
250 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
251 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
252 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700253}
254
Chris Daltonded43702020-03-02 11:45:27 -0700255void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
Chris Dalton33db9fc2020-02-25 18:52:12 -0700256 int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600257 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700258 if (!this->prepareToDraw()) {
259 return;
260 }
Chris Daltonded43702020-03-02 11:45:27 -0700261 SkASSERT(!fHasIndexBuffer);
262 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
263 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
264 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700265}
266
Chris Daltonded43702020-03-02 11:45:27 -0700267void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
268 int baseInstance, int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600269 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700270 if (!this->prepareToDraw()) {
271 return;
272 }
Chris Daltonded43702020-03-02 11:45:27 -0700273 SkASSERT(fHasIndexBuffer);
274 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
275 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
276 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
egdaniel9cb63402016-06-23 08:37:05 -0700277}
Chris Daltonbb768422020-03-12 12:13:29 -0600278
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600279void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
280 int drawCount) {
281 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
282 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
283 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
284 if (!this->prepareToDraw()) {
285 return;
286 }
287 SkASSERT(!fHasIndexBuffer);
288 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
289 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
290 if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
291 // Polyfill indirect draws with looping instanced calls.
292 SkASSERT(drawIndirectBuffer->isCpuBuffer());
293 auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
294 auto cmd = reinterpret_cast<const GrDrawIndirectCommand*>(
295 cpuIndirectBuffer->data() + bufferOffset);
296 auto end = cmd + drawCount;
297 for (; cmd != end; ++cmd) {
298 this->onDrawInstanced(cmd->fInstanceCount, cmd->fBaseInstance, cmd->fVertexCount,
299 cmd->fBaseVertex);
300 }
301 return;
302 }
303 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
304}
305
306void 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 cmd = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
323 cpuIndirectBuffer->data() + bufferOffset);
324 auto end = cmd + drawCount;
325 for (; cmd != end; ++cmd) {
326 this->onDrawIndexedInstanced(cmd->fIndexCount, cmd->fBaseIndex, cmd->fInstanceCount,
327 cmd->fBaseInstance, cmd->fBaseVertex);
328 }
329 return;
330 }
331 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
332}
333
Chris Daltonbb768422020-03-12 12:13:29 -0600334void 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}