Add fixes & test for isConfigTexturable and isConfigRenderable
[platform/upstream/libSkiaSharp.git] / gm / image.cpp
1 /*
2  * Copyright 2011 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 <functional>
9 #include "gm.h"
10 #include "sk_tool_utils.h"
11 #include "SkAutoPixmapStorage.h"
12 #include "SkData.h"
13 #include "SkCanvas.h"
14 #include "SkRandom.h"
15 #include "SkStream.h"
16 #include "SkSurface.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #endif
21
22 static void drawJpeg(SkCanvas* canvas, const SkISize& size) {
23     // TODO: Make this draw a file that is checked in, so it can
24     // be exercised on machines other than mike's. Will require a
25     // rebaseline.
26     sk_sp<SkData> data(SkData::MakeFromFileName("/Users/mike/Downloads/skia.google.jpeg"));
27     if (nullptr == data) {
28         return;
29     }
30     sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(data));
31     if (image) {
32         SkAutoCanvasRestore acr(canvas, true);
33         canvas->scale(size.width() * 1.0f / image->width(),
34                       size.height() * 1.0f / image->height());
35         canvas->drawImage(image, 0, 0, nullptr);
36     }
37 }
38
39 static void drawContents(SkSurface* surface, SkColor fillC) {
40     SkSize size = SkSize::Make(SkIntToScalar(surface->width()),
41                                SkIntToScalar(surface->height()));
42     SkCanvas* canvas = surface->getCanvas();
43
44     SkScalar stroke = size.fWidth / 10;
45     SkScalar radius = (size.fWidth - stroke) / 2;
46
47     SkPaint paint;
48
49     paint.setAntiAlias(true);
50     paint.setColor(fillC);
51     canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
52
53     paint.setStyle(SkPaint::kStroke_Style);
54     paint.setStrokeWidth(stroke);
55     paint.setColor(SK_ColorBLACK);
56     canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
57 }
58
59 static void test_surface(SkCanvas* canvas, SkSurface* surf, bool usePaint) {
60     drawContents(surf, SK_ColorRED);
61     sk_sp<SkImage> imgR = surf->makeImageSnapshot();
62
63     if (true) {
64         sk_sp<SkImage> imgR2 = surf->makeImageSnapshot();
65         SkASSERT(imgR == imgR2);
66     }
67
68     drawContents(surf, SK_ColorGREEN);
69     sk_sp<SkImage> imgG = surf->makeImageSnapshot();
70
71     // since we've drawn after we snapped imgR, imgG will be a different obj
72     SkASSERT(imgR != imgG);
73
74     drawContents(surf, SK_ColorBLUE);
75
76     SkPaint paint;
77 //    paint.setFilterBitmap(true);
78 //    paint.setAlpha(0x80);
79
80     canvas->drawImage(imgR, 0, 0, usePaint ? &paint : nullptr);
81     canvas->drawImage(imgG, 0, 80, usePaint ? &paint : nullptr);
82     surf->draw(canvas, 0, 160, usePaint ? &paint : nullptr);
83
84     SkRect src1, src2, src3;
85     src1.iset(0, 0, surf->width(), surf->height());
86     src2.iset(-surf->width() / 2, -surf->height() / 2,
87              surf->width(), surf->height());
88     src3.iset(0, 0, surf->width() / 2, surf->height() / 2);
89
90     SkRect dst1, dst2, dst3, dst4;
91     dst1.set(0, 240, 65, 305);
92     dst2.set(0, 320, 65, 385);
93     dst3.set(0, 400, 65, 465);
94     dst4.set(0, 480, 65, 545);
95
96     canvas->drawImageRect(imgR, src1, dst1, usePaint ? &paint : nullptr);
97     canvas->drawImageRect(imgG, src2, dst2, usePaint ? &paint : nullptr);
98     canvas->drawImageRect(imgR, src3, dst3, usePaint ? &paint : nullptr);
99     canvas->drawImageRect(imgG, dst4, usePaint ? &paint : nullptr);
100 }
101
102 class ImageGM : public skiagm::GM {
103     void*   fBuffer;
104     size_t  fBufferSize;
105     SkSize  fSize;
106     enum {
107         W = 64,
108         H = 64,
109         RB = W * 4 + 8,
110     };
111 public:
112     ImageGM() {
113         fBufferSize = RB * H;
114         fBuffer = sk_malloc_throw(fBufferSize);
115         fSize.set(SkIntToScalar(W), SkIntToScalar(H));
116     }
117
118     ~ImageGM() override {
119         sk_free(fBuffer);
120     }
121
122 protected:
123     SkString onShortName() override {
124         return SkString("image-surface");
125     }
126
127     SkISize onISize() override {
128         return SkISize::Make(960, 1200);
129     }
130
131     void onDraw(SkCanvas* canvas) override {
132         drawJpeg(canvas, this->getISize());
133
134         canvas->scale(2, 2);
135
136         const char* kLabel1 = "Original Img";
137         const char* kLabel2 = "Modified Img";
138         const char* kLabel3 = "Cur Surface";
139         const char* kLabel4 = "Full Crop";
140         const char* kLabel5 = "Over-crop";
141         const char* kLabel6 = "Upper-left";
142         const char* kLabel7 = "No Crop";
143
144         const char* kLabel8 = "Pre-Alloc Img";
145         const char* kLabel9 = "New Alloc Img";
146         const char* kLabel10 = "GPU";
147
148         SkPaint textPaint;
149         textPaint.setAntiAlias(true);
150         sk_tool_utils::set_portable_typeface(&textPaint);
151         textPaint.setTextSize(8);
152
153         canvas->drawString(kLabel1, 10,  60, textPaint);
154         canvas->drawString(kLabel2, 10, 140, textPaint);
155         canvas->drawString(kLabel3, 10, 220, textPaint);
156         canvas->drawString(kLabel4, 10, 300, textPaint);
157         canvas->drawString(kLabel5, 10, 380, textPaint);
158         canvas->drawString(kLabel6, 10, 460, textPaint);
159         canvas->drawString(kLabel7, 10, 540, textPaint);
160
161         canvas->drawString(kLabel8, 80, 10, textPaint);
162         canvas->drawString(kLabel9, 160, 10, textPaint);
163         canvas->drawString(kLabel10, 265, 10, textPaint);
164
165         canvas->translate(80, 20);
166
167         // since we draw into this directly, we need to start fresh
168         sk_bzero(fBuffer, fBufferSize);
169
170         SkImageInfo info = SkImageInfo::MakeN32Premul(W, H);
171         sk_sp<SkSurface> surf0(SkSurface::MakeRasterDirect(info, fBuffer, RB));
172         sk_sp<SkSurface> surf1(SkSurface::MakeRaster(info));
173         sk_sp<SkSurface> surf2;  // gpu
174
175 #if SK_SUPPORT_GPU
176         surf2 = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kNo, info);
177 #endif
178
179         test_surface(canvas, surf0.get(), true);
180         canvas->translate(80, 0);
181         test_surface(canvas, surf1.get(), true);
182         if (surf2) {
183             canvas->translate(80, 0);
184             test_surface(canvas, surf2.get(), true);
185         }
186     }
187
188 private:
189     typedef skiagm::GM INHERITED;
190 };
191 DEF_GM( return new ImageGM; )
192
193 ///////////////////////////////////////////////////////////////////////////////////////////////////
194
195 #include "SkPictureRecorder.h"
196
197 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pmap) {
198     SkBitmap bitmap;
199     bitmap.installPixels(pmap);
200     canvas->drawBitmap(bitmap, 0, 0, nullptr);
201 }
202
203 static void show_scaled_pixels(SkCanvas* canvas, SkImage* image) {
204     SkAutoCanvasRestore acr(canvas, true);
205
206     canvas->drawImage(image, 0, 0, nullptr);
207     canvas->translate(110, 10);
208
209     const SkImageInfo info = SkImageInfo::MakeN32Premul(40, 40);
210     SkAutoPixmapStorage storage;
211     storage.alloc(info);
212
213     const SkImage::CachingHint chints[] = {
214         SkImage::kAllow_CachingHint, SkImage::kDisallow_CachingHint,
215     };
216     const SkFilterQuality qualities[] = {
217         kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality,
218     };
219
220     for (auto ch : chints) {
221         canvas->save();
222         for (auto q : qualities) {
223             if (image->scalePixels(storage, q, ch)) {
224                 draw_pixmap(canvas, storage);
225             }
226             canvas->translate(70, 0);
227         }
228         canvas->restore();
229         canvas->translate(0, 45);
230     }
231 }
232
233 static void draw_contents(SkCanvas* canvas) {
234     SkPaint paint;
235     paint.setStyle(SkPaint::kStroke_Style);
236     paint.setStrokeWidth(20);
237     canvas->drawCircle(50, 50, 35, paint);
238 }
239
240 static sk_sp<SkImage> make_raster(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
241     auto surface(SkSurface::MakeRaster(info));
242     draw(surface->getCanvas());
243     return surface->makeImageSnapshot();
244 }
245
246 static sk_sp<SkImage> make_picture(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
247     SkPictureRecorder recorder;
248     draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
249     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
250                                     info.dimensions(), nullptr, nullptr, SkImage::BitDepth::kU8,
251                                     SkColorSpace::MakeSRGB());
252 }
253
254 static sk_sp<SkImage> make_codec(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
255     sk_sp<SkImage> image(make_raster(info, nullptr, draw));
256     sk_sp<SkData> data(image->encode());
257     return SkImage::MakeFromEncoded(data);
258 }
259
260 static sk_sp<SkImage> make_gpu(const SkImageInfo& info, GrContext* ctx, void (*draw)(SkCanvas*)) {
261     if (!ctx) { return nullptr; }
262     auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
263     if (!surface) { return nullptr; }
264     draw(surface->getCanvas());
265     return surface->makeImageSnapshot();
266 }
267
268 typedef sk_sp<SkImage> (*ImageMakerProc)(const SkImageInfo&, GrContext*, void (*)(SkCanvas*));
269
270 class ScalePixelsGM : public skiagm::GM {
271 public:
272     ScalePixelsGM() {}
273
274 protected:
275     SkString onShortName() override {
276         return SkString("scale-pixels");
277     }
278
279     SkISize onISize() override {
280         return SkISize::Make(960, 1200);
281     }
282
283     void onDraw(SkCanvas* canvas) override {
284         const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
285
286         const ImageMakerProc procs[] = {
287             make_codec, make_raster, make_picture, make_codec, make_gpu,
288         };
289         for (auto& proc : procs) {
290             sk_sp<SkImage> image(proc(info, canvas->getGrContext(), draw_contents));
291             if (image) {
292                 show_scaled_pixels(canvas, image.get());
293             }
294             canvas->translate(0, 120);
295         }
296     }
297
298 private:
299     typedef skiagm::GM INHERITED;
300 };
301 DEF_GM( return new ScalePixelsGM; )
302
303 ///////////////////////////////////////////////////////////////////////////////////////////////////
304
305 DEF_SIMPLE_GM(new_texture_image, canvas, 280, 60) {
306     GrContext* context = canvas->getGrContext();
307     if (!context) {
308         skiagm::GM::DrawGpuOnlyMessage(canvas);
309         return;
310     }
311
312     auto render_image = [](SkCanvas* canvas) {
313         canvas->clear(SK_ColorBLUE);
314         SkPaint paint;
315         paint.setColor(SK_ColorRED);
316         canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint);
317         paint.setColor(SK_ColorGREEN);
318         canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint);
319         paint.setColor(SK_ColorYELLOW);
320         canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint);
321         paint.setColor(SK_ColorCYAN);
322         canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint);
323     };
324
325     static constexpr int kSize = 50;
326     SkBitmap bmp;
327     bmp.allocPixels(SkImageInfo::MakeS32(kSize, kSize, kPremul_SkAlphaType));
328     SkCanvas bmpCanvas(bmp);
329     render_image(&bmpCanvas);
330
331     std::function<sk_sp<SkImage>()> imageFactories[] = {
332         // Create sw raster image.
333         [bmp] {
334             return SkImage::MakeFromBitmap(bmp);
335         },
336         // Create encoded image.
337         [bmp] {
338             sk_sp<SkData> src(
339                 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kPNG, 100));
340             return SkImage::MakeFromEncoded(std::move(src));
341         },
342         // Create YUV encoded image.
343         [bmp] {
344             sk_sp<SkData> src(
345                 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kJPEG, 100));
346             return SkImage::MakeFromEncoded(std::move(src));
347         },
348         // Create a picture image.
349         [render_image] {
350             SkPictureRecorder recorder;
351             SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize));
352             render_image(canvas);
353             sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB();
354             return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
355                                             SkISize::Make(kSize, kSize), nullptr, nullptr,
356                                             SkImage::BitDepth::kU8, srgbColorSpace);
357         },
358         // Create a texture image
359         [context, render_image]() -> sk_sp<SkImage> {
360             auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kYes,
361                                                      SkImageInfo::MakeS32(kSize, kSize,
362                                                                           kPremul_SkAlphaType)));
363             if (!surface) {
364                 return nullptr;
365             }
366             render_image(surface->getCanvas());
367             return surface->makeImageSnapshot();
368         }
369     };
370
371     constexpr SkScalar kPad = 5.f;
372     canvas->translate(kPad, kPad);
373     for (auto factory : imageFactories) {
374         auto image(factory());
375         if (image) {
376             sk_sp<SkImage> texImage(image->makeTextureImage(context,
377                                                             canvas->imageInfo().colorSpace()));
378             if (texImage) {
379                 canvas->drawImage(texImage, 0, 0);
380             }
381         }
382         canvas->translate(kSize + kPad, 0);
383     }
384 }