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