blob: 731603b2c9cd93d0c5a492328d1c6d94e335e255 [file] [log] [blame]
robertphillips76948d42016-05-04 12:47:41 -07001/*
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 GrSurfaceProxy_DEFINED
9#define GrSurfaceProxy_DEFINED
10
11#include "GrGpuResource.h"
Robert Phillipsc7635fa2016-10-28 13:25:24 -040012#include "GrSurface.h"
Robert Phillips93f16332016-11-23 19:37:13 -050013
csmartdaltonbf4a8f92016-09-06 10:01:06 -070014#include "SkRect.h"
robertphillips76948d42016-05-04 12:47:41 -070015
Robert Phillips37430132016-11-09 06:50:43 -050016class GrCaps;
Brian Osman45580d32016-11-23 09:37:01 -050017class GrRenderTargetOpList;
18class GrRenderTargetProxy;
19class GrTextureOpList;
Robert Phillipseaa86252016-11-08 13:49:39 +000020class GrTextureProvider;
robertphillips76948d42016-05-04 12:47:41 -070021class GrTextureProxy;
robertphillips76948d42016-05-04 12:47:41 -070022
Robert Phillipsc7635fa2016-10-28 13:25:24 -040023// This class replicates the functionality GrIORef<GrSurface> but tracks the
24// utilitization for later resource allocation (for the deferred case) and
25// forwards on the utilization in the wrapped case
26class GrIORefProxy : public SkNoncopyable {
27public:
28 void ref() const {
29 this->validate();
30
31 ++fRefCnt;
32 if (fTarget) {
33 fTarget->ref();
34 }
35 }
36
37 void unref() const {
38 this->validate();
39
40 if (fTarget) {
41 fTarget->unref();
42 }
43
44 if (!(--fRefCnt)) {
45 delete this;
46 return;
47 }
48
49 this->validate();
50 }
51
52 void validate() const {
53#ifdef SK_DEBUG
robertphillips1125a032016-11-16 11:17:17 -080054 SkASSERT(fRefCnt >= 1);
55 SkASSERT(fPendingReads >= 0);
56 SkASSERT(fPendingWrites >= 0);
57 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1);
58
59 if (fTarget) {
60 SkASSERT(!fPendingReads && !fPendingWrites);
61 // The backing GrSurface can have more refs than the proxy if the proxy
62 // started off wrapping an external resource (that came in with refs).
63 // The GrSurface should never have fewer refs than the proxy however.
64 SkASSERT(fTarget->fRefCnt >= fRefCnt);
65 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -040066#endif
67 }
68
robertphillips1125a032016-11-16 11:17:17 -080069 int32_t getProxyRefCnt_TestOnly() const;
70 int32_t getBackingRefCnt_TestOnly() const;
71 int32_t getPendingReadCnt_TestOnly() const;
72 int32_t getPendingWriteCnt_TestOnly() const;
73
Robert Phillipsc7635fa2016-10-28 13:25:24 -040074protected:
robertphillips1125a032016-11-16 11:17:17 -080075 GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {}
76 GrIORefProxy(sk_sp<GrSurface> surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {
Robert Phillipsc7635fa2016-10-28 13:25:24 -040077 // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing
78 // anything extra.
79 fTarget = surface.release();
80 }
81 virtual ~GrIORefProxy() {
82 // We don't unref 'fTarget' here since the 'unref' method will already
83 // have forwarded on the unref call that got use here.
84 }
85
robertphillips1125a032016-11-16 11:17:17 -080086 // This GrIORefProxy was deferred before but has just been instantiated. To
87 // make all the reffing & unreffing work out we now need to transfer any deferred
88 // refs & unrefs to the new GrSurface
89 void transferRefs() {
90 SkASSERT(fTarget);
91
92 fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref
93 fTarget->fPendingReads += fPendingReads;
94 fTarget->fPendingWrites += fPendingWrites;
95
96 fPendingReads = 0;
97 fPendingWrites = 0;
98 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -040099
100 // For deferred proxies this will be null. For wrapped proxies it will point to the
101 // wrapped resource.
102 GrSurface* fTarget;
robertphillips1125a032016-11-16 11:17:17 -0800103
104private:
105 // This class is used to manage conversion of refs to pending reads/writes.
106 friend class GrGpuResourceRef;
107 template <typename, GrIOType> friend class GrPendingIOResource;
108
109 void addPendingRead() const {
110 this->validate();
111
112 if (fTarget) {
113 fTarget->addPendingRead();
114 return;
115 }
116
117 ++fPendingReads;
118 }
119
120 void completedRead() const {
121 this->validate();
122
123 if (fTarget) {
124 fTarget->completedRead();
125 return;
126 }
127
128 SkFAIL("How was the read completed if the Proxy hasn't been instantiated?");
129 }
130
131 void addPendingWrite() const {
132 this->validate();
133
134 if (fTarget) {
135 fTarget->addPendingWrite();
136 return;
137 }
138
139 ++fPendingWrites;
140 }
141
142 void completedWrite() const {
143 this->validate();
144
145 if (fTarget) {
146 fTarget->completedWrite();
147 return;
148 }
149
150 SkFAIL("How was the write completed if the Proxy hasn't been instantiated?");
151 }
152
153 mutable int32_t fRefCnt;
154 mutable int32_t fPendingReads;
155 mutable int32_t fPendingWrites;
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400156};
157
158class GrSurfaceProxy : public GrIORefProxy {
robertphillips76948d42016-05-04 12:47:41 -0700159public:
Robert Phillips37430132016-11-09 06:50:43 -0500160 static sk_sp<GrSurfaceProxy> MakeWrapped(sk_sp<GrSurface>);
161
162 static sk_sp<GrSurfaceProxy> MakeDeferred(const GrCaps&, const GrSurfaceDesc&,
163 SkBackingFit, SkBudgeted);
164
165 // TODO: need to refine ownership semantics of 'srcData' if we're in completely
166 // deferred mode
167 static sk_sp<GrSurfaceProxy> MakeDeferred(const GrCaps&, GrTextureProvider*,
168 const GrSurfaceDesc&, SkBudgeted,
169 const void* srcData, size_t rowBytes);
170
robertphillips76948d42016-05-04 12:47:41 -0700171 const GrSurfaceDesc& desc() const { return fDesc; }
172
173 GrSurfaceOrigin origin() const {
174 SkASSERT(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin ||
175 kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin);
176 return fDesc.fOrigin;
177 }
178 int width() const { return fDesc.fWidth; }
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400179 int height() const { return fDesc.fHeight; }
robertphillips76948d42016-05-04 12:47:41 -0700180 GrPixelConfig config() const { return fDesc.fConfig; }
181
Robert Phillips294870f2016-11-11 12:38:40 -0500182 class UniqueID {
183 public:
184 // wrapped
185 explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
186 // deferred
187 UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
188
189 uint32_t asUInt() const { return fID; }
190
191 bool operator==(const UniqueID& other) const {
192 return fID == other.fID;
193 }
194 bool operator!=(const UniqueID& other) const {
195 return !(*this == other);
196 }
197
198 bool isInvalid() const { return SK_InvalidUniqueID == fID; }
199
200 private:
201 const uint32_t fID;
202 };
203
204 /*
205 * The contract for the uniqueID is:
206 * for wrapped resources:
207 * the uniqueID will match that of the wrapped resource
208 *
209 * for deferred resources:
210 * the uniqueID will be different from the real resource, when it is allocated
211 * the proxy's uniqueID will not change across the instantiate call
212 *
213 * the uniqueIDs of the proxies and the resources draw from the same pool
214 *
215 * What this boils down to is that the uniqueID of a proxy can be used to consistently
216 * track/identify a proxy but should never be used to distinguish between
217 * resources and proxies - beware!
218 */
219 UniqueID uniqueID() const { return fUniqueID; }
robertphillips76948d42016-05-04 12:47:41 -0700220
Robert Phillips37430132016-11-09 06:50:43 -0500221 GrSurface* instantiate(GrTextureProvider* texProvider);
222
robertphillips76948d42016-05-04 12:47:41 -0700223 /**
robertphillips13a7eee2016-08-31 15:06:24 -0700224 * Helper that gets the width and height of the surface as a bounding rectangle.
225 */
226 SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
Robert Phillips784b7bf2016-12-09 13:35:02 -0500227
228 int worstCaseWidth(const GrCaps& caps) const;
229 int worstCaseHeight(const GrCaps& caps) const;
Robert Phillips93f16332016-11-23 19:37:13 -0500230
robertphillips13a7eee2016-08-31 15:06:24 -0700231 /**
robertphillips76948d42016-05-04 12:47:41 -0700232 * @return the texture proxy associated with the surface proxy, may be NULL.
233 */
234 virtual GrTextureProxy* asTextureProxy() { return nullptr; }
235 virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
236
237 /**
238 * @return the render target proxy associated with the surface proxy, may be NULL.
239 */
240 virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
241 virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
242
robertphillips13a7eee2016-08-31 15:06:24 -0700243 /**
244 * Does the resource count against the resource budget?
245 */
246 SkBudgeted isBudgeted() const { return fBudgeted; }
247
Robert Phillipsf2361d22016-10-25 14:20:06 -0400248 void setLastOpList(GrOpList* opList);
249 GrOpList* getLastOpList() { return fLastOpList; }
250
Brian Osman45580d32016-11-23 09:37:01 -0500251 GrRenderTargetOpList* getLastRenderTargetOpList();
252 GrTextureOpList* getLastTextureOpList();
253
Robert Phillips8bc06d02016-11-01 17:28:40 -0400254 /**
255 * Retrieves the amount of GPU memory that will be or currently is used by this resource
256 * in bytes. It is approximate since we aren't aware of additional padding or copies made
257 * by the driver.
258 *
259 * @return the amount of GPU memory used in bytes
260 */
261 size_t gpuMemorySize() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400262 if (kInvalidGpuMemorySize == fGpuMemorySize) {
263 fGpuMemorySize = this->onGpuMemorySize();
264 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
265 }
266 return fGpuMemorySize;
267 }
268
Robert Phillipseaa86252016-11-08 13:49:39 +0000269 bool isWrapped_ForTesting() const;
270
Brian Osman45580d32016-11-23 09:37:01 -0500271 SkDEBUGCODE(void validate(GrContext*) const;)
272
robertphillips76948d42016-05-04 12:47:41 -0700273protected:
robertphillips8abb3702016-08-31 14:04:06 -0700274 // Deferred version
robertphillips76948d42016-05-04 12:47:41 -0700275 GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted)
276 : fDesc(desc)
277 , fFit(fit)
278 , fBudgeted(budgeted)
Robert Phillips8bc06d02016-11-01 17:28:40 -0400279 , fGpuMemorySize(kInvalidGpuMemorySize)
Robert Phillipsf2361d22016-10-25 14:20:06 -0400280 , fLastOpList(nullptr) {
Robert Phillips294870f2016-11-11 12:38:40 -0500281 // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
robertphillips8abb3702016-08-31 14:04:06 -0700282 }
283
284 // Wrapped version
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400285 GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit);
robertphillips76948d42016-05-04 12:47:41 -0700286
Robert Phillipsf2361d22016-10-25 14:20:06 -0400287 virtual ~GrSurfaceProxy();
288
robertphillips76948d42016-05-04 12:47:41 -0700289 // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource.
Robert Phillips294870f2016-11-11 12:38:40 -0500290 const GrSurfaceDesc fDesc;
291 const SkBackingFit fFit; // always exact for wrapped resources
292 const SkBudgeted fBudgeted; // set from the backing resource for wrapped resources
293 const UniqueID fUniqueID; // set from the backing resource for wrapped resources
robertphillips76948d42016-05-04 12:47:41 -0700294
Robert Phillips8bc06d02016-11-01 17:28:40 -0400295 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Robert Phillips29e52f12016-11-03 10:19:14 -0400296 SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
297
298private:
299 virtual size_t onGpuMemorySize() const = 0;
300
Robert Phillips8bc06d02016-11-01 17:28:40 -0400301 // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
302 // will be called but, when the proxy is deferred, it will compute the answer itself.
303 // If the proxy computes its own answer that answer is checked (in debug mode) in
304 // the instantiation method.
305 mutable size_t fGpuMemorySize;
306
Robert Phillipsf2361d22016-10-25 14:20:06 -0400307 // The last opList that wrote to or is currently going to write to this surface
Brian Osman11052242016-10-27 14:47:55 -0400308 // The opList can be closed (e.g., no render target context is currently bound
Robert Phillipsf2361d22016-10-25 14:20:06 -0400309 // to this renderTarget).
310 // This back-pointer is required so that we can add a dependancy between
311 // the opList used to create the current contents of this surface
312 // and the opList of a destination surface to which this one is being drawn or copied.
313 GrOpList* fLastOpList;
314
Robert Phillips29e52f12016-11-03 10:19:14 -0400315
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400316 typedef GrIORefProxy INHERITED;
robertphillips76948d42016-05-04 12:47:41 -0700317};
318
319#endif