Revert of Begin atlasing (https://codereview.chromium.org/354533004/)
Reason for revert:
Sigh
Original issue's description:
> Begin atlasing
>
> This CL makes it possible for pulled-forward-layers to be atlased. It currently has a couple glaring limitations (which is why it is disabled):
>
> 1) the atlased layers cannot be purged nor aged out
> 2) the texture backing the atlas is not pulled from (or returned to) the resource cache
>
> #1 is on hold until we have a recycling rectanizer
>
> A separate major limitation (the non-atlased layers aren't cached) is blocked until we can transmute entries in the resource cache from scratch to non-scratch while potentially preserving their contents.
>
> Committed: https://skia.googlesource.com/skia/+/55e61f0ef4e5c8c34ac107deaadc9b4ffef3111b
R=bsalomon@google.com
TBR=bsalomon@google.com
NOTREECHECKS=true
NOTRY=true
Author: robertphillips@google.com
Review URL: https://codereview.chromium.org/359953002
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp
index 1bff42a..30b4bac 100644
--- a/src/gpu/GrAtlas.cpp
+++ b/src/gpu/GrAtlas.cpp
@@ -54,7 +54,8 @@
loc->fY += offset.fY;
}
-bool GrPlot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
+bool GrPlot::addSubImage(int width, int height, const void* image,
+ SkIPoint16* loc) {
float percentFull = fRects->percentFull();
if (!fRects->addRect(width, height, loc)) {
return false;
@@ -87,7 +88,7 @@
adjust_for_offset(loc, fOffset);
fDirty = true;
// otherwise, just upload the image directly
- } else if (NULL != image) {
+ } else {
adjust_for_offset(loc, fOffset);
GrContext* context = fTexture->getContext();
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrPlot::uploadToTexture");
@@ -95,8 +96,6 @@
loc->fX, loc->fY, width, height,
fTexture->config(), image, 0,
GrContext::kDontFlush_PixelOpsFlag);
- } else {
- adjust_for_offset(loc, fOffset);
}
#if FONT_CACHE_STATS
@@ -147,12 +146,11 @@
///////////////////////////////////////////////////////////////////////////////
-GrAtlas::GrAtlas(GrGpu* gpu, GrPixelConfig config, GrTextureFlags flags,
+GrAtlas::GrAtlas(GrGpu* gpu, GrPixelConfig config,
const SkISize& backingTextureSize,
int numPlotsX, int numPlotsY, bool batchUploads) {
fGpu = SkRef(gpu);
fPixelConfig = config;
- fFlags = flags;
fBackingTextureSize = backingTextureSize;
fNumPlotsX = numPlotsX;
fNumPlotsY = numPlotsY;
@@ -223,7 +221,7 @@
if (NULL == fTexture) {
// TODO: Update this to use the cache rather than directly creating a texture.
GrTextureDesc desc;
- desc.fFlags = fFlags | kDynamicUpdate_GrTextureFlagBit;
+ desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
desc.fWidth = fBackingTextureSize.width();
desc.fHeight = fBackingTextureSize.height();
desc.fConfig = fPixelConfig;
diff --git a/src/gpu/GrAtlas.h b/src/gpu/GrAtlas.h
index d63c8b9..49a7bac 100644
--- a/src/gpu/GrAtlas.h
+++ b/src/gpu/GrAtlas.h
@@ -81,17 +81,13 @@
friend class GrAtlas;
};
- GrAtlas(GrGpu*, GrPixelConfig, GrTextureFlags flags,
- const SkISize& backingTextureSize,
+ GrAtlas(GrGpu*, GrPixelConfig, const SkISize& backingTextureSize,
int numPlotsX, int numPlotsY, bool batchUploads);
~GrAtlas();
- // Adds a width x height subimage to the atlas. Upon success it returns
- // the containing GrPlot and absolute location in the backing texture.
- // NULL is returned if the subimage cannot fit in the atlas.
- // If provided, the image data will either be immediately uploaded or
- // written to the CPU-side backing bitmap.
- GrPlot* addToAtlas(ClientPlotUsage*, int width, int height, const void* image, SkIPoint16* loc);
+ // add subimage of width, height dimensions to atlas
+ // returns the containing GrPlot and location relative to the backing texture
+ GrPlot* addToAtlas(ClientPlotUsage*, int width, int height, const void*, SkIPoint16*);
// remove reference to this plot
void removePlot(ClientPlotUsage* usage, const GrPlot* plot);
@@ -109,14 +105,13 @@
private:
void makeMRU(GrPlot* plot);
- GrGpu* fGpu;
- GrPixelConfig fPixelConfig;
- GrTextureFlags fFlags;
- GrTexture* fTexture;
- SkISize fBackingTextureSize;
- int fNumPlotsX;
- int fNumPlotsY;
- bool fBatchUploads;
+ GrGpu* fGpu;
+ GrPixelConfig fPixelConfig;
+ GrTexture* fTexture;
+ SkISize fBackingTextureSize;
+ int fNumPlotsX;
+ int fNumPlotsY;
+ bool fBatchUploads;
// allocated array of GrPlots
GrPlot* fPlotArray;
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp
index 5f657c7..c20d809 100644
--- a/src/gpu/GrLayerCache.cpp
+++ b/src/gpu/GrLayerCache.cpp
@@ -42,14 +42,14 @@
};
GrLayerCache::GrLayerCache(GrContext* context)
- : fContext(context) {
- this->initAtlas();
+ : fContext(context)
+ , fLayerPool(16) { // TODO: may need to increase this later
}
GrLayerCache::~GrLayerCache() {
}
-void GrLayerCache::initAtlas() {
+void GrLayerCache::init() {
static const int kAtlasTextureWidth = 1024;
static const int kAtlasTextureHeight = 1024;
@@ -58,31 +58,19 @@
// The layer cache only gets 1 plot
SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
- kRenderTarget_GrTextureFlagBit,
textureSize, 1, 1, false)));
}
void GrLayerCache::freeAll() {
- SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray();
- for (int i = 0; i < fLayerHash.count(); ++i) {
- this->unlock(layerArray[i]);
- }
-
fLayerHash.deleteAll();
-
- // The atlas only lets go of its texture when the atlas is deleted.
fAtlas.free();
- // GrLayerCache always assumes an atlas exists so recreate it. The atlas
- // lazily allocates a replacement texture so reallocating a new
- // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResources.
- // TODO: Make GrLayerCache lazily allocate the atlas manager?
- this->initAtlas();
}
GrCachedLayer* GrLayerCache::createLayer(const SkPicture* picture, int layerID) {
- SkASSERT(picture->uniqueID() != SK_InvalidGenID);
+ GrCachedLayer* layer = fLayerPool.alloc();
- GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (picture->uniqueID(), layerID));
+ SkASSERT(picture->uniqueID() != SK_InvalidGenID);
+ layer->init(picture->uniqueID(), layerID);
fLayerHash.insert(PictureLayerKey(picture->uniqueID(), layerID), layer);
return layer;
}
@@ -103,70 +91,19 @@
}
bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
+ SkASSERT(NULL == layer->getTexture());
- if (NULL != layer->texture()) {
- // This layer is already locked
-#ifdef SK_DEBUG
- if (!layer->rect().isEmpty()) {
- // It claims to be atlased
- SkASSERT(layer->rect().width() == desc.fWidth);
- SkASSERT(layer->rect().height() == desc.fHeight);
- }
-#endif
- return true;
- }
-
-#if USE_ATLAS
- SkIPoint16 loc;
- GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, desc.fWidth, desc.fHeight, NULL, &loc);
- if (NULL != plot) {
- GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
- SkToS16(desc.fWidth), SkToS16(desc.fHeight));
- layer->setTexture(fAtlas->getTexture(), bounds);
- return false;
- }
-#endif
-
- // This path always uses a new scratch texture and (thus) doesn't cache anything.
+ // This just uses scratch textures and doesn't cache the texture.
// This can yield a lot of re-rendering
- layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch),
- GrIRect16::MakeEmpty());
+ layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
return false;
}
void GrLayerCache::unlock(GrCachedLayer* layer) {
- if (NULL == layer || NULL == layer->texture()) {
+ if (NULL == layer || NULL == layer->getTexture()) {
return;
}
- // The atlas doesn't currently use a scratch texture (and we would have
- // to free up space differently anyways)
- // TODO: unlock atlas space when a recycling rectanizer is available
- if (layer->texture() != fAtlas->getTexture()) {
- fContext->unlockScratchTexture(layer->texture());
- layer->setTexture(NULL, GrIRect16::MakeEmpty());
- }
-}
-
-void GrLayerCache::purge(const SkPicture* picture) {
- // This is somewhat of an abuse of GrTHashTable. We need to find all the
- // layers associated with 'picture' but the usual hash calls only look for
- // exact key matches. This code peeks into the hash table's innards to
- // find all the 'picture'-related layers.
- // TODO: use a different data structure for the layer hash?
- SkTDArray<GrCachedLayer*> toBeRemoved;
-
- const SkTDArray<GrCachedLayer*>& layerArray = fLayerHash.getArray();
- for (int i = 0; i < fLayerHash.count(); ++i) {
- if (picture->uniqueID() == layerArray[i]->pictureID()) {
- *toBeRemoved.append() = layerArray[i];
- }
- }
-
- for (int i = 0; i < toBeRemoved.count(); ++i) {
- this->unlock(toBeRemoved[i]);
-
- PictureLayerKey key(picture->uniqueID(), toBeRemoved[i]->layerID());
- fLayerHash.remove(key, toBeRemoved[i]);
- }
+ fContext->unlockScratchTexture(layer->getTexture());
+ layer->setTexture(NULL);
}
diff --git a/src/gpu/GrLayerCache.h b/src/gpu/GrLayerCache.h
index 2747919..a7ba2af 100644
--- a/src/gpu/GrLayerCache.h
+++ b/src/gpu/GrLayerCache.h
@@ -8,8 +8,6 @@
#ifndef GrLayerCache_DEFINED
#define GrLayerCache_DEFINED
-#define USE_ATLAS 0
-
#include "GrAllocPool.h"
#include "GrAtlas.h"
#include "GrTHashTable.h"
@@ -19,38 +17,61 @@
class GrGpu;
class SkPicture;
+// GrAtlasLocation captures an atlased item's position in the atlas. This
+// means the plot in which it resides and its bounds inside the plot.
+// TODO: Make GrGlyph use one of these?
+class GrAtlasLocation {
+public:
+ GrAtlasLocation() : fPlot(NULL) {}
+
+ void set(GrPlot* plot, const GrIRect16& bounds) {
+ fPlot = plot;
+ fBounds = bounds;
+ }
+
+ const GrPlot* plot() const {
+ return fPlot;
+ }
+
+ const GrIRect16& bounds() const {
+ return fBounds;
+ }
+
+private:
+ GrPlot* fPlot;
+ GrIRect16 fBounds; // only valid is fPlot != NULL
+};
+
// GrCachedLayer encapsulates the caching information for a single saveLayer.
//
-// Atlased layers get a ref to their atlas GrTexture and 'fRect' contains
-// their absolute location in the backing texture.
+// Atlased layers get a ref to their atlas GrTexture and their GrAtlasLocation
+// is filled in.
+// In this case GrCachedLayer is roughly equivalent to a GrGlyph in the font
+// caching system.
//
-// Non-atlased layers get a ref to the GrTexture in which they reside. Their
-// 'fRect' will be empty.
-//
+// Non-atlased layers get a ref to the GrTexture in which they reside.
// TODO: can we easily reuse the empty space in the non-atlased GrTexture's?
struct GrCachedLayer {
public:
- GrCachedLayer(uint32_t pictureID, int layerID) {
- fPictureID = pictureID;
- fLayerID = layerID;
- fTexture = NULL;
- fRect = GrIRect16::MakeEmpty();
- }
-
uint32_t pictureID() const { return fPictureID; }
int layerID() const { return fLayerID; }
+ void init(uint32_t pictureID, int layerID) {
+ fPictureID = pictureID;
+ fLayerID = layerID;
+ fTexture = NULL;
+ fLocation.set(NULL, GrIRect16::MakeEmpty());
+ }
+
// This call takes over the caller's ref
- void setTexture(GrTexture* texture, const GrIRect16& rect) {
+ void setTexture(GrTexture* texture) {
if (NULL != fTexture) {
fTexture->unref();
}
fTexture = texture; // just take over caller's ref
- fRect = rect;
}
- GrTexture* texture() { return fTexture; }
- const GrIRect16& rect() const { return fRect; }
+ GrTexture* getTexture() { return fTexture; }
private:
uint32_t fPictureID;
@@ -63,9 +84,7 @@
// non-NULL, that means that the texture is locked in the texture cache.
GrTexture* fTexture;
- // For non-atlased layers 'fRect' is empty otherwise it is the bound of
- // the layer in the atlas.
- GrIRect16 fRect;
+ GrAtlasLocation fLocation; // only valid if the layer is atlased
};
// The GrLayerCache caches pre-computed saveLayers for later rendering.
@@ -96,9 +115,6 @@
// Inform the cache that layer's cached image is not currently required
void unlock(GrCachedLayer* layer);
- // Remove all the layers (and unlock any resources) associated with 'picture'
- void purge(const SkPicture* picture);
-
private:
GrContext* fContext; // pointer back to owning context
SkAutoTDelete<GrAtlas> fAtlas; // TODO: could lazily allocate
@@ -106,13 +122,10 @@
class PictureLayerKey;
GrTHashTable<GrCachedLayer, PictureLayerKey, 7> fLayerHash;
+ GrTAllocPool<GrCachedLayer> fLayerPool;
- void initAtlas();
+ void init();
GrCachedLayer* createLayer(const SkPicture* picture, int layerID);
-
- // for testing
- friend class GetNumLayers;
- int numLayers() const { return fLayerHash.count(); }
};
#endif
diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
index a9405ca..fb9d631 100644
--- a/src/gpu/GrTextStrike.cpp
+++ b/src/gpu/GrTextStrike.cpp
@@ -82,7 +82,7 @@
if (NULL == fAtlases[atlasIndex]) {
SkISize textureSize = SkISize::Make(GR_ATLAS_TEXTURE_WIDTH,
GR_ATLAS_TEXTURE_HEIGHT);
- fAtlases[atlasIndex] = SkNEW_ARGS(GrAtlas, (fGpu, config, kNone_GrTextureFlags,
+ fAtlases[atlasIndex] = SkNEW_ARGS(GrAtlas, (fGpu, config,
textureSize,
GR_NUM_PLOTS_X,
GR_NUM_PLOTS_Y,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 318de8d..3b82a33 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1825,7 +1825,7 @@
}
void SkGpuDevice::EXPERIMENTAL_purge(const SkPicture* picture) {
- fContext->getLayerCache()->purge(picture);
+
}
bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture) {
@@ -1951,68 +1951,28 @@
// TODO: need to deal with sample count
bool needsRendering = !fContext->getLayerCache()->lock(layer, desc);
- if (NULL == layer->texture()) {
+ if (NULL == layer->getTexture()) {
continue;
}
layerInfo->fBM = SkNEW(SkBitmap); // fBM is allocated so ReplacementInfo can be POD
- wrap_texture(layer->texture(),
- layer->rect().isEmpty() ? desc.fWidth : layer->texture()->width(),
- layer->rect().isEmpty() ? desc.fHeight : layer->texture()->height(),
- layerInfo->fBM);
+ wrap_texture(layer->getTexture(), desc.fWidth, desc.fHeight, layerInfo->fBM);
SkASSERT(info.fPaint);
layerInfo->fPaint = info.fPaint;
- if (layer->rect().isEmpty()) {
- layerInfo->fSrcRect = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
- } else {
- layerInfo->fSrcRect = SkIRect::MakeXYWH(layer->rect().fLeft,
- layer->rect().fTop,
- layer->rect().width(),
- layer->rect().height());
- }
-
if (needsRendering) {
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
- layer->texture()->asRenderTarget(),
- SkSurface::kStandard_TextRenderMode,
- SkSurface::kDontClear_RenderTargetFlag));
+ layer->getTexture()->asRenderTarget()));
SkCanvas* canvas = surface->getCanvas();
- if (!layer->rect().isEmpty()) {
- // Add a rect clip to make sure the rendering doesn't
- // extend beyond the boundaries of the atlased sub-rect
- SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
- SkIntToScalar(layer->rect().fTop),
- SkIntToScalar(layer->rect().width()),
- SkIntToScalar(layer->rect().height()));
- canvas->clipRect(bound);
- // Since 'clear' doesn't respect the clip we need to draw a rect
- // TODO: ensure none of the atlased layers contain a clear call!
- SkPaint paint;
- paint.setColor(SK_ColorTRANSPARENT);
- canvas->drawRect(bound, paint);
- } else {
- canvas->clear(SK_ColorTRANSPARENT);
- }
-
canvas->setMatrix(info.fCTM);
-
- if (!layer->rect().isEmpty()) {
- // info.fCTM maps the layer's top/left to the origin.
- // Since this layer is atlased the top/left corner needs
- // to be offset to some arbitrary location in the backing
- // texture.
- canvas->translate(SkIntToScalar(layer->rect().fLeft),
- SkIntToScalar(layer->rect().fTop));
- }
+ canvas->clear(SK_ColorTRANSPARENT);
picture->fPlayback->setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
picture->fPlayback->draw(*canvas, NULL);
picture->fPlayback->setDrawLimits(0, 0);
-
canvas->flush();
}
}