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