| /* |
| * Copyright 2024 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/graphite/RenderPassDesc.h" |
| |
| #include "src/gpu/graphite/Caps.h" |
| |
| namespace skgpu::graphite { |
| |
| namespace { |
| |
| const char* to_str(LoadOp op) { |
| switch (op) { |
| case LoadOp::kLoad: return "load"; |
| case LoadOp::kClear: return "clear"; |
| case LoadOp::kDiscard: return "discard"; |
| } |
| |
| SkUNREACHABLE; |
| } |
| |
| const char* to_str(StoreOp op) { |
| switch (op) { |
| case StoreOp::kStore: return "store"; |
| case StoreOp::kDiscard: return "discard"; |
| } |
| |
| SkUNREACHABLE; |
| } |
| |
| } // anonymous namespace |
| |
| RenderPassDesc RenderPassDesc::Make(const Caps* caps, |
| const TextureInfo& targetInfo, |
| LoadOp loadOp, |
| StoreOp storeOp, |
| SkEnumBitMask<DepthStencilFlags> depthStencilFlags, |
| const std::array<float, 4>& clearColor, |
| bool requiresMSAA, |
| Swizzle writeSwizzle) { |
| RenderPassDesc desc; |
| desc.fWriteSwizzle = writeSwizzle; |
| desc.fSampleCount = 1; |
| // It doesn't make sense to have a storeOp for our main target not be store. Why are we doing |
| // this DrawPass then |
| SkASSERT(storeOp == StoreOp::kStore); |
| if (requiresMSAA) { |
| if (caps->msaaRenderToSingleSampledSupport()) { |
| desc.fColorAttachment.fTextureInfo = targetInfo; |
| desc.fColorAttachment.fLoadOp = loadOp; |
| desc.fColorAttachment.fStoreOp = storeOp; |
| desc.fSampleCount = caps->defaultMSAASamplesCount(); |
| } else { |
| // TODO: If the resolve texture isn't readable, the MSAA color attachment will need to |
| // be persistently associated with the framebuffer, in which case it's not discardable. |
| auto msaaTextureInfo = caps->getDefaultMSAATextureInfo(targetInfo, Discardable::kYes); |
| if (msaaTextureInfo.isValid()) { |
| desc.fColorAttachment.fTextureInfo = msaaTextureInfo; |
| if (loadOp != LoadOp::kClear) { |
| desc.fColorAttachment.fLoadOp = LoadOp::kDiscard; |
| } else { |
| desc.fColorAttachment.fLoadOp = LoadOp::kClear; |
| } |
| desc.fColorAttachment.fStoreOp = StoreOp::kDiscard; |
| |
| desc.fColorResolveAttachment.fTextureInfo = targetInfo; |
| if (loadOp != LoadOp::kLoad) { |
| desc.fColorResolveAttachment.fLoadOp = LoadOp::kDiscard; |
| } else { |
| desc.fColorResolveAttachment.fLoadOp = LoadOp::kLoad; |
| } |
| desc.fColorResolveAttachment.fStoreOp = storeOp; |
| |
| desc.fSampleCount = msaaTextureInfo.numSamples(); |
| } else { |
| // fall back to single sampled |
| desc.fColorAttachment.fTextureInfo = targetInfo; |
| desc.fColorAttachment.fLoadOp = loadOp; |
| desc.fColorAttachment.fStoreOp = storeOp; |
| } |
| } |
| } else { |
| desc.fColorAttachment.fTextureInfo = targetInfo; |
| desc.fColorAttachment.fLoadOp = loadOp; |
| desc.fColorAttachment.fStoreOp = storeOp; |
| } |
| desc.fClearColor = clearColor; |
| |
| if (depthStencilFlags != DepthStencilFlags::kNone) { |
| desc.fDepthStencilAttachment.fTextureInfo = caps->getDefaultDepthStencilTextureInfo( |
| depthStencilFlags, desc.fSampleCount, targetInfo.isProtected()); |
| // Always clear the depth and stencil to 0 at the start of a DrawPass, but discard at the |
| // end since their contents do not affect the next frame. |
| desc.fDepthStencilAttachment.fLoadOp = LoadOp::kClear; |
| desc.fClearDepth = 0.f; |
| desc.fClearStencil = 0; |
| desc.fDepthStencilAttachment.fStoreOp = StoreOp::kDiscard; |
| } |
| |
| return desc; |
| } |
| |
| SkString RenderPassDesc::toString() const { |
| return SkStringPrintf("RP(color: %s, resolve: %s, ds: %s, samples: %u, swizzle: %s, " |
| "clear: c(%f,%f,%f,%f), d(%f), s(0x%02x))", |
| fColorAttachment.toString().c_str(), |
| fColorResolveAttachment.toString().c_str(), |
| fDepthStencilAttachment.toString().c_str(), |
| fSampleCount, |
| fWriteSwizzle.asString().c_str(), |
| fClearColor[0], fClearColor[1], fClearColor[2], fClearColor[3], |
| fClearDepth, |
| fClearStencil); |
| } |
| |
| SkString RenderPassDesc::toPipelineLabel() const { |
| // This intentionally only includes the fixed state that impacts pipeline compilation. |
| // We include the load op of the color attachment when there is a resolve attachment because |
| // the load may trigger a different renderpass description. |
| const char* colorLoadStr = ""; |
| if (fColorAttachment.fLoadOp == LoadOp::kLoad && |
| (fColorResolveAttachment.fTextureInfo.isValid() || fSampleCount > 1)) { |
| colorLoadStr = " w/ msaa load"; |
| } |
| // TODO: Remove `fSampleCount` in label when the Dawn backend manages its MSAA color attachments |
| // directly instead of relying on msaaRenderToSingleSampledSupport(). |
| return SkStringPrintf("RP(color: %s%s, resolve: %s, ds: %s, samples: %u, swizzle: %s)", |
| fColorAttachment.fTextureInfo.toRPAttachmentString().c_str(), |
| colorLoadStr, |
| fColorResolveAttachment.fTextureInfo.toRPAttachmentString().c_str(), |
| fDepthStencilAttachment.fTextureInfo.toRPAttachmentString().c_str(), |
| fSampleCount, |
| fWriteSwizzle.asString().c_str()); |
| } |
| |
| SkString AttachmentDesc::toString() const { |
| if (fTextureInfo.isValid()) { |
| return SkStringPrintf("info: %s loadOp: %s storeOp: %s", |
| fTextureInfo.toString().c_str(), |
| to_str(fLoadOp), |
| to_str(fStoreOp)); |
| } else { |
| return SkString("invalid attachment"); |
| } |
| } |
| |
| } // namespace skgpu::graphite |