blob: d0f352fb83863599321630e8717be5a39d28531c [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"
14#include "src/gpu/GrFixedClip.h"
15#include "src/gpu/GrGpu.h"
16#include "src/gpu/GrMesh.h"
17#include "src/gpu/GrPrimitiveProcessor.h"
Robert Phillips901aff02019-10-08 12:32:56 -040018#include "src/gpu/GrProgramInfo.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040019#include "src/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrRenderTargetPriv.h"
Chris Dalton4ece96d2019-08-30 11:26:39 -060021#include "src/gpu/GrTexturePriv.h"
egdaniel9cb63402016-06-23 08:37:05 -070022
Greg Daniel2d41d0d2019-08-26 11:08:51 -040023void GrOpsRenderPass::clear(const GrFixedClip& clip, const SkPMColor4f& color) {
Robert Phillips4912d902018-04-27 12:09:35 -040024 SkASSERT(fRenderTarget);
Michael Ludwigc39d0c82019-01-15 10:03:43 -050025 // A clear at this level will always be a true clear, so make sure clears were not supposed to
26 // be redirected to draws instead
27 SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws());
28 SkASSERT(!clip.scissorEnabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070029 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Robert Phillips19e51dc2017-08-09 09:30:51 -040030 this->onClear(clip, color);
egdaniel9cb63402016-06-23 08:37:05 -070031}
32
Greg Daniel2d41d0d2019-08-26 11:08:51 -040033void GrOpsRenderPass::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
Michael Ludwigc39d0c82019-01-15 10:03:43 -050034 // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings
35 SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070036 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Robert Phillips19e51dc2017-08-09 09:30:51 -040037 this->onClearStencilClip(clip, insideStencilMask);
egdaniel9cb63402016-06-23 08:37:05 -070038}
39
Chris Dalton4386ad12020-02-19 16:42:06 -070040void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
41 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
42 this->onExecuteDrawable(std::move(drawable));
43}
Robert Phillips901aff02019-10-08 12:32:56 -040044
Chris Dalton012f8492020-03-05 11:49:15 -070045void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds,
46 const SkIRect* optionalScissorRect) {
Chris Daltonbca46e22017-05-15 11:03:26 -060047#ifdef SK_DEBUG
Chris Dalton56c09f02020-03-13 17:30:03 -060048 // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
49 // place (i.e., the target renderTargetProxy) they had best agree.
50 SkASSERT(programInfo.origin() == fOrigin);
Chris Dalton4386ad12020-02-19 16:42:06 -070051 if (programInfo.primProc().hasInstanceAttributes()) {
52 SkASSERT(this->gpu()->caps()->instanceAttribSupport());
53 }
54 if (programInfo.pipeline().usesConservativeRaster()) {
55 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
56 // Conservative raster, by default, only supports triangles. Implementations can
57 // optionally indicate that they also support points and lines, but we don't currently
58 // query or track that info.
59 SkASSERT(GrIsPrimTypeTris(programInfo.primitiveType()));
60 }
61 if (programInfo.pipeline().isWireframe()) {
62 SkASSERT(this->gpu()->caps()->wireframeSupport());
63 }
64 if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
65 SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
66 }
Robert Phillips2d8a95e2019-10-10 12:50:22 -040067 programInfo.checkAllInstantiated();
68 programInfo.checkMSAAAndMIPSAreResolved();
Robert Phillips12c46292019-04-23 07:36:17 -040069#endif
Robert Phillipsa91e0b72017-05-01 13:12:20 -040070
Robert Phillips901aff02019-10-08 12:32:56 -040071 if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
Chris Dalton4386ad12020-02-19 16:42:06 -070072 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
73 return;
egdaniel9cb63402016-06-23 08:37:05 -070074 }
Chris Dalton4386ad12020-02-19 16:42:06 -070075
76 if (!this->onBindPipeline(programInfo, drawBounds)) {
77 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
78 return;
79 }
Robert Phillips901aff02019-10-08 12:32:56 -040080
Chris Dalton8c4cafd2019-04-15 19:14:36 -060081#ifdef SK_DEBUG
Robert Phillips901aff02019-10-08 12:32:56 -040082 GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
Chris Dalton8c4cafd2019-04-15 19:14:36 -060083 if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) {
84 // Verify we always have the same sample pattern key, regardless of graphics state.
85 SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget)
86 == fRenderTarget->renderTargetPriv().getSamplePatternKey());
87 }
Chris Dalton2e7ed262020-02-21 15:17:59 -070088 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
89 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
90 bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0);
91 if (!hasTextures) {
92 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipMapped) {
93 hasTextures = true;
94 });
95 }
96 fTextureBindingStatus = (hasTextures) ?
97 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Daltonded43702020-03-02 11:45:27 -070098 fHasIndexBuffer = false;
99 fInstanceBufferStatus = (programInfo.primProc().hasInstanceAttributes()) ?
100 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
101 fVertexBufferStatus = (programInfo.primProc().hasVertexAttributes()) ?
102 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600103#endif
Chris Dalton4386ad12020-02-19 16:42:06 -0700104
105 fDrawPipelineStatus = DrawPipelineStatus::kOk;
Chris Dalton2e7ed262020-02-21 15:17:59 -0700106 fXferBarrierType = programInfo.pipeline().xferBarrierType(fRenderTarget->asTexture(),
107 *this->gpu()->caps());
Chris Dalton012f8492020-03-05 11:49:15 -0700108
109 if (optionalScissorRect) {
110 SkASSERT(programInfo.pipeline().isScissorTestEnabled());
111 this->setScissorRect(*optionalScissorRect);
112 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700113}
114
115void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
116 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
117 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
118 return;
119 }
120 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
121 this->onSetScissorRect(scissor);
122 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
123}
124
Chris Daltondb20afc2020-03-05 12:13:53 -0700125void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
126 const GrSurfaceProxy* const primProcTextures[],
127 const GrPipeline& pipeline) {
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700128#ifdef SK_DEBUG
129 SkASSERT((primProc.numTextureSamplers() > 0) == SkToBool(primProcTextures));
130 for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
131 SkASSERT(primProcTextures[i]->backendFormat() ==
132 primProc.textureSampler(i).backendFormat());
133 }
134#endif
135
Chris Dalton2e7ed262020-02-21 15:17:59 -0700136 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
137 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
138 return;
139 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700140
Chris Dalton2e7ed262020-02-21 15:17:59 -0700141 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
142 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
143 // many clients it is easier to just always call this method.
Chris Daltondb20afc2020-03-05 12:13:53 -0700144 if (!this->onBindTextures(primProc, primProcTextures, pipeline)) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700145 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
146 return;
147 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700148
Chris Dalton2e7ed262020-02-21 15:17:59 -0700149 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
Chris Dalton4386ad12020-02-19 16:42:06 -0700150}
151
Chris Dalton012f8492020-03-05 11:49:15 -0700152void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
153 const GrSurfaceProxy& singlePrimProcTexture,
154 const GrPipeline& pipeline) {
155 SkASSERT(primProc.numTextureSamplers() == 1);
156 const GrSurfaceProxy* ptr = &singlePrimProcTexture;
157 this->bindTextures(primProc, &ptr, pipeline);
158}
159
Chris Dalton4386ad12020-02-19 16:42:06 -0700160void GrOpsRenderPass::drawMeshes(const GrProgramInfo& programInfo, const GrMesh meshes[],
161 int meshCount) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700162 if (programInfo.hasFixedScissor()) {
163 this->setScissorRect(programInfo.fixedScissor());
164 }
165 if (!programInfo.hasDynamicPrimProcTextures()) {
166 auto primProcTextures = (programInfo.hasFixedPrimProcTextures()) ?
167 programInfo.fixedPrimProcTextures() : nullptr;
Chris Daltondb20afc2020-03-05 12:13:53 -0700168 this->bindTextures(programInfo.primProc(), primProcTextures, programInfo.pipeline());
Chris Dalton2e7ed262020-02-21 15:17:59 -0700169 }
170 for (int i = 0; i < meshCount; ++i) {
171 if (programInfo.hasDynamicScissors()) {
172 this->setScissorRect(programInfo.dynamicScissor(i));
173 }
174 if (programInfo.hasDynamicPrimProcTextures()) {
Chris Daltondb20afc2020-03-05 12:13:53 -0700175 this->bindTextures(programInfo.primProc(), programInfo.dynamicPrimProcTextures(i),
176 programInfo.pipeline());
Chris Dalton2e7ed262020-02-21 15:17:59 -0700177 }
Chris Dalton33db9fc2020-02-25 18:52:12 -0700178 meshes[i].draw(this);
Chris Dalton2e7ed262020-02-21 15:17:59 -0700179 }
180}
181
Chris Daltonded43702020-03-02 11:45:27 -0700182void GrOpsRenderPass::bindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer,
183 const GrBuffer* vertexBuffer, GrPrimitiveRestart primRestart) {
184 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
185 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
186 return;
187 }
188
189#ifdef SK_DEBUG
190 if (indexBuffer) {
191 fHasIndexBuffer = true;
192 }
193
194 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
195 if (instanceBuffer) {
196 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
197 }
198
199 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
200 if (vertexBuffer) {
201 fVertexBufferStatus = DynamicStateStatus::kConfigured;
202 }
203
204 if (GrPrimitiveRestart::kYes == primRestart) {
205 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
206 }
207#endif
208
209 this->onBindBuffers(indexBuffer, instanceBuffer, vertexBuffer, primRestart);
210}
211
Chris Dalton33db9fc2020-02-25 18:52:12 -0700212bool GrOpsRenderPass::prepareToDraw() {
Chris Dalton4386ad12020-02-19 16:42:06 -0700213 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
214 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
215 this->gpu()->stats()->incNumFailedDraws();
Chris Dalton33db9fc2020-02-25 18:52:12 -0700216 return false;
Chris Dalton4386ad12020-02-19 16:42:06 -0700217 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700218 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
219 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
Chris Dalton4386ad12020-02-19 16:42:06 -0700220
Chris Dalton2e7ed262020-02-21 15:17:59 -0700221 if (kNone_GrXferBarrierType != fXferBarrierType) {
222 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
Chris Dalton4386ad12020-02-19 16:42:06 -0700223 }
Chris Dalton33db9fc2020-02-25 18:52:12 -0700224 return true;
225}
226
Chris Daltonded43702020-03-02 11:45:27 -0700227void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700228 if (!this->prepareToDraw()) {
229 return;
230 }
Chris Daltonded43702020-03-02 11:45:27 -0700231 SkASSERT(!fHasIndexBuffer);
232 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
233 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
234 this->onDraw(vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700235}
236
Chris Daltonded43702020-03-02 11:45:27 -0700237void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
238 uint16_t maxIndexValue, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700239 if (!this->prepareToDraw()) {
240 return;
241 }
Chris Daltonded43702020-03-02 11:45:27 -0700242 SkASSERT(fHasIndexBuffer);
243 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
244 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
245 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700246}
247
Chris Daltonded43702020-03-02 11:45:27 -0700248void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
Chris Dalton33db9fc2020-02-25 18:52:12 -0700249 int baseVertex) {
250 if (!this->prepareToDraw()) {
251 return;
252 }
Chris Daltonded43702020-03-02 11:45:27 -0700253 SkASSERT(!fHasIndexBuffer);
254 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
255 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
256 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700257}
258
Chris Daltonded43702020-03-02 11:45:27 -0700259void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
260 int baseInstance, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700261 if (!this->prepareToDraw()) {
262 return;
263 }
Chris Daltonded43702020-03-02 11:45:27 -0700264 SkASSERT(fHasIndexBuffer);
265 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
266 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
267 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
egdaniel9cb63402016-06-23 08:37:05 -0700268}
Chris Daltonbb768422020-03-12 12:13:29 -0600269
270void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
271 int maxPatternRepetitionsInIndexBuffer,
272 int patternVertexCount, int baseVertex) {
273 int baseRepetition = 0;
274 while (baseRepetition < patternRepeatCount) {
275 int repeatCount = std::min(patternRepeatCount - baseRepetition,
276 maxPatternRepetitionsInIndexBuffer);
277 int drawIndexCount = repeatCount * patternIndexCount;
278 // A patterned index buffer must contain indices in the range [0..vertexCount].
279 int minIndexValue = 0;
280 int maxIndexValue = patternVertexCount * repeatCount - 1;
281 this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
282 patternVertexCount * baseRepetition + baseVertex);
283 baseRepetition += repeatCount;
284 }
285}