blob: 0853432d79d4164777495e412aacb0c12e69bfe8 [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 Phillips301431d2017-03-29 12:08:49 -040020#include "GrContextPriv.h"
Robert Phillipsb66b42f2017-03-14 08:53:02 -040021#include "GrResourceProvider.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050022#include "GrSurfaceContext.h"
Robert Phillipsa5fdc972017-02-18 16:58:09 -050023#include "GrSurfaceProxyPriv.h"
reedad7604b2016-07-20 16:13:32 -070024#include "GrTexture.h"
Brian Salomon514baff2016-11-17 15:17:07 -050025#include "GrSamplerParams.h"
Robert Phillips8bc06d02016-11-01 17:28:40 -040026#include "GrTextureProxy.h"
reedad7604b2016-07-20 16:13:32 -070027#include "SkGr.h"
Robert Phillips6de99042017-01-31 11:31:39 -050028#include "SkImage_Gpu.h"
reedad7604b2016-07-20 16:13:32 -070029#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080030
reeda2217ef2016-07-20 06:04:34 -070031// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
32// a given info is supported.
33static bool valid_for_imagefilters(const SkImageInfo& info) {
34 // no support for other swizzles/depths yet
35 return info.colorType() == kN32_SkColorType;
36}
37
robertphillipsb6c65e92016-02-04 10:52:42 -080038///////////////////////////////////////////////////////////////////////////////
39class SkSpecialImage_Base : public SkSpecialImage {
40public:
robertphillips3e302272016-04-20 11:48:36 -070041 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
42 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080043 }
robertphillips3e302272016-04-20 11:48:36 -070044 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080045
robertphillipse8c34972016-02-16 12:09:36 -080046 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080047
robertphillips64612512016-04-08 12:10:42 -070048 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080049
Robert Phillips8bc06d02016-11-01 17:28:40 -040050 virtual GrContext* onGetContext() const { return nullptr; }
robertphillipsb6c65e92016-02-04 10:52:42 -080051
brianosmanafbf71d2016-07-21 07:15:37 -070052 virtual SkColorSpace* onGetColorSpace() const = 0;
53
robertphillipsc91fd342016-04-25 12:32:54 -070054#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -050055 virtual sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const = 0;
robertphillipsc91fd342016-04-25 12:32:54 -070056#endif
robertphillips4418dba2016-03-07 12:45:14 -080057
robertphillipsb4bd11e2016-03-21 13:44:18 -070058 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
59
brianosmaneed6b0e2016-09-23 13:04:05 -070060 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
61 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070062
Robert Phillipsa5fdc972017-02-18 16:58:09 -050063 virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
robertphillipsb4bd11e2016-03-21 13:44:18 -070064
brianosmaneed6b0e2016-09-23 13:04:05 -070065 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
66 const SkISize& size, SkAlphaType at) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080067
68private:
69 typedef SkSpecialImage INHERITED;
70};
71
72///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080073static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080074 return static_cast<const SkSpecialImage_Base*>(image);
75}
76
robertphillips3e302272016-04-20 11:48:36 -070077SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070078 uint32_t uniqueID,
79 const SkSurfaceProps* props)
80 : fProps(SkSurfacePropsCopyOrDefault(props))
81 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070082 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070083}
84
robertphillips3e302272016-04-20 11:48:36 -070085sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070086#if SK_SUPPORT_GPU
87 if (!context) {
88 return nullptr;
89 }
Robert Phillips8bc06d02016-11-01 17:28:40 -040090 if (GrContext* curContext = as_SIB(this)->onGetContext()) {
91 return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
robertphillips83c17fa2016-03-18 08:14:27 -070092 }
93
94 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070095 // At this point, we are definitely not texture-backed, so we must be raster or generator
96 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
97 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
98 // in which case getROPixels could turn into peekPixels...
99 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -0700100 return nullptr;
101 }
102
robertphillips83f2e5a2016-03-24 06:31:25 -0700103 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -0700104 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -0700105 }
106
Robert Phillipse14d3052017-02-15 13:18:21 -0500107 // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
108 // semantics). Since this is cached though we would have to bake the fit into the cache key.
Robert Phillips26c90e02017-03-14 14:39:29 -0400109 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(context->resourceProvider(), bmp);
Robert Phillipse14d3052017-02-15 13:18:21 -0500110 if (!proxy) {
robertphillips83c17fa2016-03-18 08:14:27 -0700111 return nullptr;
112 }
113
Robert Phillipse14d3052017-02-15 13:18:21 -0500114 const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
115
116 // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not
117 // bother with SkBitmap::getSubset
118 return SkSpecialImage::MakeDeferredFromGpu(context,
119 rect,
120 this->uniqueID(),
121 std::move(proxy),
122 sk_ref_sp(this->getColorSpace()),
123 &this->props(),
124 this->alphaType());
robertphillips83c17fa2016-03-18 08:14:27 -0700125#else
126 return nullptr;
127#endif
128}
129
robertphillipse8c34972016-02-16 12:09:36 -0800130void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800131 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800132}
133
robertphillips64612512016-04-08 12:10:42 -0700134bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
135 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800136}
137
robertphillips64612512016-04-08 12:10:42 -0700138bool SkSpecialImage::isTextureBacked() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400139 return SkToBool(as_SIB(this)->onGetContext());
robertphillipsb6c65e92016-02-04 10:52:42 -0800140}
141
robertphillips64612512016-04-08 12:10:42 -0700142GrContext* SkSpecialImage::getContext() const {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400143 return as_SIB(this)->onGetContext();
robertphillips64612512016-04-08 12:10:42 -0700144}
145
brianosmanafbf71d2016-07-21 07:15:37 -0700146SkColorSpace* SkSpecialImage::getColorSpace() const {
147 return as_SIB(this)->onGetColorSpace();
148}
149
robertphillipsc91fd342016-04-25 12:32:54 -0700150#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500151sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrContext* context) const {
152 return as_SIB(this)->onAsTextureProxyRef(context);
Robert Phillips8bc06d02016-11-01 17:28:40 -0400153}
robertphillipsc91fd342016-04-25 12:32:54 -0700154#endif
robertphillips4418dba2016-03-07 12:45:14 -0800155
brianosmaneed6b0e2016-09-23 13:04:05 -0700156sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
157 const SkISize& size, SkAlphaType at) const {
158 return as_SIB(this)->onMakeSurface(outProps, size, at);
robertphillipsb6c65e92016-02-04 10:52:42 -0800159}
160
brianosmaneed6b0e2016-09-23 13:04:05 -0700161sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
162 const SkISize& size, SkAlphaType at) const {
163 return as_SIB(this)->onMakeTightSurface(outProps, size, at);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700164}
165
robertphillips37bd7c32016-03-17 14:31:39 -0700166sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
167 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700168}
169
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500170sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
171 return as_SIB(this)->onAsImage(subset);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700172}
173
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500174
robertphillipsb6c65e92016-02-04 10:52:42 -0800175#ifdef SK_DEBUG
176static bool rect_fits(const SkIRect& rect, int width, int height) {
robertphillips4418dba2016-03-07 12:45:14 -0800177 if (0 == width && 0 == height) {
178 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
179 return true;
180 }
181
robertphillipsb6c65e92016-02-04 10:52:42 -0800182 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
183 rect.fRight >= 0 && rect.fRight <= width &&
184 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
185 rect.fBottom >= 0 && rect.fBottom <= height;
186}
187#endif
188
robertphillips3e302272016-04-20 11:48:36 -0700189sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700190 sk_sp<SkImage> image,
Brian Osman61624f02016-12-09 14:51:59 -0500191 SkColorSpace* dstColorSpace,
brianosman898235c2016-04-06 07:38:23 -0700192 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800193 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700194
reedad7604b2016-07-20 16:13:32 -0700195#if SK_SUPPORT_GPU
Robert Phillips6de99042017-01-31 11:31:39 -0500196 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) {
197 GrContext* context = ((SkImage_Gpu*) as_IB(image))->context();
198
199 return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
Robert Phillips256c37b2017-03-01 14:32:46 -0500200 as_IB(image)->onImageInfo().refColorSpace(), props);
reedad7604b2016-07-20 16:13:32 -0700201 } else
202#endif
203 {
204 SkBitmap bm;
Brian Osman61624f02016-12-09 14:51:59 -0500205 if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
reedad7604b2016-07-20 16:13:32 -0700206 return MakeFromRaster(subset, bm, props);
207 }
reeda2217ef2016-07-20 06:04:34 -0700208 }
reedad7604b2016-07-20 16:13:32 -0700209 return nullptr;
robertphillipsb6c65e92016-02-04 10:52:42 -0800210}
211
212///////////////////////////////////////////////////////////////////////////////
robertphillipsb6c65e92016-02-04 10:52:42 -0800213
214class SkSpecialImage_Raster : public SkSpecialImage_Base {
215public:
robertphillips3e302272016-04-20 11:48:36 -0700216 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
217 : INHERITED(subset, bm.getGenerationID(), props)
reedbd2bd5c2016-07-25 14:26:02 -0700218 , fBitmap(bm)
219 {
220 SkASSERT(bm.pixelRef());
221
222 // We have to lock now, while bm is still in scope, since it may have come from our
223 // cache, which means we need to keep it locked until we (the special) are done, since
224 // we cannot re-generate the cache entry (if bm came from a generator).
225 fBitmap.lockPixels();
226 SkASSERT(fBitmap.getPixels());
robertphillipsb6c65e92016-02-04 10:52:42 -0800227 }
228
brianosman80e96082016-08-16 07:09:47 -0700229 SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
robertphillips3b087f42016-02-18 08:48:03 -0800230
231 size_t getSize() const override { return fBitmap.getSize(); }
232
robertphillipse8c34972016-02-16 12:09:36 -0800233 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800234 SkRect dst = SkRect::MakeXYWH(x, y,
235 this->subset().width(), this->subset().height());
236
237 canvas->drawBitmapRect(fBitmap, this->subset(),
238 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
239 }
240
robertphillips64612512016-04-08 12:10:42 -0700241 bool onGetROPixels(SkBitmap* bm) const override {
242 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800243 return true;
244 }
245
brianosmanafbf71d2016-07-21 07:15:37 -0700246 SkColorSpace* onGetColorSpace() const override {
247 return fBitmap.colorSpace();
248 }
249
robertphillips64612512016-04-08 12:10:42 -0700250#if SK_SUPPORT_GPU
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500251 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400252 if (context) {
Robert Phillips26c90e02017-03-14 14:39:29 -0400253 return GrMakeCachedBitmapProxy(context->resourceProvider(), fBitmap);
Robert Phillips8bc06d02016-11-01 17:28:40 -0400254 }
255
256 return nullptr;
257 }
robertphillipsc91fd342016-04-25 12:32:54 -0700258#endif
robertphillips64612512016-04-08 12:10:42 -0700259
brianosmaneed6b0e2016-09-23 13:04:05 -0700260// TODO: The raster implementations of image filters all currently assume that the pixels are
261// legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
262// we can't enable this. (They will continue to produce incorrect results, but less-so).
263#define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
264
265 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
266 const SkISize& size, SkAlphaType at) const override {
267#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
268 SkColorSpace* colorSpace = outProps.colorSpace();
269#else
270 SkColorSpace* colorSpace = nullptr;
271#endif
272 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
273 ? kRGBA_F16_SkColorType : kN32_SkColorType;
274 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
275 sk_ref_sp(colorSpace));
robertphillips3e302272016-04-20 11:48:36 -0700276 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800277 }
278
robertphillips37bd7c32016-03-17 14:31:39 -0700279 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700280 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700281
robertphillipsc5035e72016-03-17 06:58:39 -0700282 if (!fBitmap.extractSubset(&subsetBM, subset)) {
283 return nullptr;
284 }
285
robertphillips3e302272016-04-20 11:48:36 -0700286 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700287 subsetBM,
288 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700289 }
290
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500291 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
292 if (subset) {
293 SkBitmap subsetBM;
robertphillipsb4bd11e2016-03-21 13:44:18 -0700294
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500295 if (!fBitmap.extractSubset(&subsetBM, *subset)) {
296 return nullptr;
297 }
298
299 return SkImage::MakeFromBitmap(subsetBM);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700300 }
301
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500302 return SkImage::MakeFromBitmap(fBitmap);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700303 }
304
brianosmaneed6b0e2016-09-23 13:04:05 -0700305 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
306 const SkISize& size, SkAlphaType at) const override {
307#if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
308 SkColorSpace* colorSpace = outProps.colorSpace();
309#else
310 SkColorSpace* colorSpace = nullptr;
311#endif
312 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
313 ? kRGBA_F16_SkColorType : kN32_SkColorType;
314 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
315 sk_ref_sp(colorSpace));
reede8f30622016-03-23 18:59:25 -0700316 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700317 }
318
robertphillipsb6c65e92016-02-04 10:52:42 -0800319private:
320 SkBitmap fBitmap;
321
322 typedef SkSpecialImage_Base INHERITED;
323};
324
robertphillips3e302272016-04-20 11:48:36 -0700325sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700326 const SkBitmap& bm,
327 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800328 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700329
reedbd2bd5c2016-07-25 14:26:02 -0700330 if (!bm.pixelRef()) {
331 return nullptr;
332 }
333
reeda2217ef2016-07-20 06:04:34 -0700334 const SkBitmap* srcBM = &bm;
335 SkBitmap tmpStorage;
336 // ImageFilters only handle N32 at the moment, so force our src to be that
337 if (!valid_for_imagefilters(bm.info())) {
338 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
339 return nullptr;
340 }
341 srcBM = &tmpStorage;
342 }
343 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800344}
345
346#if SK_SUPPORT_GPU
347///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700348#include "GrTexture.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800349
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400350static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, sk_sp<GrTextureProxy> proxy,
Robert Phillipse2f7d182016-12-15 09:23:05 -0500351 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400352 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, alphaType,
353 std::move(proxy), std::move(colorSpace), SkBudgeted::kYes);
Robert Phillipse2f7d182016-12-15 09:23:05 -0500354}
355
robertphillipsed086ca2016-04-26 15:02:25 -0700356class SkSpecialImage_Gpu : public SkSpecialImage_Base {
357public:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400358 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
Robert Phillips63c67462017-02-15 14:19:01 -0500359 uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400360 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
361 : INHERITED(subset, uniqueID, props)
362 , fContext(context)
Robert Phillips63c67462017-02-15 14:19:01 -0500363 , fTextureProxy(std::move(proxy))
robertphillipsed086ca2016-04-26 15:02:25 -0700364 , fAlphaType(at)
brianosmanafbf71d2016-07-21 07:15:37 -0700365 , fColorSpace(std::move(colorSpace))
robertphillipsed086ca2016-04-26 15:02:25 -0700366 , fAddedRasterVersionToCache(false) {
367 }
368
369 ~SkSpecialImage_Gpu() override {
370 if (fAddedRasterVersionToCache.load()) {
371 SkNotifyBitmapGenIDIsStale(this->uniqueID());
372 }
373 }
374
brianosman80e96082016-08-16 07:09:47 -0700375 SkAlphaType alphaType() const override { return fAlphaType; }
robertphillipsed086ca2016-04-26 15:02:25 -0700376
Robert Phillips63c67462017-02-15 14:19:01 -0500377 size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
robertphillipsed086ca2016-04-26 15:02:25 -0700378
379 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
380 SkRect dst = SkRect::MakeXYWH(x, y,
381 this->subset().width(), this->subset().height());
382
Robert Phillips7f6cd902016-11-10 17:03:43 -0500383 // TODO: In this instance we know we're going to draw a sub-portion of the backing
384 // texture into the canvas so it is okay to wrap it in an SkImage. This poses
385 // some problems for full deferral however in that when the deferred SkImage_Gpu
386 // instantiates itself it is going to have to either be okay with having a larger
Robert Phillips63c67462017-02-15 14:19:01 -0500387 // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
Robert Phillips7f6cd902016-11-10 17:03:43 -0500388 // to be tightened (if it is deferred).
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400389 sk_sp<SkImage> img = sk_sp<SkImage>(new SkImage_Gpu(canvas->getGrContext(),
390 this->uniqueID(), fAlphaType,
391 fTextureProxy,
392 fColorSpace, SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700393
reed77d6f7d2016-07-13 12:24:48 -0700394 canvas->drawImageRect(img, this->subset(),
Robert Phillips7f6cd902016-11-10 17:03:43 -0500395 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
robertphillipsed086ca2016-04-26 15:02:25 -0700396 }
397
Robert Phillips8bc06d02016-11-01 17:28:40 -0400398 GrContext* onGetContext() const override { return fContext; }
robertphillipsed086ca2016-04-26 15:02:25 -0700399
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500400 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext*) const override {
Robert Phillips63c67462017-02-15 14:19:01 -0500401 return fTextureProxy;
Robert Phillips8bc06d02016-11-01 17:28:40 -0400402 }
robertphillipsed086ca2016-04-26 15:02:25 -0700403
404 bool onGetROPixels(SkBitmap* dst) const override {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400405 const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->width(), this->height());
406 if (SkBitmapCache::Find(desc, dst)) {
robertphillipsed086ca2016-04-26 15:02:25 -0700407 SkASSERT(dst->getGenerationID() == this->uniqueID());
408 SkASSERT(dst->isImmutable());
409 SkASSERT(dst->getPixels());
410 return true;
411 }
412
Mike Reed7a542c52017-04-11 12:03:44 -0400413 SkPixmap pmap;
robertphillipsed086ca2016-04-26 15:02:25 -0700414 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
brianosman80e96082016-08-16 07:09:47 -0700415 this->alphaType(), fColorSpace);
Mike Reed7a542c52017-04-11 12:03:44 -0400416 auto rec = SkBitmapCache::Alloc(desc, info, &pmap);
417 if (!rec) {
robertphillipsed086ca2016-04-26 15:02:25 -0700418 return false;
419 }
420
Robert Phillips301431d2017-03-29 12:08:49 -0400421 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
422 fTextureProxy, nullptr);
423 if (!sContext) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500424 return false;
425 }
Robert Phillips8bc06d02016-11-01 17:28:40 -0400426
Mike Reed7a542c52017-04-11 12:03:44 -0400427 if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
robertphillipsed086ca2016-04-26 15:02:25 -0700428 return false;
429 }
430
Mike Reed7a542c52017-04-11 12:03:44 -0400431 SkBitmapCache::Add(std::move(rec), dst);
robertphillipsed086ca2016-04-26 15:02:25 -0700432 fAddedRasterVersionToCache.store(true);
433 return true;
434 }
435
brianosmanafbf71d2016-07-21 07:15:37 -0700436 SkColorSpace* onGetColorSpace() const override {
437 return fColorSpace.get();
438 }
439
brianosmaneed6b0e2016-09-23 13:04:05 -0700440 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
441 const SkISize& size, SkAlphaType at) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400442 if (!fContext) {
robertphillipsed086ca2016-04-26 15:02:25 -0700443 return nullptr;
444 }
445
brianosmaneed6b0e2016-09-23 13:04:05 -0700446 SkColorSpace* colorSpace = outProps.colorSpace();
447 return SkSpecialSurface::MakeRenderTarget(
Robert Phillips8bc06d02016-11-01 17:28:40 -0400448 fContext, size.width(), size.height(),
brianosmaneed6b0e2016-09-23 13:04:05 -0700449 GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
robertphillipsed086ca2016-04-26 15:02:25 -0700450 }
451
452 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
Robert Phillips8bc06d02016-11-01 17:28:40 -0400453 return SkSpecialImage::MakeDeferredFromGpu(fContext,
454 subset,
455 this->uniqueID(),
Robert Phillips63c67462017-02-15 14:19:01 -0500456 fTextureProxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400457 fColorSpace,
458 &this->props(),
459 fAlphaType);
robertphillipsed086ca2016-04-26 15:02:25 -0700460 }
461
Robert Phillipse2f7d182016-12-15 09:23:05 -0500462 // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500463 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
464 if (subset) {
465 // TODO: if this becomes a bottle neck we could base this logic on what the size
466 // will be when it is finally instantiated - but that is more fraught.
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400467 if (GrResourceProvider::IsFunctionallyExact(fTextureProxy.get()) &&
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500468 0 == subset->fLeft && 0 == subset->fTop &&
469 fTextureProxy->width() == subset->width() &&
470 fTextureProxy->height() == subset->height()) {
471 // The existing GrTexture is already tight so reuse it in the SkImage
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400472 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500473 }
474
475 sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
476 *subset, SkBudgeted::kYes));
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400477 if (!subsetProxy) {
478 return nullptr;
479 }
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500480
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400481 SkASSERT(subsetProxy->priv().isExact());
482 // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
483 // return a kExact-backed proxy
484 return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700485 }
486
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400487 fTextureProxy->priv().exactify();
488
489 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
robertphillipsed086ca2016-04-26 15:02:25 -0700490 }
491
brianosmaneed6b0e2016-09-23 13:04:05 -0700492 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
493 const SkISize& size, SkAlphaType at) const override {
494 SkColorSpace* colorSpace = outProps.colorSpace();
495 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
496 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
497 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
498 sk_ref_sp(colorSpace));
Robert Phillips8bc06d02016-11-01 17:28:40 -0400499 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
robertphillipsed086ca2016-04-26 15:02:25 -0700500 }
501
502private:
Robert Phillips8bc06d02016-11-01 17:28:40 -0400503 GrContext* fContext;
Robert Phillips63c67462017-02-15 14:19:01 -0500504 sk_sp<GrTextureProxy> fTextureProxy;
robertphillipsed086ca2016-04-26 15:02:25 -0700505 const SkAlphaType fAlphaType;
brianosmanafbf71d2016-07-21 07:15:37 -0700506 sk_sp<SkColorSpace> fColorSpace;
robertphillipsed086ca2016-04-26 15:02:25 -0700507 mutable SkAtomic<bool> fAddedRasterVersionToCache;
508
509 typedef SkSpecialImage_Base INHERITED;
510};
511
Robert Phillips8bc06d02016-11-01 17:28:40 -0400512sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
513 const SkIRect& subset,
514 uint32_t uniqueID,
Robert Phillips63c67462017-02-15 14:19:01 -0500515 sk_sp<GrTextureProxy> proxy,
Robert Phillips8bc06d02016-11-01 17:28:40 -0400516 sk_sp<SkColorSpace> colorSpace,
517 const SkSurfaceProps* props,
518 SkAlphaType at) {
519 SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
520 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
521 std::move(colorSpace), props);
522}
robertphillipsb6c65e92016-02-04 10:52:42 -0800523#endif