Home | History | Annotate | Download | only in private
      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 "GrGpuResource.h"
     12 #include "GrSurface.h"
     13 
     14 #include "SkRect.h"
     15 
     16 class GrBackendTexture;
     17 class GrCaps;
     18 class GrOpList;
     19 class GrRenderTargetOpList;
     20 class GrRenderTargetProxy;
     21 class GrResourceProvider;
     22 class GrSurfaceContext;
     23 class GrSurfaceProxyPriv;
     24 class GrTextureOpList;
     25 class GrTextureProxy;
     26 
     27 // This class replicates the functionality GrIORef<GrSurface> but tracks the
     28 // utilitization for later resource allocation (for the deferred case) and
     29 // forwards on the utilization in the wrapped case
     30 class GrIORefProxy : public SkNoncopyable {
     31 public:
     32     void ref() const {
     33         this->validate();
     34 
     35         ++fRefCnt;
     36         if (fTarget) {
     37             fTarget->ref();
     38         }
     39     }
     40 
     41     void unref() const {
     42         this->validate();
     43 
     44         if (fTarget) {
     45             fTarget->unref();
     46         }
     47 
     48         --fRefCnt;
     49         this->didRemoveRefOrPendingIO();
     50     }
     51 
     52     void validate() const {
     53 #ifdef SK_DEBUG
     54         SkASSERT(fRefCnt >= 0);
     55         SkASSERT(fPendingReads >= 0);
     56         SkASSERT(fPendingWrites >= 0);
     57         SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1);
     58 
     59         if (fTarget) {
     60             // The backing GrSurface can have more refs than the proxy if the proxy
     61             // started off wrapping an external resource (that came in with refs).
     62             // The GrSurface should never have fewer refs than the proxy however.
     63             SkASSERT(fTarget->fRefCnt >= fRefCnt);
     64             SkASSERT(fTarget->fPendingReads >= fPendingReads);
     65             SkASSERT(fTarget->fPendingWrites >= fPendingWrites);
     66         }
     67 #endif
     68     }
     69 
     70     int32_t getProxyRefCnt_TestOnly() const;
     71     int32_t getBackingRefCnt_TestOnly() const;
     72     int32_t getPendingReadCnt_TestOnly() const;
     73     int32_t getPendingWriteCnt_TestOnly() const;
     74 
     75 protected:
     76     GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {}
     77     GrIORefProxy(sk_sp<GrSurface> surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {
     78         // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing
     79         // anything extra.
     80         fTarget = surface.release();
     81     }
     82     virtual ~GrIORefProxy() {
     83         // We don't unref 'fTarget' here since the 'unref' method will already
     84         // have forwarded on the unref call that got use here.
     85     }
     86 
     87     // This GrIORefProxy was deferred before but has just been instantiated. To
     88     // make all the reffing & unreffing work out we now need to transfer any deferred
     89     // refs & unrefs to the new GrSurface
     90     void transferRefs() {
     91         SkASSERT(fTarget);
     92 
     93         fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref
     94         fTarget->fPendingReads += fPendingReads;
     95         fTarget->fPendingWrites += fPendingWrites;
     96     }
     97 
     98     bool internalHasPendingIO() const {
     99         if (fTarget) {
    100             return fTarget->internalHasPendingIO();
    101         }
    102 
    103         return SkToBool(fPendingWrites | fPendingReads);
    104     }
    105 
    106     bool internalHasPendingWrite() const {
    107         if (fTarget) {
    108             return fTarget->internalHasPendingWrite();
    109         }
    110 
    111         return SkToBool(fPendingWrites);
    112     }
    113 
    114     // For deferred proxies this will be null. For wrapped proxies it will point to the
    115     // wrapped resource.
    116     GrSurface* fTarget;
    117 
    118 private:
    119     // This class is used to manage conversion of refs to pending reads/writes.
    120     friend class GrSurfaceProxyRef;
    121     template <typename, GrIOType> friend class GrPendingIOResource;
    122 
    123     void addPendingRead() const {
    124         this->validate();
    125 
    126         ++fPendingReads;
    127         if (fTarget) {
    128             fTarget->addPendingRead();
    129         }
    130     }
    131 
    132     void completedRead() const {
    133         this->validate();
    134 
    135         if (fTarget) {
    136             fTarget->completedRead();
    137         }
    138 
    139         --fPendingReads;
    140         this->didRemoveRefOrPendingIO();
    141     }
    142 
    143     void addPendingWrite() const {
    144         this->validate();
    145 
    146         ++fPendingWrites;
    147         if (fTarget) {
    148             fTarget->addPendingWrite();
    149         }
    150     }
    151 
    152     void completedWrite() const {
    153         this->validate();
    154 
    155         if (fTarget) {
    156             fTarget->completedWrite();
    157         }
    158 
    159         --fPendingWrites;
    160         this->didRemoveRefOrPendingIO();
    161     }
    162 
    163     void didRemoveRefOrPendingIO() const {
    164         if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
    165             delete this;
    166         }
    167     }
    168 
    169     mutable int32_t fRefCnt;
    170     mutable int32_t fPendingReads;
    171     mutable int32_t fPendingWrites;
    172 };
    173 
    174 class GrSurfaceProxy : public GrIORefProxy {
    175 public:
    176     static sk_sp<GrSurfaceProxy> MakeWrapped(sk_sp<GrSurface>);
    177     static sk_sp<GrTextureProxy> MakeWrapped(sk_sp<GrTexture>);
    178 
    179     static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
    180                                               const GrSurfaceDesc&, SkBackingFit,
    181                                               SkBudgeted, uint32_t flags = 0);
    182 
    183     /**
    184      * Creates a proxy that will be mipmapped.
    185      *
    186      * @param desc          Description of the texture properties.
    187      * @param budgeted      Does the texture count against the resource cache budget?
    188      * @param texels        A contiguous array of mipmap levels
    189      * @param mipLevelCount The amount of elements in the texels array
    190      */
    191     static sk_sp<GrTextureProxy> MakeDeferredMipMap(GrResourceProvider*,
    192                                                     const GrSurfaceDesc& desc, SkBudgeted budgeted,
    193                                                     const GrMipLevel texels[], int mipLevelCount,
    194                                                     SkDestinationSurfaceColorMode mipColorMode =
    195                                                            SkDestinationSurfaceColorMode::kLegacy);
    196 
    197     // TODO: need to refine ownership semantics of 'srcData' if we're in completely
    198     // deferred mode
    199     static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
    200                                               const GrSurfaceDesc&, SkBudgeted,
    201                                               const void* srcData, size_t rowBytes);
    202 
    203     static sk_sp<GrTextureProxy> MakeWrappedBackend(GrContext*, GrBackendTexture&, GrSurfaceOrigin);
    204 
    205     GrSurfaceOrigin origin() const {
    206         SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin);
    207         return fOrigin;
    208     }
    209     int width() const { return fWidth; }
    210     int height() const { return fHeight; }
    211     GrPixelConfig config() const { return fConfig; }
    212 
    213     class UniqueID {
    214     public:
    215         static UniqueID InvalidID() {
    216             return UniqueID(uint32_t(SK_InvalidUniqueID));
    217         }
    218 
    219         // wrapped
    220         explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
    221         // deferred
    222         UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
    223 
    224         uint32_t asUInt() const { return fID; }
    225 
    226         bool operator==(const UniqueID& other) const {
    227             return fID == other.fID;
    228         }
    229         bool operator!=(const UniqueID& other) const {
    230             return !(*this == other);
    231         }
    232 
    233         void makeInvalid() { fID = SK_InvalidUniqueID; }
    234         bool isInvalid() const { return SK_InvalidUniqueID == fID; }
    235 
    236     private:
    237         explicit UniqueID(uint32_t id) : fID(id) {}
    238 
    239         uint32_t fID;
    240     };
    241 
    242     /*
    243      * The contract for the uniqueID is:
    244      *   for wrapped resources:
    245      *      the uniqueID will match that of the wrapped resource
    246      *
    247      *   for deferred resources:
    248      *      the uniqueID will be different from the real resource, when it is allocated
    249      *      the proxy's uniqueID will not change across the instantiate call
    250      *
    251      *    the uniqueIDs of the proxies and the resources draw from the same pool
    252      *
    253      * What this boils down to is that the uniqueID of a proxy can be used to consistently
    254      * track/identify a proxy but should never be used to distinguish between
    255      * resources and proxies - beware!
    256      */
    257     UniqueID uniqueID() const { return fUniqueID; }
    258 
    259     UniqueID underlyingUniqueID() const {
    260         if (fTarget) {
    261             return UniqueID(fTarget->uniqueID());
    262         }
    263 
    264         return fUniqueID;
    265     }
    266 
    267     virtual bool instantiate(GrResourceProvider* resourceProvider) = 0;
    268 
    269     /**
    270      * Helper that gets the width and height of the surface as a bounding rectangle.
    271      */
    272     SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
    273 
    274     /**
    275      * @return the texture proxy associated with the surface proxy, may be NULL.
    276      */
    277     virtual GrTextureProxy* asTextureProxy() { return nullptr; }
    278     virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
    279 
    280     /**
    281      * @return the render target proxy associated with the surface proxy, may be NULL.
    282      */
    283     virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
    284     virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
    285 
    286     /**
    287      * Does the resource count against the resource budget?
    288      */
    289     SkBudgeted isBudgeted() const { return fBudgeted; }
    290 
    291     void setLastOpList(GrOpList* opList);
    292     GrOpList* getLastOpList() { return fLastOpList; }
    293 
    294     GrRenderTargetOpList* getLastRenderTargetOpList();
    295     GrTextureOpList* getLastTextureOpList();
    296 
    297     /**
    298      * Retrieves the amount of GPU memory that will be or currently is used by this resource
    299      * in bytes. It is approximate since we aren't aware of additional padding or copies made
    300      * by the driver.
    301      *
    302      * @return the amount of GPU memory used in bytes
    303      */
    304     size_t gpuMemorySize() const {
    305         if (fTarget) {
    306             return fTarget->gpuMemorySize();
    307         }
    308         if (kInvalidGpuMemorySize == fGpuMemorySize) {
    309             fGpuMemorySize = this->onUninstantiatedGpuMemorySize();
    310             SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
    311         }
    312         return fGpuMemorySize;
    313     }
    314 
    315     // Helper function that creates a temporary SurfaceContext to perform the copy
    316     // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage
    317     // to an SkImage. The copy is is not a render target and not multisampled.
    318     static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src,
    319                                       SkIRect srcRect, SkBudgeted);
    320 
    321     // Copy the entire 'src'
    322     // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial
    323     static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src,
    324                                       SkBudgeted budgeted);
    325 
    326     // Test-only entry point - should decrease in use as proxies propagate
    327     static sk_sp<GrSurfaceContext> TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
    328                                             GrSurfaceProxy* srcProxy);
    329 
    330     bool isWrapped_ForTesting() const;
    331 
    332     SkDEBUGCODE(bool isInstantiated() const { return SkToBool(fTarget); })
    333     SkDEBUGCODE(void validate(GrContext*) const;)
    334 
    335     // Provides access to functions that aren't part of the public API.
    336     GrSurfaceProxyPriv priv();
    337     const GrSurfaceProxyPriv priv() const;
    338 
    339 protected:
    340     // Deferred version
    341     GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
    342             : fConfig(desc.fConfig)
    343             , fWidth(desc.fWidth)
    344             , fHeight(desc.fHeight)
    345             , fOrigin(desc.fOrigin)
    346             , fFit(fit)
    347             , fBudgeted(budgeted)
    348             , fFlags(flags)
    349             , fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag))
    350             , fGpuMemorySize(kInvalidGpuMemorySize)
    351             , fLastOpList(nullptr) {
    352         // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
    353     }
    354 
    355     // Wrapped version
    356     GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit);
    357 
    358     virtual ~GrSurfaceProxy();
    359 
    360     friend class GrSurfaceProxyPriv;
    361 
    362     // Methods made available via GrSurfaceProxyPriv
    363     bool hasPendingIO() const {
    364         return this->internalHasPendingIO();
    365     }
    366 
    367     bool hasPendingWrite() const {
    368         return this->internalHasPendingWrite();
    369     }
    370 
    371     virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
    372     void assign(sk_sp<GrSurface> surface);
    373 
    374     sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt,
    375                                        GrSurfaceFlags flags, bool isMipMapped,
    376                                        SkDestinationSurfaceColorMode mipColorMode) const;
    377 
    378     bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
    379                          GrSurfaceFlags flags, bool isMipMapped,
    380                          SkDestinationSurfaceColorMode mipColorMode);
    381 
    382     // For wrapped resources, 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always be filled in
    383     // from the wrapped resource.
    384     GrPixelConfig        fConfig;
    385     int                  fWidth;
    386     int                  fHeight;
    387     GrSurfaceOrigin      fOrigin;
    388     SkBackingFit         fFit;      // always exact for wrapped resources
    389     mutable SkBudgeted   fBudgeted; // set from the backing resource for wrapped resources
    390                                     // mutable bc of SkSurface/SkImage wishy-washiness
    391     const uint32_t       fFlags;
    392 
    393     const UniqueID       fUniqueID; // set from the backing resource for wrapped resources
    394 
    395     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
    396     SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
    397 
    398 private:
    399     virtual size_t onUninstantiatedGpuMemorySize() const = 0;
    400 
    401     bool                 fNeedsClear;
    402 
    403     // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
    404     // will be called but, when the proxy is deferred, it will compute the answer itself.
    405     // If the proxy computes its own answer that answer is checked (in debug mode) in
    406     // the instantiation method.
    407     mutable size_t      fGpuMemorySize;
    408 
    409     // The last opList that wrote to or is currently going to write to this surface
    410     // The opList can be closed (e.g., no surface context is currently bound
    411     // to this proxy).
    412     // This back-pointer is required so that we can add a dependancy between
    413     // the opList used to create the current contents of this surface
    414     // and the opList of a destination surface to which this one is being drawn or copied.
    415     // This pointer is unreffed. OpLists own a ref on their surface proxies.
    416     GrOpList* fLastOpList;
    417 
    418     typedef GrIORefProxy INHERITED;
    419 };
    420 
    421 #endif
    422