blob: 1d1a5573832faa080f2924cb088d72a22413dad5 [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"
Robert Phillips6de99042017-01-31 11:31:39 -050026#include "SkImage_Gpu.h"
reedad7604b2016-07-20 16:13:32 -070027#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080028
reeda2217ef2016-07-20 06:04:34 -070029// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
30// a given info is supported.
31static bool valid_for_imagefilters(const SkImageInfo& info) {
32 // no support for other swizzles/depths yet
33 return info.colorType() == kN32_SkColorType;
34}
35
robertphillipsb6c65e92016-02-04 10:52:42 -080036///////////////////////////////////////////////////////////////////////////////
37class SkSpecialImage_Base : public SkSpecialImage {
38public:
robertphillips3e302272016-04-20 11:48:36 -070039 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
40 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080041 }
robertphillips3e302272016-04-20 11:48:36 -070042 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080043
robertphillipse8c34972016-02-16 12:09:36 -080044 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080045
robertphillips64612512016-04-08 12:10:42 -070046 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080047
Robert Phillips8bc06d02016-11-01 17:28:40 -040048 virtual GrContext* onGetContext() const { return nullptr; }
robertphillipsb6c65e92016-02-04 10:52:42 -080049
brianosmanafbf71d2016-07-21 07:15:37 -070050 virtual SkColorSpace* onGetColorSpace() const = 0;
51
robertphillipsc91fd342016-04-25 12:32:54 -070052#if SK_SUPPORT_GPU
53 virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
Robert Phillips8bc06d02016-11-01 17:28:40 -040054 virtual sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const = 0;
robertphillipsc91fd342016-04-25 12:32:54 -070055#endif
robertphillips4418dba2016-03-07 12:45:14 -080056
robertphillipsb4bd11e2016-03-21 13:44:18 -070057 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
58
brianosmaneed6b0e2016-09-23 13:04:05 -070059 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
60 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070061
robertphillipsb4bd11e2016-03-21 13:44:18 -070062 virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
63
brianosmaneed6b0e2016-09-23 13:04:05 -070064 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
65 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080066
67private:
68 typedef SkSpecialImage INHERITED;
69};
70
71///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080072static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080073 return static_cast<const SkSpecialImage_Base*>(image);
74}
75
robertphillips3e302272016-04-20 11:48:36 -070076SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070077 uint32_t uniqueID,
78 const SkSurfaceProps* props)
79 : fProps(SkSurfacePropsCopyOrDefault(props))
80 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070081 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070082}
83
robertphillips3e302272016-04-20 11:48:36 -070084sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070085#if SK_SUPPORT_GPU
86 if (!context) {
87 return nullptr;
88 }
Robert Phillips8bc06d02016-11-01 17:28:40 -040089 if (GrContext* curContext = as_SIB(this)->onGetContext()) {
90 return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
robertphillips83c17fa2016-03-18 08:14:27 -070091 }
92
93 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070094 // At this point, we are definitely not texture-backed, so we must be raster or generator
95 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
96 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
97 // in which case getROPixels could turn into peekPixels...
98 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -070099 return nullptr;
100 }
101
robertphillips83f2e5a2016-03-24 06:31:25 -0700102 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -0700103 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -0700104 }
105
Brian Osman7b8400d2016-11-08 17:08:54 -0500106 sk_sp<GrTexture> resultTex(
Robert Phillips67c18d62017-01-20 12:44:06 -0500107 GrRefCachedBitmapTexture(context, bmp, GrSamplerParams::ClampNoFilter(), nullptr));
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,
Brian Osman61624f02016-12-09 14:51:59 -0500185 SkColorSpace* dstColorSpace,
brianosman898235c2016-04-06 07:38:23 -0700186 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800187 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700188
reedad7604b2016-07-20 16:13:32 -0700189#if SK_SUPPORT_GPU
Robert Phillips6de99042017-01-31 11:31:39 -0500190 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) {
191 GrContext* context = ((SkImage_Gpu*) as_IB(image))->context();
192
193 return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
194 sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props);
reedad7604b2016-07-20 16:13:32 -0700195 } else
196#endif
197 {
198 SkBitmap bm;
Brian Osman61624f02016-12-09 14:51:59 -0500199 if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
reedad7604b2016-07-20 16:13:32 -0700200 return MakeFromRaster(subset, bm, props);
201 }
reeda2217ef2016-07-20 06:04:34 -0700202 }
reedad7604b2016-07-20 16:13:32 -0700203 return nullptr;
robertphillipsb6c65e92016-02-04 10:52:42 -0800204}
205
206///////////////////////////////////////////////////////////////////////////////
robertphillipsb6c65e92016-02-04 10:52:42 -0800207
208class SkSpecialImage_Raster : public SkSpecialImage_Base {
209public:
robertphillips3e302272016-04-20 11:48:36 -0700210 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
211 : INHERITED(subset, bm.getGenerationID(), props)
reedbd2bd5c2016-07-25 14:26:02 -0700212 , fBitmap(bm)
213 {
214 SkASSERT(bm.pixelRef());
215
216 // We have to lock now, while bm is still in scope, since it may have come from our
217 // cache, which means we need to keep it locked until we (the special) are done, since
218 // we cannot re-generate the cache entry (if bm came from a generator).
219 fBitmap.lockPixels();
220 SkASSERT(fBitmap.getPixels());
robertphillipsb6c65e92016-02-04 10:52:42 -0800221 }
222
brianosman80e96082016-08-16 07:09:47 -0700223 SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
robertphillips3b087f42016-02-18 08:48:03 -0800224
225 size_t getSize() const override { return fBitmap.getSize(); }
226
robertphillipse8c34972016-02-16 12:09:36 -0800227 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800228 SkRect dst = SkRect::MakeXYWH(x, y,
229 this->subset().width(), this->subset().height());
230
231 canvas->drawBitmapRect(fBitmap, this->subset(),
232 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
233 }
234
robertphillips64612512016-04-08 12:10:42 -0700235 bool onGetROPixels(SkBitmap* bm) const override {
236 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800237 return true;
238 }
239
brianosmanafbf71d2016-07-21 07:15:37 -0700240 SkColorSpace* onGetColorSpace() const override {
241 return fBitmap.colorSpace();
242 }
243
robertphillips64612512016-04-08 12:10:42 -0700244#if SK_SUPPORT_GPU
robertphillipsc91fd342016-04-25 12:32:54 -0700245 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
robertphillips64612512016-04-08 12:10:42 -0700246 if (context) {
Robert Phillips67c18d62017-01-20 12:44:06 -0500247 return sk_ref_sp(GrRefCachedBitmapTexture(context, fBitmap,
248 GrSamplerParams::ClampNoFilter(), nullptr));
robertphillips64612512016-04-08 12:10:42 -0700249 }
robertphillips64612512016-04-08 12:10:42 -0700250
251 return nullptr;
252 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400253
254 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const override {
255 if (context) {
Robert Phillips37430132016-11-09 06:50:43 -0500256 sk_sp<GrTexture> tex(sk_ref_sp(GrRefCachedBitmapTexture(
Robert Phillips67c18d62017-01-20 12:44:06 -0500257 context, fBitmap, GrSamplerParams::ClampNoFilter(), nullptr)));
Robert Phillips37430132016-11-09 06:50:43 -0500258 sk_sp<GrSurfaceProxy> sProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
259 return sk_ref_sp(sProxy->asTextureProxy());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400260 }
261
262 return nullptr;
263 }
robertphillipsc91fd342016-04-25 12:32:54 -0700264#endif
robertphillips64612512016-04-08 12:10:42 -0700265
brianosmaneed6b0e2016-09-23 13:04:05 -0700266// TODO: The raster implementations of image filters all currently assume that the pixels are
267// legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
268// we can't enable this. (They will continue to produce incorrect results, but less-so).
269#define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
270
271 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
272 const SkISize& size, SkAlphaType at) const override {
273#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
274 SkColorSpace* colorSpace = outProps.colorSpace();
275#else
276 SkColorSpace* colorSpace = nullptr;
277#endif
278 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
279 ? kRGBA_F16_SkColorType : kN32_SkColorType;
280 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
281 sk_ref_sp(colorSpace));
robertphillips3e302272016-04-20 11:48:36 -0700282 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800283 }
284
robertphillips37bd7c32016-03-17 14:31:39 -0700285 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700286 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700287
robertphillipsc5035e72016-03-17 06:58:39 -0700288 if (!fBitmap.extractSubset(&subsetBM, subset)) {
289 return nullptr;
290 }
291
robertphillips3e302272016-04-20 11:48:36 -0700292 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700293 subsetBM,
294 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700295 }
296
robertphillipsb4bd11e2016-03-21 13:44:18 -0700297 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
298 SkBitmap subsetBM;
299
300 if (!fBitmap.extractSubset(&subsetBM, subset)) {
301 return nullptr;
302 }
303
304 return SkImage::MakeFromBitmap(subsetBM);
305 }
306
brianosmaneed6b0e2016-09-23 13:04:05 -0700307 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
308 const SkISize& size, SkAlphaType at) const override {
309#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
310 SkColorSpace* colorSpace = outProps.colorSpace();
311#else
312 SkColorSpace* colorSpace = nullptr;
313#endif
314 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
315 ? kRGBA_F16_SkColorType : kN32_SkColorType;
316 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
317 sk_ref_sp(colorSpace));
reede8f30622016-03-23 18:59:25 -0700318 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700319 }
320
robertphillipsb6c65e92016-02-04 10:52:42 -0800321private:
322 SkBitmap fBitmap;
323
324 typedef SkSpecialImage_Base INHERITED;
325};
326
robertphillips3e302272016-04-20 11:48:36 -0700327sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700328 const SkBitmap& bm,
329 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800330 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700331
reedbd2bd5c2016-07-25 14:26:02 -0700332 if (!bm.pixelRef()) {
333 return nullptr;
334 }
335
reeda2217ef2016-07-20 06:04:34 -0700336 const SkBitmap* srcBM = &bm;
337 SkBitmap tmpStorage;
338 // ImageFilters only handle N32 at the moment, so force our src to be that
339 if (!valid_for_imagefilters(bm.info())) {
340 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
341 return nullptr;
342 }
343 srcBM = &tmpStorage;
344 }
345 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800346}
347
348#if SK_SUPPORT_GPU
349///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700350#include "GrTexture.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800351
Robert Phillipse2f7d182016-12-15 09:23:05 -0500352static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, GrSurfaceProxy* proxy,
353 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
354 // TODO: add GrTextureProxy-backed SkImage_Gpus
355 GrSurface* surf = proxy->instantiate(context->textureProvider());
356 if (!surf) {
357 return nullptr;
358 }
359
360 return sk_make_sp<SkImage_Gpu>(proxy->width(), proxy->height(),
361 kNeedNewImageUniqueID, alphaType,
362 sk_ref_sp(surf->asTexture()),
363 std::move(colorSpace), SkBudgeted::kYes);
364}
365
robertphillipsed086ca2016-04-26 15:02:25 -0700366class SkSpecialImage_Gpu : public SkSpecialImage_Base {
367public:
368 SkSpecialImage_Gpu(const SkIRect& subset,
369 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
brianosmanafbf71d2016-07-21 07:15:37 -0700370 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
robertphillipsed086ca2016-04-26 15:02:25 -0700371 : INHERITED(subset, uniqueID, props)
Robert Phillips8bc06d02016-11-01 17:28:40 -0400372 , fContext(tex->getContext())
373 , fAlphaType(at)
374 , fColorSpace(std::move(colorSpace))
375 , fAddedRasterVersionToCache(false) {
Robert Phillips37430132016-11-09 06:50:43 -0500376 fSurfaceProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400377 }
378
379 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
Robert Phillips37430132016-11-09 06:50:43 -0500380 uint32_t uniqueID, sk_sp<GrSurfaceProxy> proxy, SkAlphaType at,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400381 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
382 : INHERITED(subset, uniqueID, props)
383 , fContext(context)
Robert Phillips37430132016-11-09 06:50:43 -0500384 , fSurfaceProxy(std::move(proxy))
robertphillipsed086ca2016-04-26 15:02:25 -0700385 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700386 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700387 , fAddedRasterVersionToCache(false) {
388 }
389
390 ~SkSpecialImage_Gpu() override {
391 if (fAddedRasterVersionToCache.load()) {
392 SkNotifyBitmapGenIDIsStale(this->uniqueID());
393 }
394 }
395
brianosman80e96082016-08-16 07:09:47 -0700396 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700397
Robert Phillips37430132016-11-09 06:50:43 -0500398 size_t getSize() const override { return fSurfaceProxy->gpuMemorySize(); }
robertphillipsed086ca2016-04-26 15:02:25 -0700399
400 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
401 SkRect dst = SkRect::MakeXYWH(x, y,
402 this->subset().width(), this->subset().height());
403
Robert Phillips8bc06d02016-11-01 17:28:40 -0400404 // TODO: add GrTextureProxy-backed SkImage_Gpus
Robert Phillips37430132016-11-09 06:50:43 -0500405 GrSurface* surf = fSurfaceProxy->instantiate(fContext->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500406 if (!surf) {
407 return;
408 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400409
Robert Phillips7f6cd902016-11-10 17:03:43 -0500410 // TODO: In this instance we know we're going to draw a sub-portion of the backing
411 // texture into the canvas so it is okay to wrap it in an SkImage. This poses
412 // some problems for full deferral however in that when the deferred SkImage_Gpu
413 // instantiates itself it is going to have to either be okay with having a larger
414 // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
415 // to be tightened (if it is deferred).
416 auto img = sk_sp<SkImage>(new SkImage_Gpu(surf->width(), surf->height(),
Robert Phillips37430132016-11-09 06:50:43 -0500417 this->uniqueID(), fAlphaType,
418 sk_ref_sp(surf->asTexture()),
brianosmanafbf71d2016-07-21 07:15:37 -0700419 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700420
reed77d6f7d2016-07-13 12:24:48 -0700421 canvas->drawImageRect(img, this->subset(),
Robert Phillips7f6cd902016-11-10 17:03:43 -0500422 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
robertphillipsed086ca2016-04-26 15:02:25 -0700423 }
424
Robert Phillips8bc06d02016-11-01 17:28:40 -0400425 GrContext* onGetContext() const override { return fContext; }
robertphillipsed086ca2016-04-26 15:02:25 -0700426
Robert Phillips8bc06d02016-11-01 17:28:40 -0400427 // This entry point should go away in favor of asTextureProxy
428 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
Robert Phillips37430132016-11-09 06:50:43 -0500429 GrSurface* surf = fSurfaceProxy->instantiate(context->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500430 if (!surf) {
431 return nullptr;
432 }
Robert Phillips37430132016-11-09 06:50:43 -0500433 return sk_ref_sp(surf->asTexture());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400434 }
435
436 sk_sp<GrTextureProxy> onAsTextureProxy(GrContext*) const override {
Robert Phillips37430132016-11-09 06:50:43 -0500437 return sk_ref_sp(fSurfaceProxy->asTextureProxy());
Robert Phillips8bc06d02016-11-01 17:28:40 -0400438 }
robertphillipsed086ca2016-04-26 15:02:25 -0700439
440 bool onGetROPixels(SkBitmap* dst) const override {
441 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
442 SkASSERT(dst->getGenerationID() == this->uniqueID());
443 SkASSERT(dst->isImmutable());
444 SkASSERT(dst->getPixels());
445 return true;
446 }
447
448 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700449 this->alphaType(), fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700450
451 if (!dst->tryAllocPixels(info)) {
452 return false;
453 }
454
Robert Phillips8bc06d02016-11-01 17:28:40 -0400455 // Reading back to an SkBitmap ends deferral
Robert Phillips37430132016-11-09 06:50:43 -0500456 GrSurface* surface = fSurfaceProxy->instantiate(fContext->textureProvider());
Robert Phillipse60ad622016-11-17 10:22:48 -0500457 if (!surface) {
458 return false;
459 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400460
Robert Phillips37430132016-11-09 06:50:43 -0500461 if (!surface->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400462 dst->getPixels(), dst->rowBytes())) {
robertphillipsed086ca2016-04-26 15:02:25 -0700463 return false;
464 }
465
466 dst->pixelRef()->setImmutableWithID(this->uniqueID());
467 SkBitmapCache::Add(this->uniqueID(), *dst);
468 fAddedRasterVersionToCache.store(true);
469 return true;
470 }
471
brianosmanafbf71d2016-07-21 07:15:37 -0700472 SkColorSpace* onGetColorSpace() const override {
473 return fColorSpace.get();
474 }
475
brianosmaneed6b0e2016-09-23 13:04:05 -0700476 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
477 const SkISize& size, SkAlphaType at) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400478 if (!fContext) {
robertphillipsed086ca2016-04-26 15:02:25 -0700479 return nullptr;
480 }
481
brianosmaneed6b0e2016-09-23 13:04:05 -0700482 SkColorSpace* colorSpace = outProps.colorSpace();
483 return SkSpecialSurface::MakeRenderTarget(
Robert Phillips8bc06d02016-11-01 17:28:40 -0400484 fContext, size.width(), size.height(),
brianosmaneed6b0e2016-09-23 13:04:05 -0700485 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700486 }
487
488 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400489 return SkSpecialImage::MakeDeferredFromGpu(fContext,
490 subset,
491 this->uniqueID(),
Robert Phillips37430132016-11-09 06:50:43 -0500492 fSurfaceProxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400493 fColorSpace,
494 &this->props(),
495 fAlphaType);
robertphillipsed086ca2016-04-26 15:02:25 -0700496 }
497
Robert Phillipse2f7d182016-12-15 09:23:05 -0500498 // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
robertphillipsed086ca2016-04-26 15:02:25 -0700499 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500500 // TODO: this is problematic since the surfaceProxy could be loose
robertphillipsed086ca2016-04-26 15:02:25 -0700501 if (0 == subset.fLeft && 0 == subset.fTop &&
Robert Phillips37430132016-11-09 06:50:43 -0500502 fSurfaceProxy->width() == subset.width() &&
503 fSurfaceProxy->height() == subset.height()) {
robertphillipsed086ca2016-04-26 15:02:25 -0700504 // The existing GrTexture is already tight so reuse it in the SkImage
Robert Phillipse2f7d182016-12-15 09:23:05 -0500505 return wrap_proxy_in_image(fContext, fSurfaceProxy.get(),
506 fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700507 }
508
Robert Phillipse2f7d182016-12-15 09:23:05 -0500509 sk_sp<GrSurfaceProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fSurfaceProxy.get(),
510 subset, SkBudgeted::kYes));
robertphillipsed086ca2016-04-26 15:02:25 -0700511
Robert Phillipse2f7d182016-12-15 09:23:05 -0500512 return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700513 }
514
brianosmaneed6b0e2016-09-23 13:04:05 -0700515 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
516 const SkISize& size, SkAlphaType at) const override {
517 SkColorSpace* colorSpace = outProps.colorSpace();
518 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
519 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
520 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
521 sk_ref_sp(colorSpace));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400522 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
robertphillipsed086ca2016-04-26 15:02:25 -0700523 }
524
525private:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400526 GrContext* fContext;
Robert Phillips37430132016-11-09 06:50:43 -0500527 sk_sp<GrSurfaceProxy> fSurfaceProxy;
robertphillipsed086ca2016-04-26 15:02:25 -0700528 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700529 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700530 mutable SkAtomic<bool> fAddedRasterVersionToCache;
531
532 typedef SkSpecialImage_Base INHERITED;
533};
534
robertphillips3e302272016-04-20 11:48:36 -0700535sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700536 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700537 sk_sp<GrTexture> tex,
brianosmanafbf71d2016-07-21 07:15:37 -0700538 sk_sp<SkColorSpace> colorSpace,
brianosman898235c2016-04-06 07:38:23 -0700539 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700540 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800541 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
brianosmanafbf71d2016-07-21 07:15:37 -0700542 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
543 std::move(colorSpace), props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800544}
545
Robert Phillips8bc06d02016-11-01 17:28:40 -0400546sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
547 const SkIRect& subset,
548 uint32_t uniqueID,
Robert Phillips37430132016-11-09 06:50:43 -0500549 sk_sp<GrSurfaceProxy> proxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400550 sk_sp<SkColorSpace> colorSpace,
551 const SkSurfaceProps* props,
552 SkAlphaType at) {
553 SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
554 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
555 std::move(colorSpace), props);
556}
robertphillipsb6c65e92016-02-04 10:52:42 -0800557#endif