• 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 "src/core/SkSpecialImage.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkTileMode.h"
15 #include "src/core/SkSpecialSurface.h"
16 #include "src/core/SkSurfacePriv.h"
17 #include "src/image/SkImage_Base.h"
18 
19 #if SK_SUPPORT_GPU
20 #include "include/gpu/GrDirectContext.h"
21 #include "include/gpu/GrRecordingContext.h"
22 #include "src/gpu/GrImageInfo.h"
23 #include "src/gpu/GrProxyProvider.h"
24 #include "src/gpu/GrRecordingContextPriv.h"
25 #include "src/gpu/GrTextureProxy.h"
26 #include "src/image/SkImage_Gpu.h"
27 #include "src/shaders/SkImageShader.h"
28 #endif
29 
30 // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
31 // a given info is supported.
valid_for_imagefilters(const SkImageInfo & info)32 static bool valid_for_imagefilters(const SkImageInfo& info) {
33     // no support for other swizzles/depths yet
34     return info.colorType() == kN32_SkColorType;
35 }
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 class SkSpecialImage_Base : public SkSpecialImage {
39 public:
SkSpecialImage_Base(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps & props)40     SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps& props)
41         : INHERITED(subset, uniqueID, props) {
42     }
~SkSpecialImage_Base()43     ~SkSpecialImage_Base() override { }
44 
45     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkSamplingOptions&,
46                         const SkPaint*) const = 0;
47 
48     virtual bool onGetROPixels(SkBitmap*) const = 0;
49 
onGetContext() const50     virtual GrRecordingContext* onGetContext() const { return nullptr; }
51 
52     virtual SkColorSpace* onGetColorSpace() const = 0;
53 
54 #if SK_SUPPORT_GPU
55     virtual GrSurfaceProxyView onView(GrRecordingContext* context) const = 0;
56 #endif
57 
58     // This subset is relative to the backing store's coordinate frame, it has already been mapped
59     // from the content rect by the non-virtual makeSubset().
60     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
61 
62     virtual sk_sp<SkSpecialSurface> onMakeSurface(
63             SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
64             SkAlphaType at, const SkSurfaceProps&) const = 0;
65 
66     // This subset (when not null) is relative to the backing store's coordinate frame, it has
67     // already been mapped from the content rect by the non-virtual asImage().
68     virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
69 
70     virtual sk_sp<SkShader> onAsShader(SkTileMode,
71                                        const SkSamplingOptions&,
72                                        const SkMatrix&) const = 0;
73 
74     virtual sk_sp<SkSurface> onMakeTightSurface(
75             SkColorType colorType, const SkColorSpace* colorSpace,
76             const SkISize& size, SkAlphaType at) const = 0;
77 
78 private:
79     using INHERITED = SkSpecialImage;
80 };
81 
82 ///////////////////////////////////////////////////////////////////////////////
as_SIB(const SkSpecialImage * image)83 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
84     return static_cast<const SkSpecialImage_Base*>(image);
85 }
86 
SkSpecialImage(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps & props)87 SkSpecialImage::SkSpecialImage(const SkIRect& subset,
88                                uint32_t uniqueID,
89                                const SkSurfaceProps& props)
90     : fProps(props)
91     , fSubset(subset)
92     , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
93 }
94 
draw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const95 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
96                           const SkSamplingOptions& sampling, const SkPaint* paint) const {
97     return as_SIB(this)->onDraw(canvas, x, y, sampling, paint);
98 }
99 
getROPixels(SkBitmap * bm) const100 bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
101     return as_SIB(this)->onGetROPixels(bm);
102 }
103 
isTextureBacked() const104 bool SkSpecialImage::isTextureBacked() const {
105     return SkToBool(as_SIB(this)->onGetContext());
106 }
107 
getContext() const108 GrRecordingContext* SkSpecialImage::getContext() const {
109     return as_SIB(this)->onGetContext();
110 }
111 
getColorSpace() const112 SkColorSpace* SkSpecialImage::getColorSpace() const {
113     return as_SIB(this)->onGetColorSpace();
114 }
115 
116 #if SK_SUPPORT_GPU
view(GrRecordingContext * context) const117 GrSurfaceProxyView SkSpecialImage::view(GrRecordingContext* context) const {
118     return as_SIB(this)->onView(context);
119 }
120 #endif
121 
makeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const122 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(
123         SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
124         SkAlphaType at, const SkSurfaceProps& props) const {
125     return as_SIB(this)->onMakeSurface(colorType, colorSpace, size, at, props);
126 }
127 
makeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const128 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(
129         SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
130         SkAlphaType at) const {
131     return as_SIB(this)->onMakeTightSurface(colorType, colorSpace, size, at);
132 }
133 
makeSubset(const SkIRect & subset) const134 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
135     SkIRect absolute = subset.makeOffset(this->subset().topLeft());
136     return as_SIB(this)->onMakeSubset(absolute);
137 }
138 
asImage(const SkIRect * subset) const139 sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
140     if (subset) {
141         SkIRect absolute = subset->makeOffset(this->subset().topLeft());
142         return as_SIB(this)->onAsImage(&absolute);
143     } else {
144         return as_SIB(this)->onAsImage(nullptr);
145     }
146 }
147 
asShader(SkTileMode tileMode,const SkSamplingOptions & sampling,const SkMatrix & lm) const148 sk_sp<SkShader> SkSpecialImage::asShader(SkTileMode tileMode,
149                                          const SkSamplingOptions& sampling,
150                                          const SkMatrix& lm) const {
151     return as_SIB(this)->onAsShader(tileMode, sampling, lm);
152 }
153 
asShader(const SkSamplingOptions & sampling) const154 sk_sp<SkShader> SkSpecialImage::asShader(const SkSamplingOptions& sampling) const {
155     return this->asShader(sampling, SkMatrix::I());
156 }
157 
asShader(const SkSamplingOptions & sampling,const SkMatrix & lm) const158 sk_sp<SkShader> SkSpecialImage::asShader(const SkSamplingOptions& sampling,
159                                          const SkMatrix& lm) const {
160     return this->asShader(SkTileMode::kClamp, sampling, lm);
161 }
162 
163 #if defined(SK_DEBUG) || SK_SUPPORT_GPU
rect_fits(const SkIRect & rect,int width,int height)164 static bool rect_fits(const SkIRect& rect, int width, int height) {
165     if (0 == width && 0 == height) {
166         SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
167         return true;
168     }
169 
170     return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
171            rect.fRight >= 0 && rect.fRight <= width &&
172            rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
173            rect.fBottom >= 0 && rect.fBottom <= height;
174 }
175 #endif
176 
MakeFromImage(GrRecordingContext * rContext,const SkIRect & subset,sk_sp<SkImage> image,const SkSurfaceProps & props)177 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrRecordingContext* rContext,
178                                                     const SkIRect& subset,
179                                                     sk_sp<SkImage> image,
180                                                     const SkSurfaceProps& props) {
181     SkASSERT(rect_fits(subset, image->width(), image->height()));
182 
183 #if SK_SUPPORT_GPU
184     if (rContext) {
185         auto [view, ct] = as_IB(image)->asView(rContext, GrMipmapped::kNo);
186         return MakeDeferredFromGpu(rContext,
187                                    subset,
188                                    image->uniqueID(),
189                                    std::move(view),
190                                    ct,
191                                    image->refColorSpace(),
192                                    props);
193     }
194 #endif
195 
196     // raster to gpu is supported here, but gpu to raster is not
197     SkBitmap bm;
198     if (as_IB(image)->getROPixels(nullptr, &bm)) {
199         return MakeFromRaster(subset, bm, props);
200     }
201     return nullptr;
202 }
203 
204 ///////////////////////////////////////////////////////////////////////////////
205 
206 class SkSpecialImage_Raster : public SkSpecialImage_Base {
207 public:
SkSpecialImage_Raster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)208     SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps& props)
209         : INHERITED(subset, bm.getGenerationID(), props)
210         , fBitmap(bm)
211     {
212         SkASSERT(bm.pixelRef());
213         SkASSERT(fBitmap.getPixels());
214     }
215 
alphaType() const216     SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
217 
colorType() const218     SkColorType colorType() const override { return fBitmap.colorType(); }
219 
getSize() const220     size_t getSize() const override { return fBitmap.computeByteSize(); }
221 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const222     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling,
223                 const SkPaint* paint) const override {
224         SkRect dst = SkRect::MakeXYWH(x, y,
225                                       this->subset().width(), this->subset().height());
226 
227         canvas->drawImageRect(fBitmap.asImage(), SkRect::Make(this->subset()), dst,
228                               sampling, paint, SkCanvas::kStrict_SrcRectConstraint);
229     }
230 
onGetROPixels(SkBitmap * bm) const231     bool onGetROPixels(SkBitmap* bm) const override {
232         return fBitmap.extractSubset(bm, this->subset());
233     }
234 
onGetColorSpace() const235     SkColorSpace* onGetColorSpace() const override {
236         return fBitmap.colorSpace();
237     }
238 
239 #if SK_SUPPORT_GPU
onView(GrRecordingContext * context) const240     GrSurfaceProxyView onView(GrRecordingContext* context) const override {
241         if (context) {
242             return std::get<0>(GrMakeCachedBitmapProxyView(context, fBitmap, GrMipmapped::kNo));
243         }
244 
245         return {};
246     }
247 #endif
248 
onMakeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const249     sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType, const SkColorSpace* colorSpace,
250                                           const SkISize& size, SkAlphaType at,
251                                           const SkSurfaceProps& props) const override {
252         // Ignore the requested color type, the raster backend currently only supports N32
253         colorType = kN32_SkColorType;   // TODO: find ways to allow f16
254         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
255         return SkSpecialSurface::MakeRaster(info, props);
256     }
257 
onMakeSubset(const SkIRect & subset) const258     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
259         // No need to extract subset, onGetROPixels handles that when needed
260         return SkSpecialImage::MakeFromRaster(subset, fBitmap, this->props());
261     }
262 
onAsImage(const SkIRect * subset) const263     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
264         if (subset) {
265             SkBitmap subsetBM;
266 
267             if (!fBitmap.extractSubset(&subsetBM, *subset)) {
268                 return nullptr;
269             }
270 
271             return subsetBM.asImage();
272         }
273 
274         return fBitmap.asImage();
275     }
276 
onAsShader(SkTileMode tileMode,const SkSamplingOptions & sampling,const SkMatrix & lm) const277     sk_sp<SkShader> onAsShader(SkTileMode tileMode,
278                                const SkSamplingOptions& sampling,
279                                const SkMatrix& lm) const override {
280         // TODO(skbug.com/12784): SkImage::makeShader() doesn't support a subset yet, but SkBitmap
281         // supports subset views so create the shader from the subset bitmap instead of fBitmap.
282         SkBitmap subsetBM;
283         if (!this->getROPixels(&subsetBM)) {
284             return nullptr;
285         }
286         return subsetBM.asImage()->makeShader(tileMode, tileMode, sampling, lm);
287     }
288 
onMakeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const289     sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
290                                         const SkISize& size, SkAlphaType at) const override {
291         // Ignore the requested color type, the raster backend currently only supports N32
292         colorType = kN32_SkColorType;   // TODO: find ways to allow f16
293         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
294         return SkSurface::MakeRaster(info);
295     }
296 
297 private:
298     SkBitmap fBitmap;
299 
300     using INHERITED = SkSpecialImage_Base;
301 };
302 
MakeFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)303 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
304                                                      const SkBitmap& bm,
305                                                      const SkSurfaceProps& props) {
306     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
307 
308     if (!bm.pixelRef()) {
309         return nullptr;
310     }
311 
312     const SkBitmap* srcBM = &bm;
313     SkBitmap tmp;
314     // ImageFilters only handle N32 at the moment, so force our src to be that
315     if (!valid_for_imagefilters(bm.info())) {
316         if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) ||
317             !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0))
318         {
319             return nullptr;
320         }
321         srcBM = &tmp;
322     }
323     return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
324 }
325 
CopyFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)326 sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset,
327                                                      const SkBitmap& bm,
328                                                      const SkSurfaceProps& props) {
329     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
330 
331     if (!bm.pixelRef()) {
332         return nullptr;
333     }
334 
335     SkBitmap tmp;
336     SkImageInfo info = bm.info().makeDimensions(subset.size());
337     // As in MakeFromRaster, must force src to N32 for ImageFilters
338     if (!valid_for_imagefilters(bm.info())) {
339         info = info.makeColorType(kN32_SkColorType);
340     }
341     if (!tmp.tryAllocPixels(info)) {
342         return nullptr;
343     }
344     if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) {
345         return nullptr;
346     }
347 
348     // Since we're making a copy of the raster, the resulting special image is the exact size
349     // of the requested subset of the original and no longer needs to be offset by subset's left
350     // and top, since those were relative to the original's buffer.
351     return sk_make_sp<SkSpecialImage_Raster>(
352             SkIRect::MakeWH(subset.width(), subset.height()), tmp, props);
353 }
354 
355 #if SK_SUPPORT_GPU
356 ///////////////////////////////////////////////////////////////////////////////
wrap_proxy_in_image(GrRecordingContext * context,GrSurfaceProxyView view,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)357 static sk_sp<SkImage> wrap_proxy_in_image(GrRecordingContext* context, GrSurfaceProxyView view,
358                                           SkColorType colorType, SkAlphaType alphaType,
359                                           sk_sp<SkColorSpace> colorSpace) {
360     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context),
361                                    kNeedNewImageUniqueID,
362                                    std::move(view),
363                                    SkColorInfo(colorType, alphaType, std::move(colorSpace)));
364 }
365 
366 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
367 public:
SkSpecialImage_Gpu(GrRecordingContext * context,const SkIRect & subset,uint32_t uniqueID,GrSurfaceProxyView view,GrColorType ct,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps & props)368     SkSpecialImage_Gpu(GrRecordingContext* context, const SkIRect& subset,
369                        uint32_t uniqueID, GrSurfaceProxyView view, GrColorType ct,
370                        SkAlphaType at, sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps& props)
371         : INHERITED(subset, uniqueID, props)
372         , fContext(context)
373         , fView(std::move(view))
374         , fColorType(ct)
375         , fAlphaType(at)
376         , fColorSpace(std::move(colorSpace)) {
377     }
378 
alphaType() const379     SkAlphaType alphaType() const override { return fAlphaType; }
380 
colorType() const381     SkColorType colorType() const override { return GrColorTypeToSkColorType(fColorType); }
382 
getSize() const383     size_t getSize() const override {
384         return fView.proxy()->gpuMemorySize();
385     }
386 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const387     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling,
388                 const SkPaint* paint) const override {
389         SkRect dst = SkRect::MakeXYWH(x, y,
390                                       this->subset().width(), this->subset().height());
391 
392         // TODO: In this instance we know we're going to draw a sub-portion of the backing
393         // texture into the canvas so it is okay to wrap it in an SkImage. This poses
394         // some problems for full deferral however in that when the deferred SkImage_Gpu
395         // instantiates itself it is going to have to either be okay with having a larger
396         // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
397         // to be tightened (if it is deferred).
398         sk_sp<SkImage> img = sk_sp<SkImage>(
399                 new SkImage_Gpu(sk_ref_sp(canvas->recordingContext()),
400                                 this->uniqueID(),
401                                 fView,
402                                 SkColorInfo(this->colorType(), fAlphaType, fColorSpace)));
403 
404         canvas->drawImageRect(img, SkRect::Make(this->subset()), dst,
405                               sampling, paint, SkCanvas::kStrict_SrcRectConstraint);
406     }
407 
onGetContext() const408     GrRecordingContext* onGetContext() const override { return fContext; }
409 
onView(GrRecordingContext * context) const410     GrSurfaceProxyView onView(GrRecordingContext* context) const override { return fView; }
411 
onGetROPixels(SkBitmap * dst) const412     bool onGetROPixels(SkBitmap* dst) const override {
413         // This should never be called: All GPU image filters are implemented entirely on the GPU,
414         // so we never perform read-back.
415         SkASSERT(false);
416         return false;
417     }
418 
onGetColorSpace() const419     SkColorSpace* onGetColorSpace() const override {
420         return fColorSpace.get();
421     }
422 
onMakeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const423     sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType, const SkColorSpace* colorSpace,
424                                           const SkISize& size, SkAlphaType at,
425                                           const SkSurfaceProps& props) const override {
426         if (!fContext) {
427             return nullptr;
428         }
429 
430         SkImageInfo ii = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
431 
432         return SkSpecialSurface::MakeRenderTarget(fContext, ii, props, fView.origin());
433     }
434 
onMakeSubset(const SkIRect & subset) const435     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
436         return SkSpecialImage::MakeDeferredFromGpu(fContext,
437                                                    subset,
438                                                    this->uniqueID(),
439                                                    fView,
440                                                    fColorType,
441                                                    fColorSpace,
442                                                    this->props(),
443                                                    fAlphaType);
444     }
445 
onAsImage(const SkIRect * subset) const446     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
447         GrSurfaceProxy* proxy = fView.proxy();
448         if (subset) {
449             if (proxy->isFunctionallyExact() && *subset == SkIRect::MakeSize(proxy->dimensions())) {
450                 proxy->priv().exactify(false);
451                 // The existing GrTexture is already tight so reuse it in the SkImage
452                 return wrap_proxy_in_image(fContext, fView, this->colorType(), fAlphaType,
453                                            fColorSpace);
454             }
455 
456             auto subsetView = GrSurfaceProxyView::Copy(fContext, fView, GrMipmapped::kNo, *subset,
457                                                        SkBackingFit::kExact, SkBudgeted::kYes);
458             if (!subsetView) {
459                 return nullptr;
460             }
461             SkASSERT(subsetView.asTextureProxy());
462             SkASSERT(subsetView.proxy()->priv().isExact());
463 
464             // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
465             // return a kExact-backed proxy
466             return wrap_proxy_in_image(fContext, std::move(subsetView), this->colorType(),
467                                        fAlphaType, fColorSpace);
468         }
469 
470         proxy->priv().exactify(true);
471 
472         return wrap_proxy_in_image(fContext, fView, this->colorType(), fAlphaType, fColorSpace);
473     }
474 
onAsShader(SkTileMode tileMode,const SkSamplingOptions & sampling,const SkMatrix & lm) const475     sk_sp<SkShader> onAsShader(SkTileMode tileMode,
476                                const SkSamplingOptions& sampling,
477                                const SkMatrix& lm) const override {
478         // The special image's logical (0,0) is at its subset's topLeft() so we need to account for
479         // that in the local matrix used when sampling.
480         SkMatrix subsetOrigin = SkMatrix::Translate(-this->subset().topLeft());
481         subsetOrigin.postConcat(lm);
482         // However, we don't need to modify the subset itself since that is defined with respect to
483         // the base image, and the local matrix is applied before any tiling/clamping.
484         const SkRect subset = SkRect::Make(this->subset());
485 
486         // asImage() w/o a subset makes no copy; create the SkImageShader directly to remember the
487         // subset used to access the image.
488         return SkImageShader::MakeSubset(
489                 this->asImage(), subset, tileMode, tileMode, sampling, &subsetOrigin);
490     }
491 
onMakeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const492     sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
493                                         const SkISize& size, SkAlphaType at) const override {
494         // TODO (michaelludwig): Why does this ignore colorType but onMakeSurface doesn't ignore it?
495         //    Once makeTightSurface() goes away, should this type overriding behavior be moved into
496         //    onMakeSurface() or is this unnecessary?
497         colorType = colorSpace && colorSpace->gammaIsLinear()
498             ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
499         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
500         return SkSurface::MakeRenderTarget(
501                 fContext, SkBudgeted::kYes, info, 0, fView.origin(), nullptr);
502     }
503 
504 private:
505     GrRecordingContext*       fContext;
506     GrSurfaceProxyView        fView;
507     const GrColorType         fColorType;
508     const SkAlphaType         fAlphaType;
509     sk_sp<SkColorSpace>       fColorSpace;
510 
511     using INHERITED = SkSpecialImage_Base;
512 };
513 
MakeDeferredFromGpu(GrRecordingContext * context,const SkIRect & subset,uint32_t uniqueID,GrSurfaceProxyView view,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps & props,SkAlphaType at)514 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrRecordingContext* context,
515                                                           const SkIRect& subset,
516                                                           uint32_t uniqueID,
517                                                           GrSurfaceProxyView view,
518                                                           GrColorType colorType,
519                                                           sk_sp<SkColorSpace> colorSpace,
520                                                           const SkSurfaceProps& props,
521                                                           SkAlphaType at) {
522     if (!context || context->abandoned() || !view.asTextureProxy()) {
523         return nullptr;
524     }
525     SkASSERT_RELEASE(rect_fits(subset, view.proxy()->width(), view.proxy()->height()));
526     return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(view), colorType,
527                                           at, std::move(colorSpace), props);
528 }
529 #endif
530