| /* | |
| * Copyright 2026 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef sktext_gpu_PackedGPUGlyphID_DEFINED | |
| #define sktext_gpu_PackedGPUGlyphID_DEFINED | |
| #include "src/core/SkGlyph.h" | |
| #include "src/gpu/MaskFormat.h" | |
| namespace sktext::gpu { | |
| // PackedGPUGlyphID represents an SkPackedGlyphID and the assumptions around how the glyph mask | |
| // will be used on the GPU: | |
| // 1. The mask format | |
| // 2. What the mask data stores, e.g. coverage or distances | |
| // 3. The amount of padding around the glyph that can be safely sampled | |
| struct PackedGPUGlyphID { | |
| // `padding` must be 0, 1, or 2 and should be determined by the SubRun choice, it should never | |
| // be a parameter controlled by SubRun data. | |
| constexpr PackedGPUGlyphID(SkPackedGlyphID id, | |
| skgpu::MaskFormat format, | |
| int padding, | |
| bool isSDF) | |
| : fID(id.value() | PackGPUData(format, padding, isSDF)) {} | |
| bool operator==(const PackedGPUGlyphID& that) const { return fID == that.fID; } | |
| bool operator!=(const PackedGPUGlyphID& that) const { return !(*this == that); } | |
| explicit constexpr operator SkPackedGlyphID() const { return this->packedGlyphID(); } | |
| // NOTE: SkPackedGlyphID's raw uint32_t constructor masks off bits it doesn't know about. | |
| constexpr SkPackedGlyphID packedGlyphID() const { return SkPackedGlyphID(fID); } | |
| constexpr skgpu::MaskFormat maskFormat() const { | |
| return static_cast<skgpu::MaskFormat>((fID >> kMaskFormatOffset) & kMaskFormatMask); | |
| } | |
| constexpr int padding() const { | |
| return static_cast<int>((fID >> kPaddingOffset) & kPaddingMask); | |
| } | |
| constexpr bool isSDF() const { | |
| return SkToBool((fID >> kSDFOffset) & kSDFMask); | |
| } | |
| // This hash incorporates the GPU metadata so it will not necessarily hash to the same value as | |
| // what SkPackedGlyphID hashes to by itself. | |
| uint32_t hash() const { | |
| return SkChecksum::CheapMix(fID); | |
| } | |
| private: | |
| // SkPackedGlyphID is 20 bits, so we can use 5 of the spare to store the GPU metadata that | |
| // determines the full contents of a glyph entry in the atlas. | |
| enum { | |
| // Bit counts | |
| kMaskFormatBits = 2u, | |
| kPaddingBits = 2u, // only need 0, 1, or 2 pixels of padding currently | |
| kSDFBits = 1u, | |
| // Bit offsets | |
| kMaskFormatOffset = SkPackedGlyphID::kEndData, | |
| kPaddingOffset = kMaskFormatOffset + kMaskFormatBits, | |
| kSDFOffset = kPaddingOffset + kPaddingBits, | |
| kEndGPUData = kSDFOffset + kSDFBits, | |
| // Masks | |
| kMaskFormatMask = (1u << kMaskFormatBits) - 1, | |
| kPaddingMask = (1u << kPaddingBits) - 1, | |
| kSDFMask = (1u << kSDFBits) - 1, | |
| }; | |
| static_assert(skgpu::kMaskFormatCount <= (1 << kMaskFormatBits)); | |
| static_assert(kEndGPUData <= 32); // Must still fit within a uint32_t | |
| static constexpr uint32_t PackGPUData(skgpu::MaskFormat format, int padding, bool isSDF) { | |
| SkASSERT((uint32_t) format < (1u << kMaskFormatBits)); | |
| SkASSERT(0 <= padding && padding < (1 << kPaddingBits)); | |
| return ((uint32_t) format << kMaskFormatOffset) | | |
| ((uint32_t) padding << kPaddingOffset) | | |
| ((uint32_t) isSDF << kSDFOffset); | |
| } | |
| uint32_t fID; | |
| }; | |
| } // namespace sktext::gpu | |
| #endif // sktext_gpu_PackedGPUGlyphID_DEFINED |