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