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