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