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