SkSpecialImage.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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. #include "include/core/SkBitmap.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkImage.h"
  10. #include "src/core/SkBitmapCache.h"
  11. #include "src/core/SkSpecialImage.h"
  12. #include "src/core/SkSpecialSurface.h"
  13. #include "src/core/SkSurfacePriv.h"
  14. #include "src/image/SkImage_Base.h"
  15. #include <atomic>
  16. #if SK_SUPPORT_GPU
  17. #include "include/gpu/GrContext.h"
  18. #include "include/private/GrRecordingContext.h"
  19. #include "src/gpu/GrContextPriv.h"
  20. #include "src/gpu/GrProxyProvider.h"
  21. #include "src/gpu/GrRecordingContextPriv.h"
  22. #include "src/gpu/GrSurfaceContext.h"
  23. #include "src/gpu/GrTextureProxy.h"
  24. #include "src/image/SkImage_Gpu.h"
  25. #endif
  26. // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
  27. // a given info is supported.
  28. static bool valid_for_imagefilters(const SkImageInfo& info) {
  29. // no support for other swizzles/depths yet
  30. return info.colorType() == kN32_SkColorType;
  31. }
  32. ///////////////////////////////////////////////////////////////////////////////
  33. class SkSpecialImage_Base : public SkSpecialImage {
  34. public:
  35. SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
  36. : INHERITED(subset, uniqueID, props) {
  37. }
  38. ~SkSpecialImage_Base() override { }
  39. virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
  40. virtual bool onGetROPixels(SkBitmap*) const = 0;
  41. virtual GrRecordingContext* onGetContext() const { return nullptr; }
  42. virtual SkColorSpace* onGetColorSpace() const = 0;
  43. #if SK_SUPPORT_GPU
  44. virtual sk_sp<GrTextureProxy> onAsTextureProxyRef(GrRecordingContext* context) const = 0;
  45. #endif
  46. // This subset is relative to the backing store's coordinate frame, it has already been mapped
  47. // from the content rect by the non-virtual makeSubset().
  48. virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
  49. virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
  50. const SkISize& size, SkAlphaType at,
  51. const SkSurfaceProps* = nullptr) const = 0;
  52. // This subset (when not null) is relative to the backing store's coordinate frame, it has
  53. // already been mapped from the content rect by the non-virtual asImage().
  54. virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
  55. virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
  56. const SkISize& size, SkAlphaType at) const = 0;
  57. private:
  58. typedef SkSpecialImage INHERITED;
  59. };
  60. ///////////////////////////////////////////////////////////////////////////////
  61. static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
  62. return static_cast<const SkSpecialImage_Base*>(image);
  63. }
  64. SkSpecialImage::SkSpecialImage(const SkIRect& subset,
  65. uint32_t uniqueID,
  66. const SkSurfaceProps* props)
  67. : fProps(SkSurfacePropsCopyOrDefault(props))
  68. , fSubset(subset)
  69. , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
  70. }
  71. sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrRecordingContext* context) {
  72. #if SK_SUPPORT_GPU
  73. if (!context) {
  74. return nullptr;
  75. }
  76. if (GrRecordingContext* curContext = as_SIB(this)->onGetContext()) {
  77. return curContext->priv().matches(context) ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
  78. }
  79. auto proxyProvider = context->priv().proxyProvider();
  80. SkBitmap bmp;
  81. // At this point, we are definitely not texture-backed, so we must be raster or generator
  82. // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
  83. // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
  84. // in which case getROPixels could turn into peekPixels...
  85. if (!this->getROPixels(&bmp)) {
  86. return nullptr;
  87. }
  88. if (bmp.empty()) {
  89. return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
  90. }
  91. // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
  92. // semantics). Since this is cached though we would have to bake the fit into the cache key.
  93. sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(proxyProvider, bmp);
  94. if (!proxy) {
  95. return nullptr;
  96. }
  97. const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
  98. // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not
  99. // bother with SkBitmap::getSubset
  100. return SkSpecialImage::MakeDeferredFromGpu(context,
  101. rect,
  102. this->uniqueID(),
  103. std::move(proxy),
  104. sk_ref_sp(this->getColorSpace()),
  105. &this->props(),
  106. this->alphaType());
  107. #else
  108. return nullptr;
  109. #endif
  110. }
  111. void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
  112. return as_SIB(this)->onDraw(canvas, x, y, paint);
  113. }
  114. bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
  115. return as_SIB(this)->onGetROPixels(bm);
  116. }
  117. bool SkSpecialImage::isTextureBacked() const {
  118. return SkToBool(as_SIB(this)->onGetContext());
  119. }
  120. GrRecordingContext* SkSpecialImage::getContext() const {
  121. return as_SIB(this)->onGetContext();
  122. }
  123. SkColorSpace* SkSpecialImage::getColorSpace() const {
  124. return as_SIB(this)->onGetColorSpace();
  125. }
  126. #if SK_SUPPORT_GPU
  127. sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrRecordingContext* context) const {
  128. return as_SIB(this)->onAsTextureProxyRef(context);
  129. }
  130. #endif
  131. sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
  132. const SkISize& size, SkAlphaType at,
  133. const SkSurfaceProps* props) const {
  134. return as_SIB(this)->onMakeSurface(outProps, size, at, props);
  135. }
  136. sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
  137. const SkISize& size, SkAlphaType at) const {
  138. return as_SIB(this)->onMakeTightSurface(outProps, size, at);
  139. }
  140. sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
  141. SkIRect absolute = subset.makeOffset(this->subset().x(), this->subset().y());
  142. return as_SIB(this)->onMakeSubset(absolute);
  143. }
  144. sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
  145. if (subset) {
  146. SkIRect absolute = subset->makeOffset(this->subset().x(), this->subset().y());
  147. return as_SIB(this)->onAsImage(&absolute);
  148. } else {
  149. return as_SIB(this)->onAsImage(nullptr);
  150. }
  151. }
  152. #if defined(SK_DEBUG) || SK_SUPPORT_GPU
  153. static bool rect_fits(const SkIRect& rect, int width, int height) {
  154. if (0 == width && 0 == height) {
  155. SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
  156. return true;
  157. }
  158. return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
  159. rect.fRight >= 0 && rect.fRight <= width &&
  160. rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
  161. rect.fBottom >= 0 && rect.fBottom <= height;
  162. }
  163. #endif
  164. sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrRecordingContext* context,
  165. const SkIRect& subset,
  166. sk_sp<SkImage> image,
  167. const SkSurfaceProps* props) {
  168. SkASSERT(rect_fits(subset, image->width(), image->height()));
  169. #if SK_SUPPORT_GPU
  170. if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef(context)) {
  171. if (!as_IB(image)->context()->priv().matches(context)) {
  172. return nullptr;
  173. }
  174. return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
  175. image->refColorSpace(), props);
  176. } else
  177. #endif
  178. {
  179. SkBitmap bm;
  180. if (as_IB(image)->getROPixels(&bm)) {
  181. return MakeFromRaster(subset, bm, props);
  182. }
  183. }
  184. return nullptr;
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. class SkSpecialImage_Raster : public SkSpecialImage_Base {
  188. public:
  189. SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
  190. : INHERITED(subset, bm.getGenerationID(), props)
  191. , fBitmap(bm)
  192. {
  193. SkASSERT(bm.pixelRef());
  194. SkASSERT(fBitmap.getPixels());
  195. }
  196. SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
  197. size_t getSize() const override { return fBitmap.computeByteSize(); }
  198. void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
  199. SkRect dst = SkRect::MakeXYWH(x, y,
  200. this->subset().width(), this->subset().height());
  201. canvas->drawBitmapRect(fBitmap, this->subset(),
  202. dst, paint, SkCanvas::kStrict_SrcRectConstraint);
  203. }
  204. bool onGetROPixels(SkBitmap* bm) const override {
  205. return fBitmap.extractSubset(bm, this->subset());
  206. }
  207. SkColorSpace* onGetColorSpace() const override {
  208. return fBitmap.colorSpace();
  209. }
  210. #if SK_SUPPORT_GPU
  211. sk_sp<GrTextureProxy> onAsTextureProxyRef(GrRecordingContext* context) const override {
  212. if (context) {
  213. return GrMakeCachedBitmapProxy(context->priv().proxyProvider(), fBitmap);
  214. }
  215. return nullptr;
  216. }
  217. #endif
  218. sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
  219. const SkISize& size, SkAlphaType at,
  220. const SkSurfaceProps* props) const override {
  221. SkColorSpace* colorSpace = outProps.colorSpace();
  222. SkColorType colorType = kN32_SkColorType; // TODO: find ways to allow f16
  223. SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
  224. sk_ref_sp(colorSpace));
  225. return SkSpecialSurface::MakeRaster(info, props);
  226. }
  227. sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
  228. // No need to extract subset, onGetROPixels handles that when needed
  229. return SkSpecialImage::MakeFromRaster(subset, fBitmap, &this->props());
  230. }
  231. sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
  232. if (subset) {
  233. SkBitmap subsetBM;
  234. if (!fBitmap.extractSubset(&subsetBM, *subset)) {
  235. return nullptr;
  236. }
  237. return SkImage::MakeFromBitmap(subsetBM);
  238. }
  239. return SkImage::MakeFromBitmap(fBitmap);
  240. }
  241. sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
  242. const SkISize& size, SkAlphaType at) const override {
  243. SkColorSpace* colorSpace = outProps.colorSpace();
  244. SkColorType colorType = kN32_SkColorType; // TODO: find ways to allow f16
  245. SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
  246. sk_ref_sp(colorSpace));
  247. return SkSurface::MakeRaster(info);
  248. }
  249. private:
  250. SkBitmap fBitmap;
  251. typedef SkSpecialImage_Base INHERITED;
  252. };
  253. sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
  254. const SkBitmap& bm,
  255. const SkSurfaceProps* props) {
  256. SkASSERT(rect_fits(subset, bm.width(), bm.height()));
  257. if (!bm.pixelRef()) {
  258. return nullptr;
  259. }
  260. const SkBitmap* srcBM = &bm;
  261. SkBitmap tmp;
  262. // ImageFilters only handle N32 at the moment, so force our src to be that
  263. if (!valid_for_imagefilters(bm.info())) {
  264. if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) ||
  265. !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0))
  266. {
  267. return nullptr;
  268. }
  269. srcBM = &tmp;
  270. }
  271. return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
  272. }
  273. sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset,
  274. const SkBitmap& bm,
  275. const SkSurfaceProps* props) {
  276. SkASSERT(rect_fits(subset, bm.width(), bm.height()));
  277. if (!bm.pixelRef()) {
  278. return nullptr;
  279. }
  280. SkBitmap tmp;
  281. SkImageInfo info = bm.info().makeWH(subset.width(), subset.height());
  282. // As in MakeFromRaster, must force src to N32 for ImageFilters
  283. if (!valid_for_imagefilters(bm.info())) {
  284. info = info.makeColorType(kN32_SkColorType);
  285. }
  286. if (!tmp.tryAllocPixels(info)) {
  287. return nullptr;
  288. }
  289. if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) {
  290. return nullptr;
  291. }
  292. // Since we're making a copy of the raster, the resulting special image is the exact size
  293. // of the requested subset of the original and no longer needs to be offset by subset's left
  294. // and top, since those were relative to the original's buffer.
  295. return sk_make_sp<SkSpecialImage_Raster>(
  296. SkIRect::MakeWH(subset.width(), subset.height()), tmp, props);
  297. }
  298. #if SK_SUPPORT_GPU
  299. ///////////////////////////////////////////////////////////////////////////////
  300. static sk_sp<SkImage> wrap_proxy_in_image(GrRecordingContext* context, sk_sp<GrTextureProxy> proxy,
  301. SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
  302. // CONTEXT TODO: remove this use of 'backdoor' to create an SkImage
  303. return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context->priv().backdoor()),
  304. kNeedNewImageUniqueID, alphaType,
  305. std::move(proxy), std::move(colorSpace));
  306. }
  307. class SkSpecialImage_Gpu : public SkSpecialImage_Base {
  308. public:
  309. SkSpecialImage_Gpu(GrRecordingContext* context, const SkIRect& subset,
  310. uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
  311. sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
  312. : INHERITED(subset, uniqueID, props)
  313. , fContext(context)
  314. , fTextureProxy(std::move(proxy))
  315. , fAlphaType(at)
  316. , fColorSpace(std::move(colorSpace))
  317. , fAddedRasterVersionToCache(false) {
  318. }
  319. ~SkSpecialImage_Gpu() override {
  320. if (fAddedRasterVersionToCache.load()) {
  321. SkNotifyBitmapGenIDIsStale(this->uniqueID());
  322. }
  323. }
  324. SkAlphaType alphaType() const override { return fAlphaType; }
  325. size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
  326. void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
  327. SkRect dst = SkRect::MakeXYWH(x, y,
  328. this->subset().width(), this->subset().height());
  329. // TODO: In this instance we know we're going to draw a sub-portion of the backing
  330. // texture into the canvas so it is okay to wrap it in an SkImage. This poses
  331. // some problems for full deferral however in that when the deferred SkImage_Gpu
  332. // instantiates itself it is going to have to either be okay with having a larger
  333. // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
  334. // to be tightened (if it is deferred).
  335. sk_sp<SkImage> img =
  336. sk_sp<SkImage>(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()), this->uniqueID(),
  337. fAlphaType, fTextureProxy, fColorSpace));
  338. canvas->drawImageRect(img, this->subset(),
  339. dst, paint, SkCanvas::kStrict_SrcRectConstraint);
  340. }
  341. GrRecordingContext* onGetContext() const override { return fContext; }
  342. sk_sp<GrTextureProxy> onAsTextureProxyRef(GrRecordingContext*) const override {
  343. return fTextureProxy;
  344. }
  345. bool onGetROPixels(SkBitmap* dst) const override {
  346. const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->subset());
  347. if (SkBitmapCache::Find(desc, dst)) {
  348. SkASSERT(dst->getGenerationID() == this->uniqueID());
  349. SkASSERT(dst->isImmutable());
  350. SkASSERT(dst->getPixels());
  351. return true;
  352. }
  353. SkPixmap pmap;
  354. SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
  355. this->alphaType(), fColorSpace);
  356. auto rec = SkBitmapCache::Alloc(desc, info, &pmap);
  357. if (!rec) {
  358. return false;
  359. }
  360. sk_sp<GrSurfaceContext> sContext = fContext->priv().makeWrappedSurfaceContext(
  361. fTextureProxy, SkColorTypeToGrColorType(info.colorType()), this->alphaType(),
  362. fColorSpace);
  363. if (!sContext) {
  364. return false;
  365. }
  366. if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(),
  367. {this->subset().left(), this->subset().top()})) {
  368. return false;
  369. }
  370. SkBitmapCache::Add(std::move(rec), dst);
  371. fAddedRasterVersionToCache.store(true);
  372. return true;
  373. }
  374. SkColorSpace* onGetColorSpace() const override {
  375. return fColorSpace.get();
  376. }
  377. sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
  378. const SkISize& size, SkAlphaType at,
  379. const SkSurfaceProps* props) const override {
  380. if (!fContext) {
  381. return nullptr;
  382. }
  383. return SkSpecialSurface::MakeRenderTarget(fContext, size.width(), size.height(),
  384. SkColorTypeToGrColorType(outProps.colorType()),
  385. sk_ref_sp(outProps.colorSpace()), props);
  386. }
  387. sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
  388. return SkSpecialImage::MakeDeferredFromGpu(fContext,
  389. subset,
  390. this->uniqueID(),
  391. fTextureProxy,
  392. fColorSpace,
  393. &this->props(),
  394. fAlphaType);
  395. }
  396. // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
  397. sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
  398. if (subset) {
  399. // TODO: if this becomes a bottle neck we could base this logic on what the size
  400. // will be when it is finally instantiated - but that is more fraught.
  401. if (GrProxyProvider::IsFunctionallyExact(fTextureProxy.get()) &&
  402. 0 == subset->fLeft && 0 == subset->fTop &&
  403. fTextureProxy->width() == subset->width() &&
  404. fTextureProxy->height() == subset->height()) {
  405. fTextureProxy->priv().exactify();
  406. // The existing GrTexture is already tight so reuse it in the SkImage
  407. return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
  408. }
  409. sk_sp<GrTextureProxy> subsetProxy(
  410. GrSurfaceProxy::Copy(fContext, fTextureProxy.get(), GrMipMapped::kNo, *subset,
  411. SkBackingFit::kExact, SkBudgeted::kYes));
  412. if (!subsetProxy) {
  413. return nullptr;
  414. }
  415. SkASSERT(subsetProxy->priv().isExact());
  416. // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
  417. // return a kExact-backed proxy
  418. return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace);
  419. }
  420. fTextureProxy->priv().exactify();
  421. return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
  422. }
  423. sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
  424. const SkISize& size, SkAlphaType at) const override {
  425. SkColorSpace* colorSpace = outProps.colorSpace();
  426. SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
  427. ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
  428. SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
  429. sk_ref_sp(colorSpace));
  430. // CONTEXT TODO: remove this use of 'backdoor' to create an SkSurface
  431. return SkSurface::MakeRenderTarget(fContext->priv().backdoor(), SkBudgeted::kYes, info);
  432. }
  433. private:
  434. GrRecordingContext* fContext;
  435. sk_sp<GrTextureProxy> fTextureProxy;
  436. const SkAlphaType fAlphaType;
  437. sk_sp<SkColorSpace> fColorSpace;
  438. mutable std::atomic<bool> fAddedRasterVersionToCache;
  439. typedef SkSpecialImage_Base INHERITED;
  440. };
  441. sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrRecordingContext* context,
  442. const SkIRect& subset,
  443. uint32_t uniqueID,
  444. sk_sp<GrTextureProxy> proxy,
  445. sk_sp<SkColorSpace> colorSpace,
  446. const SkSurfaceProps* props,
  447. SkAlphaType at) {
  448. if (!context || context->priv().abandoned() || !proxy) {
  449. return nullptr;
  450. }
  451. SkASSERT_RELEASE(rect_fits(subset, proxy->width(), proxy->height()));
  452. return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
  453. std::move(colorSpace), props);
  454. }
  455. #endif