blob: 27623f6006341cb807eaa078bbeefdda690d9f6a [file]
/*
* 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