GrSurfaceProxy.h 19 KB

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