michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrClipMaskCache_DEFINED michael@0: #define GrClipMaskCache_DEFINED michael@0: michael@0: #include "GrContext.h" michael@0: #include "SkClipStack.h" michael@0: #include "SkTypes.h" michael@0: michael@0: class GrTexture; michael@0: michael@0: /** michael@0: * The stencil buffer stores the last clip path - providing a single entry michael@0: * "cache". This class provides similar functionality for AA clip paths michael@0: */ michael@0: class GrClipMaskCache : public SkNoncopyable { michael@0: public: michael@0: GrClipMaskCache(); michael@0: michael@0: ~GrClipMaskCache() { michael@0: michael@0: while (!fStack.empty()) { michael@0: GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back(); michael@0: temp->~GrClipStackFrame(); michael@0: fStack.pop_back(); michael@0: } michael@0: } michael@0: michael@0: bool canReuse(int32_t clipGenID, const SkIRect& bounds) { michael@0: michael@0: SkASSERT(clipGenID != SkClipStack::kWideOpenGenID); michael@0: SkASSERT(clipGenID != SkClipStack::kEmptyGenID); michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate michael@0: // an offset to the caller. michael@0: if (back->fLastMask.texture() && michael@0: back->fLastBound == bounds && michael@0: back->fLastClipGenID == clipGenID) { michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void reset() { michael@0: if (fStack.empty()) { michael@0: // SkASSERT(false); michael@0: return; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: back->reset(); michael@0: } michael@0: michael@0: /** michael@0: * After a "push" the clip state is entirely open. Currently, the michael@0: * entire clip stack will be re-rendered into a new clip mask. michael@0: * TODO: can we take advantage of the nested nature of the clips to michael@0: * reduce the mask creation cost? michael@0: */ michael@0: void push(); michael@0: michael@0: void pop() { michael@0: //SkASSERT(!fStack.empty()); michael@0: michael@0: if (!fStack.empty()) { michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: back->~GrClipStackFrame(); michael@0: fStack.pop_back(); michael@0: } michael@0: } michael@0: michael@0: int32_t getLastClipGenID() const { michael@0: michael@0: if (fStack.empty()) { michael@0: return SkClipStack::kInvalidGenID; michael@0: } michael@0: michael@0: return ((GrClipStackFrame*) fStack.back())->fLastClipGenID; michael@0: } michael@0: michael@0: GrTexture* getLastMask() { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: return NULL; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: return back->fLastMask.texture(); michael@0: } michael@0: michael@0: const GrTexture* getLastMask() const { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: return NULL; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: return back->fLastMask.texture(); michael@0: } michael@0: michael@0: void acquireMask(int32_t clipGenID, michael@0: const GrTextureDesc& desc, michael@0: const SkIRect& bound) { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: return; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: back->acquireMask(fContext, clipGenID, desc, bound); michael@0: } michael@0: michael@0: int getLastMaskWidth() const { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: return -1; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: if (NULL == back->fLastMask.texture()) { michael@0: return -1; michael@0: } michael@0: michael@0: return back->fLastMask.texture()->width(); michael@0: } michael@0: michael@0: int getLastMaskHeight() const { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: return -1; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: if (NULL == back->fLastMask.texture()) { michael@0: return -1; michael@0: } michael@0: michael@0: return back->fLastMask.texture()->height(); michael@0: } michael@0: michael@0: void getLastBound(SkIRect* bound) const { michael@0: michael@0: if (fStack.empty()) { michael@0: SkASSERT(false); michael@0: bound->setEmpty(); michael@0: return; michael@0: } michael@0: michael@0: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); michael@0: michael@0: *bound = back->fLastBound; michael@0: } michael@0: michael@0: void setContext(GrContext* context) { michael@0: fContext = context; michael@0: } michael@0: michael@0: GrContext* getContext() { michael@0: return fContext; michael@0: } michael@0: michael@0: void releaseResources() { michael@0: michael@0: SkDeque::F2BIter iter(fStack); michael@0: for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next(); michael@0: frame != NULL; michael@0: frame = (GrClipStackFrame*) iter.next()) { michael@0: frame->reset(); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: struct GrClipStackFrame { michael@0: michael@0: GrClipStackFrame() { michael@0: this->reset(); michael@0: } michael@0: michael@0: void acquireMask(GrContext* context, michael@0: int32_t clipGenID, michael@0: const GrTextureDesc& desc, michael@0: const SkIRect& bound) { michael@0: michael@0: fLastClipGenID = clipGenID; michael@0: michael@0: fLastMask.set(context, desc); michael@0: michael@0: fLastBound = bound; michael@0: } michael@0: michael@0: void reset () { michael@0: fLastClipGenID = SkClipStack::kInvalidGenID; michael@0: michael@0: GrTextureDesc desc; michael@0: michael@0: fLastMask.set(NULL, desc); michael@0: fLastBound.setEmpty(); michael@0: } michael@0: michael@0: int32_t fLastClipGenID; michael@0: // The mask's width & height values are used by GrClipMaskManager to correctly scale the michael@0: // texture coords for the geometry drawn with this mask. michael@0: GrAutoScratchTexture fLastMask; michael@0: // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is michael@0: // used by GrClipMaskManager to position a rect and compute texture coords for the mask. michael@0: SkIRect fLastBound; michael@0: }; michael@0: michael@0: GrContext* fContext; michael@0: SkDeque fStack; michael@0: michael@0: typedef SkNoncopyable INHERITED; michael@0: }; michael@0: michael@0: #endif // GrClipMaskCache_DEFINED