blob: 0e39d3b997c0a9ff4dbc8f802c98387f0cfcc952 [file] [log] [blame]
reedd5b75632015-08-13 09:37:45 -07001/*
2 * Copyright 2015 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 */
7
8#include "gm.h"
9#include "SkCanvas.h"
10#include "SkImage.h"
Brian Osmandf7e0752017-04-26 16:20:28 -040011#include "SkImageGenerator.h"
Brian Osmana28e2b02017-04-24 16:44:03 -040012#include "SkImage_Base.h"
Mike Reed185130c2017-02-15 15:14:16 -050013#include "SkMakeUnique.h"
reedd5b75632015-08-13 09:37:45 -070014#include "SkPictureRecorder.h"
reed8f343722015-08-13 13:32:39 -070015#include "SkSurface.h"
reedd5b75632015-08-13 09:37:45 -070016
17#if SK_SUPPORT_GPU
18#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050019#include "GrContextPriv.h"
20#include "GrSurfaceContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050021#include "GrTextureProxy.h"
reed8f343722015-08-13 13:32:39 -070022#include "../src/image/SkImage_Gpu.h"
reedd5b75632015-08-13 09:37:45 -070023#endif
24
25static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
26 SkPaint paint;
27 paint.setAntiAlias(true);
28 paint.setColor(SK_ColorRED);
29 paint.setStyle(SkPaint::kStroke_Style);
30 paint.setStrokeWidth(10);
31 canvas->drawRect(bounds, paint);
32 paint.setStyle(SkPaint::kFill_Style);
33 paint.setColor(SK_ColorBLUE);
34 canvas->drawOval(bounds, paint);
35}
36
37/*
38 * Exercise drawing pictures inside an image, showing that the image version is pixelated
39 * (correctly) when it is inside an image.
40 */
41class ImagePictGM : public skiagm::GM {
reedca2622b2016-03-18 07:25:55 -070042 sk_sp<SkPicture> fPicture;
reed9ce9d672016-03-17 10:51:11 -070043 sk_sp<SkImage> fImage0;
44 sk_sp<SkImage> fImage1;
reedd5b75632015-08-13 09:37:45 -070045public:
46 ImagePictGM() {}
47
48protected:
49 SkString onShortName() override {
50 return SkString("image-picture");
51 }
52
53 SkISize onISize() override {
54 return SkISize::Make(850, 450);
55 }
56
57 void onOnceBeforeDraw() override {
58 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
59 SkPictureRecorder recorder;
60 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -070061 fPicture = recorder.finishRecordingAsPicture();
reedd5b75632015-08-13 09:37:45 -070062
63 // extract enough just for the oval.
64 const SkISize size = SkISize::Make(100, 100);
Matt Sarett77a7a1b2017-02-07 13:56:11 -050065 auto srgbColorSpace = SkColorSpace::MakeSRGB();
reedd5b75632015-08-13 09:37:45 -070066
67 SkMatrix matrix;
68 matrix.setTranslate(-100, -100);
Matt Sarette94255d2017-01-09 12:38:59 -050069 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
70 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070071 matrix.postTranslate(-50, -50);
72 matrix.postRotate(45);
73 matrix.postTranslate(50, 50);
Matt Sarette94255d2017-01-09 12:38:59 -050074 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
75 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070076 }
77
78 void drawSet(SkCanvas* canvas) const {
79 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
80 canvas->drawPicture(fPicture, &matrix, nullptr);
reed9ce9d672016-03-17 10:51:11 -070081 canvas->drawImage(fImage0.get(), 150, 0);
82 canvas->drawImage(fImage1.get(), 300, 0);
reedd5b75632015-08-13 09:37:45 -070083 }
84
85 void onDraw(SkCanvas* canvas) override {
86 canvas->translate(20, 20);
87
88 this->drawSet(canvas);
89
90 canvas->save();
91 canvas->translate(0, 130);
92 canvas->scale(0.25f, 0.25f);
93 this->drawSet(canvas);
94 canvas->restore();
95
96 canvas->save();
97 canvas->translate(0, 200);
98 canvas->scale(2, 2);
99 this->drawSet(canvas);
100 canvas->restore();
101 }
102
103private:
104 typedef skiagm::GM INHERITED;
105};
106DEF_GM( return new ImagePictGM; )
107
reed8f343722015-08-13 13:32:39 -0700108///////////////////////////////////////////////////////////////////////////////////////////////////
109
Mike Reed185130c2017-02-15 15:14:16 -0500110static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700111 SkMatrix matrix;
112 matrix.setTranslate(-100, -100);
Mike Reed185130c2017-02-15 15:14:16 -0500113 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
Matt Sarette94255d2017-01-09 12:38:59 -0500114 SkImage::BitDepth::kU8,
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500115 SkColorSpace::MakeSRGB());
reed935d6cf2015-08-18 11:16:09 -0700116}
117
118class RasterGenerator : public SkImageGenerator {
119public:
Mike Reed4edb5d22017-04-17 11:02:51 -0400120 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
121 {}
122
reed935d6cf2015-08-18 11:16:09 -0700123protected:
124 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400125 const Options&) override {
reedc4a83e22015-09-11 11:47:27 -0700126 SkASSERT(fBM.width() == info.width());
127 SkASSERT(fBM.height() == info.height());
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400128 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
reed935d6cf2015-08-18 11:16:09 -0700129 }
130private:
131 SkBitmap fBM;
132};
Mike Reed185130c2017-02-15 15:14:16 -0500133static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700134 SkBitmap bm;
135 bm.allocN32Pixels(100, 100);
136 SkCanvas canvas(bm);
137 canvas.clear(0);
138 canvas.translate(-100, -100);
139 canvas.drawPicture(pic);
Mike Reed185130c2017-02-15 15:14:16 -0500140 return skstd::make_unique<RasterGenerator>(bm);
reed935d6cf2015-08-18 11:16:09 -0700141}
142
143class EmptyGenerator : public SkImageGenerator {
144public:
145 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
146};
147
148#if SK_SUPPORT_GPU
149class TextureGenerator : public SkImageGenerator {
150public:
Mike Reed185130c2017-02-15 15:14:16 -0500151 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
reed935d6cf2015-08-18 11:16:09 -0700152 : SkImageGenerator(info)
Robert Phillipse2f7d182016-12-15 09:23:05 -0500153 , fCtx(SkRef(ctx)) {
154
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400155 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
Robert Phillipse44ef102017-07-21 15:37:19 -0400156 kTopLeft_GrSurfaceOrigin, nullptr));
scroggoe6f0d6e2016-05-13 07:25:44 -0700157 if (surface) {
158 surface->getCanvas()->clear(0);
159 surface->getCanvas()->translate(-100, -100);
160 surface->getCanvas()->drawPicture(pic);
161 sk_sp<SkImage> image(surface->makeImageSnapshot());
Robert Phillips6de99042017-01-31 11:31:39 -0500162 fProxy = as_IB(image)->asTextureProxyRef();
scroggoe6f0d6e2016-05-13 07:25:44 -0700163 }
reed935d6cf2015-08-18 11:16:09 -0700164 }
165protected:
Robert Phillips4447b642017-03-03 11:10:18 -0500166 sk_sp<GrTextureProxy> onGenerateTexture(GrContext* ctx, const SkImageInfo& info,
Christopher Cameron77e96662017-07-08 01:47:47 -0700167 const SkIPoint& origin,
Greg Danielf88c12e2017-10-09 09:57:35 -0400168 SkTransferFunctionBehavior,
169 bool willBeMipped) override {
Robert Phillips4447b642017-03-03 11:10:18 -0500170 SkASSERT(ctx);
171 SkASSERT(ctx == fCtx.get());
reed935d6cf2015-08-18 11:16:09 -0700172
Robert Phillipse2f7d182016-12-15 09:23:05 -0500173 if (!fProxy) {
scroggoe6f0d6e2016-05-13 07:25:44 -0700174 return nullptr;
175 }
176
Robert Phillipse2f7d182016-12-15 09:23:05 -0500177 if (origin.fX == 0 && origin.fY == 0 &&
178 info.width() == fProxy->width() && info.height() == fProxy->height()) {
Robert Phillips4447b642017-03-03 11:10:18 -0500179 return fProxy;
Robert Phillipse2f7d182016-12-15 09:23:05 -0500180 }
181
reed935d6cf2015-08-18 11:16:09 -0700182 // need to copy the subset into a new texture
Brian Salomon63e79732017-05-15 21:23:13 -0400183 GrSurfaceDesc desc;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400184 desc.fOrigin = fProxy->origin();
Brian Osman222e9ad2016-12-14 15:42:36 -0500185 desc.fWidth = info.width();
186 desc.fHeight = info.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400187 desc.fConfig = fProxy->config();
reed935d6cf2015-08-18 11:16:09 -0700188
Robert Phillipse2f7d182016-12-15 09:23:05 -0500189 sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
190 desc,
191 SkBackingFit::kExact,
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400192 SkBudgeted::kYes));
Robert Phillipse2f7d182016-12-15 09:23:05 -0500193 if (!dstContext) {
194 return nullptr;
195 }
196
197 if (!dstContext->copy(
198 fProxy.get(),
199 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
200 SkIPoint::Make(0, 0))) {
201 return nullptr;
202 }
203
Robert Phillips4447b642017-03-03 11:10:18 -0500204 return dstContext->asTextureProxyRef();
reed935d6cf2015-08-18 11:16:09 -0700205 }
Robert Phillips4447b642017-03-03 11:10:18 -0500206
reed935d6cf2015-08-18 11:16:09 -0700207private:
Robert Phillipse2f7d182016-12-15 09:23:05 -0500208 sk_sp<GrContext> fCtx;
Robert Phillips4447b642017-03-03 11:10:18 -0500209 sk_sp<GrTextureProxy> fProxy;
reed935d6cf2015-08-18 11:16:09 -0700210};
Robert Phillips4447b642017-03-03 11:10:18 -0500211
Mike Reed185130c2017-02-15 15:14:16 -0500212static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700213 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
214
215 if (!ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500216 return skstd::make_unique<EmptyGenerator>(info);
reed935d6cf2015-08-18 11:16:09 -0700217 }
Mike Reed185130c2017-02-15 15:14:16 -0500218 return skstd::make_unique<TextureGenerator>(ctx, info, pic);
reed935d6cf2015-08-18 11:16:09 -0700219}
220#endif
reed8f343722015-08-13 13:32:39 -0700221
222class ImageCacheratorGM : public skiagm::GM {
reed935d6cf2015-08-18 11:16:09 -0700223 SkString fName;
Mike Reed185130c2017-02-15 15:14:16 -0500224 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
reedca2622b2016-03-18 07:25:55 -0700225 sk_sp<SkPicture> fPicture;
Brian Osmana28e2b02017-04-24 16:44:03 -0400226 sk_sp<SkImage> fImage;
227 sk_sp<SkImage> fImageSubset;
reed8f343722015-08-13 13:32:39 -0700228
229public:
Mike Reed185130c2017-02-15 15:14:16 -0500230 ImageCacheratorGM(const char suffix[],
231 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
reed935d6cf2015-08-18 11:16:09 -0700232 : fFactory(factory)
233 {
234 fName.printf("image-cacherator-from-%s", suffix);
235 }
reed8f343722015-08-13 13:32:39 -0700236
237protected:
238 SkString onShortName() override {
reed935d6cf2015-08-18 11:16:09 -0700239 return fName;
reed8f343722015-08-13 13:32:39 -0700240 }
241
242 SkISize onISize() override {
reeda32cc952015-08-19 06:07:29 -0700243 return SkISize::Make(960, 450);
reed8f343722015-08-13 13:32:39 -0700244 }
245
246 void onOnceBeforeDraw() override {
247 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
248 SkPictureRecorder recorder;
249 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -0700250 fPicture = recorder.finishRecordingAsPicture();
reed935d6cf2015-08-18 11:16:09 -0700251 }
reed8f343722015-08-13 13:32:39 -0700252
reed935d6cf2015-08-18 11:16:09 -0700253 void makeCaches(GrContext* ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500254 auto gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400255 fImage = SkImage::MakeFromGenerator(std::move(gen));
reed935d6cf2015-08-18 11:16:09 -0700256
257 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
258
Mike Reed185130c2017-02-15 15:14:16 -0500259 gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400260 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
reed935d6cf2015-08-18 11:16:09 -0700261
Brian Osmandf7e0752017-04-26 16:20:28 -0400262 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
263 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
reed935d6cf2015-08-18 11:16:09 -0700264 }
265
Brian Osmana28e2b02017-04-24 16:44:03 -0400266 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
reed935d6cf2015-08-18 11:16:09 -0700267 SkBitmap bitmap;
Brian Osmana28e2b02017-04-24 16:44:03 -0400268 as_IB(image)->getROPixels(&bitmap, canvas->imageInfo().colorSpace());
reed935d6cf2015-08-18 11:16:09 -0700269 canvas->drawBitmap(bitmap, x, y);
270 }
271
Brian Osmana28e2b02017-04-24 16:44:03 -0400272 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
reed935d6cf2015-08-18 11:16:09 -0700273#if SK_SUPPORT_GPU
Brian Osman7992da32016-11-18 11:28:24 -0500274 sk_sp<SkColorSpace> texColorSpace;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400275 sk_sp<GrTextureProxy> proxy(as_IB(image)->asTextureProxyRef(
276 canvas->getGrContext(), GrSamplerState::ClampBilerp(),
277 canvas->imageInfo().colorSpace(), &texColorSpace, nullptr));
Robert Phillips4f358be2017-03-23 08:21:00 -0400278 if (!proxy) {
reeda32cc952015-08-19 06:07:29 -0700279 // show placeholder if we have no texture
280 SkPaint paint;
281 paint.setStyle(SkPaint::kStroke_Style);
Brian Osmana28e2b02017-04-24 16:44:03 -0400282 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
283 SkIntToScalar(image->width()));
reeda32cc952015-08-19 06:07:29 -0700284 canvas->drawRect(r, paint);
285 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
286 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
reed935d6cf2015-08-18 11:16:09 -0700287 return;
288 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400289
reed935d6cf2015-08-18 11:16:09 -0700290 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
Brian Osmana28e2b02017-04-24 16:44:03 -0400291 sk_sp<SkImage> texImage(new SkImage_Gpu(canvas->getGrContext(), image->uniqueID(),
292 kPremul_SkAlphaType, std::move(proxy),
293 std::move(texColorSpace), SkBudgeted::kNo));
294 canvas->drawImage(texImage.get(), x, y);
reed935d6cf2015-08-18 11:16:09 -0700295#endif
reed8f343722015-08-13 13:32:39 -0700296 }
297
298 void drawSet(SkCanvas* canvas) const {
299 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
300 canvas->drawPicture(fPicture, &matrix, nullptr);
301
reed935d6cf2015-08-18 11:16:09 -0700302 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
303 // way we also can force the generateTexture call.
304
Brian Osmana28e2b02017-04-24 16:44:03 -0400305 draw_as_tex(canvas, fImage.get(), 310, 0);
306 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
reed935d6cf2015-08-18 11:16:09 -0700307
Brian Osmana28e2b02017-04-24 16:44:03 -0400308 draw_as_bitmap(canvas, fImage.get(), 150, 0);
309 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
reed8f343722015-08-13 13:32:39 -0700310 }
311
312 void onDraw(SkCanvas* canvas) override {
reed935d6cf2015-08-18 11:16:09 -0700313 this->makeCaches(canvas->getGrContext());
314
reed8f343722015-08-13 13:32:39 -0700315 canvas->translate(20, 20);
316
317 this->drawSet(canvas);
318
319 canvas->save();
320 canvas->translate(0, 130);
321 canvas->scale(0.25f, 0.25f);
322 this->drawSet(canvas);
323 canvas->restore();
324
325 canvas->save();
326 canvas->translate(0, 200);
327 canvas->scale(2, 2);
328 this->drawSet(canvas);
329 canvas->restore();
330 }
331
332private:
333 typedef skiagm::GM INHERITED;
334};
reed935d6cf2015-08-18 11:16:09 -0700335DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
336DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
337#if SK_SUPPORT_GPU
338 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
339#endif