| Index: src/gpu/GrLayerAtlas.cpp
|
| diff --git a/src/gpu/GrLayerAtlas.cpp b/src/gpu/GrLayerAtlas.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3b30607c8cfc72cea328bbea9eb3023b89842098
|
| --- /dev/null
|
| +++ b/src/gpu/GrLayerAtlas.cpp
|
| @@ -0,0 +1,145 @@
|
| +
|
| +/*
|
| + * Copyright 2010 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "GrLayerAtlas.h"
|
| +#include "GrRectanizer.h"
|
| +#include "GrTextureProvider.h"
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +GrLayerAtlas::Plot::Plot()
|
| + : fID(-1)
|
| + , fRects(nullptr) {
|
| + fOffset.set(0, 0);
|
| +}
|
| +
|
| +GrLayerAtlas::Plot::~Plot() {
|
| + delete fRects;
|
| +}
|
| +
|
| +void GrLayerAtlas::Plot::init(int id, int offX, int offY, int width, int height) {
|
| + fID = id;
|
| + fRects = GrRectanizer::Factory(width, height);
|
| + fOffset.set(offX * width, offY * height);
|
| +}
|
| +
|
| +bool GrLayerAtlas::Plot::allocateRect(int width, int height, SkIPoint16* loc) {
|
| + if (!fRects->addRect(width, height, loc)) {
|
| + return false;
|
| + }
|
| +
|
| + loc->fX += fOffset.fX;
|
| + loc->fY += fOffset.fY;
|
| + return true;
|
| +}
|
| +
|
| +void GrLayerAtlas::Plot::reset() {
|
| + SkASSERT(fRects);
|
| + fRects->reset();
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +GrLayerAtlas::GrLayerAtlas(GrTextureProvider* texProvider, GrPixelConfig config,
|
| + GrSurfaceFlags flags,
|
| + const SkISize& backingTextureSize,
|
| + int numPlotsX, int numPlotsY) {
|
| + fTexProvider = texProvider;
|
| + fPixelConfig = config;
|
| + fFlags = flags;
|
| + fBackingTextureSize = backingTextureSize;
|
| + fTexture = nullptr;
|
| +
|
| + int textureWidth = fBackingTextureSize.width();
|
| + int textureHeight = fBackingTextureSize.height();
|
| +
|
| + int plotWidth = textureWidth / numPlotsX;
|
| + int plotHeight = textureHeight / numPlotsY;
|
| +
|
| + SkASSERT(plotWidth * numPlotsX == textureWidth);
|
| + SkASSERT(plotHeight * numPlotsY == textureHeight);
|
| +
|
| + // We currently do not support compressed atlases...
|
| + SkASSERT(!GrPixelConfigIsCompressed(config));
|
| +
|
| + // set up allocated plots
|
| + fPlotArray = new Plot[numPlotsX * numPlotsY];
|
| +
|
| + Plot* currPlot = fPlotArray;
|
| + for (int y = numPlotsY-1; y >= 0; --y) {
|
| + for (int x = numPlotsX-1; x >= 0; --x) {
|
| + currPlot->init(y*numPlotsX+x, x, y, plotWidth, plotHeight);
|
| +
|
| + // build LRU list
|
| + fPlotList.addToHead(currPlot);
|
| + ++currPlot;
|
| + }
|
| + }
|
| +}
|
| +
|
| +GrLayerAtlas::~GrLayerAtlas() {
|
| + SkSafeUnref(fTexture);
|
| + delete[] fPlotArray;
|
| +}
|
| +
|
| +void GrLayerAtlas::makeMRU(Plot* plot) {
|
| + if (fPlotList.head() == plot) {
|
| + return;
|
| + }
|
| +
|
| + fPlotList.remove(plot);
|
| + fPlotList.addToHead(plot);
|
| +};
|
| +
|
| +GrLayerAtlas::Plot* GrLayerAtlas::addToAtlas(ClientPlotUsage* usage,
|
| + int width, int height, SkIPoint16* loc) {
|
| + // Iterate through the plots currently being used by this client and see if we can find a hole.
|
| + // The last one was most recently added and probably most empty.
|
| + // We want to consolidate the uses from individual clients to the same plot(s) so that
|
| + // when a specific client goes away they are more likely to completely empty a plot.
|
| + for (int i = usage->numPlots()-1; i >= 0; --i) {
|
| + Plot* plot = usage->plot(i);
|
| + if (plot->allocateRect(width, height, loc)) {
|
| + this->makeMRU(plot);
|
| + return plot;
|
| + }
|
| + }
|
| +
|
| + // before we get a new plot, make sure we have a backing texture
|
| + if (nullptr == fTexture) {
|
| + // TODO: Update this to use the cache rather than directly creating a texture.
|
| + GrSurfaceDesc desc;
|
| + desc.fFlags = fFlags;
|
| + desc.fWidth = fBackingTextureSize.width();
|
| + desc.fHeight = fBackingTextureSize.height();
|
| + desc.fConfig = fPixelConfig;
|
| +
|
| + fTexture = fTexProvider->createTexture(desc, true, nullptr, 0);
|
| + if (nullptr == fTexture) {
|
| + return nullptr;
|
| + }
|
| + }
|
| +
|
| + // Now look through all allocated plots for one we can share, in MRU order
|
| + // TODO: its seems like traversing from emptiest to fullest would make more sense
|
| + PlotList::Iter plotIter;
|
| + plotIter.init(fPlotList, PlotList::Iter::kHead_IterStart);
|
| + Plot* plot;
|
| + while ((plot = plotIter.get())) {
|
| + if (plot->allocateRect(width, height, loc)) {
|
| + this->makeMRU(plot);
|
| + // new plot for atlas, put at end of array
|
| + usage->appendPlot(plot);
|
| + return plot;
|
| + }
|
| + plotIter.next();
|
| + }
|
| +
|
| + // If the above fails, then the current plot list has no room
|
| + return nullptr;
|
| +}
|
| +
|
|
|