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