• 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 "include/core/SkRect.h"
12 #include "include/gpu/GrBackendSurface.h"
13 #include "include/gpu/GrGpuResource.h"
14 #include "include/gpu/GrSurface.h"
15 #include "include/gpu/GrTexture.h"
16 #include "include/private/SkNoncopyable.h"
17 #include "src/gpu/GrNonAtomicRef.h"
18 #include "src/gpu/GrSwizzle.h"
19 
20 class GrCaps;
21 class GrContext_Base;
22 class GrOpsTask;
23 class GrRecordingContext;
24 class GrRenderTargetProxy;
25 class GrRenderTask;
26 class GrResourceProvider;
27 class GrSurfaceContext;
28 class GrSurfaceProxyPriv;
29 class GrSurfaceProxyView;
30 class GrTextureProxy;
31 
32 class GrSurfaceProxy : public SkNVRefCnt<GrSurfaceProxy> {
33 public:
34     virtual ~GrSurfaceProxy();
35 
36     /**
37      * Indicates "resolutions" that need to be done on a surface before its pixels can be accessed.
38      * If both types of resolve are requested, the MSAA resolve will happen first.
39      */
40     enum class ResolveFlags {
41         kNone = 0,
42         kMSAA = 1 << 0,  // Blit and resolve an internal MSAA render buffer into the texture.
43         kMipMaps = 1 << 1,  // Regenerate all mipmap levels.
44     };
45 
46     /**
47      * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return.
48      * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls
49      * the key relationship between proxies and their targets.
50      */
51     enum class LazyInstantiationKeyMode {
52         /**
53          * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to
54          * return a GrSurface that already has a unique key unrelated to the proxy's key.
55          */
56         kUnsynced,
57         /**
58          * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface
59          * returned from the lazy instantiation callback must not have a unique key or have the same
60          * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned
61          * to the GrSurface.
62          */
63         kSynced
64     };
65 
66     struct LazyCallbackResult {
67         LazyCallbackResult() = default;
68         LazyCallbackResult(const LazyCallbackResult&) = default;
69         LazyCallbackResult(LazyCallbackResult&& that) = default;
70         LazyCallbackResult(sk_sp<GrSurface> surf,
71                            bool releaseCallback = true,
72                            LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced)
fSurfaceLazyCallbackResult73                 : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {}
LazyCallbackResultLazyCallbackResult74         LazyCallbackResult(sk_sp<GrTexture> tex)
75                 : LazyCallbackResult(sk_sp<GrSurface>(std::move(tex))) {}
76 
77         LazyCallbackResult& operator=(const LazyCallbackResult&) = default;
78         LazyCallbackResult& operator=(LazyCallbackResult&&) = default;
79 
80         sk_sp<GrSurface> fSurface;
81         LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced;
82         /**
83          * Should the callback be disposed of after it has returned or preserved until the proxy
84          * is freed. Only honored if fSurface is not-null. If it is null the callback is preserved.
85          */
86         bool fReleaseCallback = true;
87     };
88 
89     using LazyInstantiateCallback = std::function<LazyCallbackResult(GrResourceProvider*)>;
90 
91     enum class UseAllocator {
92         /**
93          * This proxy will be instantiated outside the allocator (e.g. for proxies that are
94          * instantiated in on-flush callbacks).
95          */
96         kNo = false,
97         /**
98          * GrResourceAllocator should instantiate this proxy.
99          */
100         kYes = true,
101     };
102 
isLazy()103     bool isLazy() const { return !this->isInstantiated() && SkToBool(fLazyInstantiateCallback); }
104 
isFullyLazy()105     bool isFullyLazy() const {
106         bool result = fDimensions.width() < 0;
107         SkASSERT(result == (fDimensions.height() < 0));
108         SkASSERT(!result || this->isLazy());
109         return result;
110     }
111 
dimensions()112     SkISize dimensions() const {
113         SkASSERT(!this->isFullyLazy());
114         return fDimensions;
115     }
width()116     int width() const { return this->dimensions().width(); }
height()117     int height() const { return this->dimensions().height(); }
118 
119     SkISize backingStoreDimensions() const;
120 
121     /**
122      * Helper that gets the width and height of the proxy as a bounding rectangle.
123      */
getBoundsRect()124     SkRect getBoundsRect() const { return SkRect::Make(this->dimensions()); }
125 
126     /* A perhaps faster check for this->dimensions() == this->backingStoreDimensions(). */
127     bool isFunctionallyExact() const;
128 
129     /**
130      * Helper that gets the dimensions the backing GrSurface will have as a bounding rectangle.
131      */
backingStoreBoundsRect()132     SkRect backingStoreBoundsRect() const {
133         return SkRect::Make(this->backingStoreDimensions());
134     }
135 
136     // Do not call this. It will shortly be removed and is just needed for a couple cases where we
137     // are getting a proxy from the cache and cannot be certain what the GrColorType of the proxy.
textureSwizzleDoNotUse()138     const GrSwizzle& textureSwizzleDoNotUse() const { return fTextureSwizzle; }
139 
backendFormat()140     const GrBackendFormat& backendFormat() const { return fFormat; }
141 
142     bool isFormatCompressed(const GrCaps*) const;
143 
144     class UniqueID {
145     public:
InvalidID()146         static UniqueID InvalidID() {
147             return UniqueID(uint32_t(SK_InvalidUniqueID));
148         }
149 
150         // wrapped
UniqueID(const GrGpuResource::UniqueID & id)151         explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
152         // deferred and lazy-callback
UniqueID()153         UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
154 
asUInt()155         uint32_t asUInt() const { return fID; }
156 
157         bool operator==(const UniqueID& other) const {
158             return fID == other.fID;
159         }
160         bool operator!=(const UniqueID& other) const {
161             return !(*this == other);
162         }
163 
makeInvalid()164         void makeInvalid() { fID = SK_InvalidUniqueID; }
isInvalid()165         bool isInvalid() const { return SK_InvalidUniqueID == fID; }
166 
167     private:
UniqueID(uint32_t id)168         explicit UniqueID(uint32_t id) : fID(id) {}
169 
170         uint32_t fID;
171     };
172 
173     /*
174      * The contract for the uniqueID is:
175      *   for wrapped resources:
176      *      the uniqueID will match that of the wrapped resource
177      *
178      *   for deferred resources:
179      *      the uniqueID will be different from the real resource, when it is allocated
180      *      the proxy's uniqueID will not change across the instantiate call
181      *
182      *    the uniqueIDs of the proxies and the resources draw from the same pool
183      *
184      * What this boils down to is that the uniqueID of a proxy can be used to consistently
185      * track/identify a proxy but should never be used to distinguish between
186      * resources and proxies - beware!
187      */
uniqueID()188     UniqueID uniqueID() const { return fUniqueID; }
189 
underlyingUniqueID()190     UniqueID underlyingUniqueID() const {
191         if (fTarget) {
192             return UniqueID(fTarget->uniqueID());
193         }
194 
195         return fUniqueID;
196     }
197 
198     virtual bool instantiate(GrResourceProvider*) = 0;
199 
200     void deinstantiate();
201 
202     /**
203      * Proxies that are already instantiated and whose backing surface cannot be recycled to
204      * instantiate other proxies do not need to be considered by GrResourceAllocator.
205      */
206     bool canSkipResourceAllocator() const;
207 
208     /**
209      * @return the texture proxy associated with the surface proxy, may be NULL.
210      */
asTextureProxy()211     virtual GrTextureProxy* asTextureProxy() { return nullptr; }
asTextureProxy()212     virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
213 
214     /**
215      * @return the render target proxy associated with the surface proxy, may be NULL.
216      */
asRenderTargetProxy()217     virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
asRenderTargetProxy()218     virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
219 
isInstantiated()220     bool isInstantiated() const { return SkToBool(fTarget); }
221 
222     // If the proxy is already instantiated, return its backing GrTexture; if not, return null.
peekSurface()223     GrSurface* peekSurface() const { return fTarget.get(); }
224 
225     // If this is a texture proxy and the proxy is already instantiated, return its backing
226     // GrTexture; if not, return null.
peekTexture()227     GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; }
228 
229     // If this is a render target proxy and the proxy is already instantiated, return its backing
230     // GrRenderTarget; if not, return null.
peekRenderTarget()231     GrRenderTarget* peekRenderTarget() const {
232         return fTarget ? fTarget->asRenderTarget() : nullptr;
233     }
234 
235     /**
236      * Does the resource count against the resource budget?
237      */
isBudgeted()238     SkBudgeted isBudgeted() const { return fBudgeted; }
239 
240     /**
241      * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write
242      * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and
243      * assignment in GrResourceAllocator.
244      */
readOnly()245     bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
framebufferOnly()246     bool framebufferOnly() const {
247         return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
248     }
249 
250     /**
251      * This means surface is a multisampled render target, and internally holds a non-msaa texture
252      * for resolving into. The render target resolves itself by blitting into this internal texture.
253      * (asTexture() might or might not return the internal texture, but if it does, we always
254      * resolve the render target before accessing this texture's data.)
255      */
requiresManualMSAAResolve()256     bool requiresManualMSAAResolve() const {
257         return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
258     }
259 
260     void setLastRenderTask(GrRenderTask*);
getLastRenderTask()261     GrRenderTask* getLastRenderTask() { return fLastRenderTask; }
262 
263     GrOpsTask* getLastOpsTask();
264 
265     /**
266      * Retrieves the amount of GPU memory that will be or currently is used by this resource
267      * in bytes. It is approximate since we aren't aware of additional padding or copies made
268      * by the driver.
269      *
270      * @return the amount of GPU memory used in bytes
271      */
gpuMemorySize(const GrCaps & caps)272     size_t gpuMemorySize(const GrCaps& caps) const {
273         SkASSERT(!this->isFullyLazy());
274         if (fTarget) {
275             return fTarget->gpuMemorySize();
276         }
277         if (kInvalidGpuMemorySize == fGpuMemorySize) {
278             fGpuMemorySize = this->onUninstantiatedGpuMemorySize(caps);
279             SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
280         }
281         return fGpuMemorySize;
282     }
283 
284     enum class RectsMustMatch : bool {
285         kNo = false,
286         kYes = true
287     };
288 
289     // Helper function that creates a temporary SurfaceContext to perform the copy
290     // The copy is is not a render target and not multisampled.
291     //
292     // The intended use of this copy call is simply to copy exact pixel values from one proxy to a
293     // new one. Thus there isn't a need for a swizzle when doing the copy. Also, there shouldn't be
294     // an assumed "view" of the copy. However, even though not really needed for the swizzle, we
295     // still pass in a srcColorType since it is required for making a GrSurface/RenderTargetContext.
296     // Additionally, almost all callers of this will immediately put the resulting proxy into a view
297     // which is compatible with the srcColorType and origin passed in here. Thus for now we just
298     // return the GrSurfaceProxyView that is already stored on the internal GrSurfaceContext. If we
299     // later decide to not pass in a srcColorType (and assume some default color type based on the
300     // backend format) then we should go back to returning a proxy here and have the callers decide
301     // what view they want of the proxy.
302     static GrSurfaceProxyView Copy(GrRecordingContext*, GrSurfaceProxy* src,
303                                    GrSurfaceOrigin, GrColorType srcColorType, GrMipMapped,
304                                    SkIRect srcRect, SkBackingFit, SkBudgeted,
305                                    RectsMustMatch = RectsMustMatch::kNo);
306 
307     // Same as above Copy but copies the entire 'src'
308     static GrSurfaceProxyView Copy(GrRecordingContext*, GrSurfaceProxy* src, GrSurfaceOrigin,
309                                    GrColorType srcColorType, GrMipMapped, SkBackingFit, SkBudgeted);
310 
311 #if GR_TEST_UTILS
312     int32_t testingOnly_getBackingRefCnt() const;
313     GrInternalSurfaceFlags testingOnly_getFlags() const;
314 #endif
315 
316     SkDEBUGCODE(void validate(GrContext_Base*) const;)
317 
318     // Provides access to functions that aren't part of the public API.
319     inline GrSurfaceProxyPriv priv();
320     inline const GrSurfaceProxyPriv priv() const;
321 
isProtected()322     GrProtected isProtected() const { return fIsProtected; }
323 
324 protected:
325     // Deferred version - takes a new UniqueID from the shared resource/proxy pool.
326     GrSurfaceProxy(const GrBackendFormat&,
327                    SkISize,
328                    GrRenderable,
329                    const GrSwizzle& textureSwizzle,
330                    SkBackingFit,
331                    SkBudgeted,
332                    GrProtected,
333                    GrInternalSurfaceFlags,
334                    UseAllocator);
335     // Lazy-callback version - takes a new UniqueID from the shared resource/proxy pool.
336     GrSurfaceProxy(LazyInstantiateCallback&&,
337                    const GrBackendFormat&,
338                    SkISize,
339                    GrRenderable,
340                    const GrSwizzle& textureSwizzle,
341                    SkBackingFit,
342                    SkBudgeted,
343                    GrProtected,
344                    GrInternalSurfaceFlags,
345                    UseAllocator);
346 
347     // Wrapped version - shares the UniqueID of the passed surface.
348     // Takes UseAllocator because even though this is already instantiated it still can participate
349     // in allocation by having its backing resource recycled to other uninstantiated proxies or
350     // not depending on UseAllocator.
351     GrSurfaceProxy(sk_sp<GrSurface>,
352                    const GrSwizzle& textureSwizzle,
353                    SkBackingFit,
354                    UseAllocator);
355 
356     friend class GrSurfaceProxyPriv;
357 
358     // Methods made available via GrSurfaceProxyPriv
ignoredByResourceAllocator()359     bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; }
setIgnoredByResourceAllocator()360     void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; }
361 
362     void computeScratchKey(const GrCaps&, GrScratchKey*) const;
363 
364     virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
365     void assign(sk_sp<GrSurface> surface);
366 
367     sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, GrRenderable,
368                                        GrMipMapped) const;
369 
370     // Once the dimensions of a fully-lazy proxy are decided, and before it gets instantiated, the
371     // client can use this optional method to specify the proxy's dimensions. (A proxy's dimensions
372     // can be less than the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise,
373     // the proxy's dimensions will be set to match the underlying GPU surface upon instantiation.
setLazyDimensions(SkISize dimensions)374     void setLazyDimensions(SkISize dimensions) {
375         SkASSERT(this->isFullyLazy());
376         SkASSERT(!dimensions.isEmpty());
377         fDimensions = dimensions;
378     }
379 
380     bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, GrRenderable,
381                          GrMipMapped, const GrUniqueKey*);
382 
383     // For deferred proxies this will be null until the proxy is instantiated.
384     // For wrapped proxies it will point to the wrapped resource.
385     sk_sp<GrSurface>       fTarget;
386 
387     // In many cases these flags aren't actually known until the proxy has been instantiated.
388     // However, Ganesh frequently needs to change its behavior based on these settings. For
389     // internally create proxies we will know these properties ahead of time. For wrapped
390     // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the
391     // call sites to provide the required information ahead of time. At instantiation time
392     // we verify that the assumed properties match the actual properties.
393     GrInternalSurfaceFlags fSurfaceFlags;
394 
395 private:
396     // For wrapped resources, 'fFormat', 'fWidth', and 'fHeight'; will always be filled in from the
397     // wrapped resource.
398     const GrBackendFormat  fFormat;
399     SkISize                fDimensions;
400     const GrSwizzle        fTextureSwizzle;
401 
402     SkBackingFit           fFit;      // always kApprox for lazy-callback resources
403                                       // always kExact for wrapped resources
404     mutable SkBudgeted     fBudgeted; // always kYes for lazy-callback resources
405                                       // set from the backing resource for wrapped resources
406                                       // mutable bc of SkSurface/SkImage wishy-washiness
407                                       // Only meaningful if fLazyInstantiateCallback is non-null.
408     UseAllocator           fUseAllocator;
409 
410     const UniqueID         fUniqueID; // set from the backing resource for wrapped resources
411 
412     LazyInstantiateCallback fLazyInstantiateCallback;
413 
414     SkDEBUGCODE(void validateSurface(const GrSurface*);)
415     SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;)
416 
417     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
418     SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
419 
420     virtual size_t onUninstantiatedGpuMemorySize(const GrCaps&) const = 0;
421 
422     bool                   fIgnoredByResourceAllocator = false;
423     GrProtected            fIsProtected;
424 
425     // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
426     // will be called but, when the proxy is deferred, it will compute the answer itself.
427     // If the proxy computes its own answer that answer is checked (in debug mode) in
428     // the instantiation method.
429     mutable size_t         fGpuMemorySize;
430 
431     // The last GrRenderTask that wrote to or is currently going to write to this surface
432     // The GrRenderTask can be closed (e.g., no surface context is currently bound
433     // to this proxy).
434     // This back-pointer is required so that we can add a dependancy between
435     // the GrRenderTask used to create the current contents of this surface
436     // and the GrRenderTask of a destination surface to which this one is being drawn or copied.
437     // This pointer is unreffed. GrRenderTasks own a ref on their surface proxies.
438     GrRenderTask*          fLastRenderTask = nullptr;
439 };
440 
441 GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags)
442 
443 #endif
444