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