blob: 4f48f7862b54048fe8dc674f2f57c108c154ea49 [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"
Robert Phillipse2f7d182016-12-15 09:23:05 -050020#include "GrSurfaceContext.h"
reedad7604b2016-07-20 16:13:32 -070021#include "GrTexture.h"
Brian Salomon514baff2016-11-17 15:17:07 -050022#include "GrSamplerParams.h"
Robert Phillips8bc06d02016-11-01 17:28:40 -040023#include "GrTextureProxy.h"
reedad7604b2016-07-20 16:13:32 -070024#include "SkGr.h"
reedad7604b2016-07-20 16:13:32 -070025#include "SkGrPriv.h"
26#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080027
reeda2217ef2016-07-20 06:04:34 -070028// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
29// a given info is supported.
30static bool valid_for_imagefilters(const SkImageInfo& info) {
31 // no support for other swizzles/depths yet
32 return info.colorType() == kN32_SkColorType;
33}
34
robertphillipsb6c65e92016-02-04 10:52:42 -080035///////////////////////////////////////////////////////////////////////////////
36class SkSpecialImage_Base : public SkSpecialImage {
37public:
robertphillips3e302272016-04-20 11:48:36 -070038 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
39 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080040 }
robertphillips3e302272016-04-20 11:48:36 -070041 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080042
robertphillipse8c34972016-02-16 12:09:36 -080043 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080044
robertphillips64612512016-04-08 12:10:42 -070045 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080046
Robert Phillips8bc06d02016-11-01 17:28:40 -040047 virtual GrContext* onGetContext() const { return nullptr; }
robertphillipsb6c65e92016-02-04 10:52:42 -080048
brianosmanafbf71d2016-07-21 07:15:37 -070049 virtual SkColorSpace* onGetColorSpace() const = 0;
50
robertphillipsc91fd342016-04-25 12:32:54 -070051#if SK_SUPPORT_GPU
52 virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
Robert Phillips8bc06d02016-11-01 17:28:40 -040053 virtual sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const = 0;
robertphillipsc91fd342016-04-25 12:32:54 -070054#endif
robertphillips4418dba2016-03-07 12:45:14 -080055
robertphillipsb4bd11e2016-03-21 13:44:18 -070056 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
57
brianosmaneed6b0e2016-09-23 13:04:05 -070058 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
59 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070060
robertphillipsb4bd11e2016-03-21 13:44:18 -070061 virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
62
brianosmaneed6b0e2016-09-23 13:04:05 -070063 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
64 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080065
66private:
67 typedef SkSpecialImage INHERITED;
68};
69
70///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080071static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080072 return static_cast<const SkSpecialImage_Base*>(image);
73}
74
robertphillips3e302272016-04-20 11:48:36 -070075SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070076 uint32_t uniqueID,
77 const SkSurfaceProps* props)
78 : fProps(SkSurfacePropsCopyOrDefault(props))
79 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070080 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070081}
82
robertphillips3e302272016-04-20 11:48:36 -070083sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070084#if SK_SUPPORT_GPU
85 if (!context) {
86 return nullptr;
87 }
Robert Phillips8bc06d02016-11-01 17:28:40 -040088 if (GrContext* curContext = as_SIB(this)->onGetContext()) {
89 return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
robertphillips83c17fa2016-03-18 08:14:27 -070090 }
91
92 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070093 // At this point, we are definitely not texture-backed, so we must be raster or generator
94 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
95 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
96 // in which case getROPixels could turn into peekPixels...
97 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -070098 return nullptr;
99 }
100
robertphillips83f2e5a2016-03-24 06:31:25 -0700101 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -0700102 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -0700103 }
104
Brian Osman7b8400d2016-11-08 17:08:54 -0500105 sk_sp<GrTexture> resultTex(
Brian Osman61624f02016-12-09 14:51:59 -0500106 GrRefCachedBitmapTexture(context, bmp, GrSamplerParams::ClampNoFilter()));
robertphillips83c17fa2016-03-18 08:14:27 -0700107 if (!resultTex) {
108 return nullptr;
109 }
110
robertphillips3e302272016-04-20 11:48:36 -0700111 return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()),
robertphillips83c17fa2016-03-18 08:14:27 -0700112 this->uniqueID(),
brianosmanafbf71d2016-07-21 07:15:37 -0700113 resultTex, sk_ref_sp(this->getColorSpace()), &this->props(),
brianosman80e96082016-08-16 07:09:47 -0700114 this->alphaType());
robertphillips83c17fa2016-03-18 08:14:27 -0700115#else
116 return nullptr;
117#endif
118}
119
robertphillipse8c34972016-02-16 12:09:36 -0800120void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800121 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800122}
123
robertphillips64612512016-04-08 12:10:42 -0700124bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
125 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800126}
127
robertphillips64612512016-04-08 12:10:42 -0700128bool SkSpecialImage::isTextureBacked() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400129 return SkToBool(as_SIB(this)->onGetContext());
robertphillipsb6c65e92016-02-04 10:52:42 -0800130}
131
robertphillips64612512016-04-08 12:10:42 -0700132GrContext* SkSpecialImage::getContext() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400133 return as_SIB(this)->onGetContext();
robertphillips64612512016-04-08 12:10:42 -0700134}
135
brianosmanafbf71d2016-07-21 07:15:37 -0700136SkColorSpace* SkSpecialImage::getColorSpace() const {
137 return as_SIB(this)->onGetColorSpace();
138}
139
robertphillipsc91fd342016-04-25 12:32:54 -0700140#if SK_SUPPORT_GPU
141sk_sp<GrTexture> SkSpecialImage::asTextureRef(GrContext* context) const {
robertphillips64612512016-04-08 12:10:42 -0700142 return as_SIB(this)->onAsTextureRef(context);
robertphillips4418dba2016-03-07 12:45:14 -0800143}
Robert Phillips8bc06d02016-11-01 17:28:40 -0400144
145sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxy(GrContext* context) const {
146 return as_SIB(this)->onAsTextureProxy(context);
147}
robertphillipsc91fd342016-04-25 12:32:54 -0700148#endif
robertphillips4418dba2016-03-07 12:45:14 -0800149
brianosmaneed6b0e2016-09-23 13:04:05 -0700150sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
151 const SkISize& size, SkAlphaType at) const {
152 return as_SIB(this)->onMakeSurface(outProps, size, at);
robertphillipsb6c65e92016-02-04 10:52:42 -0800153}
154
brianosmaneed6b0e2016-09-23 13:04:05 -0700155sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
156 const SkISize& size, SkAlphaType at) const {
157 return as_SIB(this)->onMakeTightSurface(outProps, size, at);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700158}
159
robertphillips37bd7c32016-03-17 14:31:39 -0700160sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
161 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700162}
163
robertphillipsb4bd11e2016-03-21 13:44:18 -0700164sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
165 return as_SIB(this)->onMakeTightSubset(subset);
166}
167
robertphillipsb6c65e92016-02-04 10:52:42 -0800168#ifdef SK_DEBUG
169static bool rect_fits(const SkIRect& rect, int width, int height) {
robertphillips4418dba2016-03-07 12:45:14 -0800170 if (0 == width && 0 == height) {
171 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
172 return true;
173 }
174
robertphillipsb6c65e92016-02-04 10:52:42 -0800175 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
176 rect.fRight >= 0 && rect.fRight <= width &&
177 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
178 rect.fBottom >= 0 && rect.fBottom <= height;
179}
180#endif
181
robertphillips3e302272016-04-20 11:48:36 -0700182sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700183 sk_sp<SkImage> image,
Brian Osman61624f02016-12-09 14:51:59 -0500184 SkColorSpace* dstColorSpace,
brianosman898235c2016-04-06 07:38:23 -0700185 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;
Brian Osman61624f02016-12-09 14:51:59 -0500196 if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
reedad7604b2016-07-20 16:13:32 -0700197 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) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500244 return sk_ref_sp(
Brian Osman61624f02016-12-09 14:51:59 -0500245 GrRefCachedBitmapTexture(context, fBitmap, GrSamplerParams::ClampNoFilter()));
robertphillips64612512016-04-08 12:10:42 -0700246 }
robertphillips64612512016-04-08 12:10:42 -0700247
248 return nullptr;
249 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400250
251 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const override {
252 if (context) {
Robert Phillips37430132016-11-09 06:50:43 -0500253 sk_sp<GrTexture> tex(sk_ref_sp(GrRefCachedBitmapTexture(
Brian Osman61624f02016-12-09 14:51:59 -0500254 context, fBitmap, GrSamplerParams::ClampNoFilter())));
Robert Phillips37430132016-11-09 06:50:43 -0500255 sk_sp<GrSurfaceProxy> sProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
256 return sk_ref_sp(sProxy->asTextureProxy());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400257 }
258
259 return nullptr;
260 }
robertphillipsc91fd342016-04-25 12:32:54 -0700261#endif
robertphillips64612512016-04-08 12:10:42 -0700262
brianosmaneed6b0e2016-09-23 13:04:05 -0700263// TODO: The raster implementations of image filters all currently assume that the pixels are
264// legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
265// we can't enable this. (They will continue to produce incorrect results, but less-so).
266#define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
267
268 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
269 const SkISize& size, SkAlphaType at) const override {
270#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
271 SkColorSpace* colorSpace = outProps.colorSpace();
272#else
273 SkColorSpace* colorSpace = nullptr;
274#endif
275 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
276 ? kRGBA_F16_SkColorType : kN32_SkColorType;
277 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
278 sk_ref_sp(colorSpace));
robertphillips3e302272016-04-20 11:48:36 -0700279 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800280 }
281
robertphillips37bd7c32016-03-17 14:31:39 -0700282 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700283 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700284
robertphillipsc5035e72016-03-17 06:58:39 -0700285 if (!fBitmap.extractSubset(&subsetBM, subset)) {
286 return nullptr;
287 }
288
robertphillips3e302272016-04-20 11:48:36 -0700289 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700290 subsetBM,
291 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700292 }
293
robertphillipsb4bd11e2016-03-21 13:44:18 -0700294 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
295 SkBitmap subsetBM;
296
297 if (!fBitmap.extractSubset(&subsetBM, subset)) {
298 return nullptr;
299 }
300
301 return SkImage::MakeFromBitmap(subsetBM);
302 }
303
brianosmaneed6b0e2016-09-23 13:04:05 -0700304 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
305 const SkISize& size, SkAlphaType at) const override {
306#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
307 SkColorSpace* colorSpace = outProps.colorSpace();
308#else
309 SkColorSpace* colorSpace = nullptr;
310#endif
311 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
312 ? kRGBA_F16_SkColorType : kN32_SkColorType;
313 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
314 sk_ref_sp(colorSpace));
reede8f30622016-03-23 18:59:25 -0700315 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700316 }
317
robertphillipsb6c65e92016-02-04 10:52:42 -0800318private:
319 SkBitmap fBitmap;
320
321 typedef SkSpecialImage_Base INHERITED;
322};
323
robertphillips3e302272016-04-20 11:48:36 -0700324sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700325 const SkBitmap& bm,
326 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800327 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700328
reedbd2bd5c2016-07-25 14:26:02 -0700329 if (!bm.pixelRef()) {
330 return nullptr;
331 }
332
reeda2217ef2016-07-20 06:04:34 -0700333 const SkBitmap* srcBM = &bm;
334 SkBitmap tmpStorage;
335 // ImageFilters only handle N32 at the moment, so force our src to be that
336 if (!valid_for_imagefilters(bm.info())) {
337 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
338 return nullptr;
339 }
340 srcBM = &tmpStorage;
341 }
342 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800343}
344
345#if SK_SUPPORT_GPU
346///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700347#include "GrTexture.h"
robertphillipsb4bd11e2016-03-21 13:44:18 -0700348#include "SkImage_Gpu.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800349
Robert Phillipse2f7d182016-12-15 09:23:05 -0500350static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, GrSurfaceProxy* proxy,
351 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
352 // TODO: add GrTextureProxy-backed SkImage_Gpus
353 GrSurface* surf = proxy->instantiate(context->textureProvider());
354 if (!surf) {
355 return nullptr;
356 }
357
358 return sk_make_sp<SkImage_Gpu>(proxy->width(), proxy->height(),
359 kNeedNewImageUniqueID, alphaType,
360 sk_ref_sp(surf->asTexture()),
361 std::move(colorSpace), SkBudgeted::kYes);
362}
363
robertphillipsed086ca2016-04-26 15:02:25 -0700364class SkSpecialImage_Gpu : public SkSpecialImage_Base {
365public:
366 SkSpecialImage_Gpu(const SkIRect& subset,
367 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
brianosmanafbf71d2016-07-21 07:15:37 -0700368 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
robertphillipsed086ca2016-04-26 15:02:25 -0700369 : INHERITED(subset, uniqueID, props)
Robert Phillips8bc06d02016-11-01 17:28:40 -0400370 , fContext(tex->getContext())
371 , fAlphaType(at)
372 , fColorSpace(std::move(colorSpace))
373 , fAddedRasterVersionToCache(false) {
Robert Phillips37430132016-11-09 06:50:43 -0500374 fSurfaceProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400375 }
376
377 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
Robert Phillips37430132016-11-09 06:50:43 -0500378 uint32_t uniqueID, sk_sp<GrSurfaceProxy> proxy, SkAlphaType at,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400379 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
380 : INHERITED(subset, uniqueID, props)
381 , fContext(context)
Robert Phillips37430132016-11-09 06:50:43 -0500382 , fSurfaceProxy(std::move(proxy))
robertphillipsed086ca2016-04-26 15:02:25 -0700383 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700384 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700385 , fAddedRasterVersionToCache(false) {
386 }
387
388 ~SkSpecialImage_Gpu() override {
389 if (fAddedRasterVersionToCache.load()) {
390 SkNotifyBitmapGenIDIsStale(this->uniqueID());
391 }
392 }
393
brianosman80e96082016-08-16 07:09:47 -0700394 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700395
Robert Phillips37430132016-11-09 06:50:43 -0500396 size_t getSize() const override { return fSurfaceProxy->gpuMemorySize(); }
robertphillipsed086ca2016-04-26 15:02:25 -0700397
398 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
399 SkRect dst = SkRect::MakeXYWH(x, y,
400 this->subset().width(), this->subset().height());
401
Robert Phillips8bc06d02016-11-01 17:28:40 -0400402 // TODO: add GrTextureProxy-backed SkImage_Gpus
Robert Phillips37430132016-11-09 06:50:43 -0500403 GrSurface* surf = fSurfaceProxy->instantiate(fContext->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500404 if (!surf) {
405 return;
406 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400407
Robert Phillips7f6cd902016-11-10 17:03:43 -0500408 // TODO: In this instance we know we're going to draw a sub-portion of the backing
409 // texture into the canvas so it is okay to wrap it in an SkImage. This poses
410 // some problems for full deferral however in that when the deferred SkImage_Gpu
411 // instantiates itself it is going to have to either be okay with having a larger
412 // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
413 // to be tightened (if it is deferred).
414 auto img = sk_sp<SkImage>(new SkImage_Gpu(surf->width(), surf->height(),
Robert Phillips37430132016-11-09 06:50:43 -0500415 this->uniqueID(), fAlphaType,
416 sk_ref_sp(surf->asTexture()),
brianosmanafbf71d2016-07-21 07:15:37 -0700417 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700418
reed77d6f7d2016-07-13 12:24:48 -0700419 canvas->drawImageRect(img, this->subset(),
Robert Phillips7f6cd902016-11-10 17:03:43 -0500420 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
robertphillipsed086ca2016-04-26 15:02:25 -0700421 }
422
Robert Phillips8bc06d02016-11-01 17:28:40 -0400423 GrContext* onGetContext() const override { return fContext; }
robertphillipsed086ca2016-04-26 15:02:25 -0700424
Robert Phillips8bc06d02016-11-01 17:28:40 -0400425 // This entry point should go away in favor of asTextureProxy
426 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
Robert Phillips37430132016-11-09 06:50:43 -0500427 GrSurface* surf = fSurfaceProxy->instantiate(context->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500428 if (!surf) {
429 return nullptr;
430 }
Robert Phillips37430132016-11-09 06:50:43 -0500431 return sk_ref_sp(surf->asTexture());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400432 }
433
434 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext*) const override {
Robert Phillips37430132016-11-09 06:50:43 -0500435 return sk_ref_sp(fSurfaceProxy->asTextureProxy());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400436 }
robertphillipsed086ca2016-04-26 15:02:25 -0700437
438 bool onGetROPixels(SkBitmap* dst) const override {
439 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
440 SkASSERT(dst->getGenerationID() == this->uniqueID());
441 SkASSERT(dst->isImmutable());
442 SkASSERT(dst->getPixels());
443 return true;
444 }
445
446 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700447 this->alphaType(), fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700448
449 if (!dst->tryAllocPixels(info)) {
450 return false;
451 }
452
Robert Phillips8bc06d02016-11-01 17:28:40 -0400453 // Reading back to an SkBitmap ends deferral
Robert Phillips37430132016-11-09 06:50:43 -0500454 GrSurface* surface = fSurfaceProxy->instantiate(fContext->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500455 if (!surface) {
456 return false;
457 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400458
Robert Phillips37430132016-11-09 06:50:43 -0500459 if (!surface->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400460 dst->getPixels(), dst->rowBytes())) {
robertphillipsed086ca2016-04-26 15:02:25 -0700461 return false;
462 }
463
464 dst->pixelRef()->setImmutableWithID(this->uniqueID());
465 SkBitmapCache::Add(this->uniqueID(), *dst);
466 fAddedRasterVersionToCache.store(true);
467 return true;
468 }
469
brianosmanafbf71d2016-07-21 07:15:37 -0700470 SkColorSpace* onGetColorSpace() const override {
471 return fColorSpace.get();
472 }
473
brianosmaneed6b0e2016-09-23 13:04:05 -0700474 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
475 const SkISize& size, SkAlphaType at) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400476 if (!fContext) {
robertphillipsed086ca2016-04-26 15:02:25 -0700477 return nullptr;
478 }
479
brianosmaneed6b0e2016-09-23 13:04:05 -0700480 SkColorSpace* colorSpace = outProps.colorSpace();
481 return SkSpecialSurface::MakeRenderTarget(
Robert Phillips8bc06d02016-11-01 17:28:40 -0400482 fContext, size.width(), size.height(),
brianosmaneed6b0e2016-09-23 13:04:05 -0700483 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700484 }
485
486 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400487 return SkSpecialImage::MakeDeferredFromGpu(fContext,
488 subset,
489 this->uniqueID(),
Robert Phillips37430132016-11-09 06:50:43 -0500490 fSurfaceProxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400491 fColorSpace,
492 &this->props(),
493 fAlphaType);
robertphillipsed086ca2016-04-26 15:02:25 -0700494 }
495
Robert Phillipse2f7d182016-12-15 09:23:05 -0500496 // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
robertphillipsed086ca2016-04-26 15:02:25 -0700497 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500498 // TODO: this is problematic since the surfaceProxy could be loose
robertphillipsed086ca2016-04-26 15:02:25 -0700499 if (0 == subset.fLeft && 0 == subset.fTop &&
Robert Phillips37430132016-11-09 06:50:43 -0500500 fSurfaceProxy->width() == subset.width() &&
501 fSurfaceProxy->height() == subset.height()) {
robertphillipsed086ca2016-04-26 15:02:25 -0700502 // The existing GrTexture is already tight so reuse it in the SkImage
Robert Phillipse2f7d182016-12-15 09:23:05 -0500503 return wrap_proxy_in_image(fContext, fSurfaceProxy.get(),
504 fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700505 }
506
Robert Phillipse2f7d182016-12-15 09:23:05 -0500507 sk_sp<GrSurfaceProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fSurfaceProxy.get(),
508 subset, SkBudgeted::kYes));
robertphillipsed086ca2016-04-26 15:02:25 -0700509
Robert Phillipse2f7d182016-12-15 09:23:05 -0500510 return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700511 }
512
brianosmaneed6b0e2016-09-23 13:04:05 -0700513 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
514 const SkISize& size, SkAlphaType at) const override {
515 SkColorSpace* colorSpace = outProps.colorSpace();
516 SkColorType 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));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400520 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
robertphillipsed086ca2016-04-26 15:02:25 -0700521 }
522
523private:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400524 GrContext* fContext;
Robert Phillips37430132016-11-09 06:50:43 -0500525 sk_sp<GrSurfaceProxy> fSurfaceProxy;
robertphillipsed086ca2016-04-26 15:02:25 -0700526 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700527 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700528 mutable SkAtomic<bool> fAddedRasterVersionToCache;
529
530 typedef SkSpecialImage_Base INHERITED;
531};
532
robertphillips3e302272016-04-20 11:48:36 -0700533sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700534 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700535 sk_sp<GrTexture> tex,
brianosmanafbf71d2016-07-21 07:15:37 -0700536 sk_sp<SkColorSpace> colorSpace,
brianosman898235c2016-04-06 07:38:23 -0700537 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700538 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800539 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
brianosmanafbf71d2016-07-21 07:15:37 -0700540 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
541 std::move(colorSpace), props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800542}
543
Robert Phillips8bc06d02016-11-01 17:28:40 -0400544sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
545 const SkIRect& subset,
546 uint32_t uniqueID,
Robert Phillips37430132016-11-09 06:50:43 -0500547 sk_sp<GrSurfaceProxy> proxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400548 sk_sp<SkColorSpace> colorSpace,
549 const SkSurfaceProps* props,
550 SkAlphaType at) {
551 SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
552 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
553 std::move(colorSpace), props);
554}
robertphillipsb6c65e92016-02-04 10:52:42 -0800555#endif