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 GrSurfaceProxy_DEFINED
9 #define GrSurfaceProxy_DEFINED
10 
11 #include "GrGpuResource.h"
12 #include "GrSurface.h"
13 
14 #include "SkRect.h"
15 
16 class GrCaps;
17 class GrRenderTargetOpList;
18 class GrRenderTargetProxy;
19 class GrResourceProvider;
20 class GrSurfaceContext;
21 class GrSurfaceProxyPriv;
22 class GrTextureOpList;
23 class GrTextureProxy;
24 
25 // This class replicates the functionality GrIORef<GrSurface> but tracks the
26 // utilitization for later resource allocation (for the deferred case) and
27 // forwards on the utilization in the wrapped case
28 class GrIORefProxy : public SkNoncopyable {
29 public:
ref()30     void ref() const {
31         this->validate();
32 
33         ++fRefCnt;
34         if (fTarget) {
35             fTarget->ref();
36         }
37     }
38 
unref()39     void unref() const {
40         this->validate();
41 
42         if (fTarget) {
43             fTarget->unref();
44         }
45 
46         if (!(--fRefCnt)) {
47             delete this;
48             return;
49         }
50 
51         this->validate();
52     }
53 
validate()54     void validate() const {
55 #ifdef SK_DEBUG
56         SkASSERT(fRefCnt >= 1);
57         SkASSERT(fPendingReads >= 0);
58         SkASSERT(fPendingWrites >= 0);
59         SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1);
60 
61         if (fTarget) {
62             SkASSERT(!fPendingReads && !fPendingWrites);
63             // The backing GrSurface can have more refs than the proxy if the proxy
64             // started off wrapping an external resource (that came in with refs).
65             // The GrSurface should never have fewer refs than the proxy however.
66             SkASSERT(fTarget->fRefCnt >= fRefCnt);
67         }
68 #endif
69     }
70 
71     int32_t getProxyRefCnt_TestOnly() const;
72     int32_t getBackingRefCnt_TestOnly() const;
73     int32_t getPendingReadCnt_TestOnly() const;
74     int32_t getPendingWriteCnt_TestOnly() const;
75 
76 protected:
GrIORefProxy()77     GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {}
GrIORefProxy(sk_sp<GrSurface> surface)78     GrIORefProxy(sk_sp<GrSurface> surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {
79         // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing
80         // anything extra.
81         fTarget = surface.release();
82     }
~GrIORefProxy()83     virtual ~GrIORefProxy() {
84         // We don't unref 'fTarget' here since the 'unref' method will already
85         // have forwarded on the unref call that got use here.
86     }
87 
88     // This GrIORefProxy was deferred before but has just been instantiated. To
89     // make all the reffing & unreffing work out we now need to transfer any deferred
90     // refs & unrefs to the new GrSurface
transferRefs()91     void transferRefs() {
92         SkASSERT(fTarget);
93 
94         fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref
95         fTarget->fPendingReads += fPendingReads;
96         fTarget->fPendingWrites += fPendingWrites;
97 
98         fPendingReads = 0;
99         fPendingWrites = 0;
100     }
101 
internalHasPendingIO()102     bool internalHasPendingIO() const {
103         if (fTarget) {
104             return fTarget->internalHasPendingIO();
105         }
106 
107         return SkToBool(fPendingWrites | fPendingReads);
108     }
109 
110     // For deferred proxies this will be null. For wrapped proxies it will point to the
111     // wrapped resource.
112     GrSurface* fTarget;
113 
114 private:
115     // This class is used to manage conversion of refs to pending reads/writes.
116     friend class GrGpuResourceRef;
117     template <typename, GrIOType> friend class GrPendingIOResource;
118 
addPendingRead()119     void addPendingRead() const {
120         this->validate();
121 
122         if (fTarget) {
123             fTarget->addPendingRead();
124             return;
125         }
126 
127         ++fPendingReads;
128     }
129 
completedRead()130     void completedRead() const {
131         this->validate();
132 
133         if (fTarget) {
134             fTarget->completedRead();
135             return;
136         }
137 
138         SkFAIL("How was the read completed if the Proxy hasn't been instantiated?");
139     }
140 
addPendingWrite()141     void addPendingWrite() const {
142         this->validate();
143 
144         if (fTarget) {
145             fTarget->addPendingWrite();
146             return;
147         }
148 
149         ++fPendingWrites;
150     }
151 
completedWrite()152     void completedWrite() const {
153         this->validate();
154 
155         if (fTarget) {
156             fTarget->completedWrite();
157             return;
158         }
159 
160         SkFAIL("How was the write completed if the Proxy hasn't been instantiated?");
161     }
162 
163     mutable int32_t fRefCnt;
164     mutable int32_t fPendingReads;
165     mutable int32_t fPendingWrites;
166 };
167 
168 class GrSurfaceProxy : public GrIORefProxy {
169 public:
170     static sk_sp<GrSurfaceProxy> MakeWrapped(sk_sp<GrSurface>);
171     static sk_sp<GrTextureProxy> MakeWrapped(sk_sp<GrTexture>);
172 
173     static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
174                                               const GrSurfaceDesc&, SkBackingFit,
175                                               SkBudgeted, uint32_t flags = 0);
176 
177     // TODO: need to refine ownership semantics of 'srcData' if we're in completely
178     // deferred mode
179     static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
180                                               const GrSurfaceDesc&, SkBudgeted,
181                                               const void* srcData, size_t rowBytes);
182 
183     static sk_sp<GrSurfaceProxy> MakeWrappedBackend(GrContext*, GrBackendTextureDesc&);
184 
desc()185     const GrSurfaceDesc& desc() const { return fDesc; }
186 
origin()187     GrSurfaceOrigin origin() const {
188         SkASSERT(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin ||
189                  kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin);
190         return fDesc.fOrigin;
191     }
width()192     int width() const { return fDesc.fWidth; }
height()193     int height() const { return fDesc.fHeight; }
config()194     GrPixelConfig config() const { return fDesc.fConfig; }
195 
196     class UniqueID {
197     public:
198         // wrapped
UniqueID(const GrGpuResource::UniqueID & id)199         explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
200         // deferred
UniqueID()201         UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
202 
asUInt()203         uint32_t asUInt() const { return fID; }
204 
205         bool operator==(const UniqueID& other) const {
206             return fID == other.fID;
207         }
208         bool operator!=(const UniqueID& other) const {
209             return !(*this == other);
210         }
211 
isInvalid()212         bool isInvalid() const { return SK_InvalidUniqueID == fID; }
213 
214     private:
215         const uint32_t fID;
216     };
217 
218     /*
219      * The contract for the uniqueID is:
220      *   for wrapped resources:
221      *      the uniqueID will match that of the wrapped resource
222      *
223      *   for deferred resources:
224      *      the uniqueID will be different from the real resource, when it is allocated
225      *      the proxy's uniqueID will not change across the instantiate call
226      *
227      *    the uniqueIDs of the proxies and the resources draw from the same pool
228      *
229      * What this boils down to is that the uniqueID of a proxy can be used to consistently
230      * track/identify a proxy but should never be used to distinguish between
231      * resources and proxies - beware!
232      */
uniqueID()233     UniqueID uniqueID() const { return fUniqueID; }
234 
235     GrSurface* instantiate(GrResourceProvider* resourceProvider);
236 
237     /**
238      * Helper that gets the width and height of the surface as a bounding rectangle.
239      */
getBoundsRect()240     SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
241 
242     int worstCaseWidth(const GrCaps& caps) const;
243     int worstCaseHeight(const GrCaps& caps) const;
244 
245     /**
246      * @return the texture proxy associated with the surface proxy, may be NULL.
247      */
asTextureProxy()248     virtual GrTextureProxy* asTextureProxy() { return nullptr; }
asTextureProxy()249     virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
250 
251     /**
252      * @return the render target proxy associated with the surface proxy, may be NULL.
253      */
asRenderTargetProxy()254     virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
asRenderTargetProxy()255     virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
256 
257     /**
258      * Does the resource count against the resource budget?
259      */
isBudgeted()260     SkBudgeted isBudgeted() const { return fBudgeted; }
261 
262     void setLastOpList(GrOpList* opList);
getLastOpList()263     GrOpList* getLastOpList() { return fLastOpList; }
264 
265     GrRenderTargetOpList* getLastRenderTargetOpList();
266     GrTextureOpList* getLastTextureOpList();
267 
268     /**
269      * Retrieves the amount of GPU memory that will be or currently is used by this resource
270      * in bytes. It is approximate since we aren't aware of additional padding or copies made
271      * by the driver.
272      *
273      * @return the amount of GPU memory used in bytes
274      */
gpuMemorySize()275     size_t gpuMemorySize() const {
276         if (kInvalidGpuMemorySize == fGpuMemorySize) {
277             fGpuMemorySize = this->onGpuMemorySize();
278             SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
279         }
280         return fGpuMemorySize;
281     }
282 
283     // Helper function that creates a temporary SurfaceContext to perform the copy
284     // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage
285     // to an SkImage.
286     static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src,
287                                       SkIRect srcRect, SkBudgeted);
288 
289     // Copy the entire 'src'
290     // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial
291     static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src,
292                                       SkBudgeted budgeted);
293 
294     // Test-only entry point - should decrease in use as proxies propagate
295     static sk_sp<GrSurfaceContext> TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
296                                             GrSurfaceProxy* srcProxy);
297 
298     bool isWrapped_ForTesting() const;
299 
300     SkDEBUGCODE(void validate(GrContext*) const;)
301 
302     // Provides access to functions that aren't part of the public API.
303     GrSurfaceProxyPriv priv();
304     const GrSurfaceProxyPriv priv() const;
305 
306 protected:
307     // Deferred version
GrSurfaceProxy(const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)308     GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
309         : fDesc(desc)
310         , fFit(fit)
311         , fBudgeted(budgeted)
312         , fFlags(flags)
313         // fMipColorMode is only valid for texturable proxies
314         , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
315         , fGpuMemorySize(kInvalidGpuMemorySize)
316         , fLastOpList(nullptr) {
317         // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
318     }
319 
320     // Wrapped version
321     GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit);
322 
323     virtual ~GrSurfaceProxy();
324 
325     friend class GrSurfaceProxyPriv;
326 
327     // Methods made available via GrSurfaceProxyPriv
hasPendingIO()328     bool hasPendingIO() const {
329         return this->internalHasPendingIO();
330     }
331 
332     // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource.
333     GrSurfaceDesc        fDesc;
334     SkBackingFit         fFit;      // always exact for wrapped resources
335     mutable SkBudgeted   fBudgeted; // set from the backing resource for wrapped resources
336                                     // mutable bc of SkSurface/SkImage wishy-washiness
337     const uint32_t       fFlags;
338 
339     SkDestinationSurfaceColorMode fMipColorMode;
340 
341     const UniqueID       fUniqueID; // set from the backing resource for wrapped resources
342 
343     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
344     SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
345 
346 private:
347     virtual size_t onGpuMemorySize() const = 0;
348 
349     // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
350     // will be called but, when the proxy is deferred, it will compute the answer itself.
351     // If the proxy computes its own answer that answer is checked (in debug mode) in
352     // the instantiation method.
353     mutable size_t      fGpuMemorySize;
354 
355     // The last opList that wrote to or is currently going to write to this surface
356     // The opList can be closed (e.g., no render target context is currently bound
357     // to this renderTarget).
358     // This back-pointer is required so that we can add a dependancy between
359     // the opList used to create the current contents of this surface
360     // and the opList of a destination surface to which this one is being drawn or copied.
361     GrOpList* fLastOpList;
362 
363 
364     typedef GrIORefProxy INHERITED;
365 };
366 
367 #endif
368