• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 Google LLC
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 
8 #include "src/gpu/graphite/RenderPassDesc.h"
9 
10 #include "src/gpu/graphite/Caps.h"
11 #include "src/gpu/graphite/TextureInfoPriv.h"
12 
13 namespace skgpu::graphite {
14 
15 namespace {
16 
to_str(LoadOp op)17 const char* to_str(LoadOp op) {
18     switch (op) {
19         case LoadOp::kLoad:    return "load";
20         case LoadOp::kClear:   return "clear";
21         case LoadOp::kDiscard: return "discard";
22     }
23 
24     SkUNREACHABLE;
25 }
26 
to_str(StoreOp op)27 const char* to_str(StoreOp op) {
28     switch (op) {
29         case StoreOp::kStore:   return "store";
30         case StoreOp::kDiscard: return "discard";
31     }
32 
33     SkUNREACHABLE;
34 }
35 
36 } // anonymous namespace
37 
Make(const Caps * caps,const TextureInfo & targetInfo,LoadOp loadOp,StoreOp storeOp,SkEnumBitMask<DepthStencilFlags> depthStencilFlags,const std::array<float,4> & clearColor,bool requiresMSAA,Swizzle writeSwizzle,const DstReadStrategy targetReadStrategy)38 RenderPassDesc RenderPassDesc::Make(const Caps* caps,
39                                     const TextureInfo& targetInfo,
40                                     LoadOp loadOp,
41                                     StoreOp storeOp,
42                                     SkEnumBitMask<DepthStencilFlags> depthStencilFlags,
43                                     const std::array<float, 4>& clearColor,
44                                     bool requiresMSAA,
45                                     Swizzle writeSwizzle,
46                                     const DstReadStrategy targetReadStrategy) {
47     RenderPassDesc desc;
48     desc.fWriteSwizzle = writeSwizzle;
49     desc.fSampleCount = 1;
50     // It doesn't make sense to have a storeOp for our main target not be store. Why are we doing
51     // this DrawPass then
52     SkASSERT(storeOp == StoreOp::kStore);
53     if (requiresMSAA) {
54         if (caps->msaaRenderToSingleSampledSupport()) {
55             desc.fColorAttachment.fTextureInfo = targetInfo;
56             desc.fColorAttachment.fLoadOp = loadOp;
57             desc.fColorAttachment.fStoreOp = storeOp;
58             desc.fSampleCount = caps->defaultMSAASamplesCount();
59         } else {
60             // TODO: If the resolve texture isn't readable, the MSAA color attachment will need to
61             // be persistently associated with the framebuffer, in which case it's not discardable.
62             auto msaaTextureInfo = caps->getDefaultMSAATextureInfo(targetInfo, Discardable::kYes);
63             if (msaaTextureInfo.isValid()) {
64                 desc.fColorAttachment.fTextureInfo = msaaTextureInfo;
65                 if (loadOp != LoadOp::kClear) {
66                     desc.fColorAttachment.fLoadOp = LoadOp::kDiscard;
67                 } else {
68                     desc.fColorAttachment.fLoadOp = LoadOp::kClear;
69                 }
70                 desc.fColorAttachment.fStoreOp = StoreOp::kDiscard;
71 
72                 desc.fColorResolveAttachment.fTextureInfo = targetInfo;
73                 if (loadOp != LoadOp::kLoad) {
74                     desc.fColorResolveAttachment.fLoadOp = LoadOp::kDiscard;
75                 } else {
76                     desc.fColorResolveAttachment.fLoadOp = LoadOp::kLoad;
77                 }
78                 desc.fColorResolveAttachment.fStoreOp = storeOp;
79 
80                 desc.fSampleCount = msaaTextureInfo.numSamples();
81             } else {
82                 // fall back to single sampled
83                 desc.fColorAttachment.fTextureInfo = targetInfo;
84                 desc.fColorAttachment.fLoadOp = loadOp;
85                 desc.fColorAttachment.fStoreOp = storeOp;
86             }
87         }
88     } else {
89         desc.fColorAttachment.fTextureInfo = targetInfo;
90         desc.fColorAttachment.fLoadOp = loadOp;
91         desc.fColorAttachment.fStoreOp = storeOp;
92     }
93     desc.fClearColor = clearColor;
94 
95     if (depthStencilFlags != DepthStencilFlags::kNone) {
96         desc.fDepthStencilAttachment.fTextureInfo = caps->getDefaultDepthStencilTextureInfo(
97                 depthStencilFlags, desc.fSampleCount, targetInfo.isProtected(), Discardable::kYes);
98         // Always clear the depth and stencil to 0 at the start of a DrawPass, but discard at the
99         // end since their contents do not affect the next frame.
100         desc.fDepthStencilAttachment.fLoadOp = LoadOp::kClear;
101         desc.fClearDepth = 0.f;
102         desc.fClearStencil = 0;
103         desc.fDepthStencilAttachment.fStoreOp = StoreOp::kDiscard;
104     }
105 
106     // Should a dst read be required later on, record what dst read strategy should be used. Must be
107     // a valid strategy.
108     SkASSERT(targetReadStrategy != DstReadStrategy::kNoneRequired);
109     desc.fDstReadStrategyIfRequired = targetReadStrategy;
110 
111     return desc;
112 }
113 
toString() const114 SkString RenderPassDesc::toString() const {
115     // Note: Purposefully omitting the fDstReadStrategyIfRequired attribute. Since the shader /
116     // pipeline actually determines whether a dst read is needed, it would make more sense to
117     // report the actual used dst read strategy there.
118     return SkStringPrintf("RP(color: %s, resolve: %s, ds: %s, samples: %u, swizzle: %s, "
119                           "clear: c(%f,%f,%f,%f), d(%f), s(0x%02x))",
120                           fColorAttachment.toString().c_str(),
121                           fColorResolveAttachment.toString().c_str(),
122                           fDepthStencilAttachment.toString().c_str(),
123                           fSampleCount,
124                           fWriteSwizzle.asString().c_str(),
125                           fClearColor[0], fClearColor[1], fClearColor[2], fClearColor[3],
126                           fClearDepth,
127                           fClearStencil);
128 }
129 
toPipelineLabel() const130 SkString RenderPassDesc::toPipelineLabel() const {
131     // This intentionally only includes the fixed state that impacts pipeline compilation.
132     // We include the load op of the color attachment when there is a resolve attachment because
133     // the load may trigger a different renderpass description.
134     const char* colorLoadStr = "";
135 
136     const bool loadMsaaFromResolve =
137             fColorResolveAttachment.fTextureInfo.isValid() &&
138             fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
139 
140     // This should, technically, check Caps::loadOpAffectsMSAAPipelines before adding the extra
141     // string. Only the Metal backend doesn't set that flag, however, so we just assume it is set
142     // to reduce plumbing. Since the Metal backend doesn't differentiate its UniqueKeys wrt
143     // resolve-loads, this can lead to instances where two Metal Pipeline labels will map to the
144     // same UniqueKey (i.e., one with "w/ msaa load" and one without it).
145     if (loadMsaaFromResolve /* && Caps::loadOpAffectsMSAAPipelines() */) {
146         colorLoadStr = " w/ msaa load";
147     }
148 
149     const auto& colorTexInfo = fColorAttachment.fTextureInfo;
150     const auto& resolveTexInfo = fColorResolveAttachment.fTextureInfo;
151     const auto& dsTexInfo = fDepthStencilAttachment.fTextureInfo;
152     // TODO: Remove `fSampleCount` in label when the Dawn backend manages its MSAA color attachments
153     // directly instead of relying on msaaRenderToSingleSampledSupport().
154     return SkStringPrintf("RP(color: %s%s, resolve: %s, ds: %s, samples: %u, swizzle: %s)",
155                           TextureInfoPriv::GetAttachmentLabel(colorTexInfo).c_str(),
156                           colorLoadStr,
157                           TextureInfoPriv::GetAttachmentLabel(resolveTexInfo).c_str(),
158                           TextureInfoPriv::GetAttachmentLabel(dsTexInfo).c_str(),
159                           fSampleCount,
160                           fWriteSwizzle.asString().c_str());
161 }
162 
toString() const163 SkString AttachmentDesc::toString() const {
164     if (fTextureInfo.isValid()) {
165         return SkStringPrintf("info: %s loadOp: %s storeOp: %s",
166                               fTextureInfo.toString().c_str(),
167                               to_str(fLoadOp),
168                               to_str(fStoreOp));
169     } else {
170         return SkString("invalid attachment");
171     }
172 }
173 
174 } // namespace skgpu::graphite
175