blob: 7d6dc66d61d2598f72838cf45f1d7adee1eaaf72 [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"
Robert Phillipsa5fdc972017-02-18 16:58:09 -050021#include "GrSurfaceProxyPriv.h"
reedad7604b2016-07-20 16:13:32 -070022#include "GrTexture.h"
Brian Salomon514baff2016-11-17 15:17:07 -050023#include "GrSamplerParams.h"
Robert Phillips8bc06d02016-11-01 17:28:40 -040024#include "GrTextureProxy.h"
reedad7604b2016-07-20 16:13:32 -070025#include "SkGr.h"
reedad7604b2016-07-20 16:13:32 -070026#include "SkGrPriv.h"
Robert Phillips6de99042017-01-31 11:31:39 -050027#include "SkImage_Gpu.h"
reedad7604b2016-07-20 16:13:32 -070028#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080029
reeda2217ef2016-07-20 06:04:34 -070030// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
31// a given info is supported.
32static bool valid_for_imagefilters(const SkImageInfo& info) {
33 // no support for other swizzles/depths yet
34 return info.colorType() == kN32_SkColorType;
35}
36
robertphillipsb6c65e92016-02-04 10:52:42 -080037///////////////////////////////////////////////////////////////////////////////
38class SkSpecialImage_Base : public SkSpecialImage {
39public:
robertphillips3e302272016-04-20 11:48:36 -070040 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
41 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080042 }
robertphillips3e302272016-04-20 11:48:36 -070043 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080044
robertphillipse8c34972016-02-16 12:09:36 -080045 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080046
robertphillips64612512016-04-08 12:10:42 -070047 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080048
Robert Phillips8bc06d02016-11-01 17:28:40 -040049 virtual GrContext* onGetContext() const { return nullptr; }
robertphillipsb6c65e92016-02-04 10:52:42 -080050
brianosmanafbf71d2016-07-21 07:15:37 -070051 virtual SkColorSpace* onGetColorSpace() const = 0;
52
robertphillipsc91fd342016-04-25 12:32:54 -070053#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -050054 virtual sk_sp<GrTextureProxy> onAsTextureProxyRef(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
Robert Phillipsa5fdc972017-02-18 16:58:09 -050062 virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
robertphillipsb4bd11e2016-03-21 13:44:18 -070063
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
Robert Phillipse14d3052017-02-15 13:18:21 -0500106 // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
107 // semantics). Since this is cached though we would have to bake the fit into the cache key.
108 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(context, bmp);
109 if (!proxy) {
robertphillips83c17fa2016-03-18 08:14:27 -0700110 return nullptr;
111 }
112
Robert Phillipse14d3052017-02-15 13:18:21 -0500113 const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
114
115 // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not
116 // bother with SkBitmap::getSubset
117 return SkSpecialImage::MakeDeferredFromGpu(context,
118 rect,
119 this->uniqueID(),
120 std::move(proxy),
121 sk_ref_sp(this->getColorSpace()),
122 &this->props(),
123 this->alphaType());
robertphillips83c17fa2016-03-18 08:14:27 -0700124#else
125 return nullptr;
126#endif
127}
128
robertphillipse8c34972016-02-16 12:09:36 -0800129void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800130 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800131}
132
robertphillips64612512016-04-08 12:10:42 -0700133bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
134 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800135}
136
robertphillips64612512016-04-08 12:10:42 -0700137bool SkSpecialImage::isTextureBacked() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400138 return SkToBool(as_SIB(this)->onGetContext());
robertphillipsb6c65e92016-02-04 10:52:42 -0800139}
140
robertphillips64612512016-04-08 12:10:42 -0700141GrContext* SkSpecialImage::getContext() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400142 return as_SIB(this)->onGetContext();
robertphillips64612512016-04-08 12:10:42 -0700143}
144
brianosmanafbf71d2016-07-21 07:15:37 -0700145SkColorSpace* SkSpecialImage::getColorSpace() const {
146 return as_SIB(this)->onGetColorSpace();
147}
148
robertphillipsc91fd342016-04-25 12:32:54 -0700149#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500150sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrContext* context) const {
151 return as_SIB(this)->onAsTextureProxyRef(context);
Robert Phillips8bc06d02016-11-01 17:28:40 -0400152}
robertphillipsc91fd342016-04-25 12:32:54 -0700153#endif
robertphillips4418dba2016-03-07 12:45:14 -0800154
brianosmaneed6b0e2016-09-23 13:04:05 -0700155sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
156 const SkISize& size, SkAlphaType at) const {
157 return as_SIB(this)->onMakeSurface(outProps, size, at);
robertphillipsb6c65e92016-02-04 10:52:42 -0800158}
159
brianosmaneed6b0e2016-09-23 13:04:05 -0700160sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
161 const SkISize& size, SkAlphaType at) const {
162 return as_SIB(this)->onMakeTightSurface(outProps, size, at);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700163}
164
robertphillips37bd7c32016-03-17 14:31:39 -0700165sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
166 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700167}
168
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500169sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
170 return as_SIB(this)->onAsImage(subset);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700171}
172
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500173
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,
Brian Osman61624f02016-12-09 14:51:59 -0500190 SkColorSpace* dstColorSpace,
brianosman898235c2016-04-06 07:38:23 -0700191 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800192 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700193
reedad7604b2016-07-20 16:13:32 -0700194#if SK_SUPPORT_GPU
Robert Phillips6de99042017-01-31 11:31:39 -0500195 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) {
196 GrContext* context = ((SkImage_Gpu*) as_IB(image))->context();
197
198 return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
199 sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props);
reedad7604b2016-07-20 16:13:32 -0700200 } else
201#endif
202 {
203 SkBitmap bm;
Brian Osman61624f02016-12-09 14:51:59 -0500204 if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
reedad7604b2016-07-20 16:13:32 -0700205 return MakeFromRaster(subset, bm, props);
206 }
reeda2217ef2016-07-20 06:04:34 -0700207 }
reedad7604b2016-07-20 16:13:32 -0700208 return nullptr;
robertphillipsb6c65e92016-02-04 10:52:42 -0800209}
210
211///////////////////////////////////////////////////////////////////////////////
robertphillipsb6c65e92016-02-04 10:52:42 -0800212
213class SkSpecialImage_Raster : public SkSpecialImage_Base {
214public:
robertphillips3e302272016-04-20 11:48:36 -0700215 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
216 : INHERITED(subset, bm.getGenerationID(), props)
reedbd2bd5c2016-07-25 14:26:02 -0700217 , fBitmap(bm)
218 {
219 SkASSERT(bm.pixelRef());
220
221 // We have to lock now, while bm is still in scope, since it may have come from our
222 // cache, which means we need to keep it locked until we (the special) are done, since
223 // we cannot re-generate the cache entry (if bm came from a generator).
224 fBitmap.lockPixels();
225 SkASSERT(fBitmap.getPixels());
robertphillipsb6c65e92016-02-04 10:52:42 -0800226 }
227
brianosman80e96082016-08-16 07:09:47 -0700228 SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
robertphillips3b087f42016-02-18 08:48:03 -0800229
230 size_t getSize() const override { return fBitmap.getSize(); }
231
robertphillipse8c34972016-02-16 12:09:36 -0800232 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800233 SkRect dst = SkRect::MakeXYWH(x, y,
234 this->subset().width(), this->subset().height());
235
236 canvas->drawBitmapRect(fBitmap, this->subset(),
237 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
238 }
239
robertphillips64612512016-04-08 12:10:42 -0700240 bool onGetROPixels(SkBitmap* bm) const override {
241 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800242 return true;
243 }
244
brianosmanafbf71d2016-07-21 07:15:37 -0700245 SkColorSpace* onGetColorSpace() const override {
246 return fBitmap.colorSpace();
247 }
248
robertphillips64612512016-04-08 12:10:42 -0700249#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500250 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400251 if (context) {
Robert Phillips6f9f7eb2017-02-18 15:15:51 -0500252 return GrMakeCachedBitmapProxy(context, fBitmap);
Robert Phillips8bc06d02016-11-01 17:28:40 -0400253 }
254
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
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500290 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
291 if (subset) {
292 SkBitmap subsetBM;
robertphillipsb4bd11e2016-03-21 13:44:18 -0700293
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500294 if (!fBitmap.extractSubset(&subsetBM, *subset)) {
295 return nullptr;
296 }
297
298 return SkImage::MakeFromBitmap(subsetBM);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700299 }
300
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500301 return SkImage::MakeFromBitmap(fBitmap);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700302 }
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"
robertphillipsb6c65e92016-02-04 10:52:42 -0800348
Robert Phillips63c67462017-02-15 14:19:01 -0500349static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, GrTextureProxy* proxy,
Robert Phillipse2f7d182016-12-15 09:23:05 -0500350 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
351 // TODO: add GrTextureProxy-backed SkImage_Gpus
Robert Phillips63c67462017-02-15 14:19:01 -0500352 GrTexture* tex = proxy->instantiate(context->textureProvider());
353 if (!tex) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500354 return nullptr;
355 }
356
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500357 // Note that we're explicitly using the GrTexture's width & height here b.c. SkImages
358 // must be tight.
359 return sk_make_sp<SkImage_Gpu>(tex->width(), tex->height(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500360 kNeedNewImageUniqueID, alphaType,
Robert Phillips63c67462017-02-15 14:19:01 -0500361 sk_ref_sp(tex),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500362 std::move(colorSpace), SkBudgeted::kYes);
363}
364
robertphillipsed086ca2016-04-26 15:02:25 -0700365class SkSpecialImage_Gpu : public SkSpecialImage_Base {
366public:
367 SkSpecialImage_Gpu(const SkIRect& subset,
368 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
brianosmanafbf71d2016-07-21 07:15:37 -0700369 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
robertphillipsed086ca2016-04-26 15:02:25 -0700370 : INHERITED(subset, uniqueID, props)
Robert Phillips8bc06d02016-11-01 17:28:40 -0400371 , fContext(tex->getContext())
Robert Phillips63c67462017-02-15 14:19:01 -0500372 , fTextureProxy(GrSurfaceProxy::MakeWrapped(std::move(tex)))
Robert Phillips8bc06d02016-11-01 17:28:40 -0400373 , fAlphaType(at)
374 , fColorSpace(std::move(colorSpace))
375 , fAddedRasterVersionToCache(false) {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400376 }
377
378 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
Robert Phillips63c67462017-02-15 14:19:01 -0500379 uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400380 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
381 : INHERITED(subset, uniqueID, props)
382 , fContext(context)
Robert Phillips63c67462017-02-15 14:19:01 -0500383 , fTextureProxy(std::move(proxy))
robertphillipsed086ca2016-04-26 15:02:25 -0700384 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700385 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700386 , fAddedRasterVersionToCache(false) {
387 }
388
389 ~SkSpecialImage_Gpu() override {
390 if (fAddedRasterVersionToCache.load()) {
391 SkNotifyBitmapGenIDIsStale(this->uniqueID());
392 }
393 }
394
brianosman80e96082016-08-16 07:09:47 -0700395 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700396
Robert Phillips63c67462017-02-15 14:19:01 -0500397 size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
robertphillipsed086ca2016-04-26 15:02:25 -0700398
399 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
400 SkRect dst = SkRect::MakeXYWH(x, y,
401 this->subset().width(), this->subset().height());
402
Robert Phillips8bc06d02016-11-01 17:28:40 -0400403 // TODO: add GrTextureProxy-backed SkImage_Gpus
Robert Phillips63c67462017-02-15 14:19:01 -0500404 GrTexture* tex = fTextureProxy->instantiate(fContext->textureProvider());
405 if (!tex) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500406 return;
407 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400408
Robert Phillips7f6cd902016-11-10 17:03:43 -0500409 // TODO: In this instance we know we're going to draw a sub-portion of the backing
410 // texture into the canvas so it is okay to wrap it in an SkImage. This poses
411 // some problems for full deferral however in that when the deferred SkImage_Gpu
412 // instantiates itself it is going to have to either be okay with having a larger
Robert Phillips63c67462017-02-15 14:19:01 -0500413 // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
Robert Phillips7f6cd902016-11-10 17:03:43 -0500414 // to be tightened (if it is deferred).
Robert Phillips63c67462017-02-15 14:19:01 -0500415 auto img = sk_sp<SkImage>(new SkImage_Gpu(tex->width(), tex->height(),
Robert Phillips37430132016-11-09 06:50:43 -0500416 this->uniqueID(), fAlphaType,
Robert Phillips63c67462017-02-15 14:19:01 -0500417 sk_ref_sp(tex),
brianosmanafbf71d2016-07-21 07:15:37 -0700418 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700419
reed77d6f7d2016-07-13 12:24:48 -0700420 canvas->drawImageRect(img, this->subset(),
Robert Phillips7f6cd902016-11-10 17:03:43 -0500421 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
robertphillipsed086ca2016-04-26 15:02:25 -0700422 }
423
Robert Phillips8bc06d02016-11-01 17:28:40 -0400424 GrContext* onGetContext() const override { return fContext; }
robertphillipsed086ca2016-04-26 15:02:25 -0700425
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500426 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext*) const override {
Robert Phillips63c67462017-02-15 14:19:01 -0500427 return fTextureProxy;
Robert Phillips8bc06d02016-11-01 17:28:40 -0400428 }
robertphillipsed086ca2016-04-26 15:02:25 -0700429
430 bool onGetROPixels(SkBitmap* dst) const override {
431 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
432 SkASSERT(dst->getGenerationID() == this->uniqueID());
433 SkASSERT(dst->isImmutable());
434 SkASSERT(dst->getPixels());
435 return true;
436 }
437
438 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700439 this->alphaType(), fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700440
441 if (!dst->tryAllocPixels(info)) {
442 return false;
443 }
444
Robert Phillips8bc06d02016-11-01 17:28:40 -0400445 // Reading back to an SkBitmap ends deferral
Robert Phillips63c67462017-02-15 14:19:01 -0500446 GrTexture* texture = fTextureProxy->instantiate(fContext->textureProvider());
447 if (!texture) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500448 return false;
449 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400450
Robert Phillips63c67462017-02-15 14:19:01 -0500451 if (!texture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400452 dst->getPixels(), dst->rowBytes())) {
robertphillipsed086ca2016-04-26 15:02:25 -0700453 return false;
454 }
455
456 dst->pixelRef()->setImmutableWithID(this->uniqueID());
457 SkBitmapCache::Add(this->uniqueID(), *dst);
458 fAddedRasterVersionToCache.store(true);
459 return true;
460 }
461
brianosmanafbf71d2016-07-21 07:15:37 -0700462 SkColorSpace* onGetColorSpace() const override {
463 return fColorSpace.get();
464 }
465
brianosmaneed6b0e2016-09-23 13:04:05 -0700466 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
467 const SkISize& size, SkAlphaType at) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400468 if (!fContext) {
robertphillipsed086ca2016-04-26 15:02:25 -0700469 return nullptr;
470 }
471
brianosmaneed6b0e2016-09-23 13:04:05 -0700472 SkColorSpace* colorSpace = outProps.colorSpace();
473 return SkSpecialSurface::MakeRenderTarget(
Robert Phillips8bc06d02016-11-01 17:28:40 -0400474 fContext, size.width(), size.height(),
brianosmaneed6b0e2016-09-23 13:04:05 -0700475 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700476 }
477
478 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400479 return SkSpecialImage::MakeDeferredFromGpu(fContext,
480 subset,
481 this->uniqueID(),
Robert Phillips63c67462017-02-15 14:19:01 -0500482 fTextureProxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400483 fColorSpace,
484 &this->props(),
485 fAlphaType);
robertphillipsed086ca2016-04-26 15:02:25 -0700486 }
487
Robert Phillipse2f7d182016-12-15 09:23:05 -0500488 // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500489 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
490 if (subset) {
491 // TODO: if this becomes a bottle neck we could base this logic on what the size
492 // will be when it is finally instantiated - but that is more fraught.
493 if (//fSurfaceProxy->priv().isExact() &&
494 0 == subset->fLeft && 0 == subset->fTop &&
495 fTextureProxy->width() == subset->width() &&
496 fTextureProxy->height() == subset->height()) {
497 // The existing GrTexture is already tight so reuse it in the SkImage
498 return wrap_proxy_in_image(fContext, fTextureProxy.get(), fAlphaType, fColorSpace);
499 }
500
501 sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
502 *subset, SkBudgeted::kYes));
503
504 return wrap_proxy_in_image(fContext, subsetProxy.get(), fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700505 }
506
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500507 return wrap_proxy_in_image(fContext, fTextureProxy.get(), fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700508 }
509
brianosmaneed6b0e2016-09-23 13:04:05 -0700510 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
511 const SkISize& size, SkAlphaType at) const override {
512 SkColorSpace* colorSpace = outProps.colorSpace();
513 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
514 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
515 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
516 sk_ref_sp(colorSpace));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400517 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
robertphillipsed086ca2016-04-26 15:02:25 -0700518 }
519
520private:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400521 GrContext* fContext;
Robert Phillips63c67462017-02-15 14:19:01 -0500522 sk_sp<GrTextureProxy> fTextureProxy;
robertphillipsed086ca2016-04-26 15:02:25 -0700523 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700524 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700525 mutable SkAtomic<bool> fAddedRasterVersionToCache;
526
527 typedef SkSpecialImage_Base INHERITED;
528};
529
robertphillips3e302272016-04-20 11:48:36 -0700530sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700531 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700532 sk_sp<GrTexture> tex,
brianosmanafbf71d2016-07-21 07:15:37 -0700533 sk_sp<SkColorSpace> colorSpace,
brianosman898235c2016-04-06 07:38:23 -0700534 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700535 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800536 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
brianosmanafbf71d2016-07-21 07:15:37 -0700537 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
538 std::move(colorSpace), props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800539}
540
Robert Phillips8bc06d02016-11-01 17:28:40 -0400541sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
542 const SkIRect& subset,
543 uint32_t uniqueID,
Robert Phillips63c67462017-02-15 14:19:01 -0500544 sk_sp<GrTextureProxy> proxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400545 sk_sp<SkColorSpace> colorSpace,
546 const SkSurfaceProps* props,
547 SkAlphaType at) {
548 SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
549 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
550 std::move(colorSpace), props);
551}
robertphillipsb6c65e92016-02-04 10:52:42 -0800552#endif