2 * Copyright 2016 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/gpu/ganesh/GrOpsRenderPass.h"
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"
22 void GrOpsRenderPass::begin() {
23 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
25 fScissorStatus = DynamicStateStatus::kDisabled;
26 fTextureBindingStatus = DynamicStateStatus::kDisabled;
27 fHasIndexBuffer = false;
28 fInstanceBufferStatus = DynamicStateStatus::kDisabled;
29 fVertexBufferStatus = DynamicStateStatus::kDisabled;
34 void GrOpsRenderPass::end() {
36 this->resetActiveBuffers();
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);
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);
57 void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
58 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
59 this->onExecuteDrawable(std::move(drawable));
62 void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
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());
70 if (programInfo.pipeline().usesConservativeRaster()) {
71 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
73 if (programInfo.pipeline().isWireframe()) {
74 SkASSERT(this->gpu()->caps()->wireframeSupport());
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);
85 programInfo.checkAllInstantiated();
86 programInfo.checkMSAAAndMIPSAreResolved();
89 this->resetActiveBuffers();
91 if (programInfo.geomProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
92 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
96 if (!this->onBindPipeline(programInfo, drawBounds)) {
97 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
102 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
103 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
104 bool hasTextures = (programInfo.geomProc().numTextureSamplers() > 0);
106 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
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;
119 fDrawPipelineStatus = DrawPipelineStatus::kOk;
120 fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
123 void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
124 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
125 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
128 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
129 this->onSetScissorRect(scissor);
130 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
133 void GrOpsRenderPass::bindTextures(const GrGeometryProcessor& geomProc,
134 const GrSurfaceProxy* const geomProcTextures[],
135 const GrPipeline& pipeline) {
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];
142 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
143 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
145 const GrTexture* tex = proxy->peekTexture();
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());
156 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
157 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
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;
169 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
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);
183 fHasIndexBuffer = true;
186 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
187 if (instanceBuffer) {
188 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
191 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
193 fVertexBufferStatus = DynamicStateStatus::kConfigured;
196 if (GrPrimitiveRestart::kYes == primRestart) {
197 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
201 this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
205 bool GrOpsRenderPass::prepareToDraw() {
206 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
207 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
208 this->gpu()->stats()->incNumFailedDraws();
211 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
212 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
214 if (kNone_GrXferBarrierType != fXferBarrierType) {
215 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
220 void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
221 if (!this->prepareToDraw()) {
224 SkASSERT(!fHasIndexBuffer);
225 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
226 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
227 this->onDraw(vertexCount, baseVertex);
230 void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
231 uint16_t maxIndexValue, int baseVertex) {
232 if (!this->prepareToDraw()) {
235 SkASSERT(fHasIndexBuffer);
236 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
237 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
238 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
241 void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
243 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
244 if (!this->prepareToDraw()) {
247 SkASSERT(!fHasIndexBuffer);
248 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
249 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
250 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, 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()) {
259 SkASSERT(fHasIndexBuffer);
260 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
261 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
262 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
265 void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
267 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
268 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
269 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
270 if (!this->prepareToDraw()) {
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);
288 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
291 void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
293 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
294 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
295 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
296 if (!this->prepareToDraw()) {
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,
316 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
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;