• 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 <atomic>
12 
13 #include "include/core/SkRect.h"
14 #include "include/gpu/GrBackendSurface.h"
15 #include "include/gpu/GrGpuResource.h"
16 #include "include/gpu/GrSurface.h"
17 #include "include/gpu/GrTexture.h"
18 #include "include/private/SkNoncopyable.h"
19 #include "src/gpu/GrSwizzle.h"
20 
21 class GrCaps;
22 class GrContext_Base;
23 class GrRecordingContext;
24 class GrRenderTargetOpList;
25 class GrRenderTargetProxy;
26 class GrRenderTask;
27 class GrResourceProvider;
28 class GrSurfaceContext;
29 class GrSurfaceProxyPriv;
30 class GrTextureOpList;
31 class GrTextureProxy;
32 
33 // This is basically SkRefCntBase except Ganesh uses internalGetProxyRefCnt for more than asserts.
34 class GrIORefProxy : public SkNoncopyable {
35 public:
GrIORefProxy()36     GrIORefProxy() : fRefCnt(1) {}
37 
~GrIORefProxy()38     virtual ~GrIORefProxy() {}
39 
unique()40     bool unique() const {
41         SkASSERT(fRefCnt > 0);
42         return 1 == fRefCnt;
43     }
44 
ref()45     void ref() const {
46         SkASSERT(fRefCnt > 0);
47         ++fRefCnt;
48     }
49 
unref()50     void unref() const {
51         SkASSERT(fRefCnt > 0);
52         --fRefCnt;
53         if (0 == fRefCnt) {
54             delete this;
55         }
56     }
57 
58 protected:
internalGetProxyRefCnt()59     int32_t internalGetProxyRefCnt() const { return fRefCnt; }
60 
61 private:
62     mutable std::atomic<int32_t> fRefCnt;
63 };
64 
65 class GrSurfaceProxy : public GrIORefProxy {
66 public:
67     /**
68      * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return.
69      * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls
70      * the key relationship between proxies and their targets.
71      */
72     enum class LazyInstantiationKeyMode {
73         /**
74          * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to
75          * return a GrSurface that already has a unique key unrelated to the proxy's key.
76          */
77         kUnsynced,
78         /**
79          * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface
80          * returned from the lazy instantiation callback must not have a unique key or have the same
81          * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned
82          * to the GrSurface.
83          */
84         kSynced
85     };
86 
87     struct LazyInstantiationResult {
88         LazyInstantiationResult() = default;
89         LazyInstantiationResult(const LazyInstantiationResult&) = default;
90         LazyInstantiationResult(LazyInstantiationResult&& that) = default;
91         LazyInstantiationResult(sk_sp<GrSurface> surf,
92                                 LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced)
fSurfaceLazyInstantiationResult93                 : fSurface(std::move(surf)), fKeyMode(mode) {}
LazyInstantiationResultLazyInstantiationResult94         LazyInstantiationResult(sk_sp<GrTexture> tex)
95                 : LazyInstantiationResult(sk_sp<GrSurface>(std::move(tex))) {}
96 
97         LazyInstantiationResult& operator=(const LazyInstantiationResult&) = default;
98         LazyInstantiationResult& operator=(LazyInstantiationResult&&) = default;
99 
100         sk_sp<GrSurface> fSurface;
101         LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced;
102     };
103 
104     using LazyInstantiateCallback = std::function<LazyInstantiationResult(GrResourceProvider*)>;
105 
106     enum class LazyInstantiationType {
107         kSingleUse,      // Instantiation callback is allowed to be called only once.
108         kMultipleUse,    // Instantiation callback can be called multiple times.
109         kDeinstantiate,  // Instantiation callback can be called multiple times,
110                          // but we will deinstantiate the proxy after every flush.
111     };
112 
113     enum class LazyState {
114         kNot,       // The proxy is instantiated or does not have a lazy callback
115         kPartially, // The proxy has a lazy callback but knows basic information about itself.
116         kFully,     // The proxy has a lazy callback and also doesn't know its width, height, etc.
117     };
118 
lazyInstantiationState()119     LazyState lazyInstantiationState() const {
120         if (this->isInstantiated() || !SkToBool(fLazyInstantiateCallback)) {
121             return LazyState::kNot;
122         } else {
123             if (fWidth <= 0) {
124                 SkASSERT(fHeight <= 0);
125                 return LazyState::kFully;
126             } else {
127                 SkASSERT(fHeight > 0);
128                 return LazyState::kPartially;
129             }
130         }
131     }
132 
config()133     GrPixelConfig config() const { return fConfig; }
width()134     int width() const {
135         SkASSERT(LazyState::kFully != this->lazyInstantiationState());
136         return fWidth;
137     }
height()138     int height() const {
139         SkASSERT(LazyState::kFully != this->lazyInstantiationState());
140         return fHeight;
141     }
142 
isize()143     SkISize isize() const { return {fWidth, fHeight}; }
144 
145     int worstCaseWidth() const;
146     int worstCaseHeight() const;
147     /**
148      * Helper that gets the width and height of the surface as a bounding rectangle.
149      */
getBoundsRect()150     SkRect getBoundsRect() const {
151         SkASSERT(LazyState::kFully != this->lazyInstantiationState());
152         return SkRect::MakeIWH(this->width(), this->height());
153     }
154     /**
155      * Helper that gets the worst case width and height of the surface as a bounding rectangle.
156      */
getWorstCaseBoundsRect()157     SkRect getWorstCaseBoundsRect() const {
158         SkASSERT(LazyState::kFully != this->lazyInstantiationState());
159         return SkRect::MakeIWH(this->worstCaseWidth(), this->worstCaseHeight());
160     }
161 
origin()162     GrSurfaceOrigin origin() const {
163         SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin);
164         return fOrigin;
165     }
166 
textureSwizzle()167     const GrSwizzle& textureSwizzle() const { return fTextureSwizzle; }
168 
backendFormat()169     const GrBackendFormat& backendFormat() const { return fFormat; }
170 
171     class UniqueID {
172     public:
InvalidID()173         static UniqueID InvalidID() {
174             return UniqueID(uint32_t(SK_InvalidUniqueID));
175         }
176 
177         // wrapped
UniqueID(const GrGpuResource::UniqueID & id)178         explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
179         // deferred and lazy-callback
UniqueID()180         UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
181 
asUInt()182         uint32_t asUInt() const { return fID; }
183 
184         bool operator==(const UniqueID& other) const {
185             return fID == other.fID;
186         }
187         bool operator!=(const UniqueID& other) const {
188             return !(*this == other);
189         }
190 
makeInvalid()191         void makeInvalid() { fID = SK_InvalidUniqueID; }
isInvalid()192         bool isInvalid() const { return SK_InvalidUniqueID == fID; }
193 
194     private:
UniqueID(uint32_t id)195         explicit UniqueID(uint32_t id) : fID(id) {}
196 
197         uint32_t fID;
198     };
199 
200     /*
201      * The contract for the uniqueID is:
202      *   for wrapped resources:
203      *      the uniqueID will match that of the wrapped resource
204      *
205      *   for deferred resources:
206      *      the uniqueID will be different from the real resource, when it is allocated
207      *      the proxy's uniqueID will not change across the instantiate call
208      *
209      *    the uniqueIDs of the proxies and the resources draw from the same pool
210      *
211      * What this boils down to is that the uniqueID of a proxy can be used to consistently
212      * track/identify a proxy but should never be used to distinguish between
213      * resources and proxies - beware!
214      */
uniqueID()215     UniqueID uniqueID() const { return fUniqueID; }
216 
underlyingUniqueID()217     UniqueID underlyingUniqueID() const {
218         if (fTarget) {
219             return UniqueID(fTarget->uniqueID());
220         }
221 
222         return fUniqueID;
223     }
224 
225     virtual bool instantiate(GrResourceProvider*) = 0;
226 
227     void deinstantiate();
228 
229     /**
230      * Proxies that are already instantiated and whose backing surface cannot be recycled to
231      * instantiate other proxies do not need to be considered by GrResourceAllocator.
232      */
233     bool canSkipResourceAllocator() const;
234 
235     /**
236      * @return the texture proxy associated with the surface proxy, may be NULL.
237      */
asTextureProxy()238     virtual GrTextureProxy* asTextureProxy() { return nullptr; }
asTextureProxy()239     virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
240 
241     /**
242      * @return the render target proxy associated with the surface proxy, may be NULL.
243      */
asRenderTargetProxy()244     virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
asRenderTargetProxy()245     virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
246 
isInstantiated()247     bool isInstantiated() const { return SkToBool(fTarget); }
248 
249     // If the proxy is already instantiated, return its backing GrTexture; if not, return null.
peekSurface()250     GrSurface* peekSurface() const { return fTarget.get(); }
251 
252     // If this is a texture proxy and the proxy is already instantiated, return its backing
253     // GrTexture; if not, return null.
peekTexture()254     GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; }
255 
256     // If this is a render target proxy and the proxy is already instantiated, return its backing
257     // GrRenderTarget; if not, return null.
peekRenderTarget()258     GrRenderTarget* peekRenderTarget() const {
259         return fTarget ? fTarget->asRenderTarget() : nullptr;
260     }
261 
262     /**
263      * Does the resource count against the resource budget?
264      */
isBudgeted()265     SkBudgeted isBudgeted() const { return fBudgeted; }
266 
267     /**
268      * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write
269      * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and
270      * assignment in GrResourceAllocator.
271      */
readOnly()272     bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
273 
274     void setLastRenderTask(GrRenderTask*);
getLastRenderTask()275     GrRenderTask* getLastRenderTask() { return fLastRenderTask; }
276 
277     GrRenderTargetOpList* getLastRenderTargetOpList();
278     GrTextureOpList* getLastTextureOpList();
279 
280     /**
281      * Retrieves the amount of GPU memory that will be or currently is used by this resource
282      * in bytes. It is approximate since we aren't aware of additional padding or copies made
283      * by the driver.
284      *
285      * @return the amount of GPU memory used in bytes
286      */
gpuMemorySize()287     size_t gpuMemorySize() const {
288         SkASSERT(LazyState::kFully != this->lazyInstantiationState());
289         if (fTarget) {
290             return fTarget->gpuMemorySize();
291         }
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     static sk_sp<GrTextureProxy> Copy(GrRecordingContext*, GrSurfaceProxy* src, GrMipMapped,
307                                       SkIRect srcRect, SkBackingFit, SkBudgeted,
308                                       RectsMustMatch = RectsMustMatch::kNo);
309 
310     // Copy the entire 'src'
311     static sk_sp<GrTextureProxy> Copy(GrRecordingContext*, GrSurfaceProxy* src, GrMipMapped,
312                                       SkBackingFit, SkBudgeted);
313 
314 #if GR_TEST_UTILS
315     int32_t testingOnly_getBackingRefCnt() const;
316     GrInternalSurfaceFlags testingOnly_getFlags() const;
317 #endif
318 
319     SkDEBUGCODE(void validate(GrContext_Base*) const;)
320 
321     // Provides access to functions that aren't part of the public API.
322     inline GrSurfaceProxyPriv priv();
323     inline const GrSurfaceProxyPriv priv() const;
324 
325     // Returns true if we are working with protected content.
isProtected()326     bool isProtected() const { return fIsProtected == GrProtected::kYes; }
327 
328 protected:
329     // Deferred version
GrSurfaceProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrRenderable renderable,GrSurfaceOrigin origin,const GrSwizzle & textureSwizzle,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags)330     GrSurfaceProxy(const GrBackendFormat& format, const GrSurfaceDesc& desc,
331                    GrRenderable renderable, GrSurfaceOrigin origin, const GrSwizzle& textureSwizzle,
332                    SkBackingFit fit, SkBudgeted budgeted, GrProtected isProtected,
333                    GrInternalSurfaceFlags surfaceFlags)
334             : GrSurfaceProxy(nullptr, LazyInstantiationType::kSingleUse, format, desc, renderable,
335                              origin, textureSwizzle, fit, budgeted, isProtected, surfaceFlags) {
336         // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
337     }
338 
339     // Lazy-callback version
340     GrSurfaceProxy(LazyInstantiateCallback&&, LazyInstantiationType, const GrBackendFormat& format,
341                    const GrSurfaceDesc&, GrRenderable, GrSurfaceOrigin,
342                    const GrSwizzle& textureSwizzle, SkBackingFit, SkBudgeted, GrProtected,
343                    GrInternalSurfaceFlags);
344 
345     // Wrapped version.
346     GrSurfaceProxy(sk_sp<GrSurface>, GrSurfaceOrigin, const GrSwizzle& textureSwizzle,
347                    SkBackingFit);
348 
349     ~GrSurfaceProxy() override;
350 
351     friend class GrSurfaceProxyPriv;
352 
353     // Methods made available via GrSurfaceProxyPriv
ignoredByResourceAllocator()354     bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; }
setIgnoredByResourceAllocator()355     void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; }
356 
getProxyRefCnt()357     int32_t getProxyRefCnt() const { return this->internalGetProxyRefCnt(); }
358 
359     void computeScratchKey(GrScratchKey*) const;
360 
361     virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
362     void assign(sk_sp<GrSurface> surface);
363 
364     sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt,
365                                        int minStencilSampleCount, GrRenderable, GrMipMapped) const;
366 
367     // Once the size of a fully-lazy proxy is decided, and before it gets instantiated, the client
368     // can use this optional method to specify the proxy's size. (A proxy's size can be less than
369     // the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise, the proxy's size will
370     // be set to match the underlying GPU surface upon instantiation.
setLazySize(int width,int height)371     void setLazySize(int width, int height) {
372         SkASSERT(GrSurfaceProxy::LazyState::kFully == this->lazyInstantiationState());
373         SkASSERT(width > 0 && height > 0);
374         fWidth = width;
375         fHeight = height;
376     }
377 
378     bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
379                          int minStencilSampleCount, GrRenderable, GrMipMapped, const GrUniqueKey*);
380 
381     // For deferred proxies this will be null until the proxy is instantiated.
382     // For wrapped proxies it will point to the wrapped resource.
383     sk_sp<GrSurface>       fTarget;
384 
385     // In many cases these flags aren't actually known until the proxy has been instantiated.
386     // However, Ganesh frequently needs to change its behavior based on these settings. For
387     // internally create proxies we will know these properties ahead of time. For wrapped
388     // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the
389     // call sites to provide the required information ahead of time. At instantiation time
390     // we verify that the assumed properties match the actual properties.
391     GrInternalSurfaceFlags fSurfaceFlags;
392 
393 private:
394     // For wrapped resources, 'fFormat', 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always
395     // be filled in from the wrapped resource.
396     GrBackendFormat        fFormat;
397     GrPixelConfig          fConfig;
398     int                    fWidth;
399     int                    fHeight;
400     GrSurfaceOrigin        fOrigin;
401     GrSwizzle              fTextureSwizzle;
402 
403     SkBackingFit           fFit;      // always kApprox for lazy-callback resources
404                                       // always kExact for wrapped resources
405     mutable SkBudgeted     fBudgeted; // always kYes for lazy-callback resources
406                                       // set from the backing resource for wrapped resources
407                                       // mutable bc of SkSurface/SkImage wishy-washiness
408 
409     const UniqueID         fUniqueID; // set from the backing resource for wrapped resources
410 
411     LazyInstantiateCallback fLazyInstantiateCallback;
412     // If this is set to kSingleuse, then after one call to fLazyInstantiateCallback we will cleanup
413     // the lazy callback and then delete it. This will allow for any refs and resources being held
414     // by the standard function to be released. This is specifically useful in non-dll cases where
415     // we make lazy proxies and instantiate them immediately.
416     // Note: This is ignored if fLazyInstantiateCallback is null.
417     LazyInstantiationType  fLazyInstantiationType;
418 
419     SkDEBUGCODE(void validateSurface(const GrSurface*);)
420     SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;)
421 
422     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
423     SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
424 
425     virtual size_t onUninstantiatedGpuMemorySize() const = 0;
426 
427     bool                   fIgnoredByResourceAllocator = false;
428     GrProtected            fIsProtected;
429 
430     // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
431     // will be called but, when the proxy is deferred, it will compute the answer itself.
432     // If the proxy computes its own answer that answer is checked (in debug mode) in
433     // the instantiation method.
434     mutable size_t         fGpuMemorySize;
435 
436     // The last opList that wrote to or is currently going to write to this surface
437     // The opList can be closed (e.g., no surface context is currently bound
438     // to this proxy).
439     // This back-pointer is required so that we can add a dependancy between
440     // the opList used to create the current contents of this surface
441     // and the opList of a destination surface to which this one is being drawn or copied.
442     // This pointer is unreffed. GrRenderTasks own a ref on their surface proxies.
443     GrRenderTask*          fLastRenderTask;
444 
445     typedef GrIORefProxy INHERITED;
446 };
447 
448 #endif
449