1 /*
2 * Copyright 2012 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/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkPixelRef.h"
16 #include "include/core/SkPixmap.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkSamplingOptions.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkTypes.h"
23 #include "include/private/base/SkMath.h"
24 #include "include/private/base/SkTo.h"
25 #include "src/core/SkCompressedDataUtils.h"
26 #include "src/core/SkConvertPixels.h"
27 #include "src/core/SkImageInfoPriv.h"
28 #include "src/core/SkImagePriv.h"
29 #include "src/core/SkMipmap.h"
30 #include "src/image/SkImage_Base.h"
31
32 #include <cstddef>
33 #include <cstdint>
34 #include <memory>
35 #include <tuple>
36 #include <utility>
37
38 class GrDirectContext;
39 class GrFragmentProcessor;
40 class SkMatrix;
41 enum class SkTileMode;
42
43 #if defined(SK_GANESH)
44 #include "include/gpu/GpuTypes.h"
45 #include "include/gpu/GrBackendSurface.h"
46 #include "include/gpu/GrRecordingContext.h"
47 #include "include/gpu/GrTypes.h"
48 #include "include/private/gpu/ganesh/GrTypesPriv.h"
49 #include "src/gpu/SkBackingFit.h"
50 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
51 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
52 #include "src/gpu/ganesh/SkGr.h"
53 #endif
54
55 #if defined(SK_GRAPHITE)
56 #include "include/gpu/graphite/GraphiteTypes.h"
57 #include "include/gpu/graphite/Recorder.h"
58 #include "src/gpu/graphite/Buffer.h"
59 #include "src/gpu/graphite/Caps.h"
60 #include "src/gpu/graphite/CommandBuffer.h"
61 #include "src/gpu/graphite/RecorderPriv.h"
62 #include "src/gpu/graphite/TextureUtils.h"
63 #include "src/gpu/graphite/UploadTask.h"
64 #endif
65
66 // fixes https://bug.skia.org/5096
is_not_subset(const SkBitmap & bm)67 static bool is_not_subset(const SkBitmap& bm) {
68 SkASSERT(bm.pixelRef());
69 SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
70 SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
71 return dim == bm.dimensions();
72 }
73
74 class SkImage_Raster : public SkImage_Base {
75 public:
ValidArgs(const SkImageInfo & info,size_t rowBytes,size_t * minSize)76 static bool ValidArgs(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
77 const int maxDimension = SK_MaxS32 >> 2;
78
79 // TODO(mtklein): eliminate anything here that setInfo() has already checked.
80 SkBitmap b;
81 if (!b.setInfo(info, rowBytes)) {
82 return false;
83 }
84
85 if (info.width() <= 0 || info.height() <= 0) {
86 return false;
87 }
88 if (info.width() > maxDimension || info.height() > maxDimension) {
89 return false;
90 }
91 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
92 return false;
93 }
94 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
95 return false;
96 }
97
98 if (kUnknown_SkColorType == info.colorType()) {
99 return false;
100 }
101 if (!info.validRowBytes(rowBytes)) {
102 return false;
103 }
104
105 size_t size = info.computeByteSize(rowBytes);
106 if (SkImageInfo::ByteSizeOverflowed(size)) {
107 return false;
108 }
109
110 if (minSize) {
111 *minSize = size;
112 }
113 return true;
114 }
115
116 SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
117 uint32_t id = kNeedNewImageUniqueID);
118 ~SkImage_Raster() override;
119
120 bool onReadPixels(GrDirectContext*, const SkImageInfo&, void*, size_t, int srcX, int srcY,
121 CachingHint) const override;
122 bool onPeekPixels(SkPixmap*) const override;
onPeekBitmap() const123 const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
124
125 bool getROPixels(GrDirectContext*, SkBitmap*, CachingHint) const override;
126 sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
127 #if defined(SK_GRAPHITE)
128 sk_sp<SkImage> onMakeSubset(const SkIRect&,
129 skgpu::graphite::Recorder*,
130 RequiredImageProperties) const override;
131 #endif
132
getPixelRef() const133 SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
134
135 bool onAsLegacyBitmap(GrDirectContext*, SkBitmap*) const override;
136
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable=false)137 SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
138 : INHERITED(bm.info(),
139 is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
140 , fBitmap(bm) {
141 SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
142 }
143
144 sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>,
145 GrDirectContext*) const override;
146
147 sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;
148
onIsValid(GrRecordingContext * context) const149 bool onIsValid(GrRecordingContext* context) const override { return true; }
notifyAddedToRasterCache() const150 void notifyAddedToRasterCache() const override {
151 // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
152 // lifetime of derived/cached resources to the image. In this case, we only want cached
153 // data (eg mips) tied to the lifetime of the underlying pixelRef.
154 SkASSERT(fBitmap.pixelRef());
155 fBitmap.pixelRef()->notifyAddedToCache();
156 }
157
158 #if defined(SK_GANESH)
159 bool onPinAsTexture(GrRecordingContext*) const override;
160 void onUnpinAsTexture(GrRecordingContext*) const override;
161 bool isPinnedOnContext(GrRecordingContext*) const override;
162 #endif
163
onHasMipmaps() const164 bool onHasMipmaps() const override { return SkToBool(fBitmap.fMips); }
165
onPeekMips() const166 SkMipmap* onPeekMips() const override { return fBitmap.fMips.get(); }
167
onMakeWithMipmaps(sk_sp<SkMipmap> mips) const168 sk_sp<SkImage> onMakeWithMipmaps(sk_sp<SkMipmap> mips) const override {
169 // It's dangerous to have two SkBitmaps that share a SkPixelRef but have different SkMipmaps
170 // since various caches key on SkPixelRef's generation ID. Also, SkPixelRefs that back
171 // SkSurfaces are marked "temporarily immutable" and making an image that uses the same
172 // SkPixelRef can interact badly with SkSurface/SkImage copy-on-write. So we just always
173 // make a copy with a new ID.
174 static auto constexpr kCopyMode = SkCopyPixelsMode::kAlways_SkCopyPixelsMode;
175 sk_sp<SkImage> img = SkMakeImageFromRasterBitmap(fBitmap, kCopyMode);
176 auto imgRaster = static_cast<SkImage_Raster*>(img.get());
177 if (mips) {
178 imgRaster->fBitmap.fMips = std::move(mips);
179 } else {
180 imgRaster->fBitmap.fMips.reset(SkMipmap::Build(fBitmap.pixmap(), nullptr));
181 }
182 return img;
183 }
184
185 private:
186 #if defined(SK_GANESH)
187 std::tuple<GrSurfaceProxyView, GrColorType> onAsView(GrRecordingContext*,
188 GrMipmapped,
189 GrImageTexGenPolicy) const override;
190
191 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(GrRecordingContext*,
192 SkSamplingOptions,
193 const SkTileMode[2],
194 const SkMatrix&,
195 const SkRect*,
196 const SkRect*) const override;
197 #endif
198 #if defined(SK_GRAPHITE)
199 sk_sp<SkImage> onMakeTextureImage(skgpu::graphite::Recorder*,
200 RequiredImageProperties) const override;
201 sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType targetCT,
202 sk_sp<SkColorSpace> targetCS,
203 skgpu::graphite::Recorder*,
204 RequiredImageProperties) const override;
205 #endif
206
207 SkBitmap fBitmap;
208
209 #if defined(SK_GANESH)
210 mutable GrSurfaceProxyView fPinnedView;
211 mutable int32_t fPinnedCount = 0;
212 mutable uint32_t fPinnedUniqueID = SK_InvalidUniqueID;
213 mutable uint32_t fPinnedContextID = SK_InvalidUniqueID;
214 mutable GrColorType fPinnedColorType = GrColorType::kUnknown;
215 #endif
216
217 using INHERITED = SkImage_Base;
218 };
219
220 ///////////////////////////////////////////////////////////////////////////////
221
release_data(void * addr,void * context)222 static void release_data(void* addr, void* context) {
223 SkData* data = static_cast<SkData*>(context);
224 data->unref();
225 }
226
SkImage_Raster(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)227 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
228 uint32_t id)
229 : INHERITED(info, id) {
230 void* addr = const_cast<void*>(data->data());
231
232 fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
233 fBitmap.setImmutable();
234 }
235
~SkImage_Raster()236 SkImage_Raster::~SkImage_Raster() {
237 #if defined(SK_GANESH)
238 SkASSERT(!fPinnedView); // want the caller to have manually unpinned
239 #endif
240 }
241
onReadPixels(GrDirectContext *,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const242 bool SkImage_Raster::onReadPixels(GrDirectContext*,
243 const SkImageInfo& dstInfo,
244 void* dstPixels,
245 size_t dstRowBytes,
246 int srcX,
247 int srcY,
248 CachingHint) const {
249 SkBitmap shallowCopy(fBitmap);
250 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
251 }
252
onPeekPixels(SkPixmap * pm) const253 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
254 return fBitmap.peekPixels(pm);
255 }
256
getROPixels(GrDirectContext *,SkBitmap * dst,CachingHint) const257 bool SkImage_Raster::getROPixels(GrDirectContext*, SkBitmap* dst, CachingHint) const {
258 *dst = fBitmap;
259 return true;
260 }
261
262 #if defined(SK_GANESH)
onPinAsTexture(GrRecordingContext * rContext) const263 bool SkImage_Raster::onPinAsTexture(GrRecordingContext* rContext) const {
264 if (fPinnedView) {
265 SkASSERT(fPinnedCount > 0);
266 SkASSERT(fPinnedUniqueID != 0);
267 if (rContext->priv().contextID() != fPinnedContextID) {
268 return false;
269 }
270 } else {
271 SkASSERT(fPinnedCount == 0);
272 SkASSERT(fPinnedUniqueID == 0);
273 std::tie(fPinnedView, fPinnedColorType) =
274 GrMakeCachedBitmapProxyView(rContext,
275 fBitmap,
276 /*label=*/"SkImageRaster_PinAsTexture",
277 GrMipmapped::kNo);
278 if (!fPinnedView) {
279 fPinnedColorType = GrColorType::kUnknown;
280 return false;
281 }
282 fPinnedUniqueID = fBitmap.getGenerationID();
283 fPinnedContextID = rContext->priv().contextID();
284 }
285 // Note: we only increment if the texture was successfully pinned
286 ++fPinnedCount;
287 return true;
288 }
289
onUnpinAsTexture(GrRecordingContext * rContext) const290 void SkImage_Raster::onUnpinAsTexture(GrRecordingContext* rContext) const {
291 // Note: we always decrement, even if fPinnedTexture is null
292 SkASSERT(fPinnedCount > 0);
293 SkASSERT(fPinnedUniqueID != 0);
294 #if 0 // This would be better but Android currently calls with an already freed context ptr.
295 if (rContext->priv().contextID() != fPinnedContextID) {
296 return;
297 }
298 #endif
299
300 if (0 == --fPinnedCount) {
301 fPinnedView = GrSurfaceProxyView();
302 fPinnedUniqueID = SK_InvalidUniqueID;
303 fPinnedContextID = SK_InvalidUniqueID;
304 fPinnedColorType = GrColorType::kUnknown;
305 }
306 }
307
isPinnedOnContext(GrRecordingContext * rContext) const308 bool SkImage_Raster::isPinnedOnContext(GrRecordingContext* rContext) const {
309 return fPinnedContextID == rContext->priv().contextID();
310 }
311 #endif
312
copy_bitmap_subset(const SkBitmap & orig,const SkIRect & subset)313 static SkBitmap copy_bitmap_subset(const SkBitmap& orig, const SkIRect& subset) {
314 SkImageInfo info = orig.info().makeDimensions(subset.size());
315 SkBitmap bitmap;
316 if (!bitmap.tryAllocPixels(info)) {
317 return {};
318 }
319
320 void* dst = bitmap.getPixels();
321 void* src = orig.getAddr(subset.x(), subset.y());
322 if (!dst || !src) {
323 SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
324 return {};
325 }
326
327 SkRectMemcpy(dst, bitmap.rowBytes(), src, orig.rowBytes(), bitmap.rowBytes(),
328 subset.height());
329
330 bitmap.setImmutable();
331 return bitmap;
332 }
333
onMakeSubset(const SkIRect & subset,GrDirectContext *) const334 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
335 SkBitmap copy = copy_bitmap_subset(fBitmap, subset);
336 if (copy.isNull()) {
337 return nullptr;
338 } else {
339 return copy.asImage();
340 }
341 }
342
343 #if defined(SK_GRAPHITE)
copy_mipmaps(const SkBitmap & src,SkMipmap * srcMips)344 static sk_sp<SkMipmap> copy_mipmaps(const SkBitmap& src, SkMipmap* srcMips) {
345 if (!srcMips) {
346 return nullptr;
347 }
348
349 sk_sp<SkMipmap> dst;
350 dst.reset(SkMipmap::Build(src.pixmap(), nullptr, /* computeContents= */ false));
351 for (int i = 0; i < dst->countLevels(); ++i) {
352 SkMipmap::Level srcLevel, dstLevel;
353 srcMips->getLevel(i, &srcLevel);
354 dst->getLevel(i, &dstLevel);
355 srcLevel.fPixmap.readPixels(dstLevel.fPixmap);
356 }
357
358 return dst;
359 }
360
onMakeSubset(const SkIRect & subset,skgpu::graphite::Recorder * recorder,RequiredImageProperties requiredProperties) const361 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset,
362 skgpu::graphite::Recorder* recorder,
363 RequiredImageProperties requiredProperties) const {
364 sk_sp<SkImage> img;
365
366 if (requiredProperties.fMipmapped == skgpu::Mipmapped::kYes) {
367 bool fullCopy = subset == SkIRect::MakeSize(fBitmap.dimensions());
368
369 sk_sp<SkMipmap> mips = fullCopy ? copy_mipmaps(fBitmap, fBitmap.fMips.get()) : nullptr;
370
371 // SkImage::withMipmaps will always make a copy for us so we can temporarily share
372 // the pixel ref with fBitmap
373 SkBitmap tmpSubset;
374 if (!fBitmap.extractSubset(&tmpSubset, subset)) {
375 return nullptr;
376 }
377
378 sk_sp<SkImage> tmp(new SkImage_Raster(tmpSubset, /* bitmapMayBeMutable= */ true));
379
380 // withMipmaps will auto generate the mipmaps if a nullptr is passed in
381 SkASSERT(!mips || mips->validForRootLevel(tmp->imageInfo()));
382 img = tmp->withMipmaps(std::move(mips));
383 } else {
384 SkBitmap copy = copy_bitmap_subset(fBitmap, subset);
385 if (!copy.isNull()) {
386 img = copy.asImage();
387 }
388 }
389
390 if (!img) {
391 return nullptr;
392 }
393
394 if (recorder) {
395 return img->makeTextureImage(recorder, requiredProperties);
396 } else {
397 return img;
398 }
399 }
400 #endif // SK_GRAPHITE
401
402 ///////////////////////////////////////////////////////////////////////////////
403
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)404 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
405 size_t size;
406 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
407 return nullptr;
408 }
409
410 // Here we actually make a copy of the caller's pixel data
411 sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
412 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
413 }
414
MakeRasterCopy(const SkPixmap & pmap)415 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
416 return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
417 }
418
MakeRasterData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)419 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
420 size_t rowBytes) {
421 size_t size;
422 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
423 return nullptr;
424 }
425
426 // did they give us enough data?
427 if (data->size() < size) {
428 return nullptr;
429 }
430
431 return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
432 }
433
434 // TODO: this could be improved to decode and make use of the mipmap
435 // levels potentially present in the compressed data. For now, any
436 // mipmap levels are discarded.
MakeRasterFromCompressed(sk_sp<SkData> data,int width,int height,CompressionType type)437 sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
438 int width, int height,
439 CompressionType type) {
440 size_t expectedSize = SkCompressedFormatDataSize(type, { width, height }, false);
441 if (!data || data->size() < expectedSize) {
442 return nullptr;
443 }
444
445 SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
446 : kPremul_SkAlphaType;
447
448 SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
449
450 if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
451 return nullptr;
452 }
453
454 SkBitmap bitmap;
455 if (!bitmap.tryAllocPixels(ii)) {
456 return nullptr;
457 }
458
459 if (!SkDecompress(std::move(data), { width, height }, type, &bitmap)) {
460 return nullptr;
461 }
462
463 bitmap.setImmutable();
464 return MakeFromBitmap(bitmap);
465 }
466
MakeFromRaster(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)467 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
468 ReleaseContext ctx) {
469 size_t size;
470 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
471 return nullptr;
472 }
473
474 sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
475 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
476 }
477
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)478 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
479 uint32_t idForCopy) {
480 if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
481 SkPixmap pmap;
482 if (bm.peekPixels(&pmap)) {
483 return MakeRasterCopyPriv(pmap, idForCopy);
484 } else {
485 return sk_sp<SkImage>();
486 }
487 }
488
489 return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
490 }
491
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)492 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
493 if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
494 return nullptr;
495 }
496
497 return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
498 }
499
SkBitmapImageGetPixelRef(const SkImage * image)500 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
501 return ((const SkImage_Raster*)image)->getPixelRef();
502 }
503
onAsLegacyBitmap(GrDirectContext *,SkBitmap * bitmap) const504 bool SkImage_Raster::onAsLegacyBitmap(GrDirectContext*, SkBitmap* bitmap) const {
505 // When we're a snapshot from a surface, our bitmap may not be marked immutable
506 // even though logically always we are, but in that case we can't physically share our
507 // pixelref since the caller might call setImmutable() themselves
508 // (thus changing our state).
509 if (fBitmap.isImmutable()) {
510 SkIPoint origin = fBitmap.pixelRefOrigin();
511 bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
512 bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
513 return true;
514 }
515 return this->INHERITED::onAsLegacyBitmap(nullptr, bitmap);
516 }
517
518 ///////////////////////////////////////////////////////////////////////////////
519
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext *) const520 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(SkColorType targetCT,
521 sk_sp<SkColorSpace> targetCS,
522 GrDirectContext*) const {
523 SkPixmap src;
524 SkAssertResult(fBitmap.peekPixels(&src));
525
526 SkBitmap dst;
527 if (!dst.tryAllocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS))) {
528 return nullptr;
529 }
530
531 SkAssertResult(dst.writePixels(src));
532 dst.setImmutable();
533 return dst.asImage();
534 }
535
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const536 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
537 // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
538 // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
539 // gen ID from the bitmap, which gets it from the pixelRef.
540 SkPixmap pixmap = fBitmap.pixmap();
541 pixmap.setColorSpace(std::move(newCS));
542 return SkImage::MakeRasterCopy(pixmap);
543 }
544
545 #if defined(SK_GANESH)
onAsView(GrRecordingContext * rContext,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const546 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Raster::onAsView(
547 GrRecordingContext* rContext,
548 GrMipmapped mipmapped,
549 GrImageTexGenPolicy policy) const {
550 if (fPinnedView) {
551 // We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
552 // fallback to bilinear. The pin API is used by Android Framework which does not expose
553 // mipmapping . Moreover, we're moving towards requiring that images be made with mip levels
554 // if mipmapping is desired (skbug.com/10411)
555 mipmapped = GrMipmapped::kNo;
556 if (policy != GrImageTexGenPolicy::kDraw) {
557 return {CopyView(rContext,
558 fPinnedView,
559 mipmapped,
560 policy,
561 /*label=*/"TextureForImageRasterWithPolicyNotEqualKDraw"),
562 fPinnedColorType};
563 }
564 return {fPinnedView, fPinnedColorType};
565 }
566 if (policy == GrImageTexGenPolicy::kDraw) {
567 // If the draw doesn't require mipmaps but this SkImage has them go ahead and make a
568 // mipmapped texture. There are three reasons for this:
569 // 1) Avoiding another texture creation if a later draw requires mipmaps.
570 // 2) Ensuring we upload the bitmap's levels instead of generating on the GPU from the base.
571 if (this->hasMipmaps()) {
572 mipmapped = GrMipmapped::kYes;
573 }
574 return GrMakeCachedBitmapProxyView(rContext,
575 fBitmap,
576 /*label=*/"TextureForImageRasterWithPolicyEqualKDraw",
577 mipmapped);
578 }
579 auto budgeted = (policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted)
580 ? skgpu::Budgeted::kNo
581 : skgpu::Budgeted::kYes;
582 return GrMakeUncachedBitmapProxyView(rContext,
583 fBitmap,
584 mipmapped,
585 SkBackingFit::kExact,
586 budgeted);
587 }
588
onAsFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const589 std::unique_ptr<GrFragmentProcessor> SkImage_Raster::onAsFragmentProcessor(
590 GrRecordingContext* rContext,
591 SkSamplingOptions sampling,
592 const SkTileMode tileModes[2],
593 const SkMatrix& m,
594 const SkRect* subset,
595 const SkRect* domain) const {
596 auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
597 return MakeFragmentProcessorFromView(rContext,
598 std::get<0>(this->asView(rContext, mm)),
599 this->alphaType(),
600 sampling,
601 tileModes,
602 m,
603 subset,
604 domain);
605 }
606 #endif
607
608 #if defined(SK_GRAPHITE)
onMakeTextureImage(skgpu::graphite::Recorder * recorder,RequiredImageProperties requiredProps) const609 sk_sp<SkImage> SkImage_Raster::onMakeTextureImage(skgpu::graphite::Recorder* recorder,
610 RequiredImageProperties requiredProps) const {
611 return skgpu::graphite::MakeFromBitmap(recorder,
612 this->imageInfo().colorInfo(),
613 fBitmap,
614 this->refMips(),
615 skgpu::Budgeted::kNo,
616 requiredProps);
617 }
618
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,skgpu::graphite::Recorder * recorder,RequiredImageProperties requiredProps) const619 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(
620 SkColorType targetCT,
621 sk_sp<SkColorSpace> targetCS,
622 skgpu::graphite::Recorder* recorder,
623 RequiredImageProperties requiredProps) const {
624 SkPixmap src;
625 SkAssertResult(fBitmap.peekPixels(&src));
626
627 SkBitmap dst;
628 if (!dst.tryAllocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS))) {
629 return nullptr;
630 }
631
632 SkAssertResult(dst.writePixels(src));
633 dst.setImmutable();
634
635 sk_sp<SkImage> tmp = dst.asImage();
636 if (recorder) {
637 return tmp->makeTextureImage(recorder, requiredProps);
638 } else {
639 return tmp;
640 }
641 }
642
643 #endif
644