• 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 #include "SkSpecialImage.h"
9 #include "SkBitmap.h"
10 #include "SkImage.h"
11 #include "SkBitmapCache.h"
12 #include "SkCanvas.h"
13 #include "SkImage_Base.h"
14 #include "SkSpecialSurface.h"
15 #include "SkSurfacePriv.h"
16 #include <atomic>
17 
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #include "GrContextPriv.h"
21 #include "GrProxyProvider.h"
22 #include "GrSurfaceContext.h"
23 #include "GrTextureProxy.h"
24 #include "SkImage_Gpu.h"
25 #endif
26 
27 // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
28 // a given info is supported.
valid_for_imagefilters(const SkImageInfo & info)29 static bool valid_for_imagefilters(const SkImageInfo& info) {
30     // no support for other swizzles/depths yet
31     return info.colorType() == kN32_SkColorType;
32 }
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 class SkSpecialImage_Base : public SkSpecialImage {
36 public:
SkSpecialImage_Base(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps * props)37     SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
38         : INHERITED(subset, uniqueID, props) {
39     }
~SkSpecialImage_Base()40     ~SkSpecialImage_Base() override { }
41 
42     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
43 
44     virtual bool onGetROPixels(SkBitmap*) const = 0;
45 
onGetContext() const46     virtual GrContext* onGetContext() const { return nullptr; }
47 
48     virtual SkColorSpace* onGetColorSpace() const = 0;
49 
50 #if SK_SUPPORT_GPU
51     virtual sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const = 0;
52 #endif
53 
54     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
55 
56     virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
57                                                   const SkISize& size, SkAlphaType at,
58                                                   const SkSurfaceProps* = nullptr) const = 0;
59 
60     virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
61 
62     virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
63                                                 const SkISize& size, SkAlphaType at) const = 0;
64 
65 private:
66     typedef SkSpecialImage INHERITED;
67 };
68 
69 ///////////////////////////////////////////////////////////////////////////////
as_SIB(const SkSpecialImage * image)70 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
71     return static_cast<const SkSpecialImage_Base*>(image);
72 }
73 
SkSpecialImage(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps * props)74 SkSpecialImage::SkSpecialImage(const SkIRect& subset,
75                                uint32_t uniqueID,
76                                const SkSurfaceProps* props)
77     : fProps(SkSurfacePropsCopyOrDefault(props))
78     , fSubset(subset)
79     , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
80 }
81 
makeTextureImage(GrContext * context)82 sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
83 #if SK_SUPPORT_GPU
84     if (!context) {
85         return nullptr;
86     }
87     if (GrContext* curContext = as_SIB(this)->onGetContext()) {
88         return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
89     }
90 
91     auto proxyProvider = context->contextPriv().proxyProvider();
92     SkBitmap bmp;
93     // At this point, we are definitely not texture-backed, so we must be raster or generator
94     // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
95     // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
96     // in which case getROPixels could turn into peekPixels...
97     if (!this->getROPixels(&bmp)) {
98         return nullptr;
99     }
100 
101     if (bmp.empty()) {
102         return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
103     }
104 
105     // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
106     // semantics). Since this is cached though we would have to bake the fit into the cache key.
107     sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(proxyProvider, bmp);
108     if (!proxy) {
109         return nullptr;
110     }
111 
112     const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
113 
114     // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not
115     // bother with SkBitmap::getSubset
116     return SkSpecialImage::MakeDeferredFromGpu(context,
117                                                rect,
118                                                this->uniqueID(),
119                                                std::move(proxy),
120                                                sk_ref_sp(this->getColorSpace()),
121                                                &this->props(),
122                                                this->alphaType());
123 #else
124     return nullptr;
125 #endif
126 }
127 
draw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint) const128 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
129     return as_SIB(this)->onDraw(canvas, x, y, paint);
130 }
131 
getROPixels(SkBitmap * bm) const132 bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
133     return as_SIB(this)->onGetROPixels(bm);
134 }
135 
isTextureBacked() const136 bool SkSpecialImage::isTextureBacked() const {
137     return SkToBool(as_SIB(this)->onGetContext());
138 }
139 
getContext() const140 GrContext* SkSpecialImage::getContext() const {
141     return as_SIB(this)->onGetContext();
142 }
143 
getColorSpace() const144 SkColorSpace* SkSpecialImage::getColorSpace() const {
145     return as_SIB(this)->onGetColorSpace();
146 }
147 
148 #if SK_SUPPORT_GPU
asTextureProxyRef(GrContext * context) const149 sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrContext* context) const {
150     return as_SIB(this)->onAsTextureProxyRef(context);
151 }
152 #endif
153 
makeSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at,const SkSurfaceProps * props) const154 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
155                                                     const SkISize& size, SkAlphaType at,
156                                                     const SkSurfaceProps* props) const {
157     return as_SIB(this)->onMakeSurface(outProps, size, at, props);
158 }
159 
makeTightSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at) const160 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
161                                                   const SkISize& size, SkAlphaType at) const {
162     return as_SIB(this)->onMakeTightSurface(outProps, size, at);
163 }
164 
makeSubset(const SkIRect & subset) const165 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
166     return as_SIB(this)->onMakeSubset(subset);
167 }
168 
asImage(const SkIRect * subset) const169 sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
170     return as_SIB(this)->onAsImage(subset);
171 }
172 
173 #if defined(SK_DEBUG) || SK_SUPPORT_GPU
rect_fits(const SkIRect & rect,int width,int height)174 static bool rect_fits(const SkIRect& rect, int width, int height) {
175     if (0 == width && 0 == height) {
176         SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
177         return true;
178     }
179 
180     return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
181            rect.fRight >= 0 && rect.fRight <= width &&
182            rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
183            rect.fBottom >= 0 && rect.fBottom <= height;
184 }
185 #endif
186 
MakeFromImage(GrContext * context,const SkIRect & subset,sk_sp<SkImage> image,const SkSurfaceProps * props)187 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrContext* context,
188                                                     const SkIRect& subset,
189                                                     sk_sp<SkImage> image,
190                                                     const SkSurfaceProps* props) {
191     SkASSERT(rect_fits(subset, image->width(), image->height()));
192 
193 #if SK_SUPPORT_GPU
194     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) {
195         if (as_IB(image)->contextID() != context->contextPriv().contextID()) {
196             return nullptr;
197         }
198 
199         return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
200                                    as_IB(image)->onImageInfo().refColorSpace(), props);
201     } else
202 #endif
203     {
204         SkBitmap bm;
205         if (as_IB(image)->getROPixels(&bm)) {
206             return MakeFromRaster(subset, bm, props);
207         }
208     }
209     return nullptr;
210 }
211 
212 ///////////////////////////////////////////////////////////////////////////////
213 
214 class SkSpecialImage_Raster : public SkSpecialImage_Base {
215 public:
SkSpecialImage_Raster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps * props)216     SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
217         : INHERITED(subset, bm.getGenerationID(), props)
218         , fBitmap(bm)
219     {
220         SkASSERT(bm.pixelRef());
221         SkASSERT(fBitmap.getPixels());
222     }
223 
alphaType() const224     SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
225 
getSize() const226     size_t getSize() const override { return fBitmap.computeByteSize(); }
227 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint) const228     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
229         SkRect dst = SkRect::MakeXYWH(x, y,
230                                       this->subset().width(), this->subset().height());
231 
232         canvas->drawBitmapRect(fBitmap, this->subset(),
233                                dst, paint, SkCanvas::kStrict_SrcRectConstraint);
234     }
235 
onGetROPixels(SkBitmap * bm) const236     bool onGetROPixels(SkBitmap* bm) const override {
237         *bm = fBitmap;
238         return true;
239     }
240 
onGetColorSpace() const241     SkColorSpace* onGetColorSpace() const override {
242         return fBitmap.colorSpace();
243     }
244 
245 #if SK_SUPPORT_GPU
onAsTextureProxyRef(GrContext * context) const246     sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const override {
247         if (context) {
248             return GrMakeCachedBitmapProxy(context->contextPriv().proxyProvider(), fBitmap);
249         }
250 
251         return nullptr;
252     }
253 #endif
254 
255 // TODO: The raster implementations of image filters all currently assume that the pixels are
256 // legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
257 // we can't enable this. (They will continue to produce incorrect results, but less-so).
258 #define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
259 
onMakeSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at,const SkSurfaceProps * props) const260     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
261                                           const SkISize& size, SkAlphaType at,
262                                           const SkSurfaceProps* props) const override {
263 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
264         SkColorSpace* colorSpace = outProps.colorSpace();
265 #else
266         SkColorSpace* colorSpace = nullptr;
267 #endif
268         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
269             ? kRGBA_F16_SkColorType : kN32_SkColorType;
270         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
271                                              sk_ref_sp(colorSpace));
272         return SkSpecialSurface::MakeRaster(info, props);
273     }
274 
onMakeSubset(const SkIRect & subset) const275     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
276         SkBitmap subsetBM;
277 
278         if (!fBitmap.extractSubset(&subsetBM, subset)) {
279             return nullptr;
280         }
281 
282         return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
283                                               subsetBM,
284                                               &this->props());
285     }
286 
onAsImage(const SkIRect * subset) const287     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
288         if (subset) {
289             SkBitmap subsetBM;
290 
291             if (!fBitmap.extractSubset(&subsetBM, *subset)) {
292                 return nullptr;
293             }
294 
295             return SkImage::MakeFromBitmap(subsetBM);
296         }
297 
298         return SkImage::MakeFromBitmap(fBitmap);
299     }
300 
onMakeTightSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at) const301     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
302                                         const SkISize& size, SkAlphaType at) const override {
303 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
304         SkColorSpace* colorSpace = outProps.colorSpace();
305 #else
306         SkColorSpace* colorSpace = nullptr;
307 #endif
308         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
309             ? kRGBA_F16_SkColorType : kN32_SkColorType;
310         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
311                                              sk_ref_sp(colorSpace));
312         return SkSurface::MakeRaster(info);
313     }
314 
315 private:
316     SkBitmap fBitmap;
317 
318     typedef SkSpecialImage_Base INHERITED;
319 };
320 
MakeFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps * props)321 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
322                                                      const SkBitmap& bm,
323                                                      const SkSurfaceProps* props) {
324     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
325 
326     if (!bm.pixelRef()) {
327         return nullptr;
328     }
329 
330     const SkBitmap* srcBM = &bm;
331     SkBitmap tmp;
332     // ImageFilters only handle N32 at the moment, so force our src to be that
333     if (!valid_for_imagefilters(bm.info())) {
334         if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) ||
335             !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0))
336         {
337             return nullptr;
338         }
339         srcBM = &tmp;
340     }
341     return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
342 }
343 
CopyFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps * props)344 sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset,
345                                                      const SkBitmap& bm,
346                                                      const SkSurfaceProps* props) {
347     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
348 
349     if (!bm.pixelRef()) {
350         return nullptr;
351     }
352 
353     SkBitmap tmp;
354     if (!tmp.tryAllocPixels(bm.info().makeWH(subset.width(), subset.height()))) {
355         return nullptr;
356     }
357     if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) {
358         return nullptr;
359     }
360     return sk_make_sp<SkSpecialImage_Raster>(subset, tmp, props);
361 }
362 
363 #if SK_SUPPORT_GPU
364 ///////////////////////////////////////////////////////////////////////////////
wrap_proxy_in_image(GrContext * context,sk_sp<GrTextureProxy> proxy,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)365 static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, sk_sp<GrTextureProxy> proxy,
366                                           SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
367     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType,
368                                    std::move(proxy), std::move(colorSpace));
369 }
370 
371 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
372 public:
SkSpecialImage_Gpu(GrContext * context,const SkIRect & subset,uint32_t uniqueID,sk_sp<GrTextureProxy> proxy,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)373     SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
374                        uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
375                        sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
376         : INHERITED(subset, uniqueID, props)
377         , fContext(context)
378         , fTextureProxy(std::move(proxy))
379         , fAlphaType(at)
380         , fColorSpace(std::move(colorSpace))
381         , fAddedRasterVersionToCache(false) {
382     }
383 
~SkSpecialImage_Gpu()384     ~SkSpecialImage_Gpu() override {
385         if (fAddedRasterVersionToCache.load()) {
386             SkNotifyBitmapGenIDIsStale(this->uniqueID());
387         }
388     }
389 
alphaType() const390     SkAlphaType alphaType() const override { return fAlphaType; }
391 
getSize() const392     size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
393 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint) const394     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
395         SkRect dst = SkRect::MakeXYWH(x, y,
396                                       this->subset().width(), this->subset().height());
397 
398         // TODO: In this instance we know we're going to draw a sub-portion of the backing
399         // texture into the canvas so it is okay to wrap it in an SkImage. This poses
400         // some problems for full deferral however in that when the deferred SkImage_Gpu
401         // instantiates itself it is going to have to either be okay with having a larger
402         // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
403         // to be tightened (if it is deferred).
404         sk_sp<SkImage> img =
405                 sk_sp<SkImage>(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()), this->uniqueID(),
406                                                fAlphaType, fTextureProxy, fColorSpace));
407 
408         canvas->drawImageRect(img, this->subset(),
409                               dst, paint, SkCanvas::kStrict_SrcRectConstraint);
410     }
411 
onGetContext() const412     GrContext* onGetContext() const override { return fContext; }
413 
onAsTextureProxyRef(GrContext *) const414     sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext*) const override {
415         return fTextureProxy;
416     }
417 
onGetROPixels(SkBitmap * dst) const418     bool onGetROPixels(SkBitmap* dst) const override {
419         const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->subset());
420         if (SkBitmapCache::Find(desc, dst)) {
421             SkASSERT(dst->getGenerationID() == this->uniqueID());
422             SkASSERT(dst->isImmutable());
423             SkASSERT(dst->getPixels());
424             return true;
425         }
426 
427         SkPixmap pmap;
428         SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
429                                                 this->alphaType(), fColorSpace);
430         auto rec = SkBitmapCache::Alloc(desc, info, &pmap);
431         if (!rec) {
432             return false;
433         }
434         sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
435                 fTextureProxy, fColorSpace);
436         if (!sContext) {
437             return false;
438         }
439 
440         if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(),
441                                   this->subset().left(), this->subset().top())) {
442             return false;
443         }
444 
445         SkBitmapCache::Add(std::move(rec), dst);
446         fAddedRasterVersionToCache.store(true);
447         return true;
448     }
449 
onGetColorSpace() const450     SkColorSpace* onGetColorSpace() const override {
451         return fColorSpace.get();
452     }
453 
onMakeSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at,const SkSurfaceProps * props) const454     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
455                                           const SkISize& size, SkAlphaType at,
456                                           const SkSurfaceProps* props) const override {
457         if (!fContext) {
458             return nullptr;
459         }
460 
461         GrBackendFormat format =
462             fContext->contextPriv().caps()->getBackendFormatFromColorType(outProps.colorType());
463 
464         return SkSpecialSurface::MakeRenderTarget(
465             fContext, format, size.width(), size.height(),
466             SkColorType2GrPixelConfig(outProps.colorType()), sk_ref_sp(outProps.colorSpace()),
467             props);
468     }
469 
onMakeSubset(const SkIRect & subset) const470     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
471         return SkSpecialImage::MakeDeferredFromGpu(fContext,
472                                                    subset,
473                                                    this->uniqueID(),
474                                                    fTextureProxy,
475                                                    fColorSpace,
476                                                    &this->props(),
477                                                    fAlphaType);
478     }
479 
480     // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
onAsImage(const SkIRect * subset) const481     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
482         if (subset) {
483             // TODO: if this becomes a bottle neck we could base this logic on what the size
484             // will be when it is finally instantiated - but that is more fraught.
485             if (GrProxyProvider::IsFunctionallyExact(fTextureProxy.get()) &&
486                 0 == subset->fLeft && 0 == subset->fTop &&
487                 fTextureProxy->width() == subset->width() &&
488                 fTextureProxy->height() == subset->height()) {
489                 fTextureProxy->priv().exactify();
490                 // The existing GrTexture is already tight so reuse it in the SkImage
491                 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
492             }
493 
494             sk_sp<GrTextureProxy> subsetProxy(
495                     GrSurfaceProxy::Copy(fContext, fTextureProxy.get(), GrMipMapped::kNo, *subset,
496                                          SkBackingFit::kExact, SkBudgeted::kYes));
497             if (!subsetProxy) {
498                 return nullptr;
499             }
500 
501             SkASSERT(subsetProxy->priv().isExact());
502             // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
503             // return a kExact-backed proxy
504             return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace);
505         }
506 
507         fTextureProxy->priv().exactify();
508 
509         return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
510     }
511 
onMakeTightSurface(const SkImageFilter::OutputProperties & outProps,const SkISize & size,SkAlphaType at) const512     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
513                                         const SkISize& size, SkAlphaType at) const override {
514         SkColorSpace* colorSpace = outProps.colorSpace();
515         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
516             ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
517         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
518                                              sk_ref_sp(colorSpace));
519         return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
520     }
521 
522 private:
523     GrContext*                fContext;
524     sk_sp<GrTextureProxy>     fTextureProxy;
525     const SkAlphaType         fAlphaType;
526     sk_sp<SkColorSpace>       fColorSpace;
527     mutable std::atomic<bool> fAddedRasterVersionToCache;
528 
529     typedef SkSpecialImage_Base INHERITED;
530 };
531 
MakeDeferredFromGpu(GrContext * context,const SkIRect & subset,uint32_t uniqueID,sk_sp<GrTextureProxy> proxy,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkAlphaType at)532 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
533                                                           const SkIRect& subset,
534                                                           uint32_t uniqueID,
535                                                           sk_sp<GrTextureProxy> proxy,
536                                                           sk_sp<SkColorSpace> colorSpace,
537                                                           const SkSurfaceProps* props,
538                                                           SkAlphaType at) {
539     if (!context || context->abandoned() || !proxy) {
540         return nullptr;
541     }
542     SkASSERT_RELEASE(rect_fits(subset, proxy->width(), proxy->height()));
543     return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
544                                           std::move(colorSpace), props);
545 }
546 #endif
547