C++程序  |  159行  |  4.61 KB


/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrLayerAtlas_DEFINED
#define GrLayerAtlas_DEFINED

#include "GrTexture.h"

#include "SkPoint.h"
#include "SkTDArray.h"
#include "SkTInternalLList.h"

class GrLayerAtlas;
class GrTextureProvider;
class GrRectanizer;

// The backing GrTexture for a GrLayerAtlas is broken into a spatial grid of Plots. When
// the atlas needs space on the texture (i.e., in response to an addToAtlas call), it 
// iterates through the plots in use by the requesting client looking for space and, 
// if no space is found, opens up a new Plot for that client. The Plots keep track of 
// subimage placement via their GrRectanizer. 
//
// If all Plots are full, the replacement strategy is up to the client. The Plot::reset
// call will remove a Plot's knowledge of any allocated rects - freeing its space for reuse.

class GrLayerAtlas {
public:
    class Plot {
        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot); // In an MRU llist

    public:
        // This returns a plot ID unique to each plot in the atlas. They are
        // consecutive and start at 0.
        int id() const { return fID; }

        void reset();

    private:
        friend class GrLayerAtlas;

        Plot();
        ~Plot(); // does not try to delete the fNext field

        void init(int id, int offX, int offY, int width, int height);

        bool allocateRect(int width, int height, SkIPoint16*);

        int                     fID;
        GrRectanizer*           fRects;
        SkIPoint16              fOffset;        // the offset of the plot in the backing texture
    };

    // This class allows each client to independently track the Plots in
    // which its data is stored.
    // For example, multiple pictures may simultaneously store their layers in the 
    // layer atlas. When a picture goes away it can use the ClientPlotUsage to remove itself
    // from those plots.
    class ClientPlotUsage {
    public:
        ClientPlotUsage(int maxPlots)
            SkDEBUGCODE(: fMaxPlots(maxPlots)) {
            fPlots.setReserve(maxPlots);
        }

        bool isEmpty() const { return 0 == fPlots.count(); }

        int numPlots() const { return fPlots.count(); }
        Plot* plot(int index) { return fPlots[index]; }

        void appendPlot(Plot* plot) {
            SkASSERT(fPlots.count() <= fMaxPlots);
            SkASSERT(!fPlots.contains(plot));
            *fPlots.append() = plot;
        }

        // remove reference to 'plot'
        void removePlot(const Plot* plot) {
            int index = fPlots.find(const_cast<Plot*>(plot));
            if (index >= 0) {
                fPlots.remove(index);
            }
        }

#ifdef SK_DEBUG
        bool contains(const Plot* plot) const { 
            return fPlots.contains(const_cast<Plot*>(plot)); 
        }
#endif

    private:
        SkTDArray<Plot*> fPlots;
        SkDEBUGCODE(int fMaxPlots;)
    };

    GrLayerAtlas(GrTextureProvider*, GrPixelConfig, GrSurfaceFlags flags, 
                 const SkISize& backingTextureSize,
                 int numPlotsX, int numPlotsY);
    ~GrLayerAtlas();

    // Requests a width x height block in the atlas. Upon success it returns 
    // the containing Plot and absolute location in the backing texture. 
    // nullptr is returned if there is no more space in the atlas.
    Plot* addToAtlas(ClientPlotUsage*, int width, int height, SkIPoint16* loc);

    GrTexture* getTextureOrNull() const {
        return fTexture;
    }

    GrTexture* getTexture() const {
        SkASSERT(fTexture);
        return fTexture;
    }

    bool reattachBackingTexture();

    void detachBackingTexture() {
        fTexture.reset(nullptr);
    }

    void resetPlots();

    enum IterOrder {
        kLRUFirst_IterOrder,
        kMRUFirst_IterOrder
    };

    typedef SkTInternalLList<Plot> PlotList;
    typedef PlotList::Iter PlotIter;
    Plot* iterInit(PlotIter* iter, IterOrder order) {
        return iter->init(fPlotList, kLRUFirst_IterOrder == order
                                                       ? PlotList::Iter::kTail_IterStart
                                                       : PlotList::Iter::kHead_IterStart);
    }

private:
    void createBackingTexture();

    void makeMRU(Plot* plot);

    GrTextureProvider* fTexProvider;
    GrPixelConfig      fPixelConfig;
    GrSurfaceFlags     fFlags;
    SkAutoTUnref<GrTexture> fTexture;

    SkISize            fBackingTextureSize;

    // allocated array of Plots
    Plot*              fPlotArray;
    // LRU list of Plots (MRU at head - LRU at tail)
    PlotList           fPlotList;
};

#endif