xref: /aosp_15_r20/external/skia/src/gpu/graphite/ResourceTypes.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2021 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 #ifndef skgpu_graphite_ResourceTypes_DEFINED
9 #define skgpu_graphite_ResourceTypes_DEFINED
10 
11 #include "include/core/SkSamplingOptions.h"
12 #include "include/core/SkSpan.h"
13 #include "include/core/SkTileMode.h"
14 #include "include/gpu/graphite/GraphiteTypes.h"
15 #include "include/private/base/SkTo.h"
16 #include "src/base/SkEnumBitMask.h"
17 #include "src/base/SkMathPriv.h"
18 
19 namespace skgpu::graphite {
20 
21 class Buffer;
22 
23 // This declaration of the DepthStencilFlags' SkEnumBitMask ops is here bc, internally, we use
24 // DepthStencilFlags as bit fields but, externally (i.e., from the GraphiteTypes view), we want
25 // it to appear as just an enum class.
26 SK_MAKE_BITMASK_OPS(DepthStencilFlags)
27 
28 /**
29  * This enum is used to specify the load operation to be used when a RenderPass begins execution
30  */
31 enum class LoadOp : uint8_t {
32     kLoad,
33     kClear,
34     kDiscard,
35 
36     kLast = kDiscard
37 };
38 inline static constexpr int kLoadOpCount = (int)(LoadOp::kLast) + 1;
39 
40 /**
41  * This enum is used to specify the store operation to be used when a RenderPass ends execution.
42  */
43 enum class StoreOp : uint8_t {
44     kStore,
45     kDiscard,
46 
47     kLast = kDiscard
48 };
49 inline static constexpr int kStoreOpCount = (int)(StoreOp::kLast) + 1;
50 
51 /**
52  * What a GPU buffer will be used for
53  */
54 enum class BufferType : int {
55     kVertex,
56     kIndex,
57     kXferCpuToGpu,
58     kXferGpuToCpu,
59     kUniform,
60     kStorage,
61     kQuery,
62 
63     // GPU-only buffer types
64     kIndirect,
65     kVertexStorage,
66     kIndexStorage,
67 
68     kLast = kIndexStorage,
69 };
70 static const int kBufferTypeCount = static_cast<int>(BufferType::kLast) + 1;
71 
72 /**
73  * Data layout requirements on host-shareable buffer contents.
74  */
75 enum class Layout {
76     kInvalid = 0,
77     kStd140,
78     kStd430,
79     kMetal,
80 };
81 
LayoutString(Layout layout)82 static constexpr const char* LayoutString(Layout layout) {
83     switch(layout) {
84         case Layout::kStd140:  return "std140";
85         case Layout::kStd430:  return "std430";
86         case Layout::kMetal:   return "metal";
87         case Layout::kInvalid: return "invalid";
88     }
89     SkUNREACHABLE;
90 }
91 
92 /**
93  * Indicates the intended access pattern over resource memory. This is used to select the most
94  * efficient memory type during resource creation based on the capabilities of the platform.
95  *
96  * This is only a hint and the actual memory type will be determined based on the resource type and
97  * backend capabilities.
98  */
99 enum class AccessPattern : int {
100     // GPU-only memory does not need to support reads/writes from the CPU. GPU-private memory will
101     // be preferred if the backend supports an efficient private memory type.
102     kGpuOnly,
103 
104     // The resource needs to be CPU visible, e.g. for read-back or as a copy/upload source.
105     kHostVisible,
106 };
107 
108 /**
109  * Determines whether the contents of a GPU buffer sub-allocation gets cleared to 0 before being
110  * used in a GPU command submission.
111  */
112 enum class ClearBuffer : bool {
113     kNo = false,
114     kYes = true,
115 };
116 
117 /**
118  * Must the contents of the Resource be preserved af a render pass or can a more efficient
119  * representation be chosen when supported by hardware.
120  */
121 enum class Discardable : bool {
122     kNo = false,
123     kYes = true
124 };
125 
126 enum class Ownership {
127     kOwned,
128     kWrapped,
129 };
130 
131 /** Uniquely identifies the type of resource that is cached with a GraphiteResourceKey. */
132 using ResourceType = uint32_t;
133 
134 /**
135  * Can the resource be held by multiple users at the same time?
136  * For example, stencil buffers, pipelines, etc.
137  */
138 enum class Shareable : bool {
139     kNo = false,
140     kYes = true,
141 };
142 
143 /**
144  * This enum is used to notify the ResourceCache which type of ref just dropped to zero on a
145  * Resource.
146  */
147 enum class LastRemovedRef {
148     kUsage,
149     kCommandBuffer,
150     kCache,
151 };
152 
153 /*
154  * Struct that can be passed into bind buffer calls on the CommandBuffer. The ownership of the
155  * buffer and its usage in command submission must be tracked by the caller (e.g. as with
156  * buffers created by DrawBufferManager).
157  */
158 struct BindBufferInfo {
159     const Buffer* fBuffer = nullptr;
160     uint32_t fOffset = 0;
161     uint32_t fSize = 0;
162 
163     operator bool() const { return SkToBool(fBuffer); }
164 
165     bool operator==(const BindBufferInfo& o) const {
166         return fBuffer == o.fBuffer && (!fBuffer || (fOffset == o.fOffset && fSize == o.fSize));
167     }
168     bool operator!=(const BindBufferInfo& o) const { return !(*this == o); }
169 };
170 
171 struct ImmutableSamplerInfo {
172     // If the sampler requires YCbCr conversion, backends can place that information here.
173     // In order to fit within SamplerDesc's uint32 desc field, backends can only utilize up to
174     // kMaxNumConversionInfoBits bits.
175     uint32_t fNonFormatYcbcrConversionInfo = 0;
176     // fFormat represents known OR external format numerical representation.
177     uint64_t fFormat = 0;
178 };
179 
180 
181 /**
182  * Struct used to describe how a Texture/TextureProxy/TextureProxyView is sampled.
183  */
184 struct SamplerDesc {
185     static_assert(kSkTileModeCount <= 4 && kSkFilterModeCount <= 2 && kSkMipmapModeCount <= 4);
186 
SamplerDescSamplerDesc187     constexpr SamplerDesc(const SkSamplingOptions& samplingOptions, SkTileMode tileMode)
188             : SamplerDesc(samplingOptions, {tileMode, tileMode}) {}
189 
190     constexpr SamplerDesc(const SkSamplingOptions& samplingOptions,
191                 const std::pair<SkTileMode, SkTileMode> tileModes,
192                 const ImmutableSamplerInfo info = {})
193             : fDesc((static_cast<int>(tileModes.first)            << kTileModeXShift           ) |
194                     (static_cast<int>(tileModes.second)           << kTileModeYShift           ) |
195                     (static_cast<int>(samplingOptions.filter)     << kFilterModeShift          ) |
196                     (static_cast<int>(samplingOptions.mipmap)     << kMipmapModeShift          ) |
197                     (info.fNonFormatYcbcrConversionInfo           << kImmutableSamplerInfoShift) )
198             , fFormat(info.fFormat)
199             , fExternalFormatMostSignificantBits(info.fFormat >> 32) {
200 
201         // Cubic sampling is handled in a shader, with the actual texture sampled by with NN,
202         // but that is what a cubic SkSamplingOptions is set to if you ignore 'cubic', which let's
203         // us simplify how we construct SamplerDec's from the options passed to high-level draws.
204         SkASSERT(!samplingOptions.useCubic || (samplingOptions.filter == SkFilterMode::kNearest &&
205                                                samplingOptions.mipmap == SkMipmapMode::kNone));
206 
207         // TODO: Add aniso value when used.
208 
209         // Assert that fYcbcrConversionInfo does not exceed kMaxNumConversionInfoBits such that
210         // the conversion information can fit within an uint32.
211         SkASSERT(info.fNonFormatYcbcrConversionInfo >> kMaxNumConversionInfoBits == 0);
212     }
213     constexpr SamplerDesc() = default;
214     constexpr SamplerDesc(const SamplerDesc&) = default;
215 
216     bool operator==(const SamplerDesc& o) const {
217         return o.fDesc == fDesc && o.fFormat == fFormat &&
218                o.fExternalFormatMostSignificantBits == fExternalFormatMostSignificantBits;
219     }
220 
221     bool operator!=(const SamplerDesc& o) const { return !(*this == o); }
222 
tileModeXSamplerDesc223     SkTileMode tileModeX()          const { return static_cast<SkTileMode>((fDesc >> 0) & 0b11); }
tileModeYSamplerDesc224     SkTileMode tileModeY()          const { return static_cast<SkTileMode>((fDesc >> 2) & 0b11); }
descSamplerDesc225     uint32_t   desc()               const { return fDesc;                                        }
formatSamplerDesc226     uint32_t   format()             const { return fFormat;                                      }
externalFormatMSBsSamplerDesc227     uint32_t   externalFormatMSBs() const { return fExternalFormatMostSignificantBits;           }
isImmutableSamplerDesc228     bool       isImmutable()        const { return (fDesc >> kImmutableSamplerInfoShift) != 0;   }
usesExternalFormatSamplerDesc229     bool       usesExternalFormat() const { return (fDesc >> kImmutableSamplerInfoShift) & 0b1;  }
230 
231     // NOTE: returns the HW sampling options to use, so a bicubic SkSamplingOptions will become
232     // nearest-neighbor sampling in HW.
samplingOptionsSamplerDesc233     SkSamplingOptions samplingOptions() const {
234         // TODO: Add support for anisotropic filtering
235         SkFilterMode filter = static_cast<SkFilterMode>((fDesc >> 4) & 0b01);
236         SkMipmapMode mipmap = static_cast<SkMipmapMode>((fDesc >> 5) & 0b11);
237         return SkSamplingOptions(filter, mipmap);
238     }
239 
asSpanSamplerDesc240     SkSpan<const uint32_t> asSpan() const {
241         // Span length depends upon whether the sampler is immutable and if it uses a known format
242         return {&fDesc, 1 + this->isImmutable() + this->usesExternalFormat()};
243     }
244 
245     // These are public such that backends can bitshift data in order to determine whatever
246     // sampler qualities they need from fDesc.
247     static constexpr int kNumTileModeBits   = SkNextLog2_portable(int(SkTileMode::kLastTileMode)+1);
248     static constexpr int kNumFilterModeBits = SkNextLog2_portable(int(SkFilterMode::kLast)+1);
249     static constexpr int kNumMipmapModeBits = SkNextLog2_portable(int(SkMipmapMode::kLast)+1);
250     static constexpr int kMaxNumConversionInfoBits =
251             32 - kNumFilterModeBits - kNumMipmapModeBits - kNumTileModeBits;
252 
253     static constexpr int kTileModeXShift            = 0;
254     static constexpr int kTileModeYShift            = kTileModeXShift  + kNumTileModeBits;
255     static constexpr int kFilterModeShift           = kTileModeYShift  + kNumTileModeBits;
256     static constexpr int kMipmapModeShift           = kFilterModeShift + kNumFilterModeBits;
257     static constexpr int kImmutableSamplerInfoShift = kMipmapModeShift + kNumMipmapModeBits;
258 
259     // Only relevant when using immutable samplers. Otherwise, can be ignored. The number of uint32s
260     // required to represent all relevant sampler desc information depends upon whether we are using
261     // a known or external format.
262     static constexpr int kInt32sNeededKnownFormat = 2;
263     static constexpr int kInt32sNeededExternalFormat = 3;
264 
265 private:
266     // Note: The order of these member attributes matters to keep unique object representation
267     // such that SkGoodHash can be used to hash SamplerDesc objects.
268     uint32_t fDesc = 0;
269 
270     // Data fields populated by backend Caps which store texture format information (needed for
271     // YCbCr sampling). Only relevant when using immutable samplers. Otherwise, can be ignored.
272     // Known formats only require a uint32, but external formats can be up to a uint64. We store
273     // this as two separate uint32s such that has_unique_object_representation can be true, allowing
274     // this structure to be easily hashed using SkGoodHash. So, external formats can be represented
275     // with (fExternalFormatMostSignificantBits << 32) | fFormat.
276     uint32_t fFormat = 0;
277     uint32_t fExternalFormatMostSignificantBits = 0;
278 };
279 
280 };  // namespace skgpu::graphite
281 
282 #endif // skgpu_graphite_ResourceTypes_DEFINED
283