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