• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gm/gm.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorPriv.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkData.h"
16 #include "include/core/SkFont.h"
17 #include "include/core/SkImage.h"
18 #include "include/core/SkImageInfo.h"
19 #include "include/core/SkPaint.h"
20 #include "include/core/SkPicture.h"
21 #include "include/core/SkPictureRecorder.h"
22 #include "include/core/SkPixmap.h"
23 #include "include/core/SkRect.h"
24 #include "include/core/SkRefCnt.h"
25 #include "include/core/SkScalar.h"
26 #include "include/core/SkSerialProcs.h"
27 #include "include/core/SkSize.h"
28 #include "include/core/SkString.h"
29 #include "include/core/SkSurface.h"
30 #include "include/core/SkTypeface.h"
31 #include "include/core/SkTypes.h"
32 #include "include/encode/SkJpegEncoder.h"
33 #include "include/encode/SkPngEncoder.h"
34 #include "include/gpu/GrDirectContext.h"
35 #include "include/gpu/ganesh/SkImageGanesh.h"
36 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
37 #include "include/private/base/SkMalloc.h"
38 #include "src/core/SkAutoPixmapStorage.h"
39 #include "src/core/SkReadBuffer.h"
40 #include "src/core/SkWriteBuffer.h"
41 #include "src/image/SkImage_Base.h"
42 #include "tools/GpuToolUtils.h"
43 #include "tools/ToolUtils.h"
44 #include "tools/fonts/FontToolUtils.h"
45 
46 #if defined(SK_GRAPHITE)
47 #include "include/gpu/graphite/Surface.h"
48 #endif
49 
50 #include <functional>
51 #include <utility>
52 
53 #if defined(SK_GRAPHITE)
54 #include "include/gpu/graphite/Image.h"
55 #endif
56 
57 const SkSamplingOptions gSamplings[] = {
58     SkSamplingOptions(SkFilterMode::kNearest),
59     SkSamplingOptions(SkFilterMode::kLinear),
60     SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
61     SkSamplingOptions(SkCubicResampler::Mitchell()),
62 };
63 
draw_contents(SkSurface * surface,SkColor fillC)64 static void draw_contents(SkSurface* surface, SkColor fillC) {
65     SkSize size = SkSize::Make(SkIntToScalar(surface->width()),
66                                SkIntToScalar(surface->height()));
67     SkCanvas* canvas = surface->getCanvas();
68 
69     SkScalar stroke = size.fWidth / 10;
70     SkScalar radius = (size.fWidth - stroke) / 2;
71 
72     SkPaint paint;
73 
74     paint.setAntiAlias(true);
75     paint.setColor(fillC);
76     canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
77 
78     paint.setStyle(SkPaint::kStroke_Style);
79     paint.setStrokeWidth(stroke);
80     paint.setColor(SK_ColorBLACK);
81     canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
82 }
83 
test_surface(SkCanvas * canvas,SkSurface * surf,bool usePaint)84 static void test_surface(SkCanvas* canvas, SkSurface* surf, bool usePaint) {
85     draw_contents(surf, SK_ColorRED);
86     sk_sp<SkImage> imgR = surf->makeImageSnapshot();
87 
88     if (true) {
89         sk_sp<SkImage> imgR2 = surf->makeImageSnapshot();
90         SkASSERT(imgR == imgR2);
91     }
92 
93     imgR = ToolUtils::MakeTextureImage(canvas, std::move(imgR));
94     draw_contents(surf, SK_ColorGREEN);
95     sk_sp<SkImage> imgG = ToolUtils::MakeTextureImage(canvas, surf->makeImageSnapshot());
96 
97     // since we've drawn after we snapped imgR, imgG will be a different obj unless the
98     // gpu context has been abandoned (in which case they will both be null)
99     SkASSERT(imgR != imgG || (!imgR && !imgG));
100 
101     draw_contents(surf, SK_ColorBLUE);
102 
103     SkSamplingOptions sampling;
104     SkPaint paint;
105 
106     canvas->drawImage(imgR, 0, 0, sampling, usePaint ? &paint : nullptr);
107     canvas->drawImage(imgG, 0, 80, sampling, usePaint ? &paint : nullptr);
108     surf->draw(canvas, 0, 160, SkSamplingOptions(), usePaint ? &paint : nullptr);
109 
110     SkRect src1, src2, src3;
111     src1.setIWH(surf->width(), surf->height());
112     src2.setLTRB(SkIntToScalar(-surf->width() / 2), SkIntToScalar(-surf->height() / 2),
113                  SkIntToScalar(surf->width()),       SkIntToScalar(surf->height()));
114     src3.setIWH(surf->width() / 2, surf->height() / 2);
115 
116     SkRect dst1, dst2, dst3, dst4;
117     dst1.setLTRB(0, 240, 65, 305);
118     dst2.setLTRB(0, 320, 65, 385);
119     dst3.setLTRB(0, 400, 65, 465);
120     dst4.setLTRB(0, 480, 65, 545);
121 
122     canvas->drawImageRect(imgR, src1, dst1, sampling, usePaint ? &paint : nullptr,
123                           SkCanvas::kStrict_SrcRectConstraint);
124     canvas->drawImageRect(imgG, src2, dst2, sampling, usePaint ? &paint : nullptr,
125                           SkCanvas::kStrict_SrcRectConstraint);
126     canvas->drawImageRect(imgR, src3, dst3, sampling, usePaint ? &paint : nullptr,
127                           SkCanvas::kStrict_SrcRectConstraint);
128     canvas->drawImageRect(imgG, dst4, sampling, usePaint ? &paint : nullptr);
129 }
130 
131 class ImageGM : public skiagm::GM {
132     void*   fBuffer;
133     size_t  fBufferSize;
134     SkSize  fSize;
135     enum {
136         W = 64,
137         H = 64,
138         RB = W * 4 + 8,
139     };
140 public:
ImageGM()141     ImageGM() {
142         fBufferSize = RB * H;
143         fBuffer = sk_malloc_throw(fBufferSize);
144         fSize.set(SkIntToScalar(W), SkIntToScalar(H));
145     }
146 
~ImageGM()147     ~ImageGM() override {
148         sk_free(fBuffer);
149     }
150 
151 protected:
getName() const152     SkString getName() const override { return SkString("image-surface"); }
153 
getISize()154     SkISize getISize() override { return SkISize::Make(960, 1200); }
155 
onDraw(SkCanvas * canvas)156     void onDraw(SkCanvas* canvas) override {
157         canvas->scale(2, 2);
158 
159         SkFont font(ToolUtils::DefaultPortableTypeface(), 8);
160 
161         canvas->drawString("Original Img",  10,  60, font, SkPaint());
162         canvas->drawString("Modified Img",  10, 140, font, SkPaint());
163         canvas->drawString("Cur Surface",   10, 220, font, SkPaint());
164         canvas->drawString("Full Crop",     10, 300, font, SkPaint());
165         canvas->drawString("Over-crop",     10, 380, font, SkPaint());
166         canvas->drawString("Upper-left",    10, 460, font, SkPaint());
167         canvas->drawString("No Crop",       10, 540, font, SkPaint());
168 
169         canvas->drawString("Pre-Alloc Img", 80,  10, font, SkPaint());
170         canvas->drawString("New Alloc Img", 160, 10, font, SkPaint());
171         canvas->drawString( "GPU",          265, 10, font, SkPaint());
172 
173         canvas->translate(80, 20);
174 
175         // since we draw into this directly, we need to start fresh
176         sk_bzero(fBuffer, fBufferSize);
177 
178         SkImageInfo info = SkImageInfo::MakeN32Premul(W, H);
179         sk_sp<SkSurface> surf0(SkSurfaces::WrapPixels(info, fBuffer, RB));
180         sk_sp<SkSurface> surf1(SkSurfaces::Raster(info));
181         sk_sp<SkSurface> surf2(
182                 SkSurfaces::RenderTarget(canvas->recordingContext(), skgpu::Budgeted::kNo, info));
183 
184         test_surface(canvas, surf0.get(), true);
185         canvas->translate(80, 0);
186         test_surface(canvas, surf1.get(), true);
187         if (surf2) {
188             canvas->translate(80, 0);
189             test_surface(canvas, surf2.get(), true);
190         }
191     }
192 
193 private:
194     using INHERITED = skiagm::GM;
195 };
DEF_GM(return new ImageGM;)196 DEF_GM( return new ImageGM; )
197 
198 ///////////////////////////////////////////////////////////////////////////////////////////////////
199 
200 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pmap) {
201     SkBitmap bitmap;
202     bitmap.installPixels(pmap);
203     canvas->drawImage(bitmap.asImage(), 0, 0);
204 }
205 
show_scaled_pixels(SkCanvas * canvas,SkImage * image)206 static void show_scaled_pixels(SkCanvas* canvas, SkImage* image) {
207     SkAutoCanvasRestore acr(canvas, true);
208 
209     canvas->drawImage(image, 0, 0);
210     canvas->translate(110, 10);
211 
212     const SkImageInfo info = SkImageInfo::MakeN32Premul(40, 40);
213     SkAutoPixmapStorage storage;
214     storage.alloc(info);
215 
216     const SkImage::CachingHint chints[] = {
217         SkImage::kAllow_CachingHint, SkImage::kDisallow_CachingHint,
218     };
219 
220     for (auto ch : chints) {
221         canvas->save();
222         for (auto s : gSamplings) {
223             if (image->scalePixels(storage, s, ch)) {
224                 draw_pixmap(canvas, storage);
225             }
226             canvas->translate(70, 0);
227         }
228         canvas->restore();
229         canvas->translate(0, 45);
230     }
231 }
232 
draw_contents(SkCanvas * canvas)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 
make_raster(const SkImageInfo & info,GrRecordingContext *,void (* draw)(SkCanvas *))240 static sk_sp<SkImage> make_raster(const SkImageInfo& info,
241                                   GrRecordingContext*,
242                                   void (*draw)(SkCanvas*)) {
243     auto surface(SkSurfaces::Raster(info));
244     draw(surface->getCanvas());
245     return surface->makeImageSnapshot();
246 }
247 
make_picture(const SkImageInfo & info,GrRecordingContext *,void (* draw)(SkCanvas *))248 static sk_sp<SkImage> make_picture(const SkImageInfo& info,
249                                    GrRecordingContext*,
250                                    void (*draw)(SkCanvas*)) {
251     SkPictureRecorder recorder;
252     draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
253     return SkImages::DeferredFromPicture(recorder.finishRecordingAsPicture(),
254                                          info.dimensions(),
255                                          nullptr,
256                                          nullptr,
257                                          SkImages::BitDepth::kU8,
258                                          SkColorSpace::MakeSRGB());
259 }
260 
make_codec(const SkImageInfo & info,GrRecordingContext *,void (* draw)(SkCanvas *))261 static sk_sp<SkImage> make_codec(const SkImageInfo& info,
262                                  GrRecordingContext*,
263                                  void (*draw)(SkCanvas*)) {
264     sk_sp<SkImage> image(make_raster(info, nullptr, draw));
265     return SkImages::DeferredFromEncodedData(SkPngEncoder::Encode(nullptr, image.get(), {}));
266 }
267 
make_gpu(const SkImageInfo & info,GrRecordingContext * ctx,void (* draw)(SkCanvas *))268 static sk_sp<SkImage> make_gpu(const SkImageInfo& info,
269                                GrRecordingContext* ctx,
270                                void (*draw)(SkCanvas*)) {
271     if (!ctx) {
272         return nullptr;
273     }
274 
275     auto surface(SkSurfaces::RenderTarget(ctx, skgpu::Budgeted::kNo, info));
276     if (!surface) {
277         return nullptr;
278     }
279 
280     draw(surface->getCanvas());
281     return surface->makeImageSnapshot();
282 }
283 
284 typedef sk_sp<SkImage> (*ImageMakerProc)(const SkImageInfo&,
285                                          GrRecordingContext*,
286                                          void (*)(SkCanvas*));
287 
288 class ScalePixelsGM : public skiagm::GM {
289 public:
ScalePixelsGM()290     ScalePixelsGM() {}
291 
292 protected:
getName() const293     SkString getName() const override { return SkString("scale-pixels"); }
294 
getISize()295     SkISize getISize() override { return SkISize::Make(960, 1200); }
296 
onDraw(SkCanvas * canvas)297     void onDraw(SkCanvas* canvas) override {
298         const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
299 
300         const ImageMakerProc procs[] = {
301             make_codec, make_raster, make_picture, make_codec, make_gpu,
302         };
303         for (auto& proc : procs) {
304             sk_sp<SkImage> image(proc(info, canvas->recordingContext(), draw_contents));
305             if (image) {
306                 show_scaled_pixels(canvas, image.get());
307             }
308             canvas->translate(0, 120);
309         }
310     }
311 
312 private:
313     using INHERITED = skiagm::GM;
314 };
315 DEF_GM( return new ScalePixelsGM; )
316 
317 ///////////////////////////////////////////////////////////////////////////////////////////////////
318 
319 DEF_SIMPLE_GM_CAN_FAIL(new_texture_image, canvas, errorMsg, 280, 115) {
320 
321     GrDirectContext* dContext = GrAsDirectContext(canvas->recordingContext());
322     bool isGPU = SkToBool(dContext);
323 
324 #if defined(SK_GRAPHITE)
325     skgpu::graphite::Recorder* recorder = canvas->recorder();
326     isGPU = isGPU || SkToBool(recorder);
327 #endif
328 
329     if (!isGPU) {
330         *errorMsg = skiagm::GM::kErrorMsg_DrawSkippedGpuOnly;
331         return skiagm::DrawResult::kSkip;
332     }
333 
__anon96f1e6130202(SkCanvas* canvas) 334     auto render_image = [](SkCanvas* canvas) {
335         canvas->clear(SK_ColorBLUE);
336         SkPaint paint;
337         paint.setColor(SK_ColorRED);
338         canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint);
339         paint.setColor(SK_ColorGREEN);
340         canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint);
341         paint.setColor(SK_ColorYELLOW);
342         canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint);
343         paint.setColor(SK_ColorCYAN);
344         canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint);
345     };
346 
347     static constexpr int kSize = 50;
348     SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
349                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType,
350                                        SkColorSpace::MakeSRGB());
351     SkBitmap bmp;
352     bmp.allocPixels(ii);
353     SkCanvas bmpCanvas(bmp);
354     render_image(&bmpCanvas);
355 
356     std::function<sk_sp<SkImage>()> imageFactories[] = {
357             // Create sw raster image.
__anon96f1e6130302null358             [&] { return bmp.asImage(); },
359             // Create encoded image.
__anon96f1e6130402null360             [&] {
361                 SkDynamicMemoryWStream stream;
362                 SkASSERT_RELEASE(SkPngEncoder::Encode(&stream, bmp.pixmap(), {}));
363                 return SkImages::DeferredFromEncodedData(stream.detachAsData());
364             },
365             // Create YUV encoded image.
__anon96f1e6130502null366             [&] {
367                 SkDynamicMemoryWStream stream;
368                 SkASSERT_RELEASE(SkJpegEncoder::Encode(&stream, bmp.pixmap(), {}));
369                 return SkImages::DeferredFromEncodedData(stream.detachAsData());
370             },
371             // Create a picture image.
__anon96f1e6130602null372             [&] {
373                 SkPictureRecorder recorder;
374                 SkCanvas* canvas =
375                         recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize));
376                 render_image(canvas);
377                 sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB();
378                 return SkImages::DeferredFromPicture(recorder.finishRecordingAsPicture(),
379                                                      SkISize::Make(kSize, kSize),
380                                                      nullptr,
381                                                      nullptr,
382                                                      SkImages::BitDepth::kU8,
383                                                      srgbColorSpace);
384             },
385             // Create a texture image
__anon96f1e6130702() 386             [&]() -> sk_sp<SkImage> {
387                 sk_sp<SkSurface> surface;
388                 if (dContext) {
389                     surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kYes, ii);
390                 } else {
391 #if defined(SK_GRAPHITE)
392                     surface = SkSurfaces::RenderTarget(recorder, ii);
393 #endif
394                 }
395 
396                 if (!surface) {
397                     return nullptr;
398                 }
399                 render_image(surface->getCanvas());
400                 return surface->makeImageSnapshot();
401             }};
402 
403     constexpr SkScalar kPad = 5.f;
404     canvas->translate(kPad, kPad);
405     for (const auto& factory : imageFactories) {
406         sk_sp<SkImage> image(factory());
407         if (image) {
408             for (auto mm : { false, true }) {
409                 sk_sp<SkImage> texImage;
410                 if (dContext) {
411                     texImage = SkImages::TextureFromImage(dContext,
412                                                           image,
413                                                           mm ? skgpu::Mipmapped::kYes
414                                                              : skgpu::Mipmapped::kNo);
415                 } else {
416 #if defined(SK_GRAPHITE)
417                     texImage = SkImages::TextureFromImage(recorder, image, {mm});
418 #endif
419                 }
420                 if (texImage) {
421                     canvas->drawImage(texImage, 0, mm ? kSize + kPad : 0);
422                 }
423             }
424         }
425         canvas->translate(kSize + kPad, 0);
426     }
427 
428     return skiagm::DrawResult::kOk;
429 }
430 
draw_pixmap(SkCanvas * canvas,const SkPixmap & pm,SkScalar x,SkScalar y)431 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pm, SkScalar x, SkScalar y) {
432     canvas->drawImage(SkImages::RasterFromPixmapCopy(pm), x, y);
433 }
434 
slam_ff(const SkPixmap & pm)435 static void slam_ff(const SkPixmap& pm) {
436     for (int y = 0; y < pm.height(); ++y) {
437         for (int x = 0; x < pm.width(); ++x) {
438             *pm.writable_addr32(x, y) = *pm.addr32(x, y) | SkPackARGB32(0xFF, 0, 0, 0);
439         }
440     }
441 }
442 
443 DEF_SIMPLE_GM(scalepixels_unpremul, canvas, 1080, 280) {
444     SkImageInfo info = SkImageInfo::MakeN32(16, 16, kUnpremul_SkAlphaType);
445     SkAutoPixmapStorage pm;
446     pm.alloc(info);
447     for (int y = 0; y < 16; ++y) {
448         for (int x = 0; x < 16; ++x) {
449             *pm.writable_addr32(x, y) = SkPackARGB32NoCheck(0, (y << 4) | y, (x << 4) | x, 0xFF);
450         }
451     }
452     SkAutoPixmapStorage pm2;
453     pm2.alloc(SkImageInfo::MakeN32(256, 256, kUnpremul_SkAlphaType));
454 
455     for (auto s : gSamplings) {
456         pm.scalePixels(pm2, s);
457         slam_ff(pm2);
458         draw_pixmap(canvas, pm2, 10, 10);
459         canvas->translate(pm2.width() + 10.0f, 0);
460     }
461 }
462 
463 ///////////////////////////////////////////////////////////////////////////////////////////////////
464 
make_lazy_image()465 static sk_sp<SkImage> make_lazy_image() {
466     sk_sp<SkPicture> picture;
467     {
468         SkPictureRecorder recorder;
469         SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(200, 200));
470         canvas->drawCircle(100, 100, 100, SkPaint());
471         picture = recorder.finishRecordingAsPicture();
472     }
473 
474     return SkImages::DeferredFromPicture(std::move(picture),
475                                          {200, 200},
476                                          /* matrix= */ nullptr,
477                                          /* paint= */ nullptr,
478                                          SkImages::BitDepth::kU8,
479                                          SkColorSpace::MakeSRGB());
480 }
481 
serial_deserial(SkImage * img)482 static sk_sp<SkImage> serial_deserial(SkImage* img) {
483     if (!img) {
484         return nullptr;
485     }
486 
487     SkSerialProcs sProcs;
488     sProcs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
489         return SkPngEncoder::Encode(as_IB(img)->directContext(), img, SkPngEncoder::Options{});
490     };
491     SkBinaryWriteBuffer writer(sProcs);
492 
493     writer.writeImage(img);
494     size_t length = writer.bytesWritten();
495     auto data = SkData::MakeUninitialized(length);
496     writer.writeToMemory(data->writable_data());
497 
498     SkReadBuffer reader(data->data(), length);
499     return reader.readImage();
500 }
501 
502 DEF_SIMPLE_GM_CAN_FAIL(image_subset, canvas, errorMsg, 440, 220) {
503     auto img = make_lazy_image();
504     if (!img) {
505         *errorMsg = "Failed to make lazy image.";
506         return skiagm::DrawResult::kFail;
507     }
508 
509     GrDirectContext* dContext = GrAsDirectContext(canvas->recordingContext());
510 #if defined(SK_GRAPHITE)
511     auto recorder = canvas->recorder();
512 #endif
513 
514     canvas->drawImage(img, 10, 10);
515 
516     sk_sp<SkImage> subset;
517 
518 #if defined(SK_GRAPHITE)
519     if (recorder) {
520         subset = img->makeSubset(recorder, {100, 100, 200, 200}, {});
521     } else
522 #endif
523     {
524         subset = img->makeSubset(dContext, {100, 100, 200, 200});
525     }
526 
527     canvas->drawImage(subset, 220, 10);
528     subset = serial_deserial(subset.get());
529     canvas->drawImage(subset, 220+110, 10);
530     return skiagm::DrawResult::kOk;
531 }
532