introduce a subrun linked list
Create a simple linked list to sequence the subruns preparing the way for a more focused allocator for managing subruns at the end of the GrTextBlob. Change-Id: I595e2ce2810d161332a23405e4615724d2953471 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/366957 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
990a0d8b65
commit
55f795e696
@ -57,15 +57,15 @@ class DirectMaskGlyphVertexFillBenchmark : public Benchmark {
|
||||
glyphRun, view, drawOrigin, drawPaint, props, false, options, fBlob.get());
|
||||
}
|
||||
|
||||
SkASSERT(fBlob->subRunList().head() != nullptr);
|
||||
GrAtlasSubRun* subRun = fBlob->subRunList().head()->testingOnly_atlasSubRun();
|
||||
SkASSERT(!fBlob->subRunList().isEmpty());
|
||||
GrAtlasSubRun* subRun = fBlob->subRunList().front().testingOnly_atlasSubRun();
|
||||
SkASSERT(subRun);
|
||||
subRun->testingOnly_packedGlyphIDToGrGlyph(&fCache);
|
||||
fVertices.reset(new char[subRun->vertexStride(view) * subRun->glyphCount() * 4]);
|
||||
}
|
||||
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
GrAtlasSubRun* subRun = fBlob->subRunList().head()->testingOnly_atlasSubRun();
|
||||
GrAtlasSubRun* subRun = fBlob->subRunList().front().testingOnly_atlasSubRun();
|
||||
SkASSERT(subRun);
|
||||
|
||||
SkIRect clip = SkIRect::MakeEmpty();
|
||||
|
@ -443,8 +443,8 @@ void GrSurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
|
||||
}
|
||||
}
|
||||
|
||||
for (GrSubRun* subRun : blob->subRunList()) {
|
||||
subRun->draw(clip, viewMatrix, glyphRunList, this);
|
||||
for (GrSubRun& subRun : blob->subRunList()) {
|
||||
subRun.draw(clip, viewMatrix, glyphRunList, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,11 +470,11 @@ GrOp::Owner GrAtlasTextOp::CreateOpTestingOnly(GrSurfaceDrawContext* rtc,
|
||||
rtc->surfaceProps(),
|
||||
rContext->priv().caps()->shaderCaps()->supportsDistanceFieldText(),
|
||||
SDFOptions, blob.get());
|
||||
if (!blob->subRunList().head()) {
|
||||
if (blob->subRunList().isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrAtlasSubRun* subRun = blob->subRunList().head()->testingOnly_atlasSubRun();
|
||||
GrAtlasSubRun* subRun = blob->subRunList().front().testingOnly_atlasSubRun();
|
||||
SkASSERT(subRun);
|
||||
GrOp::Owner op;
|
||||
std::tie(std::ignore, op) = subRun->makeAtlasTextOp(nullptr, mtxProvider, glyphRunList, rtc);
|
||||
|
@ -1429,8 +1429,8 @@ bool GrTextBlob::canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (GrSubRun* subRun : this->subRunList()) {
|
||||
if (!subRun->canReuse(paint, drawMatrix)) {
|
||||
for (GrSubRun& subRun : this->fSubRunList) {
|
||||
if (!subRun.canReuse(paint, drawMatrix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1451,7 +1451,7 @@ void GrTextBlob::addMultiMaskFormat(
|
||||
auto addSameFormat = [&](const SkZip<SkGlyphVariant, SkPoint>& drawable, GrMaskFormat format) {
|
||||
GrSubRun* subRun = addSingle(drawable, strikeSpec, format, this, &fAlloc);
|
||||
if (subRun != nullptr) {
|
||||
this->insertSubRun(subRun);
|
||||
fSubRunList.append(subRun);
|
||||
} else {
|
||||
fSomeGlyphsExcluded = true;
|
||||
}
|
||||
@ -1483,10 +1483,6 @@ GrTextBlob::GrTextBlob(size_t allocSize,
|
||||
, fInitialLuminance{initialLuminance}
|
||||
, fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { }
|
||||
|
||||
void GrTextBlob::insertSubRun(GrSubRun* subRun) {
|
||||
fSubRunList.addToTail(subRun);
|
||||
}
|
||||
|
||||
void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec) {
|
||||
|
||||
@ -1501,7 +1497,7 @@ void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawab
|
||||
strikeSpec,
|
||||
*this,
|
||||
&fAlloc);
|
||||
this->insertSubRun(subRun);
|
||||
fSubRunList.append(subRun);
|
||||
}
|
||||
|
||||
void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
@ -1511,7 +1507,7 @@ void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawabl
|
||||
SkScalar maxScale) {
|
||||
this->setMinAndMaxScale(minScale, maxScale);
|
||||
GrSubRun* subRun = SDFTSubRun::Make(drawables, runFont, strikeSpec, this, &fAlloc);
|
||||
this->insertSubRun(subRun);
|
||||
fSubRunList.append(subRun);
|
||||
}
|
||||
|
||||
void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
|
@ -37,125 +37,6 @@ class SkSurfaceProps;
|
||||
class SkTextBlob;
|
||||
class SkTextBlobRunIterator;
|
||||
|
||||
// A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
|
||||
// on the GPU. These are initially created with valid positions and colors, but invalid
|
||||
// texture coordinates.
|
||||
//
|
||||
// A GrTextBlob contains a number of SubRuns that are created in the blob's arena. Each SubRun
|
||||
// tracks its own GrGlyph* and vertex data. The memory is organized in the arena in the following
|
||||
// way so that the pointers for the GrGlyph* and vertex data are known before creating the SubRun.
|
||||
//
|
||||
// GrGlyph*... | vertexData... | SubRun | GrGlyph*... | vertexData... | SubRun etc.
|
||||
//
|
||||
// In these classes, I'm trying to follow the convention about matrices and origins.
|
||||
// * draw Matrix|Origin - describes the current draw command.
|
||||
// * initial Matrix - describes the combined initial matrix and origin the GrTextBlob was created
|
||||
// with.
|
||||
//
|
||||
//
|
||||
class GrTextBlob final : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
|
||||
public:
|
||||
struct Key {
|
||||
Key();
|
||||
uint32_t fUniqueID;
|
||||
// Color may affect the gamma of the mask we generate, but in a fairly limited way.
|
||||
// Each color is assigned to on of a fixed number of buckets based on its
|
||||
// luminance. For each luminance bucket there is a "canonical color" that
|
||||
// represents the bucket. This functionality is currently only supported for A8
|
||||
SkColor fCanonicalColor;
|
||||
SkPaint::Style fStyle;
|
||||
SkScalar fFrameWidth;
|
||||
SkScalar fMiterLimit;
|
||||
SkPaint::Join fJoin;
|
||||
SkPixelGeometry fPixelGeometry;
|
||||
bool fHasBlur;
|
||||
SkMaskFilterBase::BlurRec fBlurRec;
|
||||
uint32_t fScalerContextFlags;
|
||||
|
||||
bool operator==(const Key& other) const;
|
||||
};
|
||||
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
|
||||
|
||||
// Change memory management to handle the data after GrTextBlob, but in the same allocation
|
||||
// of memory. Only allow placement new.
|
||||
void operator delete(void* p);
|
||||
void* operator new(size_t);
|
||||
void* operator new(size_t, void* p);
|
||||
|
||||
~GrTextBlob() override;
|
||||
|
||||
// Make an empty GrTextBlob, with all the invariants set to make the right decisions when
|
||||
// adding SubRuns.
|
||||
static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList,
|
||||
const SkMatrix& drawMatrix);
|
||||
|
||||
static const Key& GetKey(const GrTextBlob& blob);
|
||||
static uint32_t Hash(const Key& key);
|
||||
|
||||
void addKey(const Key& key);
|
||||
bool hasPerspective() const;
|
||||
const SkMatrix& initialMatrix() const { return fInitialMatrix; }
|
||||
|
||||
void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax);
|
||||
std::tuple<SkScalar, SkScalar> scaleBounds() const {
|
||||
return {fMaxMinScale, fMinMaxScale};
|
||||
}
|
||||
|
||||
bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix);
|
||||
|
||||
const Key& key() const;
|
||||
size_t size() const;
|
||||
|
||||
template<typename AddSingleMaskFormat>
|
||||
void addMultiMaskFormat(
|
||||
AddSingleMaskFormat addSingle,
|
||||
const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec);
|
||||
|
||||
const SkTInternalLList<GrSubRun>& subRunList() const { return fSubRunList; }
|
||||
|
||||
private:
|
||||
GrTextBlob(size_t allocSize, const SkMatrix& drawMatrix, SkColor initialLuminance);
|
||||
|
||||
void insertSubRun(GrSubRun* subRun);
|
||||
|
||||
// Methods to satisfy SkGlyphRunPainterInterface
|
||||
void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkFont& runFont,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec,
|
||||
const SkFont& runFont,
|
||||
SkScalar minScale,
|
||||
SkScalar maxScale) override;
|
||||
void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
|
||||
// Overall size of this struct plus vertices and glyphs at the end.
|
||||
const size_t fSize;
|
||||
|
||||
// The initial view matrix combined with the initial origin. Used to determine if a cached
|
||||
// subRun can be used in this draw situation.
|
||||
const SkMatrix fInitialMatrix;
|
||||
|
||||
const SkColor fInitialLuminance;
|
||||
|
||||
Key fKey;
|
||||
|
||||
// We can reuse distance field text, but only if the new view matrix would not result in
|
||||
// a mip change. Because there can be multiple runs in a blob, we track the overall
|
||||
// maximum minimum scale, and minimum maximum scale, we can support before we need to regen
|
||||
SkScalar fMaxMinScale{-SK_ScalarMax};
|
||||
SkScalar fMinMaxScale{SK_ScalarMax};
|
||||
|
||||
bool fSomeGlyphsExcluded{false};
|
||||
SkTInternalLList<GrSubRun> fSubRunList;
|
||||
SkArenaAlloc fAlloc;
|
||||
};
|
||||
|
||||
// -- GrAtlasSubRun --------------------------------------------------------------------------------
|
||||
// GrAtlasSubRun is the API that GrAtlasTextOp uses to generate vertex data for drawing.
|
||||
// There are three different ways GrAtlasSubRun is specialized.
|
||||
@ -222,7 +103,158 @@ public:
|
||||
// * Don't use this API. It is only to support testing.
|
||||
virtual GrAtlasSubRun* testingOnly_atlasSubRun() = 0;
|
||||
|
||||
GrSubRun* fNext{nullptr};
|
||||
};
|
||||
|
||||
struct GrSubRunList {
|
||||
class Iterator {
|
||||
public:
|
||||
using value_type = GrSubRun;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
constexpr Iterator(GrSubRun* subRun) : fPtr{subRun} { }
|
||||
constexpr Iterator& operator++() { fPtr = fPtr->fNext; return *this; }
|
||||
constexpr Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
|
||||
constexpr bool operator==(const Iterator& rhs) const { return fPtr == rhs.fPtr; }
|
||||
constexpr bool operator!=(const Iterator& rhs) const { return fPtr != rhs.fPtr; }
|
||||
constexpr reference operator*() { return *fPtr; }
|
||||
|
||||
private:
|
||||
GrSubRun* fPtr;
|
||||
};
|
||||
|
||||
void append(GrSubRun* subRun) {
|
||||
GrSubRun** newTail = &subRun->fNext;
|
||||
*fTail = subRun;
|
||||
fTail = newTail;
|
||||
}
|
||||
bool isEmpty() const { return fHead == nullptr; }
|
||||
Iterator begin() { return Iterator{fHead}; }
|
||||
Iterator end() { return Iterator{nullptr}; }
|
||||
GrSubRun& front() const {return *fHead; }
|
||||
|
||||
GrSubRun* fHead{nullptr};
|
||||
GrSubRun** fTail{&fHead};
|
||||
};
|
||||
|
||||
// A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
|
||||
// on the GPU. These are initially created with valid positions and colors, but invalid
|
||||
// texture coordinates.
|
||||
//
|
||||
// A GrTextBlob contains a number of SubRuns that are created in the blob's arena. Each SubRun
|
||||
// tracks its own GrGlyph* and vertex data. The memory is organized in the arena in the following
|
||||
// way so that the pointers for the GrGlyph* and vertex data are known before creating the SubRun.
|
||||
//
|
||||
// GrGlyph*... | vertexData... | SubRun | GrGlyph*... | vertexData... | SubRun etc.
|
||||
//
|
||||
// In these classes, I'm trying to follow the convention about matrices and origins.
|
||||
// * draw Matrix|Origin - describes the current draw command.
|
||||
// * initial Matrix - describes the combined initial matrix and origin the GrTextBlob was created
|
||||
// with.
|
||||
//
|
||||
//
|
||||
class GrTextBlob final : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
|
||||
public:
|
||||
struct Key {
|
||||
Key();
|
||||
uint32_t fUniqueID;
|
||||
// Color may affect the gamma of the mask we generate, but in a fairly limited way.
|
||||
// Each color is assigned to on of a fixed number of buckets based on its
|
||||
// luminance. For each luminance bucket there is a "canonical color" that
|
||||
// represents the bucket. This functionality is currently only supported for A8
|
||||
SkColor fCanonicalColor;
|
||||
SkPaint::Style fStyle;
|
||||
SkScalar fFrameWidth;
|
||||
SkScalar fMiterLimit;
|
||||
SkPaint::Join fJoin;
|
||||
SkPixelGeometry fPixelGeometry;
|
||||
bool fHasBlur;
|
||||
SkMaskFilterBase::BlurRec fBlurRec;
|
||||
uint32_t fScalerContextFlags;
|
||||
|
||||
bool operator==(const Key& other) const;
|
||||
};
|
||||
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
|
||||
|
||||
// Make an empty GrTextBlob, with all the invariants set to make the right decisions when
|
||||
// adding SubRuns.
|
||||
static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList,
|
||||
const SkMatrix& drawMatrix);
|
||||
|
||||
~GrTextBlob() override;
|
||||
|
||||
// Change memory management to handle the data after GrTextBlob, but in the same allocation
|
||||
// of memory. Only allow placement new.
|
||||
void operator delete(void* p);
|
||||
void* operator new(size_t);
|
||||
void* operator new(size_t, void* p);
|
||||
|
||||
static const Key& GetKey(const GrTextBlob& blob);
|
||||
static uint32_t Hash(const Key& key);
|
||||
|
||||
void addKey(const Key& key);
|
||||
bool hasPerspective() const;
|
||||
const SkMatrix& initialMatrix() const { return fInitialMatrix; }
|
||||
|
||||
void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax);
|
||||
std::tuple<SkScalar, SkScalar> scaleBounds() const {
|
||||
return {fMaxMinScale, fMinMaxScale};
|
||||
}
|
||||
|
||||
bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix);
|
||||
|
||||
const Key& key() const;
|
||||
size_t size() const;
|
||||
|
||||
template<typename AddSingleMaskFormat>
|
||||
void addMultiMaskFormat(
|
||||
AddSingleMaskFormat addSingle,
|
||||
const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec);
|
||||
|
||||
GrSubRunList& subRunList() {
|
||||
return fSubRunList;
|
||||
}
|
||||
|
||||
private:
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun);
|
||||
GrTextBlob(size_t allocSize, const SkMatrix& drawMatrix, SkColor initialLuminance);
|
||||
|
||||
// Methods to satisfy SkGlyphRunPainterInterface
|
||||
void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkFont& runFont,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec,
|
||||
const SkFont& runFont,
|
||||
SkScalar minScale,
|
||||
SkScalar maxScale) override;
|
||||
void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
const SkStrikeSpec& strikeSpec) override;
|
||||
|
||||
// Overall size of this struct plus vertices and glyphs at the end.
|
||||
const size_t fSize;
|
||||
|
||||
// The initial view matrix combined with the initial origin. Used to determine if a cached
|
||||
// subRun can be used in this draw situation.
|
||||
const SkMatrix fInitialMatrix;
|
||||
|
||||
const SkColor fInitialLuminance;
|
||||
|
||||
Key fKey;
|
||||
|
||||
// We can reuse distance field text, but only if the new view matrix would not result in
|
||||
// a mip change. Because there can be multiple runs in a blob, we track the overall
|
||||
// maximum minimum scale, and minimum maximum scale, we can support before we need to regen
|
||||
SkScalar fMaxMinScale{-SK_ScalarMax};
|
||||
SkScalar fMinMaxScale{SK_ScalarMax};
|
||||
|
||||
bool fSomeGlyphsExcluded{false};
|
||||
GrSubRunList fSubRunList;
|
||||
SkArenaAlloc fAlloc;
|
||||
};
|
||||
#endif // GrTextBlob_DEFINED
|
||||
|
Loading…
Reference in New Issue
Block a user