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