blob: 5d62c6bc62326cd56c532ad6836efa92eba18c68 [file] [log] [blame]
robertphillipsb6c65e92016-02-04 10:52:42 -08001/*
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 */
reedad7604b2016-07-20 16:13:32 -07007
robertphillips83c17fa2016-03-18 08:14:27 -07008#include "SkSpecialImage.h"
reedad7604b2016-07-20 16:13:32 -07009#include "SkBitmap.h"
10#include "SkImage.h"
robertphillips64612512016-04-08 12:10:42 -070011#include "SkBitmapCache.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080012#include "SkCanvas.h"
bsalomon84a4e5a2016-02-29 11:41:52 -080013#include "SkImage_Base.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080014#include "SkSpecialSurface.h"
brianosman898235c2016-04-06 07:38:23 -070015#include "SkSurfacePriv.h"
reedad7604b2016-07-20 16:13:32 -070016#include "SkPixelRef.h"
17
18#if SK_SUPPORT_GPU
19#include "GrContext.h"
20#include "GrTexture.h"
21#include "GrTextureParams.h"
22#include "SkGr.h"
reedad7604b2016-07-20 16:13:32 -070023#include "SkGrPriv.h"
24#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080025
reeda2217ef2016-07-20 06:04:34 -070026// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
27// a given info is supported.
28static bool valid_for_imagefilters(const SkImageInfo& info) {
29 // no support for other swizzles/depths yet
30 return info.colorType() == kN32_SkColorType;
31}
32
robertphillipsb6c65e92016-02-04 10:52:42 -080033///////////////////////////////////////////////////////////////////////////////
34class SkSpecialImage_Base : public SkSpecialImage {
35public:
robertphillips3e302272016-04-20 11:48:36 -070036 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
37 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080038 }
robertphillips3e302272016-04-20 11:48:36 -070039 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080040
robertphillipse8c34972016-02-16 12:09:36 -080041 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080042
robertphillips64612512016-04-08 12:10:42 -070043 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080044
45 virtual GrTexture* onPeekTexture() const { return nullptr; }
46
brianosmanafbf71d2016-07-21 07:15:37 -070047 virtual SkColorSpace* onGetColorSpace() const = 0;
48
robertphillipsc91fd342016-04-25 12:32:54 -070049#if SK_SUPPORT_GPU
50 virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
51#endif
robertphillips4418dba2016-03-07 12:45:14 -080052
robertphillipsb4bd11e2016-03-21 13:44:18 -070053 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
54
brianosmaneed6b0e2016-09-23 13:04:05 -070055 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
56 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070057
robertphillipsb4bd11e2016-03-21 13:44:18 -070058 virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
59
brianosmaneed6b0e2016-09-23 13:04:05 -070060 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
61 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080062
63private:
64 typedef SkSpecialImage INHERITED;
65};
66
67///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080068static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080069 return static_cast<const SkSpecialImage_Base*>(image);
70}
71
robertphillips3e302272016-04-20 11:48:36 -070072SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070073 uint32_t uniqueID,
74 const SkSurfaceProps* props)
75 : fProps(SkSurfacePropsCopyOrDefault(props))
76 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070077 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070078}
79
robertphillips3e302272016-04-20 11:48:36 -070080sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070081#if SK_SUPPORT_GPU
82 if (!context) {
83 return nullptr;
84 }
robertphillips64612512016-04-08 12:10:42 -070085 if (GrTexture* peek = as_SIB(this)->onPeekTexture()) {
robertphillips83c17fa2016-03-18 08:14:27 -070086 return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
87 }
88
89 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070090 // At this point, we are definitely not texture-backed, so we must be raster or generator
91 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
92 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
93 // in which case getROPixels could turn into peekPixels...
94 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -070095 return nullptr;
96 }
97
robertphillips83f2e5a2016-03-24 06:31:25 -070098 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -070099 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -0700100 }
101
robertphillipsc91fd342016-04-25 12:32:54 -0700102 sk_sp<GrTexture> resultTex(GrRefCachedBitmapTexture(context,
103 bmp,
brianosman982eb7f2016-06-06 13:10:58 -0700104 GrTextureParams::ClampNoFilter(),
105 SkSourceGammaTreatment::kRespect));
robertphillips83c17fa2016-03-18 08:14:27 -0700106 if (!resultTex) {
107 return nullptr;
108 }
109
robertphillips3e302272016-04-20 11:48:36 -0700110 return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()),
robertphillips83c17fa2016-03-18 08:14:27 -0700111 this->uniqueID(),
brianosmanafbf71d2016-07-21 07:15:37 -0700112 resultTex, sk_ref_sp(this->getColorSpace()), &this->props(),
brianosman80e96082016-08-16 07:09:47 -0700113 this->alphaType());
robertphillips83c17fa2016-03-18 08:14:27 -0700114#else
115 return nullptr;
116#endif
117}
118
robertphillipse8c34972016-02-16 12:09:36 -0800119void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800120 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800121}
122
robertphillips64612512016-04-08 12:10:42 -0700123bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
124 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800125}
126
robertphillips64612512016-04-08 12:10:42 -0700127bool SkSpecialImage::isTextureBacked() const {
128#if SK_SUPPORT_GPU
129 return as_SIB(this)->onPeekTexture() && as_SIB(this)->onPeekTexture()->getContext();
130#else
131 return false;
132#endif
robertphillipsb6c65e92016-02-04 10:52:42 -0800133}
134
robertphillips64612512016-04-08 12:10:42 -0700135GrContext* SkSpecialImage::getContext() const {
136#if SK_SUPPORT_GPU
137 GrTexture* texture = as_SIB(this)->onPeekTexture();
138
139 if (texture) {
140 return texture->getContext();
141 }
142#endif
143 return nullptr;
144}
145
brianosmanafbf71d2016-07-21 07:15:37 -0700146SkColorSpace* SkSpecialImage::getColorSpace() const {
147 return as_SIB(this)->onGetColorSpace();
148}
149
robertphillipsc91fd342016-04-25 12:32:54 -0700150#if SK_SUPPORT_GPU
151sk_sp<GrTexture> SkSpecialImage::asTextureRef(GrContext* context) const {
robertphillips64612512016-04-08 12:10:42 -0700152 return as_SIB(this)->onAsTextureRef(context);
robertphillips4418dba2016-03-07 12:45:14 -0800153}
robertphillipsc91fd342016-04-25 12:32:54 -0700154#endif
robertphillips4418dba2016-03-07 12:45:14 -0800155
brianosmaneed6b0e2016-09-23 13:04:05 -0700156sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
157 const SkISize& size, SkAlphaType at) const {
158 return as_SIB(this)->onMakeSurface(outProps, size, at);
robertphillipsb6c65e92016-02-04 10:52:42 -0800159}
160
brianosmaneed6b0e2016-09-23 13:04:05 -0700161sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
162 const SkISize& size, SkAlphaType at) const {
163 return as_SIB(this)->onMakeTightSurface(outProps, size, at);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700164}
165
robertphillips37bd7c32016-03-17 14:31:39 -0700166sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
167 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700168}
169
robertphillipsb4bd11e2016-03-21 13:44:18 -0700170sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
171 return as_SIB(this)->onMakeTightSubset(subset);
172}
173
robertphillipsb6c65e92016-02-04 10:52:42 -0800174#ifdef SK_DEBUG
175static bool rect_fits(const SkIRect& rect, int width, int height) {
robertphillips4418dba2016-03-07 12:45:14 -0800176 if (0 == width && 0 == height) {
177 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
178 return true;
179 }
180
robertphillipsb6c65e92016-02-04 10:52:42 -0800181 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
182 rect.fRight >= 0 && rect.fRight <= width &&
183 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
184 rect.fBottom >= 0 && rect.fBottom <= height;
185}
186#endif
187
robertphillips3e302272016-04-20 11:48:36 -0700188sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700189 sk_sp<SkImage> image,
190 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800191 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700192
reedad7604b2016-07-20 16:13:32 -0700193#if SK_SUPPORT_GPU
194 if (GrTexture* texture = as_IB(image)->peekTexture()) {
brianosmanafbf71d2016-07-21 07:15:37 -0700195 return MakeFromGpu(subset, image->uniqueID(), sk_ref_sp(texture),
196 sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props);
reedad7604b2016-07-20 16:13:32 -0700197 } else
198#endif
199 {
200 SkBitmap bm;
201 if (as_IB(image)->getROPixels(&bm)) {
202 return MakeFromRaster(subset, bm, props);
203 }
reeda2217ef2016-07-20 06:04:34 -0700204 }
reedad7604b2016-07-20 16:13:32 -0700205 return nullptr;
robertphillipsb6c65e92016-02-04 10:52:42 -0800206}
207
208///////////////////////////////////////////////////////////////////////////////
robertphillipsb6c65e92016-02-04 10:52:42 -0800209
210class SkSpecialImage_Raster : public SkSpecialImage_Base {
211public:
robertphillips3e302272016-04-20 11:48:36 -0700212 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
213 : INHERITED(subset, bm.getGenerationID(), props)
reedbd2bd5c2016-07-25 14:26:02 -0700214 , fBitmap(bm)
215 {
216 SkASSERT(bm.pixelRef());
217
218 // We have to lock now, while bm is still in scope, since it may have come from our
219 // cache, which means we need to keep it locked until we (the special) are done, since
220 // we cannot re-generate the cache entry (if bm came from a generator).
221 fBitmap.lockPixels();
222 SkASSERT(fBitmap.getPixels());
robertphillipsb6c65e92016-02-04 10:52:42 -0800223 }
224
brianosman80e96082016-08-16 07:09:47 -0700225 SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
robertphillips3b087f42016-02-18 08:48:03 -0800226
227 size_t getSize() const override { return fBitmap.getSize(); }
228
robertphillipse8c34972016-02-16 12:09:36 -0800229 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800230 SkRect dst = SkRect::MakeXYWH(x, y,
231 this->subset().width(), this->subset().height());
232
233 canvas->drawBitmapRect(fBitmap, this->subset(),
234 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
235 }
236
robertphillips64612512016-04-08 12:10:42 -0700237 bool onGetROPixels(SkBitmap* bm) const override {
238 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800239 return true;
240 }
241
brianosmanafbf71d2016-07-21 07:15:37 -0700242 SkColorSpace* onGetColorSpace() const override {
243 return fBitmap.colorSpace();
244 }
245
robertphillips64612512016-04-08 12:10:42 -0700246#if SK_SUPPORT_GPU
robertphillipsc91fd342016-04-25 12:32:54 -0700247 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
robertphillips64612512016-04-08 12:10:42 -0700248 if (context) {
robertphillipsc91fd342016-04-25 12:32:54 -0700249 return sk_ref_sp(GrRefCachedBitmapTexture(context,
250 fBitmap,
brianosman982eb7f2016-06-06 13:10:58 -0700251 GrTextureParams::ClampNoFilter(),
252 SkSourceGammaTreatment::kRespect));
robertphillips64612512016-04-08 12:10:42 -0700253 }
robertphillips64612512016-04-08 12:10:42 -0700254
255 return nullptr;
256 }
robertphillipsc91fd342016-04-25 12:32:54 -0700257#endif
robertphillips64612512016-04-08 12:10:42 -0700258
brianosmaneed6b0e2016-09-23 13:04:05 -0700259// TODO: The raster implementations of image filters all currently assume that the pixels are
260// legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
261// we can't enable this. (They will continue to produce incorrect results, but less-so).
262#define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
263
264 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
265 const SkISize& size, SkAlphaType at) const override {
266#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
267 SkColorSpace* colorSpace = outProps.colorSpace();
268#else
269 SkColorSpace* colorSpace = nullptr;
270#endif
271 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
272 ? kRGBA_F16_SkColorType : kN32_SkColorType;
273 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
274 sk_ref_sp(colorSpace));
robertphillips3e302272016-04-20 11:48:36 -0700275 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800276 }
277
robertphillips37bd7c32016-03-17 14:31:39 -0700278 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700279 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700280
robertphillipsc5035e72016-03-17 06:58:39 -0700281 if (!fBitmap.extractSubset(&subsetBM, subset)) {
282 return nullptr;
283 }
284
robertphillips3e302272016-04-20 11:48:36 -0700285 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700286 subsetBM,
287 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700288 }
289
robertphillipsb4bd11e2016-03-21 13:44:18 -0700290 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
291 SkBitmap subsetBM;
292
293 if (!fBitmap.extractSubset(&subsetBM, subset)) {
294 return nullptr;
295 }
296
297 return SkImage::MakeFromBitmap(subsetBM);
298 }
299
brianosmaneed6b0e2016-09-23 13:04:05 -0700300 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
301 const SkISize& size, SkAlphaType at) const override {
302#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
303 SkColorSpace* colorSpace = outProps.colorSpace();
304#else
305 SkColorSpace* colorSpace = nullptr;
306#endif
307 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
308 ? kRGBA_F16_SkColorType : kN32_SkColorType;
309 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
310 sk_ref_sp(colorSpace));
reede8f30622016-03-23 18:59:25 -0700311 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700312 }
313
robertphillipsb6c65e92016-02-04 10:52:42 -0800314private:
315 SkBitmap fBitmap;
316
317 typedef SkSpecialImage_Base INHERITED;
318};
319
robertphillips3e302272016-04-20 11:48:36 -0700320sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700321 const SkBitmap& bm,
322 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800323 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700324
reedbd2bd5c2016-07-25 14:26:02 -0700325 if (!bm.pixelRef()) {
326 return nullptr;
327 }
328
reeda2217ef2016-07-20 06:04:34 -0700329 const SkBitmap* srcBM = &bm;
330 SkBitmap tmpStorage;
331 // ImageFilters only handle N32 at the moment, so force our src to be that
332 if (!valid_for_imagefilters(bm.info())) {
333 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
334 return nullptr;
335 }
336 srcBM = &tmpStorage;
337 }
338 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800339}
340
341#if SK_SUPPORT_GPU
342///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700343#include "GrTexture.h"
robertphillipsb4bd11e2016-03-21 13:44:18 -0700344#include "SkImage_Gpu.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800345
robertphillipsed086ca2016-04-26 15:02:25 -0700346class SkSpecialImage_Gpu : public SkSpecialImage_Base {
347public:
348 SkSpecialImage_Gpu(const SkIRect& subset,
349 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
brianosmanafbf71d2016-07-21 07:15:37 -0700350 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
robertphillipsed086ca2016-04-26 15:02:25 -0700351 : INHERITED(subset, uniqueID, props)
352 , fTexture(std::move(tex))
353 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700354 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700355 , fAddedRasterVersionToCache(false) {
356 }
357
358 ~SkSpecialImage_Gpu() override {
359 if (fAddedRasterVersionToCache.load()) {
360 SkNotifyBitmapGenIDIsStale(this->uniqueID());
361 }
362 }
363
brianosman80e96082016-08-16 07:09:47 -0700364 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700365
366 size_t getSize() const override { return fTexture->gpuMemorySize(); }
367
368 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
369 SkRect dst = SkRect::MakeXYWH(x, y,
370 this->subset().width(), this->subset().height());
371
reed77d6f7d2016-07-13 12:24:48 -0700372 auto img = sk_sp<SkImage>(new SkImage_Gpu(fTexture->width(), fTexture->height(),
373 this->uniqueID(), fAlphaType, fTexture.get(),
brianosmanafbf71d2016-07-21 07:15:37 -0700374 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700375
reed77d6f7d2016-07-13 12:24:48 -0700376 canvas->drawImageRect(img, this->subset(),
robertphillipsed086ca2016-04-26 15:02:25 -0700377 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
378 }
379
380 GrTexture* onPeekTexture() const override { return fTexture.get(); }
381
382 sk_sp<GrTexture> onAsTextureRef(GrContext*) const override { return fTexture; }
383
384 bool onGetROPixels(SkBitmap* dst) const override {
385 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
386 SkASSERT(dst->getGenerationID() == this->uniqueID());
387 SkASSERT(dst->isImmutable());
388 SkASSERT(dst->getPixels());
389 return true;
390 }
391
392 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700393 this->alphaType(), fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700394
395 if (!dst->tryAllocPixels(info)) {
396 return false;
397 }
398
399 if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
400 dst->getPixels(), dst->rowBytes())) {
401 return false;
402 }
403
404 dst->pixelRef()->setImmutableWithID(this->uniqueID());
405 SkBitmapCache::Add(this->uniqueID(), *dst);
406 fAddedRasterVersionToCache.store(true);
407 return true;
408 }
409
brianosmanafbf71d2016-07-21 07:15:37 -0700410 SkColorSpace* onGetColorSpace() const override {
411 return fColorSpace.get();
412 }
413
brianosmaneed6b0e2016-09-23 13:04:05 -0700414 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
415 const SkISize& size, SkAlphaType at) const override {
robertphillipsed086ca2016-04-26 15:02:25 -0700416 if (!fTexture->getContext()) {
417 return nullptr;
418 }
419
brianosmaneed6b0e2016-09-23 13:04:05 -0700420 SkColorSpace* colorSpace = outProps.colorSpace();
421 return SkSpecialSurface::MakeRenderTarget(
422 fTexture->getContext(), size.width(), size.height(),
423 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700424 }
425
426 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
427 return SkSpecialImage::MakeFromGpu(subset,
428 this->uniqueID(),
429 fTexture,
brianosmanafbf71d2016-07-21 07:15:37 -0700430 fColorSpace,
robertphillipsed086ca2016-04-26 15:02:25 -0700431 &this->props(),
432 fAlphaType);
433 }
434
435 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
436 if (0 == subset.fLeft && 0 == subset.fTop &&
437 fTexture->width() == subset.width() &&
438 fTexture->height() == subset.height()) {
439 // The existing GrTexture is already tight so reuse it in the SkImage
440 return sk_make_sp<SkImage_Gpu>(fTexture->width(), fTexture->height(),
441 kNeedNewImageUniqueID,
brianosmanafbf71d2016-07-21 07:15:37 -0700442 fAlphaType, fTexture.get(), fColorSpace,
443 SkBudgeted::kYes);
robertphillipsed086ca2016-04-26 15:02:25 -0700444 }
445
446 GrContext* ctx = fTexture->getContext();
447 GrSurfaceDesc desc = fTexture->desc();
448 desc.fWidth = subset.width();
449 desc.fHeight = subset.height();
450
451 sk_sp<GrTexture> subTx(ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes));
452 if (!subTx) {
453 return nullptr;
454 }
455 ctx->copySurface(subTx.get(), fTexture.get(), subset, SkIPoint::Make(0, 0));
456 return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
brianosmanafbf71d2016-07-21 07:15:37 -0700457 fAlphaType, subTx.get(), fColorSpace, SkBudgeted::kYes);
robertphillipsed086ca2016-04-26 15:02:25 -0700458 }
459
brianosmaneed6b0e2016-09-23 13:04:05 -0700460 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
461 const SkISize& size, SkAlphaType at) const override {
462 SkColorSpace* colorSpace = outProps.colorSpace();
463 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
464 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
465 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
466 sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700467 return SkSurface::MakeRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info);
468 }
469
470private:
471 sk_sp<GrTexture> fTexture;
472 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700473 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700474 mutable SkAtomic<bool> fAddedRasterVersionToCache;
475
476 typedef SkSpecialImage_Base INHERITED;
477};
478
robertphillips3e302272016-04-20 11:48:36 -0700479sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700480 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700481 sk_sp<GrTexture> tex,
brianosmanafbf71d2016-07-21 07:15:37 -0700482 sk_sp<SkColorSpace> colorSpace,
brianosman898235c2016-04-06 07:38:23 -0700483 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700484 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800485 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
brianosmanafbf71d2016-07-21 07:15:37 -0700486 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
487 std::move(colorSpace), props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800488}
489
490#endif