blob: 254fc44237ce8f23f92744f50d47b804584f9843 [file] [log] [blame]
joshualitt4d8da812015-01-28 12:53:54 -08001/*
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
Brian Salomon53e4c3c2016-12-21 11:38:53 -05008#ifndef GrOp_DEFINED
9#define GrOp_DEFINED
joshualitt4d8da812015-01-28 12:53:54 -080010
bungeman2c4bd072016-04-08 06:58:51 -070011#include "../private/SkAtomics.h"
Robert Phillips294870f2016-11-11 12:38:40 -050012#include "GrGpuResource.h"
joshualittdbe1e6f2015-07-16 08:12:45 -070013#include "GrNonAtomicRef.h"
Brian Salomon54d212e2017-03-21 14:22:38 -040014#include "GrXferProcessor.h"
bsalomon88cf17d2016-07-08 06:40:56 -070015#include "SkMatrix.h"
bsalomon16b99132015-08-13 14:55:50 -070016#include "SkRect.h"
bsalomon53469832015-08-18 09:20:09 -070017#include "SkString.h"
joshualitt4d8da812015-01-28 12:53:54 -080018
bungeman2c4bd072016-04-08 06:58:51 -070019#include <new>
20
bsalomon16b99132015-08-13 14:55:50 -070021class GrCaps;
egdaniel9cb63402016-06-23 08:37:05 -070022class GrGpuCommandBuffer;
Brian Salomon742e31d2016-12-07 17:06:19 -050023class GrOpFlushState;
Robert Phillipse3302df2017-04-24 07:31:02 -040024class GrRenderTargetOpList;
joshualitt4d8da812015-01-28 12:53:54 -080025
bsalomonabd30f52015-08-13 13:34:48 -070026/**
Brian Salomon53e4c3c2016-12-21 11:38:53 -050027 * GrOp is the base class for all Ganesh deferred GPU operations. To facilitate reordering and to
28 * minimize draw calls, Ganesh does not generate geometry inline with draw calls. Instead, it
29 * captures the arguments to the draw and then generates the geometry when flushing. This gives GrOp
30 * subclasses complete freedom to decide how/when to combine in order to produce fewer draw calls
31 * and minimize state changes.
joshualitt4d8da812015-01-28 12:53:54 -080032 *
Brian Salomon25a88092016-12-01 09:36:50 -050033 * Ops of the same subclass may be merged using combineIfPossible. When two ops merge, one
34 * takes on the union of the data and the other is left empty. The merged op becomes responsible
35 * for drawing the data from both the original ops.
joshualitt4d8da812015-01-28 12:53:54 -080036 *
37 * If there are any possible optimizations which might require knowing more about the full state of
Brian Salomon25a88092016-12-01 09:36:50 -050038 * the draw, e.g. whether or not the GrOp is allowed to tweak alpha for coverage, then this
39 * information will be communicated to the GrOp prior to geometry generation.
bsalomondb4758c2015-11-23 11:14:20 -080040 *
Brian Salomon25a88092016-12-01 09:36:50 -050041 * The bounds of the op must contain all the vertices in device space *irrespective* of the clip.
bsalomondb4758c2015-11-23 11:14:20 -080042 * The bounds are used in determining which clip elements must be applied and thus the bounds cannot
43 * in turn depend upon the clip.
joshualitt4d8da812015-01-28 12:53:54 -080044 */
Brian Salomon25a88092016-12-01 09:36:50 -050045#define GR_OP_SPEW 0
46#if GR_OP_SPEW
47 #define GrOP_SPEW(code) code
48 #define GrOP_INFO(...) SkDebugf(__VA_ARGS__)
joshualittca1f07e2015-08-07 08:11:19 -070049#else
Brian Salomon25a88092016-12-01 09:36:50 -050050 #define GrOP_SPEW(code)
51 #define GrOP_INFO(...)
joshualittca1f07e2015-08-07 08:11:19 -070052#endif
joshualitt4d8da812015-01-28 12:53:54 -080053
reed1b55a962015-09-17 20:16:13 -070054// A helper macro to generate a class static id
Brian Salomon25a88092016-12-01 09:36:50 -050055#define DEFINE_OP_CLASS_ID \
reed1b55a962015-09-17 20:16:13 -070056 static uint32_t ClassID() { \
Brian Salomon25a88092016-12-01 09:36:50 -050057 static uint32_t kClassID = GenOpClassID(); \
reed1b55a962015-09-17 20:16:13 -070058 return kClassID; \
59 }
60
Brian Salomonf8334782017-01-03 09:42:58 -050061class GrOp : private SkNoncopyable {
joshualitt4d8da812015-01-28 12:53:54 -080062public:
Brian Salomon25a88092016-12-01 09:36:50 -050063 GrOp(uint32_t classID);
64 virtual ~GrOp();
joshualitt4d8da812015-01-28 12:53:54 -080065
66 virtual const char* name() const = 0;
joshualitt4d8da812015-01-28 12:53:54 -080067
Brian Salomon25a88092016-12-01 09:36:50 -050068 bool combineIfPossible(GrOp* that, const GrCaps& caps) {
joshualitt4d8da812015-01-28 12:53:54 -080069 if (this->classID() != that->classID()) {
70 return false;
71 }
72
bsalomoncb02b382015-08-12 11:14:50 -070073 return this->onCombineIfPossible(that, caps);
joshualitt4d8da812015-01-28 12:53:54 -080074 }
75
bsalomon88cf17d2016-07-08 06:40:56 -070076 const SkRect& bounds() const {
77 SkASSERT(kUninitialized_BoundsFlag != fBoundsFlags);
78 return fBounds;
79 }
80
Brian Salomon9e50f7b2017-03-06 12:02:34 -050081 void setClippedBounds(const SkRect& clippedBounds) {
82 fBounds = clippedBounds;
83 // The clipped bounds already incorporate any effect of the bounds flags.
84 fBoundsFlags = 0;
85 }
86
bsalomon88cf17d2016-07-08 06:40:56 -070087 bool hasAABloat() const {
88 SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag);
89 return SkToBool(fBoundsFlags & kAABloat_BoundsFlag);
90 }
91
92 bool hasZeroArea() const {
93 SkASSERT(fBoundsFlags != kUninitialized_BoundsFlag);
94 return SkToBool(fBoundsFlags & kZeroArea_BoundsFlag);
95 }
joshualitt99c7c072015-05-01 13:43:30 -070096
joshualitt4d8da812015-01-28 12:53:54 -080097 void* operator new(size_t size);
98 void operator delete(void* target);
99
100 void* operator new(size_t size, void* placement) {
101 return ::operator new(size, placement);
102 }
103 void operator delete(void* target, void* placement) {
104 ::operator delete(target, placement);
105 }
106
107 /**
Brian Salomon25a88092016-12-01 09:36:50 -0500108 * Helper for safely down-casting to a GrOp subclass
bsalomonabd30f52015-08-13 13:34:48 -0700109 */
reed1b55a962015-09-17 20:16:13 -0700110 template <typename T> const T& cast() const {
111 SkASSERT(T::ClassID() == this->classID());
112 return *static_cast<const T*>(this);
113 }
114
115 template <typename T> T* cast() {
116 SkASSERT(T::ClassID() == this->classID());
117 return static_cast<T*>(this);
118 }
joshualitt4d8da812015-01-28 12:53:54 -0800119
Brian Salomon25a88092016-12-01 09:36:50 -0500120 uint32_t classID() const { SkASSERT(kIllegalOpID != fClassID); return fClassID; }
joshualitt4d8da812015-01-28 12:53:54 -0800121
joshualitt08e65e72016-03-08 09:31:15 -0800122 // We lazily initialize the uniqueID because currently the only user is GrAuditTrail
halcanary9d524f22016-03-29 09:03:52 -0700123 uint32_t uniqueID() const {
Brian Salomon25a88092016-12-01 09:36:50 -0500124 if (kIllegalOpID == fUniqueID) {
125 fUniqueID = GenOpID();
joshualitt08e65e72016-03-08 09:31:15 -0800126 }
halcanary9d524f22016-03-29 09:03:52 -0700127 return fUniqueID;
joshualitt08e65e72016-03-08 09:31:15 -0800128 }
joshualittca1f07e2015-08-07 08:11:19 -0700129
Brian Salomonbde42852016-12-21 11:37:49 -0500130 /**
Brian Salomond543e0a2017-03-06 16:36:49 -0500131 * This is called to notify the op that it has been recorded into a GrOpList. Ops can use this
132 * to begin preparations for the flush of the op list. Note that the op still may either be
133 * combined into another op or have another op combined into it via combineIfPossible() after
134 * this call is made.
135 */
Robert Phillipse3302df2017-04-24 07:31:02 -0400136 virtual void wasRecorded(GrRenderTargetOpList*) {}
Brian Salomond543e0a2017-03-06 16:36:49 -0500137
138 /**
Brian Salomonbde42852016-12-21 11:37:49 -0500139 * Called prior to executing. The op should perform any resource creation or data transfers
140 * necessary before execute() is called.
141 */
Brian Salomon742e31d2016-12-07 17:06:19 -0500142 void prepare(GrOpFlushState* state) { this->onPrepare(state); }
bsalomon53469832015-08-18 09:20:09 -0700143
Brian Salomon25a88092016-12-01 09:36:50 -0500144 /** Issues the op's commands to GrGpu. */
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500145 void execute(GrOpFlushState* state) { this->onExecute(state); }
bsalomon53469832015-08-18 09:20:09 -0700146
Brian Salomon25a88092016-12-01 09:36:50 -0500147 /** Used for spewing information about ops when debugging. */
robertphillips44fbc792016-06-29 06:56:12 -0700148 virtual SkString dumpInfo() const {
149 SkString string;
Brian Salomon25a88092016-12-01 09:36:50 -0500150 string.appendf("OpBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
robertphillips44fbc792016-06-29 06:56:12 -0700151 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
152 return string;
153 }
bsalomon53469832015-08-18 09:20:09 -0700154
Robert Phillips178ce3e2017-04-13 09:15:47 -0400155 virtual bool needsCommandBufferIsolation() const { return false; }
156
joshualitt4d8da812015-01-28 12:53:54 -0800157protected:
bsalomon88cf17d2016-07-08 06:40:56 -0700158 /**
Brian Salomon25a88092016-12-01 09:36:50 -0500159 * Indicates that the op will produce geometry that extends beyond its bounds for the
bsalomon88cf17d2016-07-08 06:40:56 -0700160 * purpose of ensuring that the fragment shader runs on partially covered pixels for
161 * non-MSAA antialiasing.
162 */
163 enum class HasAABloat {
164 kYes,
165 kNo
166 };
167 /**
Brian Salomon25a88092016-12-01 09:36:50 -0500168 * Indicates that the geometry represented by the op has zero area (e.g. it is hairline or
169 * points).
bsalomon88cf17d2016-07-08 06:40:56 -0700170 */
171 enum class IsZeroArea {
172 kYes,
173 kNo
174 };
Robert Phillips65a88fa2017-08-08 08:36:22 -0400175
bsalomon88cf17d2016-07-08 06:40:56 -0700176 void setBounds(const SkRect& newBounds, HasAABloat aabloat, IsZeroArea zeroArea) {
177 fBounds = newBounds;
178 this->setBoundsFlags(aabloat, zeroArea);
179 }
180 void setTransformedBounds(const SkRect& srcBounds, const SkMatrix& m,
181 HasAABloat aabloat, IsZeroArea zeroArea) {
182 m.mapRect(&fBounds, srcBounds);
183 this->setBoundsFlags(aabloat, zeroArea);
184 }
Robert Phillips65a88fa2017-08-08 08:36:22 -0400185 void makeFullScreen(GrSurfaceProxy* proxy) {
186 this->setBounds(SkRect::MakeIWH(proxy->width(), proxy->height()),
187 HasAABloat::kNo, IsZeroArea::kNo);
188 }
joshualitt99c7c072015-05-01 13:43:30 -0700189
Brian Salomon25a88092016-12-01 09:36:50 -0500190 void joinBounds(const GrOp& that) {
bsalomon88cf17d2016-07-08 06:40:56 -0700191 if (that.hasAABloat()) {
192 fBoundsFlags |= kAABloat_BoundsFlag;
193 }
194 if (that.hasZeroArea()) {
195 fBoundsFlags |= kZeroArea_BoundsFlag;
196 }
197 return fBounds.joinPossiblyEmptyRect(that.fBounds);
198 }
199
Brian Salomon25a88092016-12-01 09:36:50 -0500200 void replaceBounds(const GrOp& that) {
bsalomon88cf17d2016-07-08 06:40:56 -0700201 fBounds = that.fBounds;
202 fBoundsFlags = that.fBoundsFlags;
joshualitt99c7c072015-05-01 13:43:30 -0700203 }
204
Brian Salomon25a88092016-12-01 09:36:50 -0500205 static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); }
reed1b55a962015-09-17 20:16:13 -0700206
bsalomonabd30f52015-08-13 13:34:48 -0700207private:
Brian Salomon25a88092016-12-01 09:36:50 -0500208 virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0;
bsalomonabd30f52015-08-13 13:34:48 -0700209
Brian Salomon742e31d2016-12-07 17:06:19 -0500210 virtual void onPrepare(GrOpFlushState*) = 0;
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500211 virtual void onExecute(GrOpFlushState*) = 0;
bsalomon53469832015-08-18 09:20:09 -0700212
bsalomonabd30f52015-08-13 13:34:48 -0700213 static uint32_t GenID(int32_t* idCounter) {
reed1b55a962015-09-17 20:16:13 -0700214 // The atomic inc returns the old value not the incremented value. So we add
bsalomonabd30f52015-08-13 13:34:48 -0700215 // 1 to the returned value.
216 uint32_t id = static_cast<uint32_t>(sk_atomic_inc(idCounter)) + 1;
217 if (!id) {
Brian Salomon25a88092016-12-01 09:36:50 -0500218 SkFAIL("This should never wrap as it should only be called once for each GrOp "
bsalomonabd30f52015-08-13 13:34:48 -0700219 "subclass.");
220 }
221 return id;
222 }
223
bsalomon88cf17d2016-07-08 06:40:56 -0700224 void setBoundsFlags(HasAABloat aabloat, IsZeroArea zeroArea) {
225 fBoundsFlags = 0;
226 fBoundsFlags |= (HasAABloat::kYes == aabloat) ? kAABloat_BoundsFlag : 0;
227 fBoundsFlags |= (IsZeroArea ::kYes == zeroArea) ? kZeroArea_BoundsFlag : 0;
228 }
229
bsalomonabd30f52015-08-13 13:34:48 -0700230 enum {
Brian Salomon25a88092016-12-01 09:36:50 -0500231 kIllegalOpID = 0,
bsalomonabd30f52015-08-13 13:34:48 -0700232 };
233
bsalomon88cf17d2016-07-08 06:40:56 -0700234 enum BoundsFlags {
235 kAABloat_BoundsFlag = 0x1,
236 kZeroArea_BoundsFlag = 0x2,
237 SkDEBUGCODE(kUninitialized_BoundsFlag = 0x4)
238 };
239
bsalomon88cf17d2016-07-08 06:40:56 -0700240 const uint16_t fClassID;
241 uint16_t fBoundsFlags;
242
Brian Salomon25a88092016-12-01 09:36:50 -0500243 static uint32_t GenOpID() { return GenID(&gCurrOpUniqueID); }
joshualitt08e65e72016-03-08 09:31:15 -0800244 mutable uint32_t fUniqueID;
bsalomon88cf17d2016-07-08 06:40:56 -0700245 SkRect fBounds;
246
Brian Salomon25a88092016-12-01 09:36:50 -0500247 static int32_t gCurrOpUniqueID;
248 static int32_t gCurrOpClassID;
bsalomonabd30f52015-08-13 13:34:48 -0700249};
250
joshualitt4d8da812015-01-28 12:53:54 -0800251#endif