aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrBatchAtlas.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu/GrBatchAtlas.h')
-rw-r--r--src/gpu/GrBatchAtlas.h122
1 files changed, 116 insertions, 6 deletions
diff --git a/src/gpu/GrBatchAtlas.h b/src/gpu/GrBatchAtlas.h
index 0f36951922..bd6504030b 100644
--- a/src/gpu/GrBatchAtlas.h
+++ b/src/gpu/GrBatchAtlas.h
@@ -14,7 +14,6 @@
#include "SkTDArray.h"
#include "SkTInternalLList.h"
-class BatchPlot;
class GrRectanizer;
struct GrBatchAtlasConfig {
@@ -55,11 +54,23 @@ public:
GrTexture* getTexture() const { return fTexture; }
uint64_t atlasGeneration() const { return fAtlasGeneration; }
- bool hasID(AtlasID id);
+
+ inline bool hasID(AtlasID id) {
+ uint32_t index = GetIndexFromID(id);
+ SkASSERT(index < fNumPlots);
+ return fPlotArray[index]->genID() == GetGenerationFromID(id);
+ }
// To ensure the atlas does not evict a given entry, the client must set the last use token
- void setLastUseToken(AtlasID id, GrBatchToken batchToken);
- void registerEvictionCallback(EvictionFunc func, void* userData) {
+ inline void setLastUseToken(AtlasID id, GrBatchToken batchToken) {
+ SkASSERT(this->hasID(id));
+ uint32_t index = GetIndexFromID(id);
+ SkASSERT(index < fNumPlots);
+ this->makeMRU(fPlotArray[index]);
+ fPlotArray[index]->setLastUseToken(batchToken);
+ }
+
+ inline void registerEvictionCallback(EvictionFunc func, void* userData) {
EvictionData* data = fEvictionCallbacks.append();
data->fFunc = func;
data->fData = userData;
@@ -110,7 +121,14 @@ public:
friend class GrBatchAtlas;
};
- void setLastUseTokenBulk(const BulkUseTokenUpdater& reffer, GrBatchToken);
+ void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrBatchToken batchToken) {
+ int count = updater.fPlotsToUpdate.count();
+ for (int i = 0; i < count; i++) {
+ BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]];
+ this->makeMRU(plot);
+ plot->setLastUseToken(batchToken);
+ }
+ }
static const int kGlyphMaxDim = 256;
static bool GlyphTooLargeForAtlas(int width, int height) {
@@ -118,6 +136,89 @@ public:
}
private:
+ // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of BatchPlots.
+ // The BatchPlots keep track of subimage placement via their GrRectanizer. A BatchPlot
+ // manages the lifetime of its data using two tokens, a last use token and a last upload token.
+ // Once a BatchPlot is "full" (i.e. there is no room for the new subimage according to the
+ // GrRectanizer), it can no longer be used unless the last use of the GrPlot has already been
+ // flushed through to the gpu.
+ class BatchPlot : public SkRefCnt {
+ SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot);
+
+ public:
+ // index() is a unique id for the plot relative to the owning GrAtlas. genID() is a
+ // monotonically incremented number which is bumped every time this plot is
+ // evicted from the cache (i.e., there is continuity in genID() across atlas spills).
+ uint32_t index() const { return fIndex; }
+ uint64_t genID() const { return fGenID; }
+ GrBatchAtlas::AtlasID id() const {
+ SkASSERT(GrBatchAtlas::kInvalidAtlasID != fID);
+ return fID;
+ }
+ SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; })
+
+ bool addSubImage(int width, int height, const void* image, SkIPoint16* loc);
+
+ // To manage the lifetime of a plot, we use two tokens. We use the last upload token to
+ // know when we can 'piggy back' uploads, ie if the last upload hasn't been flushed to gpu,
+ // we don't need to issue a new upload even if we update the cpu backing store. We use
+ // lastUse to determine when we can evict a plot from the cache, ie if the last use has
+ // already flushed through the gpu then we can reuse the plot.
+ GrBatchToken lastUploadToken() const { return fLastUpload; }
+ GrBatchToken lastUseToken() const { return fLastUse; }
+ void setLastUploadToken(GrBatchToken batchToken) {
+ SkASSERT(batchToken >= fLastUpload);
+ fLastUpload = batchToken;
+ }
+ void setLastUseToken(GrBatchToken batchToken) {
+ SkASSERT(batchToken >= fLastUse);
+ fLastUse = batchToken;
+ }
+
+ void uploadToTexture(GrBatchUploader::TextureUploader* uploader, GrTexture* texture);
+ void resetRects();
+
+ private:
+ BatchPlot(int index, uint64_t genID, int offX, int offY, int width, int height,
+ GrPixelConfig config);
+
+ ~BatchPlot() override;
+
+ // Create a clone of this plot. The cloned plot will take the place of the
+ // current plot in the atlas.
+ BatchPlot* clone() const {
+ return new BatchPlot(fIndex, fGenID+1, fX, fY, fWidth, fHeight, fConfig);
+ }
+
+ static GrBatchAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) {
+ SkASSERT(index < (1 << 16));
+ SkASSERT(generation < ((uint64_t)1 << 48));
+ return generation << 16 | index;
+ }
+
+ GrBatchToken fLastUpload;
+ GrBatchToken fLastUse;
+
+ const uint32_t fIndex;
+ uint64_t fGenID;
+ GrBatchAtlas::AtlasID fID;
+ unsigned char* fData;
+ const int fWidth;
+ const int fHeight;
+ const int fX;
+ const int fY;
+ GrRectanizer* fRects;
+ const SkIPoint16 fOffset; // the offset of the plot in the backing texture
+ const GrPixelConfig fConfig;
+ const size_t fBytesPerPixel;
+ SkIRect fDirtyRect;
+ SkDEBUGCODE(bool fDirty;)
+
+ friend class GrBatchAtlas;
+
+ typedef SkRefCnt INHERITED;
+ };
+
typedef SkTInternalLList<BatchPlot> GrBatchPlotList;
static uint32_t GetIndexFromID(AtlasID id) {
@@ -131,10 +232,19 @@ private:
inline void updatePlot(GrDrawBatch::Target*, AtlasID*, BatchPlot*);
- inline void makeMRU(BatchPlot* plot);
+ inline void makeMRU(BatchPlot* plot) {
+ if (fPlotList.head() == plot) {
+ return;
+ }
+
+ fPlotList.remove(plot);
+ fPlotList.addToHead(plot);
+ }
inline void processEviction(AtlasID);
+ friend class GrPlotUploader; // to access GrBatchPlot
+
GrTexture* fTexture;
SkDEBUGCODE(uint32_t fNumPlots;)