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