Line data Source code
1 : /*
2 : * Copyright 2015 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 GrOp_DEFINED
9 : #define GrOp_DEFINED
10 :
11 : #include "../private/SkAtomics.h"
12 : #include "GrGpuResource.h"
13 : #include "GrNonAtomicRef.h"
14 : #include "GrXferProcessor.h"
15 : #include "SkMatrix.h"
16 : #include "SkRect.h"
17 : #include "SkString.h"
18 :
19 : #include <new>
20 :
21 : class GrCaps;
22 : class GrGpuCommandBuffer;
23 : class GrOpFlushState;
24 :
25 : /**
26 : * GrOp is the base class for all Ganesh deferred GPU operations. To facilitate reordering and to
27 : * minimize draw calls, Ganesh does not generate geometry inline with draw calls. Instead, it
28 : * captures the arguments to the draw and then generates the geometry when flushing. This gives GrOp
29 : * subclasses complete freedom to decide how/when to combine in order to produce fewer draw calls
30 : * and minimize state changes.
31 : *
32 : * Ops of the same subclass may be merged using combineIfPossible. When two ops merge, one
33 : * takes on the union of the data and the other is left empty. The merged op becomes responsible
34 : * for drawing the data from both the original ops.
35 : *
36 : * If there are any possible optimizations which might require knowing more about the full state of
37 : * the draw, e.g. whether or not the GrOp is allowed to tweak alpha for coverage, then this
38 : * information will be communicated to the GrOp prior to geometry generation.
39 : *
40 : * The bounds of the op must contain all the vertices in device space *irrespective* of the clip.
41 : * The bounds are used in determining which clip elements must be applied and thus the bounds cannot
42 : * in turn depend upon the clip.
43 : */
44 : #define GR_OP_SPEW 0
45 : #if GR_OP_SPEW
46 : #define GrOP_SPEW(code) code
47 : #define GrOP_INFO(...) SkDebugf(__VA_ARGS__)
48 : #else
49 : #define GrOP_SPEW(code)
50 : #define GrOP_INFO(...)
51 : #endif
52 :
53 : // A helper macro to generate a class static id
54 : #define DEFINE_OP_CLASS_ID \
55 : static uint32_t ClassID() { \
56 : static uint32_t kClassID = GenOpClassID(); \
57 : return kClassID; \
58 : }
59 :
60 : class GrOp : private SkNoncopyable {
61 : public:
62 : GrOp(uint32_t classID);
63 : virtual ~GrOp();
64 :
65 : virtual const char* name() const = 0;
66 :
67 0 : bool combineIfPossible(GrOp* that, const GrCaps& caps) {
68 0 : if (this->classID() != that->classID()) {
69 0 : return false;
70 : }
71 :
72 0 : return this->onCombineIfPossible(that, caps);
73 : }
74 :
75 0 : const SkRect& bounds() const {
76 0 : SkASSERT(kUninitialized_BoundsFlag != fBoundsFlags);
77 0 : return fBounds;
78 : }
79 :
80 0 : void setClippedBounds(const SkRect& clippedBounds) {
81 0 : fBounds = clippedBounds;
82 : // The clipped bounds already incorporate any effect of the bounds flags.
83 0 : fBoundsFlags = 0;
84 0 : }
85 :
86 0 : bool hasAABloat() const {
87 0 : SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag);
88 0 : return SkToBool(fBoundsFlags & kAABloat_BoundsFlag);
89 : }
90 :
91 0 : bool hasZeroArea() const {
92 0 : SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag);
93 0 : return SkToBool(fBoundsFlags & kZeroArea_BoundsFlag);
94 : }
95 :
96 : void* operator new(size_t size);
97 : void operator delete(void* target);
98 :
99 : void* operator new(size_t size, void* placement) {
100 : return ::operator new(size, placement);
101 : }
102 : void operator delete(void* target, void* placement) {
103 : ::operator delete(target, placement);
104 : }
105 :
106 : /**
107 : * Helper for safely down-casting to a GrOp subclass
108 : */
109 : template <typename T> const T& cast() const {
110 : SkASSERT(T::ClassID() == this->classID());
111 : return *static_cast<const T*>(this);
112 : }
113 :
114 0 : template <typename T> T* cast() {
115 0 : SkASSERT(T::ClassID() == this->classID());
116 0 : return static_cast<T*>(this);
117 : }
118 :
119 0 : uint32_t classID() const { SkASSERT(kIllegalOpID != fClassID); return fClassID; }
120 :
121 : // We lazily initialize the uniqueID because currently the only user is GrAuditTrail
122 0 : uint32_t uniqueID() const {
123 0 : if (kIllegalOpID == fUniqueID) {
124 0 : fUniqueID = GenOpID();
125 : }
126 0 : return fUniqueID;
127 : }
128 :
129 : /**
130 : * This is called to notify the op that it has been recorded into a GrOpList. Ops can use this
131 : * to begin preparations for the flush of the op list. Note that the op still may either be
132 : * combined into another op or have another op combined into it via combineIfPossible() after
133 : * this call is made.
134 : */
135 0 : virtual void wasRecorded() {}
136 :
137 : /**
138 : * Called prior to executing. The op should perform any resource creation or data transfers
139 : * necessary before execute() is called.
140 : */
141 0 : void prepare(GrOpFlushState* state) { this->onPrepare(state); }
142 :
143 : /** Issues the op's commands to GrGpu. */
144 0 : void execute(GrOpFlushState* state) { this->onExecute(state); }
145 :
146 : /** Used for spewing information about ops when debugging. */
147 0 : virtual SkString dumpInfo() const {
148 0 : SkString string;
149 0 : string.appendf("OpBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
150 0 : fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
151 0 : return string;
152 : }
153 :
154 : protected:
155 : /**
156 : * Indicates that the op will produce geometry that extends beyond its bounds for the
157 : * purpose of ensuring that the fragment shader runs on partially covered pixels for
158 : * non-MSAA antialiasing.
159 : */
160 : enum class HasAABloat {
161 : kYes,
162 : kNo
163 : };
164 : /**
165 : * Indicates that the geometry represented by the op has zero area (e.g. it is hairline or
166 : * points).
167 : */
168 : enum class IsZeroArea {
169 : kYes,
170 : kNo
171 : };
172 0 : void setBounds(const SkRect& newBounds, HasAABloat aabloat, IsZeroArea zeroArea) {
173 0 : fBounds = newBounds;
174 0 : this->setBoundsFlags(aabloat, zeroArea);
175 0 : }
176 0 : void setTransformedBounds(const SkRect& srcBounds, const SkMatrix& m,
177 : HasAABloat aabloat, IsZeroArea zeroArea) {
178 0 : m.mapRect(&fBounds, srcBounds);
179 0 : this->setBoundsFlags(aabloat, zeroArea);
180 0 : }
181 :
182 0 : void joinBounds(const GrOp& that) {
183 0 : if (that.hasAABloat()) {
184 0 : fBoundsFlags |= kAABloat_BoundsFlag;
185 : }
186 0 : if (that.hasZeroArea()) {
187 0 : fBoundsFlags |= kZeroArea_BoundsFlag;
188 : }
189 0 : return fBounds.joinPossiblyEmptyRect(that.fBounds);
190 : }
191 :
192 0 : void replaceBounds(const GrOp& that) {
193 0 : fBounds = that.fBounds;
194 0 : fBoundsFlags = that.fBoundsFlags;
195 0 : }
196 :
197 0 : static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); }
198 :
199 : private:
200 : virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0;
201 :
202 : virtual void onPrepare(GrOpFlushState*) = 0;
203 : virtual void onExecute(GrOpFlushState*) = 0;
204 :
205 0 : static uint32_t GenID(int32_t* idCounter) {
206 : // The atomic inc returns the old value not the incremented value. So we add
207 : // 1 to the returned value.
208 0 : uint32_t id = static_cast<uint32_t>(sk_atomic_inc(idCounter)) + 1;
209 0 : if (!id) {
210 0 : SkFAIL("This should never wrap as it should only be called once for each GrOp "
211 : "subclass.");
212 : }
213 0 : return id;
214 : }
215 :
216 0 : void setBoundsFlags(HasAABloat aabloat, IsZeroArea zeroArea) {
217 0 : fBoundsFlags = 0;
218 0 : fBoundsFlags |= (HasAABloat::kYes == aabloat) ? kAABloat_BoundsFlag : 0;
219 0 : fBoundsFlags |= (IsZeroArea ::kYes == zeroArea) ? kZeroArea_BoundsFlag : 0;
220 0 : }
221 :
222 : enum {
223 : kIllegalOpID = 0,
224 : };
225 :
226 : enum BoundsFlags {
227 : kAABloat_BoundsFlag = 0x1,
228 : kZeroArea_BoundsFlag = 0x2,
229 : SkDEBUGCODE(kUninitialized_BoundsFlag = 0x4)
230 : };
231 :
232 : const uint16_t fClassID;
233 : uint16_t fBoundsFlags;
234 :
235 0 : static uint32_t GenOpID() { return GenID(&gCurrOpUniqueID); }
236 : mutable uint32_t fUniqueID;
237 : SkRect fBounds;
238 :
239 : static int32_t gCurrOpUniqueID;
240 : static int32_t gCurrOpClassID;
241 : };
242 :
243 : #endif
|