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