use SkGlyphDigest for MaskSummary

Use SkGlyphDigest in the remote glyph cache. This allows future
CLs to use maximum glyph information for calculating scale factors.

Move SkGlyphDigest to a more central location in the code.

Bugs: chromium:1280180

Change-Id: Id916d39b8a46a29723bc9f244969c8d00162e5df
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/493197
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2022-01-10 14:44:51 -05:00 committed by SkCQ
parent 3e1354a592
commit 55b4dc3f7a
4 changed files with 63 additions and 83 deletions

View File

@ -278,28 +278,6 @@ private:
void commonMaskLoop(
SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject);
// Keep track of if the glyph draw has been totally satisfied. It could be that this
// strike can not draw the glyph, and it must be rejected to be handled by fallback.
// For example, if a glyph has canDrawAsMask sent, then that data is on the GPU, and this
// strike totally satisfies this result. If canDrawAsMask is false, then this glyph must be
// rejected, and handled by a later stage using a latter strike.
struct MaskSummary {
static_assert(SkPackedGlyphID::kMaskAll < (1u << 30), "SkPackedGlyphID is too big.");
uint32_t packedID:30;
uint32_t canDrawAsMask:1;
uint32_t canDrawAsSDFT:1;
};
struct MaskSummaryTraits {
static SkPackedGlyphID GetKey(MaskSummary summary) {
return SkPackedGlyphID{summary.packedID};
}
static uint32_t Hash(SkPackedGlyphID packedID) {
return packedID.hash();
}
};
// Same thing as MaskSummary, but for paths.
struct PathSummary {
constexpr static uint16_t kIsPath = 0;
@ -340,7 +318,7 @@ private:
LowerRangeBitVector fSentLowGlyphIDs;
// The masks and paths that currently reside in the GPU process.
SkTHashTable<MaskSummary, SkPackedGlyphID, MaskSummaryTraits> fSentGlyphs;
SkTHashTable<SkGlyphDigest, uint32_t, SkGlyphDigest> fSentGlyphs;
SkTHashTable<PathSummary, SkPackedGlyphID, PathSummaryTraits> fSentPaths;
// The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
@ -462,20 +440,19 @@ void RemoteStrike::commonMaskLoop(
SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject) {
drawables->forEachGlyphID(
[&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
MaskSummary* summary = fSentGlyphs.find(packedID);
if (summary == nullptr) {
SkGlyphDigest* digest = fSentGlyphs.find(packedID.value());
if (digest == nullptr) {
// Put the new SkGlyph in the glyphs to send.
this->ensureScalerContext();
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fPathAlloc));
SkGlyph* glyph = &fMasksToSend.back();
MaskSummary newSummary =
{packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
summary = fSentGlyphs.set(newSummary);
SkGlyphDigest newDigest{0, *glyph};
digest = fSentGlyphs.set(newDigest);
}
// Reject things that are too big.
if (reject(*summary)) {
if (reject(*digest)) {
rejects->reject(i);
}
});
@ -487,33 +464,32 @@ void RemoteStrike::prepareForMaskDrawing(
SkPackedGlyphID packedID = variant.packedID();
if (fSentLowGlyphIDs.test(packedID)) {
#ifdef SK_DEBUG
MaskSummary* summary = fSentGlyphs.find(packedID);
SkASSERT(summary != nullptr);
SkASSERT(summary->canDrawAsMask && summary->canDrawAsSDFT);
SkGlyphDigest* digest = fSentGlyphs.find(packedID.value());
SkASSERT(digest != nullptr);
SkASSERT(digest->canDrawAsMask() && digest->canDrawAsSDFT());
#endif
continue;
}
MaskSummary* summary = fSentGlyphs.find(packedID);
if (summary == nullptr) {
SkGlyphDigest* digest = fSentGlyphs.find(packedID.value());
if (digest == nullptr) {
// Put the new SkGlyph in the glyphs to send.
this->ensureScalerContext();
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fPathAlloc));
SkGlyph* glyph = &fMasksToSend.back();
MaskSummary newSummary =
{packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
SkGlyphDigest newDigest{0, *glyph};
summary = fSentGlyphs.set(newSummary);
digest = fSentGlyphs.set(newDigest);
if (summary->canDrawAsMask && summary->canDrawAsSDFT) {
if (digest->canDrawAsMask() && digest->canDrawAsSDFT()) {
fSentLowGlyphIDs.setIfLower(packedID);
}
}
// Reject things that are too big.
if (!summary->canDrawAsMask) {
if (!digest->canDrawAsMask()) {
rejects->reject(i);
}
}
@ -522,7 +498,7 @@ void RemoteStrike::prepareForMaskDrawing(
void RemoteStrike::prepareForSDFTDrawing(
SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
this->commonMaskLoop(drawables, rejects,
[](MaskSummary summary){return !summary.canDrawAsSDFT;});
[](SkGlyphDigest digest){return !digest.canDrawAsSDFT();});
}
void RemoteStrike::prepareForPathDrawing(

View File

@ -349,3 +349,12 @@ void SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar
}
offsetResults(intercept, array, count);
}
SkGlyphDigest::SkGlyphDigest(size_t index, const SkGlyph& glyph)
: fPackedGlyphID{glyph.getPackedID().value()}
, fIndex{SkTo<uint32_t>(index)}
, fIsEmpty(glyph.isEmpty())
, fIsColor(glyph.isColor())
, fCanDrawAsMask{SkStrikeForGPU::CanDrawAsMask(glyph)}
, fCanDrawAsSDFT{SkStrikeForGPU::CanDrawAsSDFT(glyph)}
, fMaxDimension{(uint16_t)glyph.maxDimension()} {}

View File

@ -16,6 +16,7 @@
#include "include/private/SkVx.h"
#include "src/core/SkMask.h"
#include "src/core/SkMathPriv.h"
#include "src/core/SkStrikeForGPU.h"
class SkArenaAlloc;
class SkScalerContext;
@ -238,7 +239,41 @@ inline SkGlyphRect rect_intersection(SkGlyphRect a, SkGlyphRect b) {
}
} // namespace skglyph
struct SkGlyphPrototype;
class SkGlyph;
// SkGlyphDigest contains a digest of information for making GPU drawing decisions. It can be
// referenced instead of the glyph itself in many situations. In the remote glyphs cache the
// SkGlyphDigest is the only information that needs to be stored in the cache.
class SkGlyphDigest {
public:
// Default ctor is only needed for the hash table.
SkGlyphDigest() = default;
SkGlyphDigest(size_t index, const SkGlyph& glyph);
int index() const {return fIndex; }
bool isEmpty() const {return fIsEmpty; }
bool isColor() const {return fIsColor; }
bool canDrawAsMask() const {return fCanDrawAsMask;}
bool canDrawAsSDFT() const {return fCanDrawAsSDFT;}
uint32_t packedGlyphID() const {return fPackedGlyphID;}
// Support mapping from SkPackedGlyphID stored in the digest.
static uint32_t GetKey(SkGlyphDigest digest) {
return digest.packedGlyphID();
}
static uint32_t Hash(uint32_t packedGlyphID) {
return SkGoodHash()(packedGlyphID);
}
private:
static_assert(SkPackedGlyphID::kEndData == 20);
uint64_t fPackedGlyphID : SkPackedGlyphID::kEndData;
uint64_t fIndex : SkPackedGlyphID::kEndData;
uint64_t fIsEmpty : 1;
uint64_t fIsColor : 1;
uint64_t fCanDrawAsMask : 1;
uint64_t fCanDrawAsSDFT : 1;
uint64_t fMaxDimension : 16;
};
class SkGlyph {
public:
@ -372,7 +407,7 @@ private:
// Support horizontal and vertical skipping strike-through / underlines.
// The caller walks the linked list looking for a match. For a horizontal underline,
// the fBounds contains the top and bottom of the underline. The fInterval pair contains the
// beginning and end of of the intersection of the bounds and the glyph's path.
// beginning and end of the intersection of the bounds and the glyph's path.
// If interval[0] >= interval[1], no intersection was found.
struct Intercept {
Intercept* fNext;

View File

@ -21,38 +21,6 @@
class SkScalerContext;
// The value stored in fDigestForPackedGlyphID.
// index() is the index into fGlyphForIndex.
class SkGlyphDigest {
public:
// Default ctor is only needed for the hash table.
SkGlyphDigest() = default;
SkGlyphDigest(size_t i, const SkGlyph& glyph)
: fPackedGlyphID{glyph.getPackedID().value()}
, fIndex{SkTo<uint32_t>(i)}
, fIsEmpty(glyph.isEmpty())
, fIsColor(glyph.isColor())
, fCanDrawAsMask{SkStrikeForGPU::CanDrawAsMask(glyph)}
, fCanDrawAsSDFT{SkStrikeForGPU::CanDrawAsSDFT(glyph)}
, fMaxDimension{(uint16_t)glyph.maxDimension()} {}
int index() const {return fIndex; }
bool isEmpty() const {return fIsEmpty; }
bool isColor() const {return fIsColor; }
bool canDrawAsMask() const {return fCanDrawAsMask;}
bool canDrawAsSDFT() const {return fCanDrawAsSDFT;}
uint32_t packedGlyphID() const {return fPackedGlyphID;}
private:
static_assert(SkPackedGlyphID::kEndData == 20);
uint64_t fPackedGlyphID : SkPackedGlyphID::kEndData;
uint64_t fIndex : SkPackedGlyphID::kEndData;
uint64_t fIsEmpty : 1;
uint64_t fIsColor : 1;
uint64_t fCanDrawAsMask : 1;
uint64_t fCanDrawAsSDFT : 1;
uint64_t fMaxDimension : 16;
};
// This class represents a strike: a specific combination of typeface, size, matrix, etc., and
// holds the glyphs for that strike.
class SkScalerCache {
@ -153,15 +121,7 @@ private:
// SkGlyphDigest's fIndex field stores the index. This pointer provides an unchanging
// reference to the SkGlyph as long as the strike is alive, and fGlyphForIndex
// provides a dense index for glyphs.
struct DigestTraits {
static uint32_t GetKey(SkGlyphDigest digest) {
return digest.packedGlyphID();
}
static uint32_t Hash(uint32_t packedGlyphID) {
return SkGoodHash()(packedGlyphID);
}
};
SkTHashTable<SkGlyphDigest, uint32_t, DigestTraits> fDigestForPackedGlyphID SK_GUARDED_BY(fMu);
SkTHashTable<SkGlyphDigest, uint32_t, SkGlyphDigest> fDigestForPackedGlyphID SK_GUARDED_BY(fMu);
std::vector<SkGlyph*> fGlyphForIndex SK_GUARDED_BY(fMu);
// so we don't grow our arrays a lot