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