/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_graphite_ResourceTypes_DEFINED #define skgpu_graphite_ResourceTypes_DEFINED #include "include/core/SkSamplingOptions.h" #include "include/core/SkSpan.h" #include "include/core/SkTileMode.h" #include "include/gpu/graphite/GraphiteTypes.h" #include "include/private/SkEnumBitMask.h" #include "include/private/SkTo.h" #include "src/core/SkMathPriv.h" namespace skgpu::graphite { class Buffer; // This declaration of the DepthStencilFlags' SkEnumBitMask ops is here bc, internally, we use // DepthStencilFlags as bit fields but, externally (i.e., from the GraphiteTypes view), we want // it to appear as just an enum class. SK_MAKE_BITMASK_OPS(DepthStencilFlags) // The same goes for SampleCount SK_MAKE_BITMASK_OPS(SampleCount) /** * There are only a few possible valid sample counts (1, 2, 4, 8, 16). So we can key on those 5 * options instead of the actual sample value. The resulting key value only requires 3 bits of space */ static constexpr uint32_t SamplesToKey(SampleCount numSamples) { switch (numSamples) { case SampleCount::k1: return 0; case SampleCount::k2: return 1; case SampleCount::k4: return 2; case SampleCount::k8: return 3; case SampleCount::k16: return 4; } SkUNREACHABLE; } static constexpr SampleCount KeyToSamples(uint32_t keyBits) { SkASSERT(keyBits <= 4); return static_cast(1 << keyBits); } static constexpr int kNumSampleKeyBits = 3; /** * The strategy that a renderpass and/or pipeline use to access the current dst pixel when blending. */ enum class DstReadStrategy : uint8_t { kNoneRequired, kTextureCopy, kTextureSample, // TODO(b/238756862): To be used once direct texture sampling is implemented kReadFromInput, kFramebufferFetch, kLast = kFramebufferFetch }; inline static constexpr int kDstReadStrategyCount = (int)(DstReadStrategy::kLast) + 1; /** * This enum is used to specify the load operation to be used when a RenderPass begins execution. */ enum class LoadOp : uint8_t { kLoad, kClear, kDiscard, kLast = kDiscard }; inline static constexpr int kLoadOpCount = (int)(LoadOp::kLast) + 1; /** * This enum is used to specify the store operation to be used when a RenderPass ends execution. */ enum class StoreOp : uint8_t { kStore, kDiscard, kLast = kDiscard }; inline static constexpr int kStoreOpCount = (int)(StoreOp::kLast) + 1; /** * What a GPU buffer will be used for */ enum class BufferType : int { kVertex, kIndex, kXferCpuToGpu, kXferGpuToCpu, kUniform, kStorage, kQuery, // GPU-only buffer types kIndirect, kVertexStorage, kIndexStorage, kLast = kIndexStorage, }; static const int kBufferTypeCount = static_cast(BufferType::kLast) + 1; /** * Data layout requirements on host-shareable buffer contents. */ enum class Layout : uint8_t { kInvalid = 0, kStd140, kStd140_F16, kStd430, kStd430_F16, kMetal, }; static constexpr const char* LayoutString(Layout layout) { switch(layout) { case Layout::kStd140: return "std140"; case Layout::kStd140_F16: return "std140-f16"; case Layout::kStd430: return "std430"; case Layout::kStd430_F16: return "std430-f16"; case Layout::kMetal: return "metal"; case Layout::kInvalid: return "invalid"; } SkUNREACHABLE; } /** * Indicates the intended access pattern over resource memory. This is used to select the most * efficient memory type during resource creation based on the capabilities of the platform. * * This is only a hint and the actual memory type will be determined based on the resource type and * backend capabilities. */ enum class AccessPattern : uint8_t { // GPU-only memory does not need to support reads/writes from the CPU. GPU-private memory will // be preferred if the backend supports an efficient private memory type. kGpuOnly, // The resource needs to be CPU visible, e.g. for read-back or as a copy/upload source. kHostVisible, // Use to debug GPU only buffers. kGpuOnlyCopySrc, }; /** * Determines whether the contents of a GPU buffer sub-allocation gets cleared to 0 before being * used in a GPU command submission. */ enum class ClearBuffer : bool { kNo = false, kYes = true, }; /** * Must the contents of the Resource be preserved af a render pass or can a more efficient * representation be chosen when supported by hardware. */ enum class Discardable : bool { kNo = false, kYes = true }; enum class Ownership : uint8_t { kOwned, kWrapped, }; /** Uniquely identifies the type of resource that is cached with a GraphiteResourceKey. */ using ResourceType = uint32_t; /** * Can the resource be held by multiple users at the same time? * For example, stencil buffers, pipelines, etc. */ enum class Shareable : uint8_t { kNo, // The resource is visible in the ResourceCache once all its usage refs are dropped kScratch, // The resource is visible to other Recorders, but acts like kNo within a Recording kYes, // The resource is always visible in the ResourceCache }; /* * Struct that can be passed into bind buffer calls on the CommandBuffer. The ownership of the * buffer and its usage in command submission must be tracked by the caller (e.g. as with * buffers created by DrawBufferManager). */ struct BindBufferInfo { const Buffer* fBuffer = nullptr; uint32_t fOffset = 0; uint32_t fSize = 0; explicit operator bool() const { return SkToBool(fBuffer); } bool operator==(const BindBufferInfo& o) const { return fBuffer == o.fBuffer && (!fBuffer || (fOffset == o.fOffset && fSize == o.fSize)); } bool operator!=(const BindBufferInfo& o) const { return !(*this == o); } }; // How texture memory is arranged on the GPU, which can impact what operations are supported. enum class Tiling : uint8_t { kOptimal, kLinear }; // Coarse ways in which a specific texture can be used, or the theoretic set of usages a texture // format supports. enum class TextureUsage : uint8_t { kRender = 0x01, // Can be used as a rendering attachment kMSRTSS = 0x02, // Can be rendered with MSAA-render-to-single-sampled functionality kSample = 0x04, // Can be sampled within a shader with linear filtering kCopySrc = 0x08, // Can be copied into another texture or buffer kCopyDst = 0x10, // Can be the copy target of another texture or buffer kStorage = 0x20, // Can be read and written to in a compute pipeline kHostCopy = 0x40, // Can be written to directly from host memory kRead = 0x80, // Can be read in a shader (point/nearest sampling or texel fetch; used as // readonly proxy for storage buffers) }; SK_MAKE_BITMASK_OPS(TextureUsage) struct ImmutableSamplerInfo { // If the sampler requires YCbCr conversion, backends can place that information here. // In order to fit within SamplerDesc's uint32 desc field, backends can only utilize up to // kMaxNumConversionInfoBits bits. uint32_t fNonFormatYcbcrConversionInfo = 0; // fFormat represents known OR external format numerical representation. uint64_t fFormat = 0; }; /** * Struct used to describe how a Texture/TextureProxy/TextureProxyView is sampled. */ struct SamplerDesc { static_assert(kSkTileModeCount <= 4 && kSkFilterModeCount <= 2 && kSkMipmapModeCount <= 4); constexpr SamplerDesc(const SkSamplingOptions& samplingOptions, SkTileMode tileMode) : SamplerDesc(samplingOptions, {tileMode, tileMode}) {} constexpr SamplerDesc(const SkSamplingOptions& samplingOptions, const std::pair tileModes, const ImmutableSamplerInfo info = {}) : fDesc((static_cast(tileModes.first) << kTileModeXShift ) | (static_cast(tileModes.second) << kTileModeYShift ) | (static_cast(samplingOptions.filter) << kFilterModeShift ) | (static_cast(samplingOptions.mipmap) << kMipmapModeShift ) | (info.fNonFormatYcbcrConversionInfo << kImmutableSamplerInfoShift) ) , fFormat(info.fFormat) , fExternalFormatMostSignificantBits(info.fFormat >> 32) { // Cubic sampling is handled in a shader, with the actual texture sampled by with NN, // but that is what a cubic SkSamplingOptions is set to if you ignore 'cubic', which let's // us simplify how we construct SamplerDec's from the options passed to high-level draws. SkASSERT(!samplingOptions.useCubic || (samplingOptions.filter == SkFilterMode::kNearest && samplingOptions.mipmap == SkMipmapMode::kNone)); // TODO: Add aniso value when used. // Assert that fYcbcrConversionInfo does not exceed kMaxNumConversionInfoBits such that // the conversion information can fit within an uint32. SkASSERT(info.fNonFormatYcbcrConversionInfo >> kMaxNumConversionInfoBits == 0); } constexpr SamplerDesc() = default; constexpr SamplerDesc(const SamplerDesc&) = default; constexpr SamplerDesc& operator=(const SamplerDesc&) = default; constexpr SamplerDesc(uint32_t desc, uint32_t format, uint32_t extFormatMSB) : fDesc(desc) , fFormat(format) , fExternalFormatMostSignificantBits(extFormatMSB) {} bool operator==(const SamplerDesc& o) const { return o.fDesc == fDesc && o.fFormat == fFormat && o.fExternalFormatMostSignificantBits == fExternalFormatMostSignificantBits; } bool operator!=(const SamplerDesc& o) const { return !(*this == o); } SkTileMode tileModeX() const { return static_cast((fDesc >> kTileModeXShift) & 0b11); } SkTileMode tileModeY() const { return static_cast((fDesc >> kTileModeYShift) & 0b11); } SkFilterMode filterMode() const { return static_cast((fDesc >> kFilterModeShift) & 0b01); } SkMipmapMode mipmap() const { return static_cast((fDesc >> kMipmapModeShift) & 0b11); } uint32_t desc() const { return fDesc; } uint32_t format() const { return fFormat; } uint32_t externalFormatMSBs() const { return fExternalFormatMostSignificantBits; } bool isImmutable() const { return (fDesc >> kImmutableSamplerInfoShift) != 0; } bool usesExternalFormat() const { return (fDesc >> kImmutableSamplerInfoShift) & 0b1; } // NOTE: returns the HW sampling options to use, so a bicubic SkSamplingOptions will become // nearest-neighbor sampling in HW. SkSamplingOptions samplingOptions() const { // TODO: Add support for anisotropic filtering SkFilterMode filter = static_cast((fDesc >> kFilterModeShift) & 0b01); SkMipmapMode mipmap = static_cast((fDesc >> kMipmapModeShift) & 0b11); return SkSamplingOptions(filter, mipmap); } ImmutableSamplerInfo immutableSamplerInfo() const { return {this->desc() >> kImmutableSamplerInfoShift, ((uint64_t) this->externalFormatMSBs() << 32) | (uint64_t) this->format()}; } SkSpan asSpan() const { // Span length depends upon whether the sampler is immutable and if it uses a known format return {&fDesc, 1u + this->isImmutable() + this->usesExternalFormat()}; } // These are public such that backends can bitshift data in order to determine whatever // sampler qualities they need from fDesc. static constexpr int kNumTileModeBits = SkNextLog2(int(SkTileMode::kLastTileMode)+1); static constexpr int kNumFilterModeBits = SkNextLog2(int(SkFilterMode::kLast)+1); static constexpr int kNumMipmapModeBits = SkNextLog2(int(SkMipmapMode::kLast)+1); static constexpr int kMaxNumConversionInfoBits = 32 - kNumFilterModeBits - kNumMipmapModeBits - kNumTileModeBits; static constexpr int kTileModeXShift = 0; static constexpr int kTileModeYShift = kTileModeXShift + kNumTileModeBits; static constexpr int kFilterModeShift = kTileModeYShift + kNumTileModeBits; static constexpr int kMipmapModeShift = kFilterModeShift + kNumFilterModeBits; static constexpr int kImmutableSamplerInfoShift = kMipmapModeShift + kNumMipmapModeBits; // Only relevant when using immutable samplers. Otherwise, can be ignored. The number of uint32s // required to represent all relevant sampler desc information depends upon whether we are using // a known or external format. static constexpr int kInt32sNeededKnownFormat = 2; static constexpr int kInt32sNeededExternalFormat = 3; private: // Note: The order of these member attributes matters to keep unique object representation // such that SkGoodHash can be used to hash SamplerDesc objects. uint32_t fDesc = 0; // Data fields populated by backend Caps which store texture format information (needed for // YCbCr sampling). Only relevant when using immutable samplers. Otherwise, can be ignored. // Known formats only require a uint32, but external formats can be up to a uint64. We store // this as two separate uint32s such that has_unique_object_representation can be true, allowing // this structure to be easily hashed using SkGoodHash. So, external formats can be represented // with (fExternalFormatMostSignificantBits << 32) | fFormat. uint32_t fFormat = 0; uint32_t fExternalFormatMostSignificantBits = 0; }; } // namespace skgpu::graphite #endif // skgpu_graphite_ResourceTypes_DEFINED