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 "SkClipStack.h"
     13 #include "SkTypes.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 : SkNoncopyable {
     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         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     40 
     41         // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
     42         // an offset to the caller.
     43         if (back->fLastMask.texture() &&
     44             !back->fLastMask.texture()->wasDestroyed() &&
     45             back->fLastBound == bounds &&
     46             back->fLastClipGenID == clipGenID) {
     47             return true;
     48         }
     49 
     50         return false;
     51     }
     52 
     53     void reset() {
     54         if (fStack.empty()) {
     55 //            SkASSERT(false);
     56             return;
     57         }
     58 
     59         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     60 
     61         back->reset();
     62     }
     63 
     64     /**
     65      * After a "push" the clip state is entirely open. Currently, the
     66      * entire clip stack will be re-rendered into a new clip mask.
     67      * TODO: can we take advantage of the nested nature of the clips to
     68      * reduce the mask creation cost?
     69      */
     70     void push();
     71 
     72     void pop() {
     73         //SkASSERT(!fStack.empty());
     74 
     75         if (!fStack.empty()) {
     76             GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
     77 
     78             back->~GrClipStackFrame();
     79             fStack.pop_back();
     80         }
     81     }
     82 
     83     int32_t getLastClipGenID() const {
     84 
     85         if (fStack.empty()) {
     86             return SkClipStack::kInvalidGenID;
     87         }
     88 
     89         return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
     90     }
     91 
     92     GrTexture* getLastMask() {
     93 
     94         if (fStack.empty()) {
     95             SkASSERT(false);
     96             return NULL;
     97         }
     98 
     99         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    100 
    101         return back->fLastMask.texture();
    102     }
    103 
    104     const GrTexture* getLastMask() const {
    105 
    106         if (fStack.empty()) {
    107             SkASSERT(false);
    108             return NULL;
    109         }
    110 
    111         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    112 
    113         return back->fLastMask.texture();
    114     }
    115 
    116     void acquireMask(int32_t clipGenID,
    117                      const GrTextureDesc& desc,
    118                      const SkIRect& bound) {
    119 
    120         if (fStack.empty()) {
    121             SkASSERT(false);
    122             return;
    123         }
    124 
    125         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    126 
    127         back->acquireMask(fContext, clipGenID, desc, bound);
    128     }
    129 
    130     int getLastMaskWidth() const {
    131 
    132         if (fStack.empty()) {
    133             SkASSERT(false);
    134             return -1;
    135         }
    136 
    137         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    138 
    139         if (NULL == back->fLastMask.texture()) {
    140             return -1;
    141         }
    142 
    143         return back->fLastMask.texture()->width();
    144     }
    145 
    146     int getLastMaskHeight() const {
    147 
    148         if (fStack.empty()) {
    149             SkASSERT(false);
    150             return -1;
    151         }
    152 
    153         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    154 
    155         if (NULL == back->fLastMask.texture()) {
    156             return -1;
    157         }
    158 
    159         return back->fLastMask.texture()->height();
    160     }
    161 
    162     void getLastBound(SkIRect* bound) const {
    163 
    164         if (fStack.empty()) {
    165             SkASSERT(false);
    166             bound->setEmpty();
    167             return;
    168         }
    169 
    170         GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
    171 
    172         *bound = back->fLastBound;
    173     }
    174 
    175     void setContext(GrContext* context) {
    176         fContext = context;
    177     }
    178 
    179     GrContext* getContext() {
    180         return fContext;
    181     }
    182 
    183     //  TODO: Remove this when we hold cache keys instead of refs to textures.
    184     void purgeResources() {
    185         SkDeque::F2BIter iter(fStack);
    186         for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
    187                 frame != NULL;
    188                 frame = (GrClipStackFrame*) iter.next()) {
    189             frame->reset();
    190         }
    191     }
    192 
    193 private:
    194     struct GrClipStackFrame {
    195 
    196         GrClipStackFrame() {
    197             this->reset();
    198         }
    199 
    200         void acquireMask(GrContext* context,
    201                          int32_t clipGenID,
    202                          const GrTextureDesc& desc,
    203                          const SkIRect& bound) {
    204 
    205             fLastClipGenID = clipGenID;
    206 
    207             fLastMask.set(context, desc);
    208 
    209             fLastBound = bound;
    210         }
    211 
    212         void reset () {
    213             fLastClipGenID = SkClipStack::kInvalidGenID;
    214 
    215             GrTextureDesc desc;
    216 
    217             fLastMask.set(NULL, desc);
    218             fLastBound.setEmpty();
    219         }
    220 
    221         int32_t                 fLastClipGenID;
    222         // The mask's width & height values are used by GrClipMaskManager to correctly scale the
    223         // texture coords for the geometry drawn with this mask. TODO: This should be a cache key
    224         // and not a hard ref to a texture.
    225         GrAutoScratchTexture    fLastMask;
    226         // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
    227         // used by GrClipMaskManager to position a rect and compute texture coords for the mask.
    228         SkIRect                 fLastBound;
    229     };
    230 
    231     GrContext*   fContext;
    232     SkDeque      fStack;
    233 
    234     typedef SkNoncopyable INHERITED;
    235 };
    236 
    237 #endif // GrClipMaskCache_DEFINED
    238