Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrClipMaskCache_DEFINED
      9 #define GrClipMaskCache_DEFINED
     10 
     11 #include "GrContext.h"
     12 #include "GrNoncopyable.h"
     13 #include "SkClipStack.h"
     14 
     15 class GrTexture;
     16 
     17 /**
     18  * The stencil buffer stores the last clip path - providing a single entry
     19  * "cache". This class provides similar functionality for AA clip paths
     20  */
     21 class GrClipMaskCache : public GrNoncopyable {
     22 public:
     23     GrClipMaskCache();
     24 
     25     ~GrClipMaskCache() {
     26 
     27         while (!fStack.empty()) {
     28             GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
     29             temp->~GrClipStackFrame();
     30             fStack.pop_back();
     31         }
     32     }
     33 
     34     bool canReuse(int32_t clipGenID, const SkIRect& bounds) {
     35 
     36         SkASSERT(clipGenID != SkClipStack::kWideOpenGenID);
     37         SkASSERT(clipGenID != SkClipStack::kEmptyGenID);
     38 
     39         if (SkClipStack::kInvalidGenID == clipGenID) {
     40             return false;
     41         }
     42 
     43         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     44 
     45         // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
     46         // an offset to the caller.
     47         if (back->fLastMask.texture() &&
     48             back->fLastBound == bounds &&
     49             back->fLastClipGenID == clipGenID) {
     50             return true;
     51         }
     52 
     53         return false;
     54     }
     55 
     56     void reset() {
     57         if (fStack.empty()) {
     58 //            GrAssert(false);
     59             return;
     60         }
     61 
     62         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     63 
     64         back->reset();
     65     }
     66 
     67     /**
     68      * After a "push" the clip state is entirely open. Currently, the
     69      * entire clip stack will be re-rendered into a new clip mask.
     70      * TODO: can we take advantage of the nested nature of the clips to
     71      * reduce the mask creation cost?
     72      */
     73     void push();
     74 
     75     void pop() {
     76         //GrAssert(!fStack.empty());
     77 
     78         if (!fStack.empty()) {
     79             GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     80 
     81             back->~GrClipStackFrame();
     82             fStack.pop_back();
     83         }
     84     }
     85 
     86     int32_t getLastClipGenID() const {
     87 
     88         if (fStack.empty()) {
     89             return SkClipStack::kInvalidGenID;
     90         }
     91 
     92         return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
     93     }
     94 
     95     GrTexture* getLastMask() {
     96 
     97         if (fStack.empty()) {
     98             GrAssert(false);
     99             return NULL;
    100         }
    101 
    102         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    103 
    104         return back->fLastMask.texture();
    105     }
    106 
    107     const GrTexture* getLastMask() const {
    108 
    109         if (fStack.empty()) {
    110             GrAssert(false);
    111             return NULL;
    112         }
    113 
    114         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    115 
    116         return back->fLastMask.texture();
    117     }
    118 
    119     void acquireMask(int32_t clipGenID,
    120                      const GrTextureDesc& desc,
    121                      const SkIRect& bound) {
    122 
    123         if (fStack.empty()) {
    124             GrAssert(false);
    125             return;
    126         }
    127 
    128         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    129 
    130         back->acquireMask(fContext, clipGenID, desc, bound);
    131     }
    132 
    133     int getLastMaskWidth() const {
    134 
    135         if (fStack.empty()) {
    136             GrAssert(false);
    137             return -1;
    138         }
    139 
    140         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    141 
    142         if (NULL == back->fLastMask.texture()) {
    143             return -1;
    144         }
    145 
    146         return back->fLastMask.texture()->width();
    147     }
    148 
    149     int getLastMaskHeight() const {
    150 
    151         if (fStack.empty()) {
    152             GrAssert(false);
    153             return -1;
    154         }
    155 
    156         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    157 
    158         if (NULL == back->fLastMask.texture()) {
    159             return -1;
    160         }
    161 
    162         return back->fLastMask.texture()->height();
    163     }
    164 
    165     void getLastBound(SkIRect* bound) const {
    166 
    167         if (fStack.empty()) {
    168             GrAssert(false);
    169             bound->setEmpty();
    170             return;
    171         }
    172 
    173         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    174 
    175         *bound = back->fLastBound;
    176     }
    177 
    178     void setContext(GrContext* context) {
    179         fContext = context;
    180     }
    181 
    182     GrContext* getContext() {
    183         return fContext;
    184     }
    185 
    186     void releaseResources() {
    187 
    188         SkDeque::F2BIter iter(fStack);
    189         for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
    190                 frame != NULL;
    191                 frame = (GrClipStackFrame*) iter.next()) {
    192             frame->reset();
    193         }
    194     }
    195 
    196 private:
    197     struct GrClipStackFrame {
    198 
    199         GrClipStackFrame() {
    200             this->reset();
    201         }
    202 
    203         void acquireMask(GrContext* context,
    204                          int32_t clipGenID,
    205                          const GrTextureDesc& desc,
    206                          const SkIRect& bound) {
    207 
    208             fLastClipGenID = clipGenID;
    209 
    210             fLastMask.set(context, desc);
    211 
    212             fLastBound = bound;
    213         }
    214 
    215         void reset () {
    216             fLastClipGenID = SkClipStack::kInvalidGenID;
    217 
    218             GrTextureDesc desc;
    219 
    220             fLastMask.set(NULL, desc);
    221             fLastBound.setEmpty();
    222         }
    223 
    224         int32_t                 fLastClipGenID;
    225         // The mask's width & height values are used by GrClipMaskManager to correctly scale the
    226         // texture coords for the geometry drawn with this mask.
    227         GrAutoScratchTexture    fLastMask;
    228         // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
    229         // used by GrClipMaskManager to position a rect and compute texture coords for the mask.
    230         SkIRect                 fLastBound;
    231     };
    232 
    233     GrContext*   fContext;
    234     SkDeque      fStack;
    235 
    236     typedef GrNoncopyable INHERITED;
    237 };
    238 
    239 #endif // GrClipMaskCache_DEFINED
    240