blob: e750571ff316e53b84b2aee273a0731adc3a389e [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"
Robert Phillips8bc06d02016-11-01 17:28:40 -040022#include "GrTextureProxy.h"
reedad7604b2016-07-20 16:13:32 -070023#include "SkGr.h"
reedad7604b2016-07-20 16:13:32 -070024#include "SkGrPriv.h"
25#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080026
reeda2217ef2016-07-20 06:04:34 -070027// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
28// a given info is supported.
29static bool valid_for_imagefilters(const SkImageInfo& info) {
30 // no support for other swizzles/depths yet
31 return info.colorType() == kN32_SkColorType;
32}
33
robertphillipsb6c65e92016-02-04 10:52:42 -080034///////////////////////////////////////////////////////////////////////////////
35class SkSpecialImage_Base : public SkSpecialImage {
36public:
robertphillips3e302272016-04-20 11:48:36 -070037 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
38 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080039 }
robertphillips3e302272016-04-20 11:48:36 -070040 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080041
robertphillipse8c34972016-02-16 12:09:36 -080042 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080043
robertphillips64612512016-04-08 12:10:42 -070044 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080045
Robert Phillips8bc06d02016-11-01 17:28:40 -040046 virtual GrContext* onGetContext() const { return nullptr; }
robertphillipsb6c65e92016-02-04 10:52:42 -080047
brianosmanafbf71d2016-07-21 07:15:37 -070048 virtual SkColorSpace* onGetColorSpace() const = 0;
49
robertphillipsc91fd342016-04-25 12:32:54 -070050#if SK_SUPPORT_GPU
51 virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
Robert Phillips8bc06d02016-11-01 17:28:40 -040052 virtual sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const = 0;
robertphillipsc91fd342016-04-25 12:32:54 -070053#endif
robertphillips4418dba2016-03-07 12:45:14 -080054
robertphillipsb4bd11e2016-03-21 13:44:18 -070055 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
56
brianosmaneed6b0e2016-09-23 13:04:05 -070057 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
58 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070059
robertphillipsb4bd11e2016-03-21 13:44:18 -070060 virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
61
brianosmaneed6b0e2016-09-23 13:04:05 -070062 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
63 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080064
65private:
66 typedef SkSpecialImage INHERITED;
67};
68
69///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080070static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080071 return static_cast<const SkSpecialImage_Base*>(image);
72}
73
robertphillips3e302272016-04-20 11:48:36 -070074SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070075 uint32_t uniqueID,
76 const SkSurfaceProps* props)
77 : fProps(SkSurfacePropsCopyOrDefault(props))
78 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070079 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070080}
81
robertphillips3e302272016-04-20 11:48:36 -070082sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070083#if SK_SUPPORT_GPU
84 if (!context) {
85 return nullptr;
86 }
Robert Phillips8bc06d02016-11-01 17:28:40 -040087 if (GrContext* curContext = as_SIB(this)->onGetContext()) {
88 return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
robertphillips83c17fa2016-03-18 08:14:27 -070089 }
90
91 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070092 // At this point, we are definitely not texture-backed, so we must be raster or generator
93 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
94 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
95 // in which case getROPixels could turn into peekPixels...
96 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -070097 return nullptr;
98 }
99
robertphillips83f2e5a2016-03-24 06:31:25 -0700100 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -0700101 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -0700102 }
103
robertphillipsc91fd342016-04-25 12:32:54 -0700104 sk_sp<GrTexture> resultTex(GrRefCachedBitmapTexture(context,
105 bmp,
brianosman982eb7f2016-06-06 13:10:58 -0700106 GrTextureParams::ClampNoFilter(),
107 SkSourceGammaTreatment::kRespect));
robertphillips83c17fa2016-03-18 08:14:27 -0700108 if (!resultTex) {
109 return nullptr;
110 }
111
robertphillips3e302272016-04-20 11:48:36 -0700112 return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()),
robertphillips83c17fa2016-03-18 08:14:27 -0700113 this->uniqueID(),
brianosmanafbf71d2016-07-21 07:15:37 -0700114 resultTex, sk_ref_sp(this->getColorSpace()), &this->props(),
brianosman80e96082016-08-16 07:09:47 -0700115 this->alphaType());
robertphillips83c17fa2016-03-18 08:14:27 -0700116#else
117 return nullptr;
118#endif
119}
120
robertphillipse8c34972016-02-16 12:09:36 -0800121void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800122 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800123}
124
robertphillips64612512016-04-08 12:10:42 -0700125bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
126 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800127}
128
robertphillips64612512016-04-08 12:10:42 -0700129bool SkSpecialImage::isTextureBacked() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400130 return SkToBool(as_SIB(this)->onGetContext());
robertphillipsb6c65e92016-02-04 10:52:42 -0800131}
132
robertphillips64612512016-04-08 12:10:42 -0700133GrContext* SkSpecialImage::getContext() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400134 return as_SIB(this)->onGetContext();
robertphillips64612512016-04-08 12:10:42 -0700135}
136
brianosmanafbf71d2016-07-21 07:15:37 -0700137SkColorSpace* SkSpecialImage::getColorSpace() const {
138 return as_SIB(this)->onGetColorSpace();
139}
140
robertphillipsc91fd342016-04-25 12:32:54 -0700141#if SK_SUPPORT_GPU
142sk_sp<GrTexture> SkSpecialImage::asTextureRef(GrContext* context) const {
robertphillips64612512016-04-08 12:10:42 -0700143 return as_SIB(this)->onAsTextureRef(context);
robertphillips4418dba2016-03-07 12:45:14 -0800144}
Robert Phillips8bc06d02016-11-01 17:28:40 -0400145
146sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxy(GrContext* context) const {
147 return as_SIB(this)->onAsTextureProxy(context);
148}
robertphillipsc91fd342016-04-25 12:32:54 -0700149#endif
robertphillips4418dba2016-03-07 12:45:14 -0800150
brianosmaneed6b0e2016-09-23 13:04:05 -0700151sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
152 const SkISize& size, SkAlphaType at) const {
153 return as_SIB(this)->onMakeSurface(outProps, size, at);
robertphillipsb6c65e92016-02-04 10:52:42 -0800154}
155
brianosmaneed6b0e2016-09-23 13:04:05 -0700156sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
157 const SkISize& size, SkAlphaType at) const {
158 return as_SIB(this)->onMakeTightSurface(outProps, size, at);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700159}
160
robertphillips37bd7c32016-03-17 14:31:39 -0700161sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
162 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700163}
164
robertphillipsb4bd11e2016-03-21 13:44:18 -0700165sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
166 return as_SIB(this)->onMakeTightSubset(subset);
167}
168
robertphillipsb6c65e92016-02-04 10:52:42 -0800169#ifdef SK_DEBUG
170static bool rect_fits(const SkIRect& rect, int width, int height) {
robertphillips4418dba2016-03-07 12:45:14 -0800171 if (0 == width && 0 == height) {
172 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
173 return true;
174 }
175
robertphillipsb6c65e92016-02-04 10:52:42 -0800176 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
177 rect.fRight >= 0 && rect.fRight <= width &&
178 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
179 rect.fBottom >= 0 && rect.fBottom <= height;
180}
181#endif
182
robertphillips3e302272016-04-20 11:48:36 -0700183sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700184 sk_sp<SkImage> image,
185 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800186 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700187
reedad7604b2016-07-20 16:13:32 -0700188#if SK_SUPPORT_GPU
189 if (GrTexture* texture = as_IB(image)->peekTexture()) {
brianosmanafbf71d2016-07-21 07:15:37 -0700190 return MakeFromGpu(subset, image->uniqueID(), sk_ref_sp(texture),
191 sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props);
reedad7604b2016-07-20 16:13:32 -0700192 } else
193#endif
194 {
195 SkBitmap bm;
196 if (as_IB(image)->getROPixels(&bm)) {
197 return MakeFromRaster(subset, bm, props);
198 }
reeda2217ef2016-07-20 06:04:34 -0700199 }
reedad7604b2016-07-20 16:13:32 -0700200 return nullptr;
robertphillipsb6c65e92016-02-04 10:52:42 -0800201}
202
203///////////////////////////////////////////////////////////////////////////////
robertphillipsb6c65e92016-02-04 10:52:42 -0800204
205class SkSpecialImage_Raster : public SkSpecialImage_Base {
206public:
robertphillips3e302272016-04-20 11:48:36 -0700207 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
208 : INHERITED(subset, bm.getGenerationID(), props)
reedbd2bd5c2016-07-25 14:26:02 -0700209 , fBitmap(bm)
210 {
211 SkASSERT(bm.pixelRef());
212
213 // We have to lock now, while bm is still in scope, since it may have come from our
214 // cache, which means we need to keep it locked until we (the special) are done, since
215 // we cannot re-generate the cache entry (if bm came from a generator).
216 fBitmap.lockPixels();
217 SkASSERT(fBitmap.getPixels());
robertphillipsb6c65e92016-02-04 10:52:42 -0800218 }
219
brianosman80e96082016-08-16 07:09:47 -0700220 SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
robertphillips3b087f42016-02-18 08:48:03 -0800221
222 size_t getSize() const override { return fBitmap.getSize(); }
223
robertphillipse8c34972016-02-16 12:09:36 -0800224 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800225 SkRect dst = SkRect::MakeXYWH(x, y,
226 this->subset().width(), this->subset().height());
227
228 canvas->drawBitmapRect(fBitmap, this->subset(),
229 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
230 }
231
robertphillips64612512016-04-08 12:10:42 -0700232 bool onGetROPixels(SkBitmap* bm) const override {
233 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800234 return true;
235 }
236
brianosmanafbf71d2016-07-21 07:15:37 -0700237 SkColorSpace* onGetColorSpace() const override {
238 return fBitmap.colorSpace();
239 }
240
robertphillips64612512016-04-08 12:10:42 -0700241#if SK_SUPPORT_GPU
robertphillipsc91fd342016-04-25 12:32:54 -0700242 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
robertphillips64612512016-04-08 12:10:42 -0700243 if (context) {
robertphillipsc91fd342016-04-25 12:32:54 -0700244 return sk_ref_sp(GrRefCachedBitmapTexture(context,
245 fBitmap,
brianosman982eb7f2016-06-06 13:10:58 -0700246 GrTextureParams::ClampNoFilter(),
247 SkSourceGammaTreatment::kRespect));
robertphillips64612512016-04-08 12:10:42 -0700248 }
robertphillips64612512016-04-08 12:10:42 -0700249
250 return nullptr;
251 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400252
253 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const override {
254 if (context) {
255 sk_sp<GrTexture> tex(sk_ref_sp(GrRefCachedBitmapTexture(
256 context,
257 fBitmap,
258 GrTextureParams::ClampNoFilter(),
259 SkSourceGammaTreatment::kRespect)));
260 return GrTextureProxy::Make(tex);
261 }
262
263 return nullptr;
264 }
robertphillipsc91fd342016-04-25 12:32:54 -0700265#endif
robertphillips64612512016-04-08 12:10:42 -0700266
brianosmaneed6b0e2016-09-23 13:04:05 -0700267// TODO: The raster implementations of image filters all currently assume that the pixels are
268// legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
269// we can't enable this. (They will continue to produce incorrect results, but less-so).
270#define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
271
272 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
273 const SkISize& size, SkAlphaType at) const override {
274#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
275 SkColorSpace* colorSpace = outProps.colorSpace();
276#else
277 SkColorSpace* colorSpace = nullptr;
278#endif
279 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
280 ? kRGBA_F16_SkColorType : kN32_SkColorType;
281 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
282 sk_ref_sp(colorSpace));
robertphillips3e302272016-04-20 11:48:36 -0700283 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800284 }
285
robertphillips37bd7c32016-03-17 14:31:39 -0700286 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700287 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700288
robertphillipsc5035e72016-03-17 06:58:39 -0700289 if (!fBitmap.extractSubset(&subsetBM, subset)) {
290 return nullptr;
291 }
292
robertphillips3e302272016-04-20 11:48:36 -0700293 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700294 subsetBM,
295 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700296 }
297
robertphillipsb4bd11e2016-03-21 13:44:18 -0700298 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
299 SkBitmap subsetBM;
300
301 if (!fBitmap.extractSubset(&subsetBM, subset)) {
302 return nullptr;
303 }
304
305 return SkImage::MakeFromBitmap(subsetBM);
306 }
307
brianosmaneed6b0e2016-09-23 13:04:05 -0700308 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
309 const SkISize& size, SkAlphaType at) const override {
310#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
311 SkColorSpace* colorSpace = outProps.colorSpace();
312#else
313 SkColorSpace* colorSpace = nullptr;
314#endif
315 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
316 ? kRGBA_F16_SkColorType : kN32_SkColorType;
317 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
318 sk_ref_sp(colorSpace));
reede8f30622016-03-23 18:59:25 -0700319 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700320 }
321
robertphillipsb6c65e92016-02-04 10:52:42 -0800322private:
323 SkBitmap fBitmap;
324
325 typedef SkSpecialImage_Base INHERITED;
326};
327
robertphillips3e302272016-04-20 11:48:36 -0700328sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700329 const SkBitmap& bm,
330 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800331 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700332
reedbd2bd5c2016-07-25 14:26:02 -0700333 if (!bm.pixelRef()) {
334 return nullptr;
335 }
336
reeda2217ef2016-07-20 06:04:34 -0700337 const SkBitmap* srcBM = &bm;
338 SkBitmap tmpStorage;
339 // ImageFilters only handle N32 at the moment, so force our src to be that
340 if (!valid_for_imagefilters(bm.info())) {
341 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
342 return nullptr;
343 }
344 srcBM = &tmpStorage;
345 }
346 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800347}
348
349#if SK_SUPPORT_GPU
350///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700351#include "GrTexture.h"
robertphillipsb4bd11e2016-03-21 13:44:18 -0700352#include "SkImage_Gpu.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800353
robertphillipsed086ca2016-04-26 15:02:25 -0700354class SkSpecialImage_Gpu : public SkSpecialImage_Base {
355public:
356 SkSpecialImage_Gpu(const SkIRect& subset,
357 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
brianosmanafbf71d2016-07-21 07:15:37 -0700358 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
robertphillipsed086ca2016-04-26 15:02:25 -0700359 : INHERITED(subset, uniqueID, props)
Robert Phillips8bc06d02016-11-01 17:28:40 -0400360 , fContext(tex->getContext())
361 , fAlphaType(at)
362 , fColorSpace(std::move(colorSpace))
363 , fAddedRasterVersionToCache(false) {
364 fTextureProxy = GrTextureProxy::Make(std::move(tex));
365 }
366
367 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
368 uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
369 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
370 : INHERITED(subset, uniqueID, props)
371 , fContext(context)
372 , fTextureProxy(std::move(proxy))
robertphillipsed086ca2016-04-26 15:02:25 -0700373 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700374 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700375 , fAddedRasterVersionToCache(false) {
376 }
377
378 ~SkSpecialImage_Gpu() override {
379 if (fAddedRasterVersionToCache.load()) {
380 SkNotifyBitmapGenIDIsStale(this->uniqueID());
381 }
382 }
383
brianosman80e96082016-08-16 07:09:47 -0700384 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700385
Robert Phillips8bc06d02016-11-01 17:28:40 -0400386 size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
robertphillipsed086ca2016-04-26 15:02:25 -0700387
388 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
389 SkRect dst = SkRect::MakeXYWH(x, y,
390 this->subset().width(), this->subset().height());
391
Robert Phillips8bc06d02016-11-01 17:28:40 -0400392 // TODO: add GrTextureProxy-backed SkImage_Gpus
393 sk_sp<GrTexture> tex = sk_ref_sp(fTextureProxy->instantiate(fContext->textureProvider()));
394
395 auto img = sk_sp<SkImage>(new SkImage_Gpu(fTextureProxy->width(), fTextureProxy->height(),
396 this->uniqueID(), fAlphaType, std::move(tex),
brianosmanafbf71d2016-07-21 07:15:37 -0700397 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700398
reed77d6f7d2016-07-13 12:24:48 -0700399 canvas->drawImageRect(img, this->subset(),
robertphillipsed086ca2016-04-26 15:02:25 -0700400 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
401 }
402
Robert Phillips8bc06d02016-11-01 17:28:40 -0400403 GrContext* onGetContext() const override { return fContext; }
robertphillipsed086ca2016-04-26 15:02:25 -0700404
Robert Phillips8bc06d02016-11-01 17:28:40 -0400405 // This entry point should go away in favor of asTextureProxy
406 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
407 return sk_ref_sp(fTextureProxy->instantiate(context->textureProvider()));
408 }
409
410 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext*) const override {
411 return fTextureProxy;
412 }
robertphillipsed086ca2016-04-26 15:02:25 -0700413
414 bool onGetROPixels(SkBitmap* dst) const override {
415 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
416 SkASSERT(dst->getGenerationID() == this->uniqueID());
417 SkASSERT(dst->isImmutable());
418 SkASSERT(dst->getPixels());
419 return true;
420 }
421
422 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700423 this->alphaType(), fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700424
425 if (!dst->tryAllocPixels(info)) {
426 return false;
427 }
428
Robert Phillips8bc06d02016-11-01 17:28:40 -0400429 // Reading back to an SkBitmap ends deferral
430 GrTexture* texture = fTextureProxy->instantiate(fContext->textureProvider());
431
432 if (!texture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
433 dst->getPixels(), dst->rowBytes())) {
robertphillipsed086ca2016-04-26 15:02:25 -0700434 return false;
435 }
436
437 dst->pixelRef()->setImmutableWithID(this->uniqueID());
438 SkBitmapCache::Add(this->uniqueID(), *dst);
439 fAddedRasterVersionToCache.store(true);
440 return true;
441 }
442
brianosmanafbf71d2016-07-21 07:15:37 -0700443 SkColorSpace* onGetColorSpace() const override {
444 return fColorSpace.get();
445 }
446
brianosmaneed6b0e2016-09-23 13:04:05 -0700447 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
448 const SkISize& size, SkAlphaType at) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400449 if (!fContext) {
robertphillipsed086ca2016-04-26 15:02:25 -0700450 return nullptr;
451 }
452
brianosmaneed6b0e2016-09-23 13:04:05 -0700453 SkColorSpace* colorSpace = outProps.colorSpace();
454 return SkSpecialSurface::MakeRenderTarget(
Robert Phillips8bc06d02016-11-01 17:28:40 -0400455 fContext, size.width(), size.height(),
brianosmaneed6b0e2016-09-23 13:04:05 -0700456 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700457 }
458
459 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400460 return SkSpecialImage::MakeDeferredFromGpu(fContext,
461 subset,
462 this->uniqueID(),
463 fTextureProxy,
464 fColorSpace,
465 &this->props(),
466 fAlphaType);
robertphillipsed086ca2016-04-26 15:02:25 -0700467 }
468
469 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400470 // TODO: add GrTextureProxy-backed SkImage_Gpus
471 sk_sp<GrTexture> tex = sk_ref_sp(fTextureProxy->instantiate(fContext->textureProvider()));
472
robertphillipsed086ca2016-04-26 15:02:25 -0700473 if (0 == subset.fLeft && 0 == subset.fTop &&
Robert Phillips8bc06d02016-11-01 17:28:40 -0400474 fTextureProxy->width() == subset.width() &&
475 fTextureProxy->height() == subset.height()) {
robertphillipsed086ca2016-04-26 15:02:25 -0700476 // The existing GrTexture is already tight so reuse it in the SkImage
Robert Phillips8bc06d02016-11-01 17:28:40 -0400477 return sk_make_sp<SkImage_Gpu>(tex->width(), tex->height(),
robertphillipsed086ca2016-04-26 15:02:25 -0700478 kNeedNewImageUniqueID,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400479 fAlphaType, std::move(tex), fColorSpace,
brianosmanafbf71d2016-07-21 07:15:37 -0700480 SkBudgeted::kYes);
robertphillipsed086ca2016-04-26 15:02:25 -0700481 }
482
Robert Phillips8bc06d02016-11-01 17:28:40 -0400483 GrSurfaceDesc desc = fTextureProxy->desc();
robertphillipsed086ca2016-04-26 15:02:25 -0700484 desc.fWidth = subset.width();
485 desc.fHeight = subset.height();
486
Robert Phillips8bc06d02016-11-01 17:28:40 -0400487 sk_sp<GrTexture> subTx(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes));
robertphillipsed086ca2016-04-26 15:02:25 -0700488 if (!subTx) {
489 return nullptr;
490 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400491 fContext->copySurface(subTx.get(), tex.get(), subset, SkIPoint::Make(0, 0));
robertphillipsed086ca2016-04-26 15:02:25 -0700492 return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
bungeman6bd52842016-10-27 09:30:08 -0700493 fAlphaType, std::move(subTx), fColorSpace, SkBudgeted::kYes);
robertphillipsed086ca2016-04-26 15:02:25 -0700494 }
495
brianosmaneed6b0e2016-09-23 13:04:05 -0700496 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
497 const SkISize& size, SkAlphaType at) const override {
498 SkColorSpace* colorSpace = outProps.colorSpace();
499 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
500 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
501 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
502 sk_ref_sp(colorSpace));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400503 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
robertphillipsed086ca2016-04-26 15:02:25 -0700504 }
505
506private:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400507 GrContext* fContext;
508 sk_sp<GrTextureProxy> fTextureProxy;
robertphillipsed086ca2016-04-26 15:02:25 -0700509 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700510 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700511 mutable SkAtomic<bool> fAddedRasterVersionToCache;
512
513 typedef SkSpecialImage_Base INHERITED;
514};
515
robertphillips3e302272016-04-20 11:48:36 -0700516sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700517 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700518 sk_sp<GrTexture> tex,
brianosmanafbf71d2016-07-21 07:15:37 -0700519 sk_sp<SkColorSpace> colorSpace,
brianosman898235c2016-04-06 07:38:23 -0700520 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700521 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800522 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
brianosmanafbf71d2016-07-21 07:15:37 -0700523 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
524 std::move(colorSpace), props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800525}
526
Robert Phillips8bc06d02016-11-01 17:28:40 -0400527sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
528 const SkIRect& subset,
529 uint32_t uniqueID,
530 sk_sp<GrTextureProxy> proxy,
531 sk_sp<SkColorSpace> colorSpace,
532 const SkSurfaceProps* props,
533 SkAlphaType at) {
534 SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
535 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
536 std::move(colorSpace), props);
537}
robertphillipsb6c65e92016-02-04 10:52:42 -0800538#endif