blob: a4ffa198d5a9d05d883bc8d6c3f9e5b229fe704c [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 */
robertphillips83c17fa2016-03-18 08:14:27 -07007#include "SkSpecialImage.h"
8
9#if SK_SUPPORT_GPU
10#include "GrTexture.h"
11#include "GrTextureParams.h"
12#include "SkGr.h"
13#endif
robertphillipsb6c65e92016-02-04 10:52:42 -080014
robertphillips64612512016-04-08 12:10:42 -070015#include "SkBitmapCache.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080016#include "SkCanvas.h"
bsalomon84a4e5a2016-02-29 11:41:52 -080017#include "SkImage_Base.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080018#include "SkSpecialSurface.h"
brianosman898235c2016-04-06 07:38:23 -070019#include "SkSurfacePriv.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080020
reeda2217ef2016-07-20 06:04:34 -070021// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
22// a given info is supported.
23static bool valid_for_imagefilters(const SkImageInfo& info) {
24 // no support for other swizzles/depths yet
25 return info.colorType() == kN32_SkColorType;
26}
27
robertphillipsb6c65e92016-02-04 10:52:42 -080028///////////////////////////////////////////////////////////////////////////////
29class SkSpecialImage_Base : public SkSpecialImage {
30public:
robertphillips3e302272016-04-20 11:48:36 -070031 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
32 : INHERITED(subset, uniqueID, props) {
robertphillips3b087f42016-02-18 08:48:03 -080033 }
robertphillips3e302272016-04-20 11:48:36 -070034 ~SkSpecialImage_Base() override { }
robertphillipsb6c65e92016-02-04 10:52:42 -080035
robertphillipse8c34972016-02-16 12:09:36 -080036 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080037
robertphillips64612512016-04-08 12:10:42 -070038 virtual bool onGetROPixels(SkBitmap*) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080039
40 virtual GrTexture* onPeekTexture() const { return nullptr; }
41
robertphillipsc91fd342016-04-25 12:32:54 -070042#if SK_SUPPORT_GPU
43 virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
44#endif
robertphillips4418dba2016-03-07 12:45:14 -080045
robertphillips3b087f42016-02-18 08:48:03 -080046 // Delete this entry point ASAP (see skbug.com/4965)
robertphillipsab01ccd2016-03-08 10:45:32 -080047 virtual bool getBitmapDeprecated(SkBitmap* result) const = 0;
robertphillips3b087f42016-02-18 08:48:03 -080048
robertphillipsb4bd11e2016-03-21 13:44:18 -070049 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
50
robertphillips37bd7c32016-03-17 14:31:39 -070051 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const = 0;
robertphillipsc5035e72016-03-17 06:58:39 -070052
robertphillipsb4bd11e2016-03-21 13:44:18 -070053 virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
54
reede8f30622016-03-23 18:59:25 -070055 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const = 0;
robertphillipsb6c65e92016-02-04 10:52:42 -080056
57private:
58 typedef SkSpecialImage INHERITED;
59};
60
61///////////////////////////////////////////////////////////////////////////////
bsalomon84a4e5a2016-02-29 11:41:52 -080062static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
robertphillipsb6c65e92016-02-04 10:52:42 -080063 return static_cast<const SkSpecialImage_Base*>(image);
64}
65
robertphillips3e302272016-04-20 11:48:36 -070066SkSpecialImage::SkSpecialImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -070067 uint32_t uniqueID,
68 const SkSurfaceProps* props)
69 : fProps(SkSurfacePropsCopyOrDefault(props))
70 , fSubset(subset)
robertphillips3e302272016-04-20 11:48:36 -070071 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
brianosman898235c2016-04-06 07:38:23 -070072}
73
robertphillips3e302272016-04-20 11:48:36 -070074sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
robertphillips83c17fa2016-03-18 08:14:27 -070075#if SK_SUPPORT_GPU
76 if (!context) {
77 return nullptr;
78 }
robertphillips64612512016-04-08 12:10:42 -070079 if (GrTexture* peek = as_SIB(this)->onPeekTexture()) {
robertphillips83c17fa2016-03-18 08:14:27 -070080 return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
81 }
82
83 SkBitmap bmp;
reedcf5c8462016-07-20 12:28:40 -070084 // At this point, we are definitely not texture-backed, so we must be raster or generator
85 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
86 // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
87 // in which case getROPixels could turn into peekPixels...
88 if (!this->getROPixels(&bmp)) {
robertphillips83c17fa2016-03-18 08:14:27 -070089 return nullptr;
90 }
91
robertphillips83f2e5a2016-03-24 06:31:25 -070092 if (bmp.empty()) {
robertphillips3e302272016-04-20 11:48:36 -070093 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
robertphillips83f2e5a2016-03-24 06:31:25 -070094 }
95
robertphillipsc91fd342016-04-25 12:32:54 -070096 sk_sp<GrTexture> resultTex(GrRefCachedBitmapTexture(context,
97 bmp,
brianosman982eb7f2016-06-06 13:10:58 -070098 GrTextureParams::ClampNoFilter(),
99 SkSourceGammaTreatment::kRespect));
robertphillips83c17fa2016-03-18 08:14:27 -0700100 if (!resultTex) {
101 return nullptr;
102 }
103
104 SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
105
robertphillips3e302272016-04-20 11:48:36 -0700106 return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()),
robertphillips83c17fa2016-03-18 08:14:27 -0700107 this->uniqueID(),
brianosman898235c2016-04-06 07:38:23 -0700108 resultTex, &this->props(), at);
robertphillips83c17fa2016-03-18 08:14:27 -0700109#else
110 return nullptr;
111#endif
112}
113
robertphillipse8c34972016-02-16 12:09:36 -0800114void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
bsalomon84a4e5a2016-02-29 11:41:52 -0800115 return as_SIB(this)->onDraw(canvas, x, y, paint);
robertphillipsb6c65e92016-02-04 10:52:42 -0800116}
117
robertphillips64612512016-04-08 12:10:42 -0700118bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
119 return as_SIB(this)->onGetROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800120}
121
robertphillips64612512016-04-08 12:10:42 -0700122bool SkSpecialImage::isTextureBacked() const {
123#if SK_SUPPORT_GPU
124 return as_SIB(this)->onPeekTexture() && as_SIB(this)->onPeekTexture()->getContext();
125#else
126 return false;
127#endif
robertphillipsb6c65e92016-02-04 10:52:42 -0800128}
129
robertphillips64612512016-04-08 12:10:42 -0700130GrContext* SkSpecialImage::getContext() const {
131#if SK_SUPPORT_GPU
132 GrTexture* texture = as_SIB(this)->onPeekTexture();
133
134 if (texture) {
135 return texture->getContext();
136 }
137#endif
138 return nullptr;
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}
robertphillipsc91fd342016-04-25 12:32:54 -0700145#endif
robertphillips4418dba2016-03-07 12:45:14 -0800146
robertphillips37bd7c32016-03-17 14:31:39 -0700147sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageInfo& info) const {
148 return as_SIB(this)->onMakeSurface(info);
robertphillipsb6c65e92016-02-04 10:52:42 -0800149}
150
robertphillipsb4bd11e2016-03-21 13:44:18 -0700151sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageInfo& info) const {
reede8f30622016-03-23 18:59:25 -0700152 return as_SIB(this)->onMakeTightSurface(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700153}
154
robertphillips37bd7c32016-03-17 14:31:39 -0700155sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
156 return as_SIB(this)->onMakeSubset(subset);
robertphillipsc5035e72016-03-17 06:58:39 -0700157}
158
robertphillipsb4bd11e2016-03-21 13:44:18 -0700159sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
160 return as_SIB(this)->onMakeTightSubset(subset);
161}
162
robertphillips3b087f42016-02-18 08:48:03 -0800163#if SK_SUPPORT_GPU
164#include "SkGr.h"
165#include "SkGrPixelRef.h"
166#endif
167
robertphillipsb6c65e92016-02-04 10:52:42 -0800168///////////////////////////////////////////////////////////////////////////////
169#include "SkImage.h"
170#if SK_SUPPORT_GPU
brianosmana6359362016-03-21 06:55:37 -0700171#include "GrContext.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800172#include "SkGrPriv.h"
173#endif
174
175class SkSpecialImage_Image : public SkSpecialImage_Base {
176public:
robertphillips3e302272016-04-20 11:48:36 -0700177 SkSpecialImage_Image(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700178 sk_sp<SkImage> image,
179 const SkSurfaceProps* props)
robertphillips3e302272016-04-20 11:48:36 -0700180 : INHERITED(subset, image->uniqueID(), props)
robertphillips37bd7c32016-03-17 14:31:39 -0700181 , fImage(image) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800182 }
183
184 ~SkSpecialImage_Image() override { }
halcanary9d524f22016-03-29 09:03:52 -0700185
robertphillips3b087f42016-02-18 08:48:03 -0800186 bool isOpaque() const override { return fImage->isOpaque(); }
187
188 size_t getSize() const override {
189#if SK_SUPPORT_GPU
bsalomon84a4e5a2016-02-29 11:41:52 -0800190 if (GrTexture* texture = as_IB(fImage.get())->peekTexture()) {
191 return texture->gpuMemorySize();
robertphillips3b087f42016-02-18 08:48:03 -0800192 } else
193#endif
194 {
reed6ceeebd2016-03-09 14:26:26 -0800195 SkPixmap pm;
196 if (fImage->peekPixels(&pm)) {
197 return pm.height() * pm.rowBytes();
robertphillips3b087f42016-02-18 08:48:03 -0800198 }
199 }
200 return 0;
201 }
202
robertphillipse8c34972016-02-16 12:09:36 -0800203 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800204 SkRect dst = SkRect::MakeXYWH(x, y, this->subset().width(), this->subset().height());
205
robertphillips37bd7c32016-03-17 14:31:39 -0700206 canvas->drawImageRect(fImage.get(), this->subset(),
robertphillipsb6c65e92016-02-04 10:52:42 -0800207 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
208 }
209
robertphillips64612512016-04-08 12:10:42 -0700210 bool onGetROPixels(SkBitmap* bm) const override {
robertphillipsed086ca2016-04-26 15:02:25 -0700211 return as_IB(fImage)->getROPixels(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800212 }
213
robertphillips64612512016-04-08 12:10:42 -0700214 GrTexture* onPeekTexture() const override { return as_IB(fImage)->peekTexture(); }
215
robertphillips64612512016-04-08 12:10:42 -0700216#if SK_SUPPORT_GPU
robertphillipsc91fd342016-04-25 12:32:54 -0700217 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
218 return sk_sp<GrTexture>(as_IB(fImage)->asTextureRef(context,
brianosman982eb7f2016-06-06 13:10:58 -0700219 GrTextureParams::ClampNoFilter(),
220 SkSourceGammaTreatment::kRespect));
robertphillips64612512016-04-08 12:10:42 -0700221 }
robertphillipsc91fd342016-04-25 12:32:54 -0700222#endif
robertphillipsb6c65e92016-02-04 10:52:42 -0800223
robertphillipsab01ccd2016-03-08 10:45:32 -0800224 bool getBitmapDeprecated(SkBitmap* result) const override {
robertphillips6ac97b72016-03-09 05:17:10 -0800225#if SK_SUPPORT_GPU
226 if (GrTexture* texture = as_IB(fImage.get())->peekTexture()) {
halcanary9d524f22016-03-29 09:03:52 -0700227 const SkImageInfo info = GrMakeInfoFromTexture(texture,
robertphillips6ac97b72016-03-09 05:17:10 -0800228 fImage->width(), fImage->height(),
229 fImage->isOpaque());
230 if (!result->setInfo(info)) {
231 return false;
232 }
233
234 result->setPixelRef(new SkGrPixelRef(info, texture))->unref();
235 return true;
236 }
237#endif
238
239 return as_IB(fImage.get())->asBitmapForImageFilters(result);
robertphillips3b087f42016-02-18 08:48:03 -0800240 }
241
robertphillips37bd7c32016-03-17 14:31:39 -0700242 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800243#if SK_SUPPORT_GPU
bsalomon84a4e5a2016-02-29 11:41:52 -0800244 GrTexture* texture = as_IB(fImage.get())->peekTexture();
robertphillipsb6c65e92016-02-04 10:52:42 -0800245 if (texture) {
robertphillips4df16562016-04-28 15:09:34 -0700246 GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *texture->getContext()->caps());
robertphillipsb6c65e92016-02-04 10:52:42 -0800247
robertphillips4df16562016-04-28 15:09:34 -0700248 return SkSpecialSurface::MakeRenderTarget(texture->getContext(),
249 info.width(),
250 info.height(),
251 config);
robertphillipsb6c65e92016-02-04 10:52:42 -0800252 }
253#endif
robertphillips3e302272016-04-20 11:48:36 -0700254 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800255 }
256
robertphillips37bd7c32016-03-17 14:31:39 -0700257 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsed086ca2016-04-26 15:02:25 -0700258 sk_sp<SkImage> subsetImg(fImage->makeSubset(subset));
259 if (!subsetImg) {
260 return nullptr;
261 }
262
263 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(subset.width(), subset.height()),
264 subsetImg,
265 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700266 }
267
robertphillipsb4bd11e2016-03-21 13:44:18 -0700268 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
269 return fImage->makeSubset(subset);
270 }
271
reede8f30622016-03-23 18:59:25 -0700272 sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override {
robertphillipsb4bd11e2016-03-21 13:44:18 -0700273#if SK_SUPPORT_GPU
274 GrTexture* texture = as_IB(fImage.get())->peekTexture();
275 if (texture) {
reede8f30622016-03-23 18:59:25 -0700276 return SkSurface::MakeRenderTarget(texture->getContext(), SkBudgeted::kYes, info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700277 }
278#endif
reede8f30622016-03-23 18:59:25 -0700279 return SkSurface::MakeRaster(info, nullptr);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700280 }
281
robertphillipsb6c65e92016-02-04 10:52:42 -0800282private:
robertphillips37bd7c32016-03-17 14:31:39 -0700283 sk_sp<SkImage> fImage;
robertphillipsb6c65e92016-02-04 10:52:42 -0800284
285 typedef SkSpecialImage_Base INHERITED;
286};
287
288#ifdef SK_DEBUG
289static bool rect_fits(const SkIRect& rect, int width, int height) {
robertphillips4418dba2016-03-07 12:45:14 -0800290 if (0 == width && 0 == height) {
291 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
292 return true;
293 }
294
robertphillipsb6c65e92016-02-04 10:52:42 -0800295 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
296 rect.fRight >= 0 && rect.fRight <= width &&
297 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
298 rect.fBottom >= 0 && rect.fBottom <= height;
299}
300#endif
301
robertphillips3e302272016-04-20 11:48:36 -0700302sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700303 sk_sp<SkImage> image,
304 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800305 SkASSERT(rect_fits(subset, image->width(), image->height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700306
reeda2217ef2016-07-20 06:04:34 -0700307 if (valid_for_imagefilters(as_IB(image.get())->onImageInfo())) {
308 return sk_make_sp<SkSpecialImage_Image>(subset, image, props);
309 } else {
310 return nullptr;
311 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800312}
313
314///////////////////////////////////////////////////////////////////////////////
315#include "SkBitmap.h"
316#include "SkImageInfo.h"
317#include "SkPixelRef.h"
318
319class SkSpecialImage_Raster : public SkSpecialImage_Base {
320public:
robertphillips3e302272016-04-20 11:48:36 -0700321 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
322 : INHERITED(subset, bm.getGenerationID(), props)
robertphillipsb6c65e92016-02-04 10:52:42 -0800323 , fBitmap(bm) {
robertphillips4418dba2016-03-07 12:45:14 -0800324 if (bm.pixelRef() && bm.pixelRef()->isPreLocked()) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800325 // we only preemptively lock if there is no chance of triggering something expensive
326 // like a lazy decode or imagegenerator. PreLocked means it is flat pixels already.
327 fBitmap.lockPixels();
328 }
329 }
330
robertphillips3b087f42016-02-18 08:48:03 -0800331 bool isOpaque() const override { return fBitmap.isOpaque(); }
332
333 size_t getSize() const override { return fBitmap.getSize(); }
334
robertphillipse8c34972016-02-16 12:09:36 -0800335 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
robertphillipsb6c65e92016-02-04 10:52:42 -0800336 SkRect dst = SkRect::MakeXYWH(x, y,
337 this->subset().width(), this->subset().height());
338
339 canvas->drawBitmapRect(fBitmap, this->subset(),
340 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
341 }
342
robertphillips64612512016-04-08 12:10:42 -0700343 bool onGetROPixels(SkBitmap* bm) const override {
344 *bm = fBitmap;
robertphillips3b087f42016-02-18 08:48:03 -0800345 return true;
346 }
347
robertphillips64612512016-04-08 12:10:42 -0700348#if SK_SUPPORT_GPU
robertphillipsc91fd342016-04-25 12:32:54 -0700349 sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
robertphillips64612512016-04-08 12:10:42 -0700350 if (context) {
robertphillipsc91fd342016-04-25 12:32:54 -0700351 return sk_ref_sp(GrRefCachedBitmapTexture(context,
352 fBitmap,
brianosman982eb7f2016-06-06 13:10:58 -0700353 GrTextureParams::ClampNoFilter(),
354 SkSourceGammaTreatment::kRespect));
robertphillips64612512016-04-08 12:10:42 -0700355 }
robertphillips64612512016-04-08 12:10:42 -0700356
357 return nullptr;
358 }
robertphillipsc91fd342016-04-25 12:32:54 -0700359#endif
robertphillips64612512016-04-08 12:10:42 -0700360
361 bool getBitmapDeprecated(SkBitmap* result) const override {
robertphillips4418dba2016-03-07 12:45:14 -0800362 *result = fBitmap;
363 return true;
364 }
365
robertphillips37bd7c32016-03-17 14:31:39 -0700366 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
robertphillips3e302272016-04-20 11:48:36 -0700367 return SkSpecialSurface::MakeRaster(info, nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -0800368 }
369
robertphillips37bd7c32016-03-17 14:31:39 -0700370 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
robertphillipsc5035e72016-03-17 06:58:39 -0700371 SkBitmap subsetBM;
halcanary9d524f22016-03-29 09:03:52 -0700372
robertphillipsc5035e72016-03-17 06:58:39 -0700373 if (!fBitmap.extractSubset(&subsetBM, subset)) {
374 return nullptr;
375 }
376
robertphillips3e302272016-04-20 11:48:36 -0700377 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
brianosman898235c2016-04-06 07:38:23 -0700378 subsetBM,
379 &this->props());
robertphillipsc5035e72016-03-17 06:58:39 -0700380 }
381
robertphillipsb4bd11e2016-03-21 13:44:18 -0700382 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
383 SkBitmap subsetBM;
384
385 if (!fBitmap.extractSubset(&subsetBM, subset)) {
386 return nullptr;
387 }
388
389 return SkImage::MakeFromBitmap(subsetBM);
390 }
391
reede8f30622016-03-23 18:59:25 -0700392 sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override {
393 return SkSurface::MakeRaster(info);
robertphillipsb4bd11e2016-03-21 13:44:18 -0700394 }
395
robertphillipsb6c65e92016-02-04 10:52:42 -0800396private:
397 SkBitmap fBitmap;
398
399 typedef SkSpecialImage_Base INHERITED;
400};
401
robertphillips3e302272016-04-20 11:48:36 -0700402sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
brianosman898235c2016-04-06 07:38:23 -0700403 const SkBitmap& bm,
404 const SkSurfaceProps* props) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800405 SkASSERT(nullptr == bm.getTexture());
406 SkASSERT(rect_fits(subset, bm.width(), bm.height()));
robertphillips37bd7c32016-03-17 14:31:39 -0700407
reeda2217ef2016-07-20 06:04:34 -0700408 const SkBitmap* srcBM = &bm;
409 SkBitmap tmpStorage;
410 // ImageFilters only handle N32 at the moment, so force our src to be that
411 if (!valid_for_imagefilters(bm.info())) {
412 if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
413 return nullptr;
414 }
415 srcBM = &tmpStorage;
416 }
417 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800418}
419
420#if SK_SUPPORT_GPU
421///////////////////////////////////////////////////////////////////////////////
robertphillipsed086ca2016-04-26 15:02:25 -0700422#include "GrTexture.h"
robertphillipsb4bd11e2016-03-21 13:44:18 -0700423#include "SkImage_Gpu.h"
robertphillipsb6c65e92016-02-04 10:52:42 -0800424
robertphillipsed086ca2016-04-26 15:02:25 -0700425class SkSpecialImage_Gpu : public SkSpecialImage_Base {
426public:
427 SkSpecialImage_Gpu(const SkIRect& subset,
428 uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
429 const SkSurfaceProps* props)
430 : INHERITED(subset, uniqueID, props)
431 , fTexture(std::move(tex))
432 , fAlphaType(at)
433 , fAddedRasterVersionToCache(false) {
434 }
435
436 ~SkSpecialImage_Gpu() override {
437 if (fAddedRasterVersionToCache.load()) {
438 SkNotifyBitmapGenIDIsStale(this->uniqueID());
439 }
440 }
441
442 bool isOpaque() const override {
443 return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
444 }
445
446 size_t getSize() const override { return fTexture->gpuMemorySize(); }
447
448 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
449 SkRect dst = SkRect::MakeXYWH(x, y,
450 this->subset().width(), this->subset().height());
451
reed77d6f7d2016-07-13 12:24:48 -0700452 auto img = sk_sp<SkImage>(new SkImage_Gpu(fTexture->width(), fTexture->height(),
453 this->uniqueID(), fAlphaType, fTexture.get(),
454 SkBudgeted::kNo));
robertphillipsed086ca2016-04-26 15:02:25 -0700455
reed77d6f7d2016-07-13 12:24:48 -0700456 canvas->drawImageRect(img, this->subset(),
robertphillipsed086ca2016-04-26 15:02:25 -0700457 dst, paint, SkCanvas::kStrict_SrcRectConstraint);
458 }
459
460 GrTexture* onPeekTexture() const override { return fTexture.get(); }
461
462 sk_sp<GrTexture> onAsTextureRef(GrContext*) const override { return fTexture; }
463
464 bool onGetROPixels(SkBitmap* dst) const override {
465 if (SkBitmapCache::Find(this->uniqueID(), dst)) {
466 SkASSERT(dst->getGenerationID() == this->uniqueID());
467 SkASSERT(dst->isImmutable());
468 SkASSERT(dst->getPixels());
469 return true;
470 }
471
472 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
473 this->isOpaque() ? kOpaque_SkAlphaType
474 : kPremul_SkAlphaType);
475
476 if (!dst->tryAllocPixels(info)) {
477 return false;
478 }
479
480 if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
481 dst->getPixels(), dst->rowBytes())) {
482 return false;
483 }
484
485 dst->pixelRef()->setImmutableWithID(this->uniqueID());
486 SkBitmapCache::Add(this->uniqueID(), *dst);
487 fAddedRasterVersionToCache.store(true);
488 return true;
489 }
490
491 bool getBitmapDeprecated(SkBitmap* result) const override {
492 const SkImageInfo info = GrMakeInfoFromTexture(fTexture.get(),
493 this->width(), this->height(),
494 this->isOpaque());
495 if (!result->setInfo(info)) {
496 return false;
497 }
498
499 const SkImageInfo prInfo = info.makeWH(fTexture->width(), fTexture->height());
500
501 SkAutoTUnref<SkGrPixelRef> pixelRef(new SkGrPixelRef(prInfo, fTexture.get()));
502 result->setPixelRef(pixelRef, this->subset().fLeft, this->subset().fTop);
503 return true;
504 }
505
506 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
507 if (!fTexture->getContext()) {
508 return nullptr;
509 }
510
robertphillips4df16562016-04-28 15:09:34 -0700511 GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *fTexture->getContext()->caps());
robertphillipsed086ca2016-04-26 15:02:25 -0700512
robertphillips4df16562016-04-28 15:09:34 -0700513 return SkSpecialSurface::MakeRenderTarget(fTexture->getContext(),
514 info.width(), info.height(),
515 config);
robertphillipsed086ca2016-04-26 15:02:25 -0700516 }
517
518 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
519 return SkSpecialImage::MakeFromGpu(subset,
520 this->uniqueID(),
521 fTexture,
522 &this->props(),
523 fAlphaType);
524 }
525
526 sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
527 if (0 == subset.fLeft && 0 == subset.fTop &&
528 fTexture->width() == subset.width() &&
529 fTexture->height() == subset.height()) {
530 // The existing GrTexture is already tight so reuse it in the SkImage
531 return sk_make_sp<SkImage_Gpu>(fTexture->width(), fTexture->height(),
532 kNeedNewImageUniqueID,
533 fAlphaType, fTexture.get(), SkBudgeted::kYes);
534 }
535
536 GrContext* ctx = fTexture->getContext();
537 GrSurfaceDesc desc = fTexture->desc();
538 desc.fWidth = subset.width();
539 desc.fHeight = subset.height();
540
541 sk_sp<GrTexture> subTx(ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes));
542 if (!subTx) {
543 return nullptr;
544 }
545 ctx->copySurface(subTx.get(), fTexture.get(), subset, SkIPoint::Make(0, 0));
546 return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
547 fAlphaType, subTx.get(), SkBudgeted::kYes);
548 }
549
550 sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override {
551 return SkSurface::MakeRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info);
552 }
553
554private:
555 sk_sp<GrTexture> fTexture;
556 const SkAlphaType fAlphaType;
557 mutable SkAtomic<bool> fAddedRasterVersionToCache;
558
559 typedef SkSpecialImage_Base INHERITED;
560};
561
robertphillips3e302272016-04-20 11:48:36 -0700562sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
robertphillips37bd7c32016-03-17 14:31:39 -0700563 uint32_t uniqueID,
robertphillipsc91fd342016-04-25 12:32:54 -0700564 sk_sp<GrTexture> tex,
brianosman898235c2016-04-06 07:38:23 -0700565 const SkSurfaceProps* props,
robertphillips37bd7c32016-03-17 14:31:39 -0700566 SkAlphaType at) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800567 SkASSERT(rect_fits(subset, tex->width(), tex->height()));
robertphillipsed086ca2016-04-26 15:02:25 -0700568 return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at, props);
robertphillipsb6c65e92016-02-04 10:52:42 -0800569}
570
571#endif