blob: b9a9060d137c3951443350617b50fcb20692e3d1 [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/GrTypes.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040030#include "include/private/GrTypesPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "src/gpu/GrContextPriv.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040032#include "src/gpu/GrSamplerState.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050033#include "src/gpu/GrSurfaceContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040034#include "src/gpu/GrTextureProxy.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040035#include "src/image/SkImage_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/image/SkImage_Gpu.h"
reedd5b75632015-08-13 09:37:45 -070037
Ben Wagner7fde8e12019-05-01 17:28:53 -040038#include <memory>
39#include <utility>
40
41class GrRecordingContext;
42
reedd5b75632015-08-13 09:37:45 -070043static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
44 SkPaint paint;
45 paint.setAntiAlias(true);
46 paint.setColor(SK_ColorRED);
47 paint.setStyle(SkPaint::kStroke_Style);
48 paint.setStrokeWidth(10);
49 canvas->drawRect(bounds, paint);
50 paint.setStyle(SkPaint::kFill_Style);
51 paint.setColor(SK_ColorBLUE);
52 canvas->drawOval(bounds, paint);
53}
54
55/*
56 * Exercise drawing pictures inside an image, showing that the image version is pixelated
57 * (correctly) when it is inside an image.
58 */
59class ImagePictGM : public skiagm::GM {
reedca2622b2016-03-18 07:25:55 -070060 sk_sp<SkPicture> fPicture;
reed9ce9d672016-03-17 10:51:11 -070061 sk_sp<SkImage> fImage0;
62 sk_sp<SkImage> fImage1;
reedd5b75632015-08-13 09:37:45 -070063public:
64 ImagePictGM() {}
65
66protected:
67 SkString onShortName() override {
68 return SkString("image-picture");
69 }
70
71 SkISize onISize() override {
72 return SkISize::Make(850, 450);
73 }
74
75 void onOnceBeforeDraw() override {
76 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
77 SkPictureRecorder recorder;
78 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -070079 fPicture = recorder.finishRecordingAsPicture();
reedd5b75632015-08-13 09:37:45 -070080
81 // extract enough just for the oval.
82 const SkISize size = SkISize::Make(100, 100);
Matt Sarett77a7a1b2017-02-07 13:56:11 -050083 auto srgbColorSpace = SkColorSpace::MakeSRGB();
reedd5b75632015-08-13 09:37:45 -070084
85 SkMatrix matrix;
86 matrix.setTranslate(-100, -100);
Matt Sarette94255d2017-01-09 12:38:59 -050087 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
88 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070089 matrix.postTranslate(-50, -50);
90 matrix.postRotate(45);
91 matrix.postTranslate(50, 50);
Matt Sarette94255d2017-01-09 12:38:59 -050092 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
93 SkImage::BitDepth::kU8, srgbColorSpace);
reedd5b75632015-08-13 09:37:45 -070094 }
95
96 void drawSet(SkCanvas* canvas) const {
Mike Reed1f607332020-05-21 12:11:27 -040097 SkMatrix matrix = SkMatrix::Translate(-100, -100);
reedd5b75632015-08-13 09:37:45 -070098 canvas->drawPicture(fPicture, &matrix, nullptr);
reed9ce9d672016-03-17 10:51:11 -070099 canvas->drawImage(fImage0.get(), 150, 0);
100 canvas->drawImage(fImage1.get(), 300, 0);
reedd5b75632015-08-13 09:37:45 -0700101 }
102
103 void onDraw(SkCanvas* canvas) override {
104 canvas->translate(20, 20);
105
106 this->drawSet(canvas);
107
108 canvas->save();
109 canvas->translate(0, 130);
110 canvas->scale(0.25f, 0.25f);
111 this->drawSet(canvas);
112 canvas->restore();
113
114 canvas->save();
115 canvas->translate(0, 200);
116 canvas->scale(2, 2);
117 this->drawSet(canvas);
118 canvas->restore();
119 }
120
121private:
122 typedef skiagm::GM INHERITED;
123};
124DEF_GM( return new ImagePictGM; )
125
reed8f343722015-08-13 13:32:39 -0700126///////////////////////////////////////////////////////////////////////////////////////////////////
127
Mike Reed185130c2017-02-15 15:14:16 -0500128static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700129 SkMatrix matrix;
130 matrix.setTranslate(-100, -100);
Mike Reed185130c2017-02-15 15:14:16 -0500131 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
Matt Sarette94255d2017-01-09 12:38:59 -0500132 SkImage::BitDepth::kU8,
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500133 SkColorSpace::MakeSRGB());
reed935d6cf2015-08-18 11:16:09 -0700134}
135
136class RasterGenerator : public SkImageGenerator {
137public:
Mike Reed4edb5d22017-04-17 11:02:51 -0400138 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
139 {}
140
reed935d6cf2015-08-18 11:16:09 -0700141protected:
142 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400143 const Options&) override {
reedc4a83e22015-09-11 11:47:27 -0700144 SkASSERT(fBM.width() == info.width());
145 SkASSERT(fBM.height() == info.height());
Matt Sarettebb1b5c2017-05-12 11:41:27 -0400146 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
reed935d6cf2015-08-18 11:16:09 -0700147 }
148private:
149 SkBitmap fBM;
150};
Mike Reed185130c2017-02-15 15:14:16 -0500151static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700152 SkBitmap bm;
153 bm.allocN32Pixels(100, 100);
154 SkCanvas canvas(bm);
155 canvas.clear(0);
156 canvas.translate(-100, -100);
157 canvas.drawPicture(pic);
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500158 return std::make_unique<RasterGenerator>(bm);
reed935d6cf2015-08-18 11:16:09 -0700159}
160
161class EmptyGenerator : public SkImageGenerator {
162public:
163 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
164};
165
reed935d6cf2015-08-18 11:16:09 -0700166class TextureGenerator : public SkImageGenerator {
167public:
Mike Reed185130c2017-02-15 15:14:16 -0500168 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
reed935d6cf2015-08-18 11:16:09 -0700169 : SkImageGenerator(info)
Robert Phillipse2f7d182016-12-15 09:23:05 -0500170 , fCtx(SkRef(ctx)) {
171
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400172 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
Robert Phillipse44ef102017-07-21 15:37:19 -0400173 kTopLeft_GrSurfaceOrigin, nullptr));
scroggoe6f0d6e2016-05-13 07:25:44 -0700174 if (surface) {
175 surface->getCanvas()->clear(0);
176 surface->getCanvas()->translate(-100, -100);
177 surface->getCanvas()->drawPicture(pic);
178 sk_sp<SkImage> image(surface->makeImageSnapshot());
Greg Daniel37c127f2020-02-05 10:37:27 -0500179 const GrSurfaceProxyView* view = as_IB(image)->view(fCtx.get());
180 if (view) {
181 fView = *view;
182 }
scroggoe6f0d6e2016-05-13 07:25:44 -0700183 }
reed935d6cf2015-08-18 11:16:09 -0700184 }
185protected:
Brian Salomonc5243782020-04-02 12:50:34 -0400186 GrSurfaceProxyView onGenerateTexture(GrRecordingContext* ctx,
187 const SkImageInfo& info,
188 const SkIPoint& origin,
189 GrMipMapped mipMapped,
190 GrImageTexGenPolicy policy) override {
Robert Phillips4447b642017-03-03 11:10:18 -0500191 SkASSERT(ctx);
192 SkASSERT(ctx == fCtx.get());
reed935d6cf2015-08-18 11:16:09 -0700193
Greg Danielfebdedf2020-02-05 17:06:27 -0500194 if (!fView) {
Greg Danielcc104db2020-02-03 14:17:08 -0500195 return {};
scroggoe6f0d6e2016-05-13 07:25:44 -0700196 }
197
Brian Salomonc5243782020-04-02 12:50:34 -0400198 if (origin.fX == 0 && origin.fY == 0 && info.dimensions() == fView.proxy()->dimensions() &&
199 policy == GrImageTexGenPolicy::kDraw) {
Greg Danielcc104db2020-02-03 14:17:08 -0500200 return fView;
Robert Phillipse2f7d182016-12-15 09:23:05 -0500201 }
Brian Salomon30275712020-04-03 15:56:36 -0400202 auto budgeted = policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted ? SkBudgeted::kNo
203 : SkBudgeted::kYes;
Brian Salomonc5243782020-04-02 12:50:34 -0400204 return GrSurfaceProxyView::Copy(
205 fCtx.get(), fView, mipMapped,
Greg Daniel46cfbc62019-06-07 11:43:30 -0400206 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
Brian Salomonc5243782020-04-02 12:50:34 -0400207 SkBackingFit::kExact, budgeted);
reed935d6cf2015-08-18 11:16:09 -0700208 }
Robert Phillips4447b642017-03-03 11:10:18 -0500209
reed935d6cf2015-08-18 11:16:09 -0700210private:
Greg Danielcc104db2020-02-03 14:17:08 -0500211 sk_sp<GrContext> fCtx;
212 GrSurfaceProxyView fView;
reed935d6cf2015-08-18 11:16:09 -0700213};
Robert Phillips4447b642017-03-03 11:10:18 -0500214
Mike Reed185130c2017-02-15 15:14:16 -0500215static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
reed935d6cf2015-08-18 11:16:09 -0700216 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
217
218 if (!ctx) {
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500219 return std::make_unique<EmptyGenerator>(info);
reed935d6cf2015-08-18 11:16:09 -0700220 }
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500221 return std::make_unique<TextureGenerator>(ctx, info, pic);
reed935d6cf2015-08-18 11:16:09 -0700222}
reed8f343722015-08-13 13:32:39 -0700223
224class ImageCacheratorGM : public skiagm::GM {
reed935d6cf2015-08-18 11:16:09 -0700225 SkString fName;
Mike Reed185130c2017-02-15 15:14:16 -0500226 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
reedca2622b2016-03-18 07:25:55 -0700227 sk_sp<SkPicture> fPicture;
Brian Osmana28e2b02017-04-24 16:44:03 -0400228 sk_sp<SkImage> fImage;
229 sk_sp<SkImage> fImageSubset;
reed8f343722015-08-13 13:32:39 -0700230
231public:
Mike Reed185130c2017-02-15 15:14:16 -0500232 ImageCacheratorGM(const char suffix[],
233 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
reed935d6cf2015-08-18 11:16:09 -0700234 : fFactory(factory)
235 {
236 fName.printf("image-cacherator-from-%s", suffix);
237 }
reed8f343722015-08-13 13:32:39 -0700238
239protected:
240 SkString onShortName() override {
reed935d6cf2015-08-18 11:16:09 -0700241 return fName;
reed8f343722015-08-13 13:32:39 -0700242 }
243
244 SkISize onISize() override {
reeda32cc952015-08-19 06:07:29 -0700245 return SkISize::Make(960, 450);
reed8f343722015-08-13 13:32:39 -0700246 }
247
248 void onOnceBeforeDraw() override {
249 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
250 SkPictureRecorder recorder;
251 draw_something(recorder.beginRecording(bounds), bounds);
reedca2622b2016-03-18 07:25:55 -0700252 fPicture = recorder.finishRecordingAsPicture();
reed935d6cf2015-08-18 11:16:09 -0700253 }
reed8f343722015-08-13 13:32:39 -0700254
reed935d6cf2015-08-18 11:16:09 -0700255 void makeCaches(GrContext* ctx) {
Mike Reed185130c2017-02-15 15:14:16 -0500256 auto gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400257 fImage = SkImage::MakeFromGenerator(std::move(gen));
reed935d6cf2015-08-18 11:16:09 -0700258
259 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
260
Mike Reed185130c2017-02-15 15:14:16 -0500261 gen = fFactory(ctx, fPicture);
Brian Osmana28e2b02017-04-24 16:44:03 -0400262 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
reed935d6cf2015-08-18 11:16:09 -0700263
Brian Osmandf7e0752017-04-26 16:20:28 -0400264 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
265 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
reed935d6cf2015-08-18 11:16:09 -0700266 }
267
Brian Osmana28e2b02017-04-24 16:44:03 -0400268 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
reed935d6cf2015-08-18 11:16:09 -0700269 SkBitmap bitmap;
Brian Osmane50cdf02018-10-19 13:02:14 -0400270 as_IB(image)->getROPixels(&bitmap);
reed935d6cf2015-08-18 11:16:09 -0700271 canvas->drawBitmap(bitmap, x, y);
272 }
273
Brian Osmana28e2b02017-04-24 16:44:03 -0400274 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500275 GrSurfaceProxyView view = as_IB(image)->refView(canvas->getGrContext(), GrMipMapped::kNo);
Greg Danielfebdedf2020-02-05 17:06:27 -0500276 if (!view) {
reeda32cc952015-08-19 06:07:29 -0700277 // show placeholder if we have no texture
278 SkPaint paint;
279 paint.setStyle(SkPaint::kStroke_Style);
Brian Osmana28e2b02017-04-24 16:44:03 -0400280 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
281 SkIntToScalar(image->width()));
reeda32cc952015-08-19 06:07:29 -0700282 canvas->drawRect(r, paint);
283 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
284 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
reed935d6cf2015-08-18 11:16:09 -0700285 return;
286 }
Brian Salomon729fc0c2019-09-30 16:33:11 +0000287
288 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
289 sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()),
Greg Daniel7c165a42020-01-22 12:22:36 -0500290 image->uniqueID(), std::move(view),
291 image->colorType(), image->alphaType(),
292 image->refColorSpace()));
Brian Osmana28e2b02017-04-24 16:44:03 -0400293 canvas->drawImage(texImage.get(), x, y);
reed8f343722015-08-13 13:32:39 -0700294 }
295
296 void drawSet(SkCanvas* canvas) const {
Mike Reed1f607332020-05-21 12:11:27 -0400297 SkMatrix matrix = SkMatrix::Translate(-100, -100);
reed8f343722015-08-13 13:32:39 -0700298 canvas->drawPicture(fPicture, &matrix, nullptr);
299
reed935d6cf2015-08-18 11:16:09 -0700300 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
301 // way we also can force the generateTexture call.
302
Brian Osmana28e2b02017-04-24 16:44:03 -0400303 draw_as_tex(canvas, fImage.get(), 310, 0);
304 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
reed935d6cf2015-08-18 11:16:09 -0700305
Brian Osmana28e2b02017-04-24 16:44:03 -0400306 draw_as_bitmap(canvas, fImage.get(), 150, 0);
307 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
reed8f343722015-08-13 13:32:39 -0700308 }
309
310 void onDraw(SkCanvas* canvas) override {
reed935d6cf2015-08-18 11:16:09 -0700311 this->makeCaches(canvas->getGrContext());
312
reed8f343722015-08-13 13:32:39 -0700313 canvas->translate(20, 20);
314
315 this->drawSet(canvas);
316
317 canvas->save();
318 canvas->translate(0, 130);
319 canvas->scale(0.25f, 0.25f);
320 this->drawSet(canvas);
321 canvas->restore();
322
323 canvas->save();
324 canvas->translate(0, 200);
325 canvas->scale(2, 2);
326 this->drawSet(canvas);
327 canvas->restore();
328 }
329
330private:
331 typedef skiagm::GM INHERITED;
332};
reed935d6cf2015-08-18 11:16:09 -0700333DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
334DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400335DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )