blob: 1d8f4695a302798e12b8926f71574c11c546cd53 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040011#include "include/core/SkColor.h"
12#include "include/core/SkColorSpace.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkImage.h"
14#include "include/core/SkImageGenerator.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040015#include "include/core/SkImageInfo.h"
16#include "include/core/SkMatrix.h"
17#include "include/core/SkPaint.h"
18#include "include/core/SkPicture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/core/SkPictureRecorder.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040020#include "include/core/SkPoint.h"
21#include "include/core/SkRect.h"
22#include "include/core/SkRefCnt.h"
23#include "include/core/SkScalar.h"
24#include "include/core/SkSize.h"
25#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "include/core/SkSurface.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040027#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "include/gpu/GrContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040029#include "include/gpu/GrSamplerState.h"
30#include "include/gpu/GrTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "include/private/GrTextureProxy.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040032#include "include/private/GrTypesPriv.h"
33#include "src/core/SkMakeUnique.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050034#include "src/gpu/GrContextPriv.h"
35#include "src/gpu/GrSurfaceContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040036#include "src/image/SkImage_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/image/SkImage_Gpu.h"
reedd5b75632015-08-13 09:37:45 -070038
Ben Wagner7fde8e12019-05-01 17:28:53 -040039#include <memory>
40#include <utility>
41
42class GrRecordingContext;
43
reedd5b75632015-08-13 09:37:45 -070044static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
45 SkPaint paint;
46 paint.setAntiAlias(true);
47 paint.setColor(SK_ColorRED);
48 paint.setStyle(SkPaint::kStroke_Style);
49 paint.setStrokeWidth(10);
50 canvas->drawRect(bounds, paint);
51 paint.setStyle(SkPaint::kFill_Style);
52 paint.setColor(SK_ColorBLUE);
53 canvas->drawOval(bounds, paint);
54}
55
56/*
57 * Exercise drawing pictures inside an image, showing that the image version is pixelated
58 * (correctly) when it is inside an image.
59 */
60class ImagePictGM : public skiagm::GM {
reedca2622b2016-03-18 07:25:55 -070061 sk_sp<SkPicture> fPicture;
reed9ce9d672016-03-17 10:51:11 -070062 sk_sp<SkImage> fImage0;
63 sk_sp<SkImage> fImage1;
reedd5b75632015-08-13 09:37:45 -070064public:
65 ImagePictGM() {}
66
67protected:
68 SkString onShortName() override {
69 return SkString("image-picture");
70 }
71
72 SkISize onISize() override {
73 return SkISize::Make(850, 450);
74 }
75
76 void onOnceBeforeDraw() override {
77 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
78 SkPictureRecorder recorder;
79 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -070080 fPicture = recorder.finishRecordingAsPicture();
reedd5b75632015-08-13 09:37:45 -070081
82 // extract enough just for the oval.
83 const SkISize size = SkISize::Make(100, 100);
Matt Sarett77a7a1b2017-02-07 13:56:11 -050084 auto srgbColorSpace = SkColorSpace::MakeSRGB();
reedd5b75632015-08-13 09:37:45 -070085
86 SkMatrix matrix;
87 matrix.setTranslate(-100, -100);
Matt Sarette94255d2017-01-09 12:38:59 -050088 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
89 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070090 matrix.postTranslate(-50, -50);
91 matrix.postRotate(45);
92 matrix.postTranslate(50, 50);
Matt Sarette94255d2017-01-09 12:38:59 -050093 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
94 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070095 }
96
97 void drawSet(SkCanvas* canvas) const {
98 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
99 canvas->drawPicture(fPicture, &matrix, nullptr);
reed9ce9d672016-03-17 10:51:11 -0700100 canvas->drawImage(fImage0.get(), 150, 0);
101 canvas->drawImage(fImage1.get(), 300, 0);
reedd5b75632015-08-13 09:37:45 -0700102 }
103
104 void onDraw(SkCanvas* canvas) override {
105 canvas->translate(20, 20);
106
107 this->drawSet(canvas);
108
109 canvas->save();
110 canvas->translate(0, 130);
111 canvas->scale(0.25f, 0.25f);
112 this->drawSet(canvas);
113 canvas->restore();
114
115 canvas->save();
116 canvas->translate(0, 200);
117 canvas->scale(2, 2);
118 this->drawSet(canvas);
119 canvas->restore();
120 }
121
122private:
123 typedef skiagm::GM INHERITED;
124};
125DEF_GM( return new ImagePictGM; )
126
reed8f343722015-08-13 13:32:39 -0700127///////////////////////////////////////////////////////////////////////////////////////////////////
128
Mike Reed185130c2017-02-15 15:14:16 -0500129static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700130 SkMatrix matrix;
131 matrix.setTranslate(-100, -100);
Mike Reed185130c2017-02-15 15:14:16 -0500132 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
Matt Sarette94255d2017-01-09 12:38:59 -0500133 SkImage::BitDepth::kU8,
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500134 SkColorSpace::MakeSRGB());
reed935d6cf2015-08-18 11:16:09 -0700135}
136
137class RasterGenerator : public SkImageGenerator {
138public:
Mike Reed4edb5d22017-04-17 11:02:51 -0400139 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
140 {}
141
reed935d6cf2015-08-18 11:16:09 -0700142protected:
143 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400144 const Options&) override {
reedc4a83e22015-09-11 11:47:27 -0700145 SkASSERT(fBM.width() == info.width());
146 SkASSERT(fBM.height() == info.height());
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400147 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
reed935d6cf2015-08-18 11:16:09 -0700148 }
149private:
150 SkBitmap fBM;
151};
Mike Reed185130c2017-02-15 15:14:16 -0500152static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700153 SkBitmap bm;
154 bm.allocN32Pixels(100, 100);
155 SkCanvas canvas(bm);
156 canvas.clear(0);
157 canvas.translate(-100, -100);
158 canvas.drawPicture(pic);
Mike Reed185130c2017-02-15 15:14:16 -0500159 return skstd::make_unique<RasterGenerator>(bm);
reed935d6cf2015-08-18 11:16:09 -0700160}
161
162class EmptyGenerator : public SkImageGenerator {
163public:
164 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
165};
166
reed935d6cf2015-08-18 11:16:09 -0700167class TextureGenerator : public SkImageGenerator {
168public:
Mike Reed185130c2017-02-15 15:14:16 -0500169 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
reed935d6cf2015-08-18 11:16:09 -0700170 : SkImageGenerator(info)
Robert Phillipse2f7d182016-12-15 09:23:05 -0500171 , fCtx(SkRef(ctx)) {
172
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400173 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
Robert Phillipse44ef102017-07-21 15:37:19 -0400174 kTopLeft_GrSurfaceOrigin, nullptr));
scroggoe6f0d6e2016-05-13 07:25:44 -0700175 if (surface) {
176 surface->getCanvas()->clear(0);
177 surface->getCanvas()->translate(-100, -100);
178 surface->getCanvas()->drawPicture(pic);
179 sk_sp<SkImage> image(surface->makeImageSnapshot());
Robert Phillips6603a172019-03-05 12:35:44 -0500180 fProxy = as_IB(image)->asTextureProxyRef(fCtx.get());
scroggoe6f0d6e2016-05-13 07:25:44 -0700181 }
reed935d6cf2015-08-18 11:16:09 -0700182 }
183protected:
Robert Phillips9338c602019-02-19 12:52:29 -0500184 sk_sp<GrTextureProxy> onGenerateTexture(GrRecordingContext* ctx, const SkImageInfo& info,
Christopher Cameron77e96662017-07-08 01:47:47 -0700185 const SkIPoint& origin,
Greg Danielf88c12e2017-10-09 09:57:35 -0400186 bool willBeMipped) override {
Robert Phillips4447b642017-03-03 11:10:18 -0500187 SkASSERT(ctx);
188 SkASSERT(ctx == fCtx.get());
reed935d6cf2015-08-18 11:16:09 -0700189
Robert Phillipse2f7d182016-12-15 09:23:05 -0500190 if (!fProxy) {
scroggoe6f0d6e2016-05-13 07:25:44 -0700191 return nullptr;
192 }
193
Robert Phillipse2f7d182016-12-15 09:23:05 -0500194 if (origin.fX == 0 && origin.fY == 0 &&
195 info.width() == fProxy->width() && info.height() == fProxy->height()) {
Robert Phillips4447b642017-03-03 11:10:18 -0500196 return fProxy;
Robert Phillipse2f7d182016-12-15 09:23:05 -0500197 }
198
reed935d6cf2015-08-18 11:16:09 -0700199 // need to copy the subset into a new texture
Brian Salomon63e79732017-05-15 21:23:13 -0400200 GrSurfaceDesc desc;
Brian Osman222e9ad2016-12-14 15:42:36 -0500201 desc.fWidth = info.width();
202 desc.fHeight = info.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400203 desc.fConfig = fProxy->config();
reed935d6cf2015-08-18 11:16:09 -0700204
Greg Daniel65c7f662017-10-30 13:39:09 -0400205 GrMipMapped mipMapped = willBeMipped ? GrMipMapped::kYes : GrMipMapped::kNo;
206
Robert Phillips9da87e02019-02-04 13:26:26 -0500207 sk_sp<GrSurfaceContext> dstContext(fCtx->priv().makeDeferredSurfaceContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500208 fProxy->backendFormat(), desc, fProxy->origin(), mipMapped, SkBackingFit::kExact,
209 SkBudgeted::kYes));
Robert Phillipse2f7d182016-12-15 09:23:05 -0500210 if (!dstContext) {
211 return nullptr;
212 }
213
214 if (!dstContext->copy(
215 fProxy.get(),
216 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
217 SkIPoint::Make(0, 0))) {
218 return nullptr;
219 }
220
Robert Phillips4447b642017-03-03 11:10:18 -0500221 return dstContext->asTextureProxyRef();
reed935d6cf2015-08-18 11:16:09 -0700222 }
Robert Phillips4447b642017-03-03 11:10:18 -0500223
reed935d6cf2015-08-18 11:16:09 -0700224private:
Robert Phillipse2f7d182016-12-15 09:23:05 -0500225 sk_sp<GrContext> fCtx;
Robert Phillips4447b642017-03-03 11:10:18 -0500226 sk_sp<GrTextureProxy> fProxy;
reed935d6cf2015-08-18 11:16:09 -0700227};
Robert Phillips4447b642017-03-03 11:10:18 -0500228
Mike Reed185130c2017-02-15 15:14:16 -0500229static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700230 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
231
232 if (!ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500233 return skstd::make_unique<EmptyGenerator>(info);
reed935d6cf2015-08-18 11:16:09 -0700234 }
Mike Reed185130c2017-02-15 15:14:16 -0500235 return skstd::make_unique<TextureGenerator>(ctx, info, pic);
reed935d6cf2015-08-18 11:16:09 -0700236}
reed8f343722015-08-13 13:32:39 -0700237
238class ImageCacheratorGM : public skiagm::GM {
reed935d6cf2015-08-18 11:16:09 -0700239 SkString fName;
Mike Reed185130c2017-02-15 15:14:16 -0500240 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
reedca2622b2016-03-18 07:25:55 -0700241 sk_sp<SkPicture> fPicture;
Brian Osmana28e2b02017-04-24 16:44:03 -0400242 sk_sp<SkImage> fImage;
243 sk_sp<SkImage> fImageSubset;
reed8f343722015-08-13 13:32:39 -0700244
245public:
Mike Reed185130c2017-02-15 15:14:16 -0500246 ImageCacheratorGM(const char suffix[],
247 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
reed935d6cf2015-08-18 11:16:09 -0700248 : fFactory(factory)
249 {
250 fName.printf("image-cacherator-from-%s", suffix);
251 }
reed8f343722015-08-13 13:32:39 -0700252
253protected:
254 SkString onShortName() override {
reed935d6cf2015-08-18 11:16:09 -0700255 return fName;
reed8f343722015-08-13 13:32:39 -0700256 }
257
258 SkISize onISize() override {
reeda32cc952015-08-19 06:07:29 -0700259 return SkISize::Make(960, 450);
reed8f343722015-08-13 13:32:39 -0700260 }
261
262 void onOnceBeforeDraw() override {
263 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
264 SkPictureRecorder recorder;
265 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -0700266 fPicture = recorder.finishRecordingAsPicture();
reed935d6cf2015-08-18 11:16:09 -0700267 }
reed8f343722015-08-13 13:32:39 -0700268
reed935d6cf2015-08-18 11:16:09 -0700269 void makeCaches(GrContext* ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500270 auto gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400271 fImage = SkImage::MakeFromGenerator(std::move(gen));
reed935d6cf2015-08-18 11:16:09 -0700272
273 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
274
Mike Reed185130c2017-02-15 15:14:16 -0500275 gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400276 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
reed935d6cf2015-08-18 11:16:09 -0700277
Brian Osmandf7e0752017-04-26 16:20:28 -0400278 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
279 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
reed935d6cf2015-08-18 11:16:09 -0700280 }
281
Brian Osmana28e2b02017-04-24 16:44:03 -0400282 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
reed935d6cf2015-08-18 11:16:09 -0700283 SkBitmap bitmap;
Brian Osmane50cdf02018-10-19 13:02:14 -0400284 as_IB(image)->getROPixels(&bitmap);
reed935d6cf2015-08-18 11:16:09 -0700285 canvas->drawBitmap(bitmap, x, y);
286 }
287
Brian Osmana28e2b02017-04-24 16:44:03 -0400288 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400289 sk_sp<GrTextureProxy> proxy(as_IB(image)->asTextureProxyRef(
Brian Osman6064e1c2018-10-19 14:27:54 -0400290 canvas->getGrContext(), GrSamplerState::ClampBilerp(), nullptr));
Robert Phillips4f358be2017-03-23 08:21:00 -0400291 if (!proxy) {
reeda32cc952015-08-19 06:07:29 -0700292 // show placeholder if we have no texture
293 SkPaint paint;
294 paint.setStyle(SkPaint::kStroke_Style);
Brian Osmana28e2b02017-04-24 16:44:03 -0400295 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
296 SkIntToScalar(image->width()));
reeda32cc952015-08-19 06:07:29 -0700297 canvas->drawRect(r, paint);
298 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
299 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
reed935d6cf2015-08-18 11:16:09 -0700300 return;
301 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400302
reed935d6cf2015-08-18 11:16:09 -0700303 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
Brian Salomonf05e6d32018-12-20 08:41:41 -0500304 sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()),
305 image->uniqueID(), kPremul_SkAlphaType,
306 std::move(proxy), image->refColorSpace()));
Brian Osmana28e2b02017-04-24 16:44:03 -0400307 canvas->drawImage(texImage.get(), x, y);
reed8f343722015-08-13 13:32:39 -0700308 }
309
310 void drawSet(SkCanvas* canvas) const {
311 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
312 canvas->drawPicture(fPicture, &matrix, nullptr);
313
reed935d6cf2015-08-18 11:16:09 -0700314 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
315 // way we also can force the generateTexture call.
316
Brian Osmana28e2b02017-04-24 16:44:03 -0400317 draw_as_tex(canvas, fImage.get(), 310, 0);
318 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
reed935d6cf2015-08-18 11:16:09 -0700319
Brian Osmana28e2b02017-04-24 16:44:03 -0400320 draw_as_bitmap(canvas, fImage.get(), 150, 0);
321 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
reed8f343722015-08-13 13:32:39 -0700322 }
323
324 void onDraw(SkCanvas* canvas) override {
reed935d6cf2015-08-18 11:16:09 -0700325 this->makeCaches(canvas->getGrContext());
326
reed8f343722015-08-13 13:32:39 -0700327 canvas->translate(20, 20);
328
329 this->drawSet(canvas);
330
331 canvas->save();
332 canvas->translate(0, 130);
333 canvas->scale(0.25f, 0.25f);
334 this->drawSet(canvas);
335 canvas->restore();
336
337 canvas->save();
338 canvas->translate(0, 200);
339 canvas->scale(2, 2);
340 this->drawSet(canvas);
341 canvas->restore();
342 }
343
344private:
345 typedef skiagm::GM INHERITED;
346};
reed935d6cf2015-08-18 11:16:09 -0700347DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
348DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400349DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )