xref: /third_party/skia/src/gpu/GrSurfaceProxy.h (revision cb93a386)
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
18class GrCaps;
19class GrContext_Base;
20class GrRecordingContext;
21class GrRenderTargetProxy;
22class GrRenderTask;
23class GrResourceProvider;
24class GrSurfaceProxyPriv;
25class GrSurfaceProxyView;
26class GrTextureProxy;
27
28class SK_API GrSurfaceProxy : public SkNVRefCnt<GrSurfaceProxy> {
29public:
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)
85                : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {}
86        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
116    bool isLazy() const { return !this->isInstantiated() && SkToBool(fLazyInstantiateCallback); }
117
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
125    SkISize dimensions() const {
126        SkASSERT(!this->isFullyLazy());
127        return fDimensions;
128    }
129    int width() const { return this->dimensions().width(); }
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     */
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     */
145    SkRect backingStoreBoundsRect() const {
146        return SkRect::Make(this->backingStoreDimensions());
147    }
148
149    SkIRect backingStoreBoundsIRect() const {
150        return SkIRect::MakeSize(this->backingStoreDimensions());
151    }
152
153    const GrBackendFormat& backendFormat() const { return fFormat; }
154
155    bool isFormatCompressed(const GrCaps*) const;
156
157    class UniqueID {
158    public:
159        static UniqueID InvalidID() {
160            return UniqueID(uint32_t(SK_InvalidUniqueID));
161        }
162
163        // wrapped
164        explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
165        // deferred and lazy-callback
166        UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
167
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
177        void makeInvalid() { fID = SK_InvalidUniqueID; }
178        bool isInvalid() const { return SK_InvalidUniqueID == fID; }
179
180    private:
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     */
201    UniqueID uniqueID() const { return fUniqueID; }
202
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     */
224    virtual GrTextureProxy* asTextureProxy() { return nullptr; }
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     */
230    virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
231    virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
232
233    /** @return The unique key for this proxy. May be invalid. */
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
240    bool isInstantiated() const { return SkToBool(fTarget); }
241
242    /** Called when this task becomes a target of a GrRenderTask. */
243    void isUsedAsTaskTarget() { ++fTaskTargetCount; }
244
245    /** How many render tasks has this proxy been the target of? */
246    int getTaskTargetCount() const { return fTaskTargetCount; }
247
248    // If the proxy is already instantiated, return its backing GrTexture; if not, return null.
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.
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.
257    GrRenderTarget* peekRenderTarget() const {
258        return fTarget ? fTarget->asRenderTarget() : nullptr;
259    }
260
261    /**
262     * Does the resource count against the resource budget?
263     */
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     */
271    bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
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     */
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     */
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;
345    SkString getDebugName() {
346        return fDebugName.isEmpty() ? SkStringPrintf("%d", this->uniqueID().asUInt()) : fDebugName;
347    }
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
355    bool isDDLTarget() const { return fIsDDLTarget; }
356
357    GrProtected isProtected() const { return fIsProtected; }
358
359    bool isPromiseProxy() { return fIsPromiseProxy; }
360
361    // Get the proxy tag.
362    void setGrProxyTag(const GrGpuResourceTag& tag) { fGrProxyTag = tag; }
363
364protected:
365    // Deferred version - takes a new UniqueID from the shared resource/proxy pool.
366    GrSurfaceProxy(const GrBackendFormat&,
367                   SkISize,
368                   SkBackingFit,
369                   SkBudgeted,
370                   GrProtected,
371                   GrInternalSurfaceFlags,
372                   UseAllocator);
373    // Lazy-callback version - takes a new UniqueID from the shared resource/proxy pool.
374    GrSurfaceProxy(LazyInstantiateCallback&&,
375                   const GrBackendFormat&,
376                   SkISize,
377                   SkBackingFit,
378                   SkBudgeted,
379                   GrProtected,
380                   GrInternalSurfaceFlags,
381                   UseAllocator);
382
383    // Wrapped version - shares the UniqueID of the passed surface.
384    // Takes UseAllocator because even though this is already instantiated it still can participate
385    // in allocation by having its backing resource recycled to other uninstantiated proxies or
386    // not depending on UseAllocator.
387    GrSurfaceProxy(sk_sp<GrSurface>,
388                   SkBackingFit,
389                   UseAllocator);
390
391    friend class GrSurfaceProxyPriv;
392
393    // Methods made available via GrSurfaceProxyPriv
394    bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; }
395    void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; }
396
397    void computeScratchKey(const GrCaps&, GrScratchKey*) const;
398
399    virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
400    void assign(sk_sp<GrSurface> surface);
401
402    sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, GrRenderable,
403                                       GrMipmapped) const;
404
405    // Once the dimensions of a fully-lazy proxy are decided, and before it gets instantiated, the
406    // client can use this optional method to specify the proxy's dimensions. (A proxy's dimensions
407    // can be less than the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise,
408    // the proxy's dimensions will be set to match the underlying GPU surface upon instantiation.
409    void setLazyDimensions(SkISize dimensions) {
410        SkASSERT(this->isFullyLazy());
411        SkASSERT(!dimensions.isEmpty());
412        fDimensions = dimensions;
413    }
414
415    bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, GrRenderable,
416                         GrMipmapped, const GrUniqueKey*);
417
418    // For deferred proxies this will be null until the proxy is instantiated.
419    // For wrapped proxies it will point to the wrapped resource.
420    sk_sp<GrSurface>       fTarget;
421
422    // In many cases these flags aren't actually known until the proxy has been instantiated.
423    // However, Ganesh frequently needs to change its behavior based on these settings. For
424    // internally create proxies we will know these properties ahead of time. For wrapped
425    // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the
426    // call sites to provide the required information ahead of time. At instantiation time
427    // we verify that the assumed properties match the actual properties.
428    GrInternalSurfaceFlags fSurfaceFlags;
429
430private:
431    // For wrapped resources, 'fFormat' and 'fDimensions' will always be filled in from the
432    // wrapped resource.
433    const GrBackendFormat  fFormat;
434    SkISize                fDimensions;
435
436    SkBackingFit           fFit;      // always kApprox for lazy-callback resources
437                                      // always kExact for wrapped resources
438    mutable SkBudgeted     fBudgeted; // always kYes for lazy-callback resources
439                                      // set from the backing resource for wrapped resources
440                                      // mutable bc of SkSurface/SkImage wishy-washiness
441                                      // Only meaningful if fLazyInstantiateCallback is non-null.
442    UseAllocator           fUseAllocator;
443
444    const UniqueID         fUniqueID; // set from the backing resource for wrapped resources
445
446    LazyInstantiateCallback fLazyInstantiateCallback;
447
448    SkDEBUGCODE(void validateSurface(const GrSurface*);)
449    SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;)
450
451    static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
452    SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
453
454    virtual size_t onUninstantiatedGpuMemorySize() const = 0;
455
456    virtual LazySurfaceDesc callbackDesc() const = 0;
457
458    bool                   fIgnoredByResourceAllocator = false;
459    bool                   fIsDDLTarget = false;
460    bool                   fIsPromiseProxy = false;
461    GrProtected            fIsProtected;
462
463    int                     fTaskTargetCount = 0;
464
465    // The proxy tag.
466    GrGpuResourceTag    fGrProxyTag;
467
468    // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
469    // will be called but, when the proxy is deferred, it will compute the answer itself.
470    // If the proxy computes its own answer that answer is checked (in debug mode) in
471    // the instantiation method. The image may be shared between threads, hence atomic.
472    mutable std::atomic<size_t>         fGpuMemorySize{kInvalidGpuMemorySize};
473    SkDEBUGCODE(SkString   fDebugName;)
474};
475
476GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags)
477
478#endif
479