blob: 7081f196215ecfff0b4163a79c9f5763f3651751 [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
reedd5b75632015-08-13 09:37:45 -070017#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050018#include "GrContextPriv.h"
19#include "GrSurfaceContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050020#include "GrTextureProxy.h"
reed8f343722015-08-13 13:32:39 -070021#include "../src/image/SkImage_Gpu.h"
reedd5b75632015-08-13 09:37:45 -070022
23static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
24 SkPaint paint;
25 paint.setAntiAlias(true);
26 paint.setColor(SK_ColorRED);
27 paint.setStyle(SkPaint::kStroke_Style);
28 paint.setStrokeWidth(10);
29 canvas->drawRect(bounds, paint);
30 paint.setStyle(SkPaint::kFill_Style);
31 paint.setColor(SK_ColorBLUE);
32 canvas->drawOval(bounds, paint);
33}
34
35/*
36 * Exercise drawing pictures inside an image, showing that the image version is pixelated
37 * (correctly) when it is inside an image.
38 */
39class ImagePictGM : public skiagm::GM {
reedca2622b2016-03-18 07:25:55 -070040 sk_sp<SkPicture> fPicture;
reed9ce9d672016-03-17 10:51:11 -070041 sk_sp<SkImage> fImage0;
42 sk_sp<SkImage> fImage1;
reedd5b75632015-08-13 09:37:45 -070043public:
44 ImagePictGM() {}
45
46protected:
47 SkString onShortName() override {
48 return SkString("image-picture");
49 }
50
51 SkISize onISize() override {
52 return SkISize::Make(850, 450);
53 }
54
55 void onOnceBeforeDraw() override {
56 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
57 SkPictureRecorder recorder;
58 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -070059 fPicture = recorder.finishRecordingAsPicture();
reedd5b75632015-08-13 09:37:45 -070060
61 // extract enough just for the oval.
62 const SkISize size = SkISize::Make(100, 100);
Matt Sarett77a7a1b2017-02-07 13:56:11 -050063 auto srgbColorSpace = SkColorSpace::MakeSRGB();
reedd5b75632015-08-13 09:37:45 -070064
65 SkMatrix matrix;
66 matrix.setTranslate(-100, -100);
Matt Sarette94255d2017-01-09 12:38:59 -050067 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
68 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070069 matrix.postTranslate(-50, -50);
70 matrix.postRotate(45);
71 matrix.postTranslate(50, 50);
Matt Sarette94255d2017-01-09 12:38:59 -050072 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
73 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070074 }
75
76 void drawSet(SkCanvas* canvas) const {
77 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
78 canvas->drawPicture(fPicture, &matrix, nullptr);
reed9ce9d672016-03-17 10:51:11 -070079 canvas->drawImage(fImage0.get(), 150, 0);
80 canvas->drawImage(fImage1.get(), 300, 0);
reedd5b75632015-08-13 09:37:45 -070081 }
82
83 void onDraw(SkCanvas* canvas) override {
84 canvas->translate(20, 20);
85
86 this->drawSet(canvas);
87
88 canvas->save();
89 canvas->translate(0, 130);
90 canvas->scale(0.25f, 0.25f);
91 this->drawSet(canvas);
92 canvas->restore();
93
94 canvas->save();
95 canvas->translate(0, 200);
96 canvas->scale(2, 2);
97 this->drawSet(canvas);
98 canvas->restore();
99 }
100
101private:
102 typedef skiagm::GM INHERITED;
103};
104DEF_GM( return new ImagePictGM; )
105
reed8f343722015-08-13 13:32:39 -0700106///////////////////////////////////////////////////////////////////////////////////////////////////
107
Mike Reed185130c2017-02-15 15:14:16 -0500108static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700109 SkMatrix matrix;
110 matrix.setTranslate(-100, -100);
Mike Reed185130c2017-02-15 15:14:16 -0500111 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
Matt Sarette94255d2017-01-09 12:38:59 -0500112 SkImage::BitDepth::kU8,
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500113 SkColorSpace::MakeSRGB());
reed935d6cf2015-08-18 11:16:09 -0700114}
115
116class RasterGenerator : public SkImageGenerator {
117public:
Mike Reed4edb5d22017-04-17 11:02:51 -0400118 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
119 {}
120
reed935d6cf2015-08-18 11:16:09 -0700121protected:
122 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400123 const Options&) override {
reedc4a83e22015-09-11 11:47:27 -0700124 SkASSERT(fBM.width() == info.width());
125 SkASSERT(fBM.height() == info.height());
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400126 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
reed935d6cf2015-08-18 11:16:09 -0700127 }
128private:
129 SkBitmap fBM;
130};
Mike Reed185130c2017-02-15 15:14:16 -0500131static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700132 SkBitmap bm;
133 bm.allocN32Pixels(100, 100);
134 SkCanvas canvas(bm);
135 canvas.clear(0);
136 canvas.translate(-100, -100);
137 canvas.drawPicture(pic);
Mike Reed185130c2017-02-15 15:14:16 -0500138 return skstd::make_unique<RasterGenerator>(bm);
reed935d6cf2015-08-18 11:16:09 -0700139}
140
141class EmptyGenerator : public SkImageGenerator {
142public:
143 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
144};
145
reed935d6cf2015-08-18 11:16:09 -0700146class TextureGenerator : public SkImageGenerator {
147public:
Mike Reed185130c2017-02-15 15:14:16 -0500148 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
reed935d6cf2015-08-18 11:16:09 -0700149 : SkImageGenerator(info)
Robert Phillipse2f7d182016-12-15 09:23:05 -0500150 , fCtx(SkRef(ctx)) {
151
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400152 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
Robert Phillipse44ef102017-07-21 15:37:19 -0400153 kTopLeft_GrSurfaceOrigin, nullptr));
scroggoe6f0d6e2016-05-13 07:25:44 -0700154 if (surface) {
155 surface->getCanvas()->clear(0);
156 surface->getCanvas()->translate(-100, -100);
157 surface->getCanvas()->drawPicture(pic);
158 sk_sp<SkImage> image(surface->makeImageSnapshot());
Robert Phillips6de99042017-01-31 11:31:39 -0500159 fProxy = as_IB(image)->asTextureProxyRef();
scroggoe6f0d6e2016-05-13 07:25:44 -0700160 }
reed935d6cf2015-08-18 11:16:09 -0700161 }
162protected:
Robert Phillips4447b642017-03-03 11:10:18 -0500163 sk_sp<GrTextureProxy> onGenerateTexture(GrContext* ctx, const SkImageInfo& info,
Christopher Cameron77e96662017-07-08 01:47:47 -0700164 const SkIPoint& origin,
Greg Danielf88c12e2017-10-09 09:57:35 -0400165 bool willBeMipped) override {
Robert Phillips4447b642017-03-03 11:10:18 -0500166 SkASSERT(ctx);
167 SkASSERT(ctx == fCtx.get());
reed935d6cf2015-08-18 11:16:09 -0700168
Robert Phillipse2f7d182016-12-15 09:23:05 -0500169 if (!fProxy) {
scroggoe6f0d6e2016-05-13 07:25:44 -0700170 return nullptr;
171 }
172
Robert Phillipse2f7d182016-12-15 09:23:05 -0500173 if (origin.fX == 0 && origin.fY == 0 &&
174 info.width() == fProxy->width() && info.height() == fProxy->height()) {
Robert Phillips4447b642017-03-03 11:10:18 -0500175 return fProxy;
Robert Phillipse2f7d182016-12-15 09:23:05 -0500176 }
177
reed935d6cf2015-08-18 11:16:09 -0700178 // need to copy the subset into a new texture
Brian Salomon63e79732017-05-15 21:23:13 -0400179 GrSurfaceDesc desc;
Brian Osman222e9ad2016-12-14 15:42:36 -0500180 desc.fWidth = info.width();
181 desc.fHeight = info.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400182 desc.fConfig = fProxy->config();
reed935d6cf2015-08-18 11:16:09 -0700183
Greg Daniel65c7f662017-10-30 13:39:09 -0400184 GrMipMapped mipMapped = willBeMipped ? GrMipMapped::kYes : GrMipMapped::kNo;
185
Robert Phillipse2f7d182016-12-15 09:23:05 -0500186 sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
Brian Salomon2a4f9832018-03-03 22:43:43 -0500187 desc, fProxy->origin(), mipMapped, SkBackingFit::kExact, SkBudgeted::kYes));
Robert Phillipse2f7d182016-12-15 09:23:05 -0500188 if (!dstContext) {
189 return nullptr;
190 }
191
192 if (!dstContext->copy(
193 fProxy.get(),
194 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
195 SkIPoint::Make(0, 0))) {
196 return nullptr;
197 }
198
Robert Phillips4447b642017-03-03 11:10:18 -0500199 return dstContext->asTextureProxyRef();
reed935d6cf2015-08-18 11:16:09 -0700200 }
Robert Phillips4447b642017-03-03 11:10:18 -0500201
reed935d6cf2015-08-18 11:16:09 -0700202private:
Robert Phillipse2f7d182016-12-15 09:23:05 -0500203 sk_sp<GrContext> fCtx;
Robert Phillips4447b642017-03-03 11:10:18 -0500204 sk_sp<GrTextureProxy> fProxy;
reed935d6cf2015-08-18 11:16:09 -0700205};
Robert Phillips4447b642017-03-03 11:10:18 -0500206
Mike Reed185130c2017-02-15 15:14:16 -0500207static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700208 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
209
210 if (!ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500211 return skstd::make_unique<EmptyGenerator>(info);
reed935d6cf2015-08-18 11:16:09 -0700212 }
Mike Reed185130c2017-02-15 15:14:16 -0500213 return skstd::make_unique<TextureGenerator>(ctx, info, pic);
reed935d6cf2015-08-18 11:16:09 -0700214}
reed8f343722015-08-13 13:32:39 -0700215
216class ImageCacheratorGM : public skiagm::GM {
reed935d6cf2015-08-18 11:16:09 -0700217 SkString fName;
Mike Reed185130c2017-02-15 15:14:16 -0500218 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
reedca2622b2016-03-18 07:25:55 -0700219 sk_sp<SkPicture> fPicture;
Brian Osmana28e2b02017-04-24 16:44:03 -0400220 sk_sp<SkImage> fImage;
221 sk_sp<SkImage> fImageSubset;
reed8f343722015-08-13 13:32:39 -0700222
223public:
Mike Reed185130c2017-02-15 15:14:16 -0500224 ImageCacheratorGM(const char suffix[],
225 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
reed935d6cf2015-08-18 11:16:09 -0700226 : fFactory(factory)
227 {
228 fName.printf("image-cacherator-from-%s", suffix);
229 }
reed8f343722015-08-13 13:32:39 -0700230
231protected:
232 SkString onShortName() override {
reed935d6cf2015-08-18 11:16:09 -0700233 return fName;
reed8f343722015-08-13 13:32:39 -0700234 }
235
236 SkISize onISize() override {
reeda32cc952015-08-19 06:07:29 -0700237 return SkISize::Make(960, 450);
reed8f343722015-08-13 13:32:39 -0700238 }
239
240 void onOnceBeforeDraw() override {
241 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
242 SkPictureRecorder recorder;
243 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -0700244 fPicture = recorder.finishRecordingAsPicture();
reed935d6cf2015-08-18 11:16:09 -0700245 }
reed8f343722015-08-13 13:32:39 -0700246
reed935d6cf2015-08-18 11:16:09 -0700247 void makeCaches(GrContext* ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500248 auto gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400249 fImage = SkImage::MakeFromGenerator(std::move(gen));
reed935d6cf2015-08-18 11:16:09 -0700250
251 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
252
Mike Reed185130c2017-02-15 15:14:16 -0500253 gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400254 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
reed935d6cf2015-08-18 11:16:09 -0700255
Brian Osmandf7e0752017-04-26 16:20:28 -0400256 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
257 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
reed935d6cf2015-08-18 11:16:09 -0700258 }
259
Brian Osmana28e2b02017-04-24 16:44:03 -0400260 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
reed935d6cf2015-08-18 11:16:09 -0700261 SkBitmap bitmap;
Brian Osmane50cdf02018-10-19 13:02:14 -0400262 as_IB(image)->getROPixels(&bitmap);
reed935d6cf2015-08-18 11:16:09 -0700263 canvas->drawBitmap(bitmap, x, y);
264 }
265
Brian Osmana28e2b02017-04-24 16:44:03 -0400266 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400267 sk_sp<GrTextureProxy> proxy(as_IB(image)->asTextureProxyRef(
Brian Osman6064e1c2018-10-19 14:27:54 -0400268 canvas->getGrContext(), GrSamplerState::ClampBilerp(), nullptr));
Robert Phillips4f358be2017-03-23 08:21:00 -0400269 if (!proxy) {
reeda32cc952015-08-19 06:07:29 -0700270 // show placeholder if we have no texture
271 SkPaint paint;
272 paint.setStyle(SkPaint::kStroke_Style);
Brian Osmana28e2b02017-04-24 16:44:03 -0400273 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
274 SkIntToScalar(image->width()));
reeda32cc952015-08-19 06:07:29 -0700275 canvas->drawRect(r, paint);
276 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
277 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
reed935d6cf2015-08-18 11:16:09 -0700278 return;
279 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400280
reed935d6cf2015-08-18 11:16:09 -0700281 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
Brian Salomon8a8dd332018-05-24 14:08:31 -0400282 sk_sp<SkImage> texImage(new SkImage_Gpu(
283 sk_ref_sp(canvas->getGrContext()), image->uniqueID(), kPremul_SkAlphaType,
Brian Osman6064e1c2018-10-19 14:27:54 -0400284 std::move(proxy), image->refColorSpace(), SkBudgeted::kNo));
Brian Osmana28e2b02017-04-24 16:44:03 -0400285 canvas->drawImage(texImage.get(), x, y);
reed8f343722015-08-13 13:32:39 -0700286 }
287
288 void drawSet(SkCanvas* canvas) const {
289 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
290 canvas->drawPicture(fPicture, &matrix, nullptr);
291
reed935d6cf2015-08-18 11:16:09 -0700292 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
293 // way we also can force the generateTexture call.
294
Brian Osmana28e2b02017-04-24 16:44:03 -0400295 draw_as_tex(canvas, fImage.get(), 310, 0);
296 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
reed935d6cf2015-08-18 11:16:09 -0700297
Brian Osmana28e2b02017-04-24 16:44:03 -0400298 draw_as_bitmap(canvas, fImage.get(), 150, 0);
299 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
reed8f343722015-08-13 13:32:39 -0700300 }
301
302 void onDraw(SkCanvas* canvas) override {
reed935d6cf2015-08-18 11:16:09 -0700303 this->makeCaches(canvas->getGrContext());
304
reed8f343722015-08-13 13:32:39 -0700305 canvas->translate(20, 20);
306
307 this->drawSet(canvas);
308
309 canvas->save();
310 canvas->translate(0, 130);
311 canvas->scale(0.25f, 0.25f);
312 this->drawSet(canvas);
313 canvas->restore();
314
315 canvas->save();
316 canvas->translate(0, 200);
317 canvas->scale(2, 2);
318 this->drawSet(canvas);
319 canvas->restore();
320 }
321
322private:
323 typedef skiagm::GM INHERITED;
324};
reed935d6cf2015-08-18 11:16:09 -0700325DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
326DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400327DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )