Consolidate the conversion of plot location to uvs to be w/in GrDrawOpAtlas

Bug: 1056730
Change-Id: Icb3e8e32585d1abc38205e1baf86b5a5291c8d8a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/281196
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2020-04-06 10:29:28 -04:00 committed by Skia Commit-Bot
parent 9b56cea5fa
commit 6d3bc2951d
13 changed files with 198 additions and 228 deletions

View File

@ -24,6 +24,20 @@
static bool gDumpAtlasData = false;
#endif
std::array<uint16_t, 4> GrDrawOpAtlas::AtlasLocator::getUVs(int padding) const {
uint16_t left = fRect.fLeft + padding;
uint16_t top = fRect.fTop + padding;
uint16_t right = fRect.fRight - padding;
uint16_t bottom = fRect.fBottom - padding;
// We pack the 2bit page index in the low bit of the u and v texture coords
uint32_t pageIndex = this->pageIndex();
std::tie(left, bottom) = GrDrawOpAtlas::PackIndexInTexCoords(left, bottom, pageIndex);
std::tie(right, top) = GrDrawOpAtlas::PackIndexInTexCoords(right, top, pageIndex);
return { left, top, right, bottom };
}
// When proxy allocation is deferred until flush time the proxies acting as atlases require
// special handling. This is because the usage that can be determined from the ops themselves
// isn't sufficient. Independent of the ops there will be ASAP and inline uploads to the
@ -125,13 +139,16 @@ GrDrawOpAtlas::Plot::~Plot() {
sk_free(fData);
}
bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, GrIRect16* rect) {
SkASSERT(width <= fWidth && height <= fHeight);
if (!fRectanizer.addRect(width, height, loc)) {
SkIPoint16 loc;
if (!fRectanizer.addRect(width, height, &loc)) {
return false;
}
*rect = GrIRect16::MakeXYWH(loc.fX, loc.fY, width, height);
if (!fData) {
fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPixel * fWidth *
fHeight));
@ -140,8 +157,8 @@ bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image,
const unsigned char* imagePtr = (const unsigned char*)image;
// point ourselves at the right starting spot
unsigned char* dataPtr = fData;
dataPtr += fBytesPerPixel * fWidth * loc->fY;
dataPtr += fBytesPerPixel * loc->fX;
dataPtr += fBytesPerPixel * fWidth * rect->fTop;
dataPtr += fBytesPerPixel * rect->fLeft;
// copy into the data buffer, swizzling as we go if this is ARGB data
if (4 == fBytesPerPixel && kN32_SkColorType == kBGRA_8888_SkColorType) {
for (int i = 0; i < height; ++i) {
@ -157,10 +174,9 @@ bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image,
}
}
fDirtyRect.join({loc->fX, loc->fY, loc->fX + width, loc->fY + height});
fDirtyRect.join({rect->fLeft, rect->fTop, rect->fRight, rect->fBottom});
loc->fX += fOffset.fX;
loc->fY += fOffset.fY;
rect->offset(fOffset.fX, fOffset.fY);
SkDEBUGCODE(fDirty = true;)
return true;
@ -244,8 +260,8 @@ inline void GrDrawOpAtlas::processEviction(PlotLocator plotLocator) {
}
inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target,
PlotLocator* plotLocator, Plot* plot) {
int pageIdx = GetPageIndexFromID(plot->plotLocator());
AtlasLocator* atlasLocator, Plot* plot) {
int pageIdx = plot->pageIndex();
this->makeMRU(plot, pageIdx);
// If our most recent upload has already occurred then we have to insert a new
@ -264,13 +280,13 @@ inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target,
});
plot->setLastUploadToken(lastUploadToken);
}
*plotLocator = plot->plotLocator();
atlasLocator->fPlotLocator = plot->plotLocator();
return true;
}
bool GrDrawOpAtlas::uploadToPage(const GrCaps& caps, unsigned int pageIdx, PlotLocator* plotLocator,
bool GrDrawOpAtlas::uploadToPage(const GrCaps& caps, unsigned int pageIdx,
GrDeferredUploadTarget* target, int width, int height,
const void* image, SkIPoint16* loc) {
const void* image, AtlasLocator* atlasLocator) {
SkASSERT(fViews[pageIdx].proxy() && fViews[pageIdx].proxy()->isInstantiated());
// look through all allocated plots for one we can share, in Most Recently Refed order
@ -280,8 +296,8 @@ bool GrDrawOpAtlas::uploadToPage(const GrCaps& caps, unsigned int pageIdx, PlotL
for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
SkASSERT(caps.bytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) == plot->bpp());
if (plot->addSubImage(width, height, image, loc)) {
return this->updatePlot(target, plotLocator, plot);
if (plot->addSubImage(width, height, image, &atlasLocator->fRect)) {
return this->updatePlot(target, atlasLocator, plot);
}
}
@ -298,10 +314,9 @@ static constexpr auto kPlotRecentlyUsedCount = 256;
static constexpr auto kAtlasRecentlyUsedCount = 1024;
GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceProvider,
PlotLocator* plotLocator,
GrDeferredUploadTarget* target,
int width, int height,
const void* image, SkIPoint16* loc) {
int width, int height, const void* image,
AtlasLocator* atlasLocator) {
if (width > fPlotWidth || height > fPlotHeight) {
return ErrorCode::kError;
}
@ -312,7 +327,7 @@ GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceP
// We prioritize this upload to the first pages, not the most recently used, to make it easier
// to remove unused pages in reverse page order.
for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
if (this->uploadToPage(caps, pageIdx, plotLocator, target, width, height, image, loc)) {
if (this->uploadToPage(caps, pageIdx, target, width, height, image, atlasLocator)) {
return ErrorCode::kSucceeded;
}
}
@ -330,9 +345,10 @@ GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceP
this->processEvictionAndResetRects(plot);
SkASSERT(caps.bytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
plot->bpp());
SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image,
&atlasLocator->fRect);
SkASSERT(verify);
if (!this->updatePlot(target, plotLocator, plot)) {
if (!this->updatePlot(target, atlasLocator, plot)) {
return ErrorCode::kError;
}
return ErrorCode::kSucceeded;
@ -344,8 +360,8 @@ GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceP
return ErrorCode::kError;
}
if (this->uploadToPage(
caps, fNumActivePages-1, plotLocator, target, width, height, image, loc)) {
if (this->uploadToPage(caps, fNumActivePages-1, target, width, height, image,
atlasLocator)) {
return ErrorCode::kSucceeded;
} else {
// If we fail to upload to a newly activated page then something has gone terribly
@ -379,14 +395,14 @@ GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceP
}
this->processEviction(plot->plotLocator());
int pageIdx = GetPageIndexFromID(plot->plotLocator());
int pageIdx = plot->pageIndex();
fPages[pageIdx].fPlotList.remove(plot);
sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->index()];
sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->plotIndex()];
newPlot.reset(plot->clone());
fPages[pageIdx].fPlotList.addToHead(newPlot.get());
SkASSERT(caps.bytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) == newPlot->bpp());
SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc);
SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, &atlasLocator->fRect);
SkASSERT(verify);
// Note that this plot will be uploaded inline with the draws whereas the
@ -403,7 +419,7 @@ GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceP
});
newPlot->setLastUploadToken(lastUploadToken);
*plotLocator = newPlot->plotLocator();
atlasLocator->fPlotLocator = newPlot->plotLocator();
return ErrorCode::kSucceeded;
}

View File

@ -70,6 +70,40 @@ public:
static const uint64_t kInvalidPlotLocator = 0;
static const uint64_t kInvalidAtlasGeneration = 0;
class AtlasLocator {
public:
std::array<uint16_t, 4> getUVs(int padding) const;
// TODO: Remove the small path renderer's use of this for eviction
GrDrawOpAtlas::PlotLocator plotLocator() const { return fPlotLocator; }
uint32_t pageIndex() const {
uint32_t pageIndex = fPlotLocator & 0xff;
SkASSERT(pageIndex < 4);
return pageIndex;
}
uint32_t plotIndex() const {
uint32_t plotIndex = (fPlotLocator >> 8) & 0xff;
SkASSERT(plotIndex < kMaxPlots);
return plotIndex;
}
uint64_t genID() const {
// top 48 bits are reserved for the generation ID
return (fPlotLocator >> 16) & 0xffffffffffff;
}
private:
friend class GrDrawOpAtlas;
GrDrawOpAtlas::PlotLocator fPlotLocator{GrDrawOpAtlas::kInvalidPlotLocator};
GrIRect16 fRect{0, 0, 0, 0};
// TODO: the inset to the actual data w/in 'fRect' could also be stored in this class
// This would simplify the 'getUVs' call. The valid values would be 0, 1, 2 & 4.
};
/**
* An interface for eviction callbacks. Whenever GrDrawOpAtlas evicts a
* specific PlotLocator, it will call all of the registered listeners so they can process the
@ -160,32 +194,31 @@ public:
kTryAgain
};
ErrorCode addToAtlas(GrResourceProvider*, PlotLocator*, GrDeferredUploadTarget*,
int width, int height,
const void* image, SkIPoint16* loc);
ErrorCode addToAtlas(GrResourceProvider*, GrDeferredUploadTarget*,
int width, int height, const void* image, AtlasLocator*);
const GrSurfaceProxyView* getViews() const { return fViews; }
uint64_t atlasGeneration() const { return fAtlasGeneration; }
bool hasID(PlotLocator plotLocator) {
if (kInvalidPlotLocator == plotLocator) {
bool hasID(const AtlasLocator& atlasLocator) {
if (kInvalidPlotLocator == atlasLocator.fPlotLocator) {
return false;
}
uint32_t plot = GetPlotIndexFromID(plotLocator);
uint32_t page = GetPageIndexFromID(plotLocator);
uint32_t plot = atlasLocator.plotIndex();
uint32_t page = atlasLocator.pageIndex();
uint64_t plotGeneration = fPages[page].fPlotArray[plot]->genID();
uint64_t locatorGeneration = GetGenerationFromID(plotLocator);
uint64_t locatorGeneration = atlasLocator.genID();
return plot < fNumPlots && page < fNumActivePages && plotGeneration == locatorGeneration;
}
/** To ensure the atlas does not evict a given entry, the client must set the last use token. */
void setLastUseToken(PlotLocator plotLocator, GrDeferredUploadToken token) {
SkASSERT(this->hasID(plotLocator));
uint32_t plotIdx = GetPlotIndexFromID(plotLocator);
void setLastUseToken(const AtlasLocator& atlasLocator, GrDeferredUploadToken token) {
SkASSERT(this->hasID(atlasLocator));
uint32_t plotIdx = atlasLocator.plotIndex();
SkASSERT(plotIdx < fNumPlots);
uint32_t pageIdx = GetPageIndexFromID(plotLocator);
uint32_t pageIdx = atlasLocator.pageIndex();
SkASSERT(pageIdx < fNumActivePages);
Plot* plot = fPages[pageIdx].fPlotArray[plotIdx].get();
this->makeMRU(plot, pageIdx);
@ -205,17 +238,17 @@ public:
memset(fPlotAlreadyUpdated, 0, sizeof(fPlotAlreadyUpdated));
}
BulkUseTokenUpdater(const BulkUseTokenUpdater& that)
: fPlotsToUpdate(that.fPlotsToUpdate) {
: fPlotsToUpdate(that.fPlotsToUpdate) {
memcpy(fPlotAlreadyUpdated, that.fPlotAlreadyUpdated, sizeof(fPlotAlreadyUpdated));
}
bool add(PlotLocator plotLocator) {
int index = GrDrawOpAtlas::GetPlotIndexFromID(plotLocator);
int pageIdx = GrDrawOpAtlas::GetPageIndexFromID(plotLocator);
if (this->find(pageIdx, index)) {
bool add(const AtlasLocator& atlasLocator) {
int plotIdx = atlasLocator.plotIndex();
int pageIdx = atlasLocator.pageIndex();
if (this->find(pageIdx, plotIdx)) {
return false;
}
this->set(pageIdx, index);
this->set(pageIdx, plotIdx);
return true;
}
@ -266,10 +299,6 @@ public:
void compact(GrDeferredUploadToken startTokenForNextFlush);
static uint32_t GetPageIndexFromID(PlotLocator plotLocator) {
return plotLocator & 0xff;
}
void instantiate(GrOnFlushResourceProvider*);
uint32_t maxPages() const {
@ -295,8 +324,10 @@ private:
SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot);
public:
/** index() is a unique id for the plot relative to the owning GrAtlas and page. */
uint32_t index() const { return fPlotIndex; }
uint32_t pageIndex() const { return fPageIndex; }
/** plotIndex() is a unique id for the plot relative to the owning GrAtlas and page. */
uint32_t plotIndex() const { return fPlotIndex; }
/**
* genID() is incremented when the plot is evicted due to a atlas spill. It is used to know
* if a particular subimage is still present in the atlas.
@ -308,7 +339,7 @@ private:
}
SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; })
bool addSubImage(int width, int height, const void* image, SkIPoint16* loc);
bool addSubImage(int width, int height, const void* image, GrIRect16* rect);
/**
* To manage the lifetime of a plot, we use two tokens. We use the last upload token to
@ -384,16 +415,7 @@ private:
typedef SkTInternalLList<Plot> PlotList;
static uint32_t GetPlotIndexFromID(PlotLocator plotLocator) {
return (plotLocator >> 8) & 0xff;
}
// top 48 bits are reserved for the generation ID
static uint64_t GetGenerationFromID(PlotLocator plotLocator) {
return (plotLocator >> 16) & 0xffffffffffff;
}
inline bool updatePlot(GrDeferredUploadTarget*, PlotLocator*, Plot*);
inline bool updatePlot(GrDeferredUploadTarget*, AtlasLocator*, Plot*);
inline void makeMRU(Plot* plot, int pageIdx) {
if (fPages[pageIdx].fPlotList.head() == plot) {
@ -407,9 +429,8 @@ private:
// the front and remove from the back there is no need for MRU.
}
bool uploadToPage(const GrCaps&, unsigned int pageIdx, PlotLocator* plotLocator,
GrDeferredUploadTarget* target, int width, int height, const void* image,
SkIPoint16* loc);
bool uploadToPage(const GrCaps&, unsigned int pageIdx, GrDeferredUploadTarget*,
int width, int height, const void* image, AtlasLocator*);
bool createPages(GrProxyProvider*, GenerationCounter*);
bool activateNewPage(GrResourceProvider*);

View File

@ -36,20 +36,10 @@ public:
SkUNREACHABLE;
}
GrGlyph(const SkGlyph& skGlyph)
: fPackedID{skGlyph.getPackedID()}
, fWidthHeight(SkIPoint16::Make(skGlyph.width(), skGlyph.height())) {
}
GrGlyph(const SkGlyph& skGlyph) : fPackedID(skGlyph.getPackedID()) {}
int width() const { return fWidthHeight.fX; }
int height() const { return fWidthHeight.fY; }
uint32_t pageIndex() const { return GrDrawOpAtlas::GetPageIndexFromID(fPlotLocator); }
const SkPackedGlyphID fPackedID;
const SkIPoint16 fWidthHeight{0, 0};
SkIPoint16 fAtlasLocation{0, 0};
GrDrawOpAtlas::PlotLocator fPlotLocator{GrDrawOpAtlas::kInvalidPlotLocator};
const SkPackedGlyphID fPackedID;
GrDrawOpAtlas::AtlasLocator fAtlasLocator;
};
#endif

View File

@ -124,6 +124,10 @@ struct GrVertexWriter {
return { r.fLeft, r.fTop, r.fRight, r.fBottom };
}
static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
return { rect[0], rect[1], rect[2], rect[3] };
}
template <typename T>
struct TriFan { T l, t, r, b; };

View File

@ -60,6 +60,13 @@ struct GrIRect16 {
fRight = SkToS16(r.fRight);
fBottom = SkToS16(r.fBottom);
}
void offset(int16_t dx, int16_t dy) {
fLeft += dx;
fTop += dy;
fRight += dx;
fBottom += dy;
}
};
/** Returns true if the rectangles have a nonzero area of overlap. It assumed that rects can be

View File

@ -116,10 +116,10 @@ private:
class ShapeData {
public:
ShapeDataKey fKey;
GrDrawOpAtlas::PlotLocator fPlotLocator;
SkRect fBounds;
GrIRect16 fTextureCoords;
ShapeDataKey fKey;
SkRect fBounds;
GrDrawOpAtlas::AtlasLocator fAtlasLocator;
SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData);
static inline const ShapeDataKey& GetKey(const ShapeData& data) {
@ -141,7 +141,7 @@ void GrSmallPathRenderer::evict(GrDrawOpAtlas::PlotLocator plotLocator) {
ShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
if (plotLocator == shapeData->fPlotLocator) {
if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;
@ -214,7 +214,7 @@ GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPath
////////////////////////////////////////////////////////////////////////////////
// padding around path bounds to allow for antialiased pixels
static const SkScalar kAntiAliasPad = 1.0f;
static const int kAntiAliasPad = 1;
class GrSmallPathRenderer::SmallPathOp final : public GrMeshDrawOp {
private:
@ -458,7 +458,7 @@ private:
// check to see if df path is cached
ShapeDataKey key(args.fShape, SkScalarCeilToInt(desiredDimension));
shapeData = fShapeCache->find(key);
if (nullptr == shapeData || !fAtlas->hasID(shapeData->fPlotLocator)) {
if (nullptr == shapeData || !fAtlas->hasID(shapeData->fAtlasLocator)) {
// Remove the stale cache entry
if (shapeData) {
fShapeCache->remove(shapeData->fKey);
@ -483,7 +483,7 @@ private:
// check to see if bitmap path is cached
ShapeDataKey key(args.fShape, args.fViewMatrix);
shapeData = fShapeCache->find(key);
if (nullptr == shapeData || !fAtlas->hasID(shapeData->fPlotLocator)) {
if (nullptr == shapeData || !fAtlas->hasID(shapeData->fAtlasLocator)) {
// Remove the stale cache entry
if (shapeData) {
fShapeCache->remove(shapeData->fKey);
@ -506,7 +506,7 @@ private:
auto uploadTarget = target->deferredUploadTarget();
fAtlas->setLastUseToken(
shapeData->fPlotLocator, uploadTarget->tokenTracker()->nextDrawToken());
shapeData->fAtlasLocator, uploadTarget->tokenTracker()->nextDrawToken());
this->writePathVertices(fAtlas, vertices, GrVertexColor(args.fColor, fWideColor),
args.fViewMatrix, shapeData);
@ -518,13 +518,12 @@ private:
bool addToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrDrawOpAtlas* atlas,
int width, int height, const void* image,
GrDrawOpAtlas::PlotLocator* plotLocator, SkIPoint16* atlasLocation) const {
GrDrawOpAtlas::AtlasLocator* atlasLocator) const {
auto resourceProvider = target->resourceProvider();
auto uploadTarget = target->deferredUploadTarget();
GrDrawOpAtlas::ErrorCode code = atlas->addToAtlas(resourceProvider, plotLocator,
uploadTarget, width, height,
image, atlasLocation);
GrDrawOpAtlas::ErrorCode code = atlas->addToAtlas(resourceProvider, uploadTarget,
width, height, image, atlasLocator);
if (GrDrawOpAtlas::ErrorCode::kError == code) {
return false;
}
@ -532,8 +531,8 @@ private:
if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
this->flush(target, flushInfo);
code = atlas->addToAtlas(resourceProvider, plotLocator, uploadTarget, width, height,
image, atlasLocation);
code = atlas->addToAtlas(resourceProvider, uploadTarget, width, height,
image, atlasLocator);
}
return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
@ -560,14 +559,12 @@ private:
// get integer boundary
SkIRect devPathBounds;
scaledBounds.roundOut(&devPathBounds);
// pad to allow room for antialiasing
const int intPad = SkScalarCeilToInt(kAntiAliasPad);
// place devBounds at origin
int width = devPathBounds.width() + 2*intPad;
int height = devPathBounds.height() + 2*intPad;
// place devBounds at origin with padding to allow room for antialiasing
int width = devPathBounds.width() + 2 * kAntiAliasPad;
int height = devPathBounds.height() + 2 * kAntiAliasPad;
devPathBounds = SkIRect::MakeWH(width, height);
SkScalar translateX = intPad - dx;
SkScalar translateY = intPad - dy;
SkScalar translateX = kAntiAliasPad - dx;
SkScalar translateY = kAntiAliasPad - dy;
// draw path to bitmap
SkMatrix drawMatrix;
@ -623,17 +620,13 @@ private:
}
// add to atlas
SkIPoint16 atlasLocation;
GrDrawOpAtlas::PlotLocator plotLocator;
if (!this->addToAtlas(target, flushInfo, atlas,
width, height, dfStorage.get(), &plotLocator, &atlasLocation)) {
if (!this->addToAtlas(target, flushInfo, atlas, width, height, dfStorage.get(),
&shapeData->fAtlasLocator)) {
return false;
}
// add to cache
shapeData->fKey.set(shape, dimension);
shapeData->fPlotLocator = plotLocator;
shapeData->fBounds = SkRect::Make(devPathBounds);
shapeData->fBounds.offset(-translateX, -translateY);
@ -642,20 +635,6 @@ private:
shapeData->fBounds.fRight /= scale;
shapeData->fBounds.fBottom /= scale;
// Pack the page index into the u and v texture coords
uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(plotLocator);
uint16_t left, top, right, bottom;
std::tie(left, top, right, bottom) =
std::make_tuple(atlasLocation.fX + SK_DistanceFieldPad,
atlasLocation.fY + SK_DistanceFieldPad,
atlasLocation.fX + SK_DistanceFieldPad + devPathBounds.width(),
atlasLocation.fY + SK_DistanceFieldPad + devPathBounds.height());
std::tie(left, top) =
GrDrawOpAtlas::PackIndexInTexCoords(left, top, pageIndex);
std::tie(right, bottom) =
GrDrawOpAtlas::PackIndexInTexCoords(right, bottom, pageIndex);
shapeData->fTextureCoords.set(left, top, right, bottom);
fShapeCache->add(shapeData);
fShapeList->addToTail(shapeData);
#ifdef DF_PATH_TRACKING
@ -686,14 +665,12 @@ private:
// get integer boundary
SkIRect devPathBounds;
shapeDevBounds.roundOut(&devPathBounds);
// pad to allow room for antialiasing
const int intPad = SkScalarCeilToInt(kAntiAliasPad);
// place devBounds at origin
int width = devPathBounds.width() + 2 * intPad;
int height = devPathBounds.height() + 2 * intPad;
// place devBounds at origin with padding to allow room for antialiasing
int width = devPathBounds.width() + 2 * kAntiAliasPad;
int height = devPathBounds.height() + 2 * kAntiAliasPad;
devPathBounds = SkIRect::MakeWH(width, height);
SkScalar translateX = intPad - dx;
SkScalar translateY = intPad - dy;
SkScalar translateX = kAntiAliasPad - dx;
SkScalar translateY = kAntiAliasPad - dy;
SkASSERT(devPathBounds.fLeft == 0);
SkASSERT(devPathBounds.fTop == 0);
@ -727,33 +704,17 @@ private:
draw.drawPathCoverage(path, paint);
// add to atlas
SkIPoint16 atlasLocation;
GrDrawOpAtlas::PlotLocator plotLocator;
if (!this->addToAtlas(target, flushInfo, atlas, dst.width(), dst.height(),
dst.addr(), &plotLocator, &atlasLocation)) {
if (!this->addToAtlas(target, flushInfo, atlas, dst.width(), dst.height(), dst.addr(),
&shapeData->fAtlasLocator)) {
return false;
}
// add to cache
shapeData->fKey.set(shape, ctm);
shapeData->fPlotLocator = plotLocator;
shapeData->fBounds = SkRect::Make(devPathBounds);
shapeData->fBounds.offset(-translateX, -translateY);
// Pack the page index into the u and v texture coords
uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(plotLocator);
uint16_t left, top, right, bottom;
std::tie(left, top, right, bottom) = std::make_tuple(atlasLocation.fX, atlasLocation.fY,
atlasLocation.fX+width,
atlasLocation.fY+height);
std::tie(left, top) =
GrDrawOpAtlas::PackIndexInTexCoords(left, top, pageIndex);
std::tie(right, bottom) =
GrDrawOpAtlas::PackIndexInTexCoords(right, bottom, pageIndex);
shapeData->fTextureCoords.set(left, top, right, bottom);
fShapeCache->add(shapeData);
fShapeList->addToTail(shapeData);
#ifdef DF_PATH_TRACKING
@ -774,12 +735,8 @@ private:
}
// set up texture coordinates
GrVertexWriter::TriStrip<uint16_t> texCoords{
(uint16_t)shapeData->fTextureCoords.fLeft,
(uint16_t)shapeData->fTextureCoords.fTop,
(uint16_t)shapeData->fTextureCoords.fRight,
(uint16_t)shapeData->fTextureCoords.fBottom
};
auto texCoords = GrVertexWriter::TriStripFromUVs(shapeData->fAtlasLocator.getUVs(
fUsesDistanceField ? SK_DistanceFieldPad : 0));
if (fUsesDistanceField && !ctm.hasPerspective()) {
vertices.writeQuad(GrQuad::MakeFromRect(translatedBounds, ctm),
@ -959,7 +916,7 @@ struct GrSmallPathRenderer::PathTestStruct : public GrDrawOpAtlas::EvictionCallb
ShapeData* shapeData;
while ((shapeData = iter.get())) {
iter.next();
if (plotLocator == shapeData->fPlotLocator) {
if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
fShapeCache.remove(shapeData->fKey);
fShapeList.remove(shapeData);
delete shapeData;

View File

@ -30,25 +30,25 @@ void GrAtlasManager::freeAll() {
bool GrAtlasManager::hasGlyph(GrMaskFormat format, GrGlyph* glyph) {
SkASSERT(glyph);
return this->getAtlas(format)->hasID(glyph->fPlotLocator);
return this->getAtlas(format)->hasID(glyph->fAtlasLocator);
}
// add to texture atlas that matches this format
GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(
GrResourceProvider* resourceProvider,
GrDrawOpAtlas::PlotLocator* plotLocator,
GrDeferredUploadTarget* target, GrMaskFormat format,
int width, int height, const void* image, SkIPoint16* loc) {
GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(GrResourceProvider* resourceProvider,
GrDeferredUploadTarget* target,
GrMaskFormat format,
int width, int height, const void* image,
GrDrawOpAtlas::AtlasLocator* atlasLocator) {
return this->getAtlas(format)->addToAtlas(
resourceProvider, plotLocator, target, width, height, image, loc);
resourceProvider, target, width, height, image, atlasLocator);
}
void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater,
GrMaskFormat format, GrGlyph* glyph,
GrDeferredUploadToken token) {
SkASSERT(glyph);
if (updater->add(glyph->fPlotLocator)) {
this->getAtlas(format)->setLastUseToken(glyph->fPlotLocator, token);
if (updater->add(glyph->fAtlasLocator)) {
this->getAtlas(format)->setLastUseToken(glyph->fAtlasLocator, token);
}
}

View File

@ -74,10 +74,9 @@ public:
}
// add to texture atlas that matches this format
GrDrawOpAtlas::ErrorCode addToAtlas(
GrResourceProvider*,
GrDrawOpAtlas::PlotLocator*, GrDeferredUploadTarget*, GrMaskFormat,
int width, int height, const void* image, SkIPoint16* loc);
GrDrawOpAtlas::ErrorCode addToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, GrMaskFormat,
int width, int height, const void* image,
GrDrawOpAtlas::AtlasLocator*);
// Some clients may wish to verify the integrity of the texture backing store of the
// GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which

View File

@ -141,32 +141,31 @@ GrTextStrike::GrTextStrike(const SkDescriptor& key)
GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(const SkGlyph& skGlyph,
GrMaskFormat expectedMaskFormat,
bool isScaledGlyph,
bool needsPadding,
GrResourceProvider* resourceProvider,
GrDeferredUploadTarget* target,
GrAtlasManager* fullAtlasManager,
GrGlyph* grGlyph) {
SkASSERT(grGlyph != nullptr);
SkASSERT(fCache.findOrNull(grGlyph->fPackedID));
SkASSERT(grGlyph->width() == skGlyph.width());
SkASSERT(grGlyph->height() == skGlyph.height());
SkASSERT(skGlyph.image() != nullptr);
expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
bool isSDFGlyph = skGlyph.maskFormat() == SkMask::kSDF_Format;
SkDEBUGCODE(bool isSDFGlyph = skGlyph.maskFormat() == SkMask::kSDF_Format;)
SkASSERT(!needsPadding || !isSDFGlyph);
// Add 1 pixel padding around grGlyph if needed.
bool addPad = isScaledGlyph && !isSDFGlyph;
const int width = addPad ? skGlyph.width() + 2 : skGlyph.width();
const int height = addPad ? skGlyph.height() + 2 : skGlyph.height();
const int width = needsPadding ? skGlyph.width() + 2 : skGlyph.width();
const int height = needsPadding ? skGlyph.height() + 2 : skGlyph.height();
int rowBytes = width * bytesPerPixel;
size_t size = height * rowBytes;
// Temporary storage for normalizing grGlyph image.
SkAutoSMalloc<1024> storage(size);
void* dataPtr = storage.get();
if (addPad) {
if (needsPadding) {
sk_bzero(dataPtr, size);
// Advance in one row and one column.
dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
@ -174,18 +173,8 @@ GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(const SkGlyph& skGlyph,
get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr);
GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
resourceProvider, &grGlyph->fPlotLocator, target, expectedMaskFormat,
width, height,
storage.get(), &grGlyph->fAtlasLocation);
if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
if (addPad) {
grGlyph->fAtlasLocation.fX += 1;
grGlyph->fAtlasLocation.fY += 1;
}
SkASSERT(grGlyph->fPlotLocator != GrDrawOpAtlas::kInvalidPlotLocator);
}
return result;
return fullAtlasManager->addToAtlas(resourceProvider, target, expectedMaskFormat, width, height,
storage.get(), &grGlyph->fAtlasLocator);
}
GrGlyph* GrTextStrike::getGlyph(const SkGlyph& skGlyph) {

View File

@ -40,7 +40,7 @@ public:
// get the actual glyph image itself when we get the glyph metrics.
GrDrawOpAtlas::ErrorCode addGlyphToAtlas(const SkGlyph&,
GrMaskFormat expectedMaskFormat,
bool isScaledGlyph,
bool needsPadding,
GrResourceProvider*,
GrDeferredUploadTarget*,
GrAtlasManager*,

View File

@ -196,9 +196,13 @@ bool GrTextBlob::SubRun::drawAsDistanceFields() const { return fType == kTransfo
bool GrTextBlob::SubRun::drawAsPaths() const { return fType == kTransformedPath; }
bool GrTextBlob::SubRun::needsTransform() const {
return fType == kTransformedPath
|| fType == kTransformedMask
|| fType == kTransformedSDFT;
return fType == kTransformedPath ||
fType == kTransformedMask ||
fType == kTransformedSDFT;
}
bool GrTextBlob::SubRun::needsPadding() const {
return fType == kTransformedPath || fType == kTransformedMask;
}
bool GrTextBlob::SubRun::hasW() const {
@ -265,37 +269,21 @@ void GrTextBlob::SubRun::updateTexCoords(int begin, int end) {
GrGlyph* glyph = this->fGlyphs[i];
SkASSERT(glyph != nullptr);
int width = glyph->width();
int height = glyph->height();
uint16_t u0, v0, u1, v1;
if (this->drawAsDistanceFields()) {
u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
u1 = u0 + width - 2 * SK_DistanceFieldInset;
v1 = v0 + height - 2 * SK_DistanceFieldInset;
} else {
u0 = glyph->fAtlasLocation.fX;
v0 = glyph->fAtlasLocation.fY;
u1 = u0 + width;
v1 = v0 + height;
}
int pad = this->drawAsDistanceFields() ? SK_DistanceFieldInset
: (this->needsPadding() ? 1 : 0);
std::array<uint16_t, 4> uvs = glyph->fAtlasLocator.getUVs(pad);
// We pack the 2bit page index in the low bit of the u and v texture coords
uint32_t pageIndex = glyph->pageIndex();
std::tie(u0, v0) = GrDrawOpAtlas::PackIndexInTexCoords(u0, v0, pageIndex);
std::tie(u1, v1) = GrDrawOpAtlas::PackIndexInTexCoords(u1, v1, pageIndex);
textureCoords[0] = u0;
textureCoords[1] = v0;
textureCoords[0] = uvs[0];
textureCoords[1] = uvs[1];
textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
textureCoords[0] = u0;
textureCoords[1] = v1;
textureCoords[0] = uvs[0];
textureCoords[1] = uvs[3];
textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
textureCoords[0] = u1;
textureCoords[1] = v0;
textureCoords[0] = uvs[2];
textureCoords[1] = uvs[1];
textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
textureCoords[0] = u1;
textureCoords[1] = v1;
textureCoords[0] = uvs[2];
textureCoords[1] = uvs[3];
textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
}
}
@ -823,10 +811,9 @@ std::tuple<bool, int> GrTextBlob::VertexRegenerator::updateTextureCoordinates(
if (skGlyph.image() == nullptr) {
return {false, 0};
}
code = grStrike->addGlyphToAtlas(skGlyph,
fSubRun->maskFormat(),
fSubRun->needsTransform(),
fResourceProvider, fUploadTarget, fFullAtlasManager, grGlyph);
code = grStrike->addGlyphToAtlas(skGlyph, fSubRun->maskFormat(),
fSubRun->needsPadding(), fResourceProvider,
fUploadTarget, fFullAtlasManager, grGlyph);
if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
break;
}

View File

@ -347,6 +347,7 @@ public:
bool drawAsDistanceFields() const;
bool drawAsPaths() const;
bool needsTransform() const;
bool needsPadding() const;
void translateVerticesIfNeeded(const SkMatrix& drawMatrix, SkPoint drawOrigin);
void updateVerticesColorIfNeeded(GrColor newColor);

View File

@ -114,7 +114,7 @@ private:
static bool fill_plot(GrDrawOpAtlas* atlas,
GrResourceProvider* resourceProvider,
GrDeferredUploadTarget* target,
GrDrawOpAtlas::PlotLocator* plotLocator,
GrDrawOpAtlas::AtlasLocator* atlasLocator,
int alpha) {
SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
@ -122,10 +122,9 @@ static bool fill_plot(GrDrawOpAtlas* atlas,
data.allocPixels(ii);
data.eraseARGB(alpha, 0, 0, 0);
SkIPoint16 loc;
GrDrawOpAtlas::ErrorCode code;
code = atlas->addToAtlas(resourceProvider, plotLocator, target, kPlotSize, kPlotSize,
data.getAddr(0, 0), &loc);
code = atlas->addToAtlas(resourceProvider, target, kPlotSize, kPlotSize,
data.getAddr(0, 0), atlasLocator);
return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
}
@ -160,10 +159,10 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
check(reporter, atlas.get(), 0, 4, 0);
// Fill up the first level
GrDrawOpAtlas::PlotLocator plotLocators[kNumPlots * kNumPlots];
GrDrawOpAtlas::AtlasLocator atlasLocators[kNumPlots * kNumPlots];
for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
bool result = fill_plot(
atlas.get(), resourceProvider, &uploadTarget, &plotLocators[i], i * 32);
atlas.get(), resourceProvider, &uploadTarget, &atlasLocators[i], i * 32);
REPORTER_ASSERT(reporter, result);
check(reporter, atlas.get(), 1, 4, 1);
}
@ -172,14 +171,14 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
check(reporter, atlas.get(), 1, 4, 1);
// Force allocation of a second level
GrDrawOpAtlas::PlotLocator plotLocator;
bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &plotLocator, 4 * 32);
GrDrawOpAtlas::AtlasLocator atlasLocator;
bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasLocator, 4 * 32);
REPORTER_ASSERT(reporter, result);
check(reporter, atlas.get(), 2, 4, 2);
// Simulate a lot of draws using only the first plot. The last texture should be compacted.
for (int i = 0; i < 512; ++i) {
atlas->setLastUseToken(plotLocators[0], uploadTarget.tokenTracker()->nextDrawToken());
atlas->setLastUseToken(atlasLocators[0], uploadTarget.tokenTracker()->nextDrawToken());
uploadTarget.issueDrawToken();
uploadTarget.flushToken();
atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());