1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkEncodedImageFormat.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkPngEncoder.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
34*c8dee2aaSAndroid Build Coastguard Worker
draw_something(SkCanvas * canvas,const SkRect & bounds)35*c8dee2aaSAndroid Build Coastguard Worker static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
36*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
37*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
38*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorRED);
39*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
40*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(10);
41*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(bounds, paint);
42*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kFill_Style);
43*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
44*c8dee2aaSAndroid Build Coastguard Worker canvas->drawOval(bounds, paint);
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker typedef sk_sp<SkImage> (*ImageMakerProc)(GrRecordingContext*, SkPicture*, const SkImageInfo&);
48*c8dee2aaSAndroid Build Coastguard Worker
make_raster(GrRecordingContext *,SkPicture * pic,const SkImageInfo & info)49*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_raster(GrRecordingContext*,
50*c8dee2aaSAndroid Build Coastguard Worker SkPicture* pic,
51*c8dee2aaSAndroid Build Coastguard Worker const SkImageInfo& info) {
52*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::Raster(info));
53*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->clear(0);
54*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawPicture(pic);
55*c8dee2aaSAndroid Build Coastguard Worker return surface->makeImageSnapshot();
56*c8dee2aaSAndroid Build Coastguard Worker }
57*c8dee2aaSAndroid Build Coastguard Worker
make_texture(GrRecordingContext * ctx,SkPicture * pic,const SkImageInfo & info)58*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_texture(GrRecordingContext* ctx,
59*c8dee2aaSAndroid Build Coastguard Worker SkPicture* pic,
60*c8dee2aaSAndroid Build Coastguard Worker const SkImageInfo& info) {
61*c8dee2aaSAndroid Build Coastguard Worker if (!ctx) {
62*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::RenderTarget(ctx, skgpu::Budgeted::kNo, info));
65*c8dee2aaSAndroid Build Coastguard Worker if (!surface) {
66*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->clear(0);
69*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawPicture(pic);
70*c8dee2aaSAndroid Build Coastguard Worker return surface->makeImageSnapshot();
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker
make_pict_gen(GrRecordingContext *,SkPicture * pic,const SkImageInfo & info)73*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_pict_gen(GrRecordingContext*,
74*c8dee2aaSAndroid Build Coastguard Worker SkPicture* pic,
75*c8dee2aaSAndroid Build Coastguard Worker const SkImageInfo& info) {
76*c8dee2aaSAndroid Build Coastguard Worker return SkImages::DeferredFromPicture(sk_ref_sp(pic),
77*c8dee2aaSAndroid Build Coastguard Worker info.dimensions(),
78*c8dee2aaSAndroid Build Coastguard Worker nullptr,
79*c8dee2aaSAndroid Build Coastguard Worker nullptr,
80*c8dee2aaSAndroid Build Coastguard Worker SkImages::BitDepth::kU8,
81*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace::MakeSRGB());
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker
make_encode_gen(GrRecordingContext * ctx,SkPicture * pic,const SkImageInfo & info)84*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_encode_gen(GrRecordingContext* ctx,
85*c8dee2aaSAndroid Build Coastguard Worker SkPicture* pic,
86*c8dee2aaSAndroid Build Coastguard Worker const SkImageInfo& info) {
87*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> src(make_raster(ctx, pic, info));
88*c8dee2aaSAndroid Build Coastguard Worker if (!src) {
89*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> encoded = SkPngEncoder::Encode(nullptr, src.get(), {});
92*c8dee2aaSAndroid Build Coastguard Worker if (!encoded) {
93*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
94*c8dee2aaSAndroid Build Coastguard Worker }
95*c8dee2aaSAndroid Build Coastguard Worker return SkImages::DeferredFromEncodedData(std::move(encoded));
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker const ImageMakerProc gProcs[] = {
99*c8dee2aaSAndroid Build Coastguard Worker make_raster,
100*c8dee2aaSAndroid Build Coastguard Worker make_texture,
101*c8dee2aaSAndroid Build Coastguard Worker make_pict_gen,
102*c8dee2aaSAndroid Build Coastguard Worker make_encode_gen,
103*c8dee2aaSAndroid Build Coastguard Worker };
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker /*
106*c8dee2aaSAndroid Build Coastguard Worker * Exercise drawing pictures inside an image, showing that the image version is pixelated
107*c8dee2aaSAndroid Build Coastguard Worker * (correctly) when it is inside an image.
108*c8dee2aaSAndroid Build Coastguard Worker */
109*c8dee2aaSAndroid Build Coastguard Worker class ImageShaderGM : public skiagm::GM {
110*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> fPicture;
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker public:
ImageShaderGM()113*c8dee2aaSAndroid Build Coastguard Worker ImageShaderGM() {}
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const116*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("image-shader"); }
117*c8dee2aaSAndroid Build Coastguard Worker
getISize()118*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(850, 450); }
119*c8dee2aaSAndroid Build Coastguard Worker
onOnceBeforeDraw()120*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
121*c8dee2aaSAndroid Build Coastguard Worker const SkRect bounds = SkRect::MakeWH(100, 100);
122*c8dee2aaSAndroid Build Coastguard Worker SkPictureRecorder recorder;
123*c8dee2aaSAndroid Build Coastguard Worker draw_something(recorder.beginRecording(bounds), bounds);
124*c8dee2aaSAndroid Build Coastguard Worker fPicture = recorder.finishRecordingAsPicture();
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker
testImage(SkCanvas * canvas,SkImage * image)127*c8dee2aaSAndroid Build Coastguard Worker void testImage(SkCanvas* canvas, SkImage* image) {
128*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(image, 0, 0);
131*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 120);
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker const SkTileMode tile = SkTileMode::kRepeat;
134*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix localM = SkMatrix::Translate(-50, -50);
135*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
136*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(image->makeShader(tile, tile, SkSamplingOptions(), &localM));
137*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
138*c8dee2aaSAndroid Build Coastguard Worker canvas->drawCircle(50, 50, 50, paint);
139*c8dee2aaSAndroid Build Coastguard Worker }
140*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)141*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
142*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(20, 20);
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gProcs); ++i) {
147*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image(gProcs[i](canvas->recordingContext(), fPicture.get(), info));
148*c8dee2aaSAndroid Build Coastguard Worker if (image) {
149*c8dee2aaSAndroid Build Coastguard Worker this->testImage(canvas, image.get());
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(120, 0);
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker private:
156*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = skiagm::GM;
157*c8dee2aaSAndroid Build Coastguard Worker };
DEF_GM(return new ImageShaderGM;)158*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ImageShaderGM; )
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////////////////////
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_checker_img(int w, int h, SkColor c0, SkColor c1, int size) {
165*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bm = ToolUtils::create_checkerboard_bitmap(w, h, c0, c1, size);
166*c8dee2aaSAndroid Build Coastguard Worker bm.setImmutable();
167*c8dee2aaSAndroid Build Coastguard Worker return bm.asImage();
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(drawimage_sampling, canvas, 500, 500) {
171*c8dee2aaSAndroid Build Coastguard Worker constexpr int N = 256;
172*c8dee2aaSAndroid Build Coastguard Worker constexpr float kScale = 1.0f/6;
173*c8dee2aaSAndroid Build Coastguard Worker const SkRect dst = {0, 0, kScale*N, kScale*N};
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker auto img = make_checker_img(N, N, SK_ColorBLACK, SK_ColorWHITE, 7)->withDefaultMipmaps();
176*c8dee2aaSAndroid Build Coastguard Worker const SkRect src = SkRect::MakeIWH(img->width(), img->height());
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker SkMatrix mx = SkMatrix::RectToRect(src, dst);
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker for (auto mm : {SkMipmapMode::kNone, SkMipmapMode::kNearest, SkMipmapMode::kLinear}) {
183*c8dee2aaSAndroid Build Coastguard Worker for (auto fm : {SkFilterMode::kNearest, SkFilterMode::kLinear}) {
184*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions sampling(fm, mm);
185*c8dee2aaSAndroid Build Coastguard Worker
186*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
189*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(mx);
190*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(img.get(), 0, 0, sampling);
191*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(dst.width() + 4, 0);
194*c8dee2aaSAndroid Build Coastguard Worker
195*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(img->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, &mx));
196*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(dst, paint);
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(dst.width() + 4, 0);
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(img.get(), src, dst, sampling, nullptr,
201*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint);
202*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, dst.height() + 8);
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker
210*c8dee2aaSAndroid Build Coastguard Worker // Test case for skbug.com/12685 (texture-backed image shaders silently fail drawing to CPU canvas)
211*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(textureimage_and_shader, canvas, 100, 50) {
212*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorGREEN);
213*c8dee2aaSAndroid Build Coastguard Worker
214*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image;
215*c8dee2aaSAndroid Build Coastguard Worker if (canvas->getSurface()) {
216*c8dee2aaSAndroid Build Coastguard Worker image = canvas->getSurface()->makeImageSnapshot();
217*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorRED);
218*c8dee2aaSAndroid Build Coastguard Worker } else {
219*c8dee2aaSAndroid Build Coastguard Worker auto greenSurface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(50, 50));
220*c8dee2aaSAndroid Build Coastguard Worker greenSurface->getCanvas()->clear(SK_ColorGREEN);
221*c8dee2aaSAndroid Build Coastguard Worker image = greenSurface->makeImageSnapshot();
222*c8dee2aaSAndroid Build Coastguard Worker }
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker // At this point, 'image' contains a green image. If our original canvas is GPU-backed, then
225*c8dee2aaSAndroid Build Coastguard Worker // the snapped image will be a (GPU) texture. We will try to draw that image to a non-GPU
226*c8dee2aaSAndroid Build Coastguard Worker // surface, to ensure that we get automatic read-back. If all goes well, we will get a pure
227*c8dee2aaSAndroid Build Coastguard Worker // green result. If either draw fails, we'll get red (most likely).
228*c8dee2aaSAndroid Build Coastguard Worker
229*c8dee2aaSAndroid Build Coastguard Worker auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(50, 50));
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker // First, use drawImage:
232*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->clear(SK_ColorRED);
233*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawImage(image, 0, 0);
234*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(surface->makeImageSnapshot(), 0, 0);
235*c8dee2aaSAndroid Build Coastguard Worker
236*c8dee2aaSAndroid Build Coastguard Worker // Now, use an image shader:
237*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
238*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(image->makeShader(SkSamplingOptions()));
239*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->clear(SK_ColorRED);
240*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawPaint(paint);
241*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(surface->makeImageSnapshot(), 50, 0);
242*c8dee2aaSAndroid Build Coastguard Worker }
243