Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2016 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 GrReducedClip_DEFINED
      9 #define GrReducedClip_DEFINED
     10 
     11 #include "GrFragmentProcessor.h"
     12 #include "GrWindowRectangles.h"
     13 #include "SkClipStack.h"
     14 #include "SkTLList.h"
     15 
     16 class GrContext;
     17 class GrCoverageCountingPathRenderer;
     18 class GrRenderTargetContext;
     19 
     20 /**
     21  * This class takes a clip stack and produces a reduced set of elements that are equivalent to
     22  * applying that full stack within a specified query rectangle.
     23  */
     24 class SK_API GrReducedClip {
     25 public:
     26     using Element = SkClipStack::Element;
     27     using ElementList = SkTLList<SkClipStack::Element, 16>;
     28 
     29     GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrShaderCaps* caps,
     30                   int maxWindowRectangles = 0, int maxAnalyticFPs = 0,
     31                   GrCoverageCountingPathRenderer* = nullptr);
     32 
     33     enum class InitialState : bool {
     34         kAllIn,
     35         kAllOut
     36     };
     37 
     38     InitialState initialState() const { return fInitialState; }
     39 
     40     /**
     41      * If hasScissor() is true, the clip mask is not valid outside this rect and the caller must
     42      * enforce this scissor during draw.
     43      */
     44     const SkIRect& scissor() const { SkASSERT(fHasScissor); return fScissor; }
     45     int left() const { return this->scissor().left(); }
     46     int top() const { return this->scissor().top(); }
     47     int width() const { return this->scissor().width(); }
     48     int height() const { return this->scissor().height(); }
     49 
     50     /**
     51      * Indicates whether scissor() is defined. It will always be defined if the maskElements() are
     52      * nonempty.
     53      */
     54     bool hasScissor() const { return fHasScissor; }
     55 
     56     /**
     57      * If nonempty, the clip mask is not valid inside these windows and the caller must clip them
     58      * out using the window rectangles GPU extension.
     59      */
     60     const GrWindowRectangles& windowRectangles() const { return fWindowRects; }
     61 
     62     /**
     63      * An ordered list of clip elements that could not be skipped or implemented by other means. If
     64      * nonempty, the caller must create an alpha and/or stencil mask for these elements and apply it
     65      * during draw.
     66      */
     67     const ElementList& maskElements() const { return fMaskElements; }
     68 
     69     /**
     70      * If maskElements() are nonempty, uniquely identifies the region of the clip mask that falls
     71      * inside of scissor().
     72      *
     73      * NOTE: since clip elements might fall outside the query bounds, different regions of the same
     74      * clip stack might have more or less restrictive IDs.
     75      *
     76      * FIXME: this prevents us from reusing a sub-rect of a perfectly good mask when that rect has
     77      * been assigned a less restrictive ID.
     78      */
     79     uint32_t maskGenID() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskGenID; }
     80 
     81     /**
     82      * Indicates whether antialiasing is required to process any of the mask elements.
     83      */
     84     bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; }
     85 
     86     bool drawAlphaClipMask(GrRenderTargetContext*) const;
     87     bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const;
     88 
     89     int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); }
     90 
     91     /**
     92      * Called once the client knows the ID of the opList that the clip FPs will operate in. This
     93      * method finishes any outstanding work that was waiting for the opList ID, then detaches and
     94      * returns this class's list of FPs that complete the clip.
     95      *
     96      * NOTE: this must be called AFTER producing the clip mask (if any) because draw calls on
     97      * the render target context, surface allocations, and even switching render targets (pre MDB)
     98      * may cause flushes or otherwise change which opList the actual draw is going into.
     99      */
    100     std::unique_ptr<GrFragmentProcessor> finishAndDetachAnalyticFPs(GrProxyProvider*,
    101                                                                     uint32_t opListID,
    102                                                                     int rtWidth, int rtHeight);
    103 
    104 private:
    105     void walkStack(const SkClipStack&, const SkRect& queryBounds);
    106 
    107     enum class ClipResult {
    108         kNotClipped,
    109         kClipped,
    110         kMadeEmpty
    111     };
    112 
    113     // Intersects the clip with the element's interior, regardless of inverse fill type.
    114     // NOTE: do not call for elements followed by ops that can grow the clip.
    115     ClipResult clipInsideElement(const Element*);
    116 
    117     // Intersects the clip with the element's exterior, regardless of inverse fill type.
    118     // NOTE: do not call for elements followed by ops that can grow the clip.
    119     ClipResult clipOutsideElement(const Element*);
    120 
    121     void addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA);
    122 
    123     enum class Invert : bool {
    124         kNo = false,
    125         kYes = true
    126     };
    127 
    128     static GrClipEdgeType GetClipEdgeType(Invert, GrAA);
    129     ClipResult addAnalyticFP(const SkRect& deviceSpaceRect, Invert, GrAA);
    130     ClipResult addAnalyticFP(const SkRRect& deviceSpaceRRect, Invert, GrAA);
    131     ClipResult addAnalyticFP(const SkPath& deviceSpacePath, Invert, GrAA);
    132 
    133     void makeEmpty();
    134 
    135     const GrShaderCaps* fCaps;
    136     const int fMaxWindowRectangles;
    137     const int fMaxAnalyticFPs;
    138     GrCoverageCountingPathRenderer* const fCCPR;
    139 
    140     InitialState fInitialState;
    141     SkIRect fScissor;
    142     bool fHasScissor;
    143     SkRect fAAClipRect;
    144     uint32_t fAAClipRectGenID; // GenID the mask will have if includes the AA clip rect.
    145     GrWindowRectangles fWindowRects;
    146     ElementList fMaskElements;
    147     uint32_t fMaskGenID;
    148     bool fMaskRequiresAA;
    149     SkSTArray<4, std::unique_ptr<GrFragmentProcessor>> fAnalyticFPs;
    150     SkSTArray<4, SkPath> fCCPRClipPaths; // Will convert to FPs once we have an opList ID for CCPR.
    151 };
    152 
    153 #endif
    154