egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 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 | |
Greg Daniel | 2d41d0d | 2019-08-26 11:08:51 -0400 | [diff] [blame] | 8 | #include "src/gpu/GrOpsRenderPass.h" |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 9 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 10 | #include "include/core/SkRect.h" |
| 11 | #include "include/gpu/GrContext.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 12 | #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 Phillips | 901aff0 | 2019-10-08 12:32:56 -0400 | [diff] [blame] | 18 | #include "src/gpu/GrProgramInfo.h" |
Brian Salomon | 201cdbb | 2019-08-14 17:00:30 -0400 | [diff] [blame] | 19 | #include "src/gpu/GrRenderTarget.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 20 | #include "src/gpu/GrRenderTargetPriv.h" |
Chris Dalton | 4ece96d | 2019-08-30 11:26:39 -0600 | [diff] [blame] | 21 | #include "src/gpu/GrTexturePriv.h" |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 22 | |
Greg Daniel | 2d41d0d | 2019-08-26 11:08:51 -0400 | [diff] [blame] | 23 | void GrOpsRenderPass::clear(const GrFixedClip& clip, const SkPMColor4f& color) { |
Robert Phillips | 4912d90 | 2018-04-27 12:09:35 -0400 | [diff] [blame] | 24 | SkASSERT(fRenderTarget); |
Michael Ludwig | c39d0c8 | 2019-01-15 10:03:43 -0500 | [diff] [blame] | 25 | // 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 Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 29 | fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured; |
Robert Phillips | 19e51dc | 2017-08-09 09:30:51 -0400 | [diff] [blame] | 30 | this->onClear(clip, color); |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 31 | } |
| 32 | |
Greg Daniel | 2d41d0d | 2019-08-26 11:08:51 -0400 | [diff] [blame] | 33 | void GrOpsRenderPass::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { |
Michael Ludwig | c39d0c8 | 2019-01-15 10:03:43 -0500 | [diff] [blame] | 34 | // 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 Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 36 | fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured; |
Robert Phillips | 19e51dc | 2017-08-09 09:30:51 -0400 | [diff] [blame] | 37 | this->onClearStencilClip(clip, insideStencilMask); |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 38 | } |
| 39 | |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 40 | void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) { |
| 41 | fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured; |
| 42 | this->onExecuteDrawable(std::move(drawable)); |
| 43 | } |
Robert Phillips | 901aff0 | 2019-10-08 12:32:56 -0400 | [diff] [blame] | 44 | |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 45 | void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) { |
Chris Dalton | bca46e2 | 2017-05-15 11:03:26 -0600 | [diff] [blame] | 46 | #ifdef SK_DEBUG |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 47 | if (programInfo.primProc().hasInstanceAttributes()) { |
| 48 | SkASSERT(this->gpu()->caps()->instanceAttribSupport()); |
| 49 | } |
| 50 | if (programInfo.pipeline().usesConservativeRaster()) { |
| 51 | SkASSERT(this->gpu()->caps()->conservativeRasterSupport()); |
| 52 | // Conservative raster, by default, only supports triangles. Implementations can |
| 53 | // optionally indicate that they also support points and lines, but we don't currently |
| 54 | // query or track that info. |
| 55 | SkASSERT(GrIsPrimTypeTris(programInfo.primitiveType())); |
| 56 | } |
| 57 | if (programInfo.pipeline().isWireframe()) { |
| 58 | SkASSERT(this->gpu()->caps()->wireframeSupport()); |
| 59 | } |
| 60 | if (GrPrimitiveType::kPatches == programInfo.primitiveType()) { |
| 61 | SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport()); |
| 62 | } |
Robert Phillips | 2d8a95e | 2019-10-10 12:50:22 -0400 | [diff] [blame] | 63 | programInfo.checkAllInstantiated(); |
| 64 | programInfo.checkMSAAAndMIPSAreResolved(); |
Robert Phillips | 12c4629 | 2019-04-23 07:36:17 -0400 | [diff] [blame] | 65 | #endif |
Robert Phillips | a91e0b7 | 2017-05-01 13:12:20 -0400 | [diff] [blame] | 66 | |
Robert Phillips | 901aff0 | 2019-10-08 12:32:56 -0400 | [diff] [blame] | 67 | if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) { |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 68 | fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind; |
| 69 | return; |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 70 | } |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 71 | |
| 72 | if (!this->onBindPipeline(programInfo, drawBounds)) { |
| 73 | fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind; |
| 74 | return; |
| 75 | } |
Robert Phillips | 901aff0 | 2019-10-08 12:32:56 -0400 | [diff] [blame] | 76 | |
Chris Dalton | 8c4cafd | 2019-04-15 19:14:36 -0600 | [diff] [blame] | 77 | #ifdef SK_DEBUG |
Robert Phillips | 901aff0 | 2019-10-08 12:32:56 -0400 | [diff] [blame] | 78 | GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures(); |
Chris Dalton | 8c4cafd | 2019-04-15 19:14:36 -0600 | [diff] [blame] | 79 | if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) { |
| 80 | // Verify we always have the same sample pattern key, regardless of graphics state. |
| 81 | SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget) |
| 82 | == fRenderTarget->renderTargetPriv().getSamplePatternKey()); |
| 83 | } |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 84 | fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ? |
| 85 | DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled; |
| 86 | bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0); |
| 87 | if (!hasTextures) { |
| 88 | programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipMapped) { |
| 89 | hasTextures = true; |
| 90 | }); |
| 91 | } |
| 92 | fTextureBindingStatus = (hasTextures) ? |
| 93 | DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled; |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 94 | fHasIndexBuffer = false; |
| 95 | fInstanceBufferStatus = (programInfo.primProc().hasInstanceAttributes()) ? |
| 96 | DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled; |
| 97 | fVertexBufferStatus = (programInfo.primProc().hasVertexAttributes()) ? |
| 98 | DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled; |
Chris Dalton | 8c4cafd | 2019-04-15 19:14:36 -0600 | [diff] [blame] | 99 | #endif |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 100 | |
| 101 | fDrawPipelineStatus = DrawPipelineStatus::kOk; |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 102 | fXferBarrierType = programInfo.pipeline().xferBarrierType(fRenderTarget->asTexture(), |
| 103 | *this->gpu()->caps()); |
| 104 | } |
| 105 | |
| 106 | void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) { |
| 107 | if (DrawPipelineStatus::kOk != fDrawPipelineStatus) { |
| 108 | SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus); |
| 109 | return; |
| 110 | } |
| 111 | SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus); |
| 112 | this->onSetScissorRect(scissor); |
| 113 | SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured); |
| 114 | } |
| 115 | |
Chris Dalton | db20afc | 2020-03-05 12:13:53 -0700 | [diff] [blame^] | 116 | void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc, |
| 117 | const GrSurfaceProxy* const primProcTextures[], |
| 118 | const GrPipeline& pipeline) { |
Chris Dalton | 1b1b0d5 | 2020-03-03 12:00:59 -0700 | [diff] [blame] | 119 | #ifdef SK_DEBUG |
| 120 | SkASSERT((primProc.numTextureSamplers() > 0) == SkToBool(primProcTextures)); |
| 121 | for (int i = 0; i < primProc.numTextureSamplers(); ++i) { |
| 122 | SkASSERT(primProcTextures[i]->backendFormat() == |
| 123 | primProc.textureSampler(i).backendFormat()); |
| 124 | } |
| 125 | #endif |
| 126 | |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 127 | if (DrawPipelineStatus::kOk != fDrawPipelineStatus) { |
| 128 | SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus); |
| 129 | return; |
| 130 | } |
Chris Dalton | 1b1b0d5 | 2020-03-03 12:00:59 -0700 | [diff] [blame] | 131 | |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 132 | // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there |
| 133 | // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For |
| 134 | // many clients it is easier to just always call this method. |
Chris Dalton | db20afc | 2020-03-05 12:13:53 -0700 | [diff] [blame^] | 135 | if (!this->onBindTextures(primProc, primProcTextures, pipeline)) { |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 136 | fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind; |
| 137 | return; |
| 138 | } |
Chris Dalton | 1b1b0d5 | 2020-03-03 12:00:59 -0700 | [diff] [blame] | 139 | |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 140 | SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured); |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | void GrOpsRenderPass::drawMeshes(const GrProgramInfo& programInfo, const GrMesh meshes[], |
| 144 | int meshCount) { |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 145 | if (programInfo.hasFixedScissor()) { |
| 146 | this->setScissorRect(programInfo.fixedScissor()); |
| 147 | } |
| 148 | if (!programInfo.hasDynamicPrimProcTextures()) { |
| 149 | auto primProcTextures = (programInfo.hasFixedPrimProcTextures()) ? |
| 150 | programInfo.fixedPrimProcTextures() : nullptr; |
Chris Dalton | db20afc | 2020-03-05 12:13:53 -0700 | [diff] [blame^] | 151 | this->bindTextures(programInfo.primProc(), primProcTextures, programInfo.pipeline()); |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 152 | } |
| 153 | for (int i = 0; i < meshCount; ++i) { |
| 154 | if (programInfo.hasDynamicScissors()) { |
| 155 | this->setScissorRect(programInfo.dynamicScissor(i)); |
| 156 | } |
| 157 | if (programInfo.hasDynamicPrimProcTextures()) { |
Chris Dalton | db20afc | 2020-03-05 12:13:53 -0700 | [diff] [blame^] | 158 | this->bindTextures(programInfo.primProc(), programInfo.dynamicPrimProcTextures(i), |
| 159 | programInfo.pipeline()); |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 160 | } |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 161 | meshes[i].draw(this); |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 162 | } |
| 163 | } |
| 164 | |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 165 | void GrOpsRenderPass::bindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer, |
| 166 | const GrBuffer* vertexBuffer, GrPrimitiveRestart primRestart) { |
| 167 | if (DrawPipelineStatus::kOk != fDrawPipelineStatus) { |
| 168 | SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus); |
| 169 | return; |
| 170 | } |
| 171 | |
| 172 | #ifdef SK_DEBUG |
| 173 | if (indexBuffer) { |
| 174 | fHasIndexBuffer = true; |
| 175 | } |
| 176 | |
| 177 | SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer)); |
| 178 | if (instanceBuffer) { |
| 179 | fInstanceBufferStatus = DynamicStateStatus::kConfigured; |
| 180 | } |
| 181 | |
| 182 | SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer)); |
| 183 | if (vertexBuffer) { |
| 184 | fVertexBufferStatus = DynamicStateStatus::kConfigured; |
| 185 | } |
| 186 | |
| 187 | if (GrPrimitiveRestart::kYes == primRestart) { |
| 188 | SkASSERT(this->gpu()->caps()->usePrimitiveRestart()); |
| 189 | } |
| 190 | #endif |
| 191 | |
| 192 | this->onBindBuffers(indexBuffer, instanceBuffer, vertexBuffer, primRestart); |
| 193 | } |
| 194 | |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 195 | bool GrOpsRenderPass::prepareToDraw() { |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 196 | if (DrawPipelineStatus::kOk != fDrawPipelineStatus) { |
| 197 | SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus); |
| 198 | this->gpu()->stats()->incNumFailedDraws(); |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 199 | return false; |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 200 | } |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 201 | SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus); |
| 202 | SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus); |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 203 | |
Chris Dalton | 2e7ed26 | 2020-02-21 15:17:59 -0700 | [diff] [blame] | 204 | if (kNone_GrXferBarrierType != fXferBarrierType) { |
| 205 | this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType); |
Chris Dalton | 4386ad1 | 2020-02-19 16:42:06 -0700 | [diff] [blame] | 206 | } |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 207 | return true; |
| 208 | } |
| 209 | |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 210 | void GrOpsRenderPass::draw(int vertexCount, int baseVertex) { |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 211 | if (!this->prepareToDraw()) { |
| 212 | return; |
| 213 | } |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 214 | SkASSERT(!fHasIndexBuffer); |
| 215 | SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus); |
| 216 | SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus); |
| 217 | this->onDraw(vertexCount, baseVertex); |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 218 | } |
| 219 | |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 220 | void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, |
| 221 | uint16_t maxIndexValue, int baseVertex) { |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 222 | if (!this->prepareToDraw()) { |
| 223 | return; |
| 224 | } |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 225 | SkASSERT(fHasIndexBuffer); |
| 226 | SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus); |
| 227 | SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus); |
| 228 | this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex); |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 229 | } |
| 230 | |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 231 | void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount, |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 232 | int baseVertex) { |
| 233 | if (!this->prepareToDraw()) { |
| 234 | return; |
| 235 | } |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 236 | SkASSERT(!fHasIndexBuffer); |
| 237 | SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus); |
| 238 | SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus); |
| 239 | this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex); |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 240 | } |
| 241 | |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 242 | void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, |
| 243 | int baseInstance, int baseVertex) { |
Chris Dalton | 33db9fc | 2020-02-25 18:52:12 -0700 | [diff] [blame] | 244 | if (!this->prepareToDraw()) { |
| 245 | return; |
| 246 | } |
Chris Dalton | ded4370 | 2020-03-02 11:45:27 -0700 | [diff] [blame] | 247 | SkASSERT(fHasIndexBuffer); |
| 248 | SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus); |
| 249 | SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus); |
| 250 | this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex); |
egdaniel | 9cb6340 | 2016-06-23 08:37:05 -0700 | [diff] [blame] | 251 | } |