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