xref: /aosp_15_r20/external/skia/gm/nearesthalfpixelimage.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 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 #include "include/core/SkCanvas.h"
10 #include "include/core/SkImage.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPixmap.h"
13 #include "include/core/SkShader.h"
14 #include "include/core/SkSurface.h"
15 
16 /**
17  * Tests drawing images are half pixel offsets in device space with nearest filtering to show how
18  * rasterization and image sample snapping at boundary points interact. Both drawImage and drawRect
19  * with an image shader are tested. Scale factors 1 and -1 are tested. The images are all two pixels
20  * wide or tall so we either get both values once each or one value repeated twice.
21  */
22 DEF_SIMPLE_GM_CAN_FAIL(nearest_half_pixel_image, canvas, errorMsg, 264, 235) {
23     // We don't run this test on the GPU because we're at the driver/hw's mercy for how this
24     // is handled.
25     if (canvas->recordingContext() || (canvas->getSurface() && canvas->getSurface()->recorder())) {
26         *errorMsg = "Test is only relevant to CPU backend";
27         return skiagm::DrawResult::kSkip;
28     }
29 
30     // We make 2x1 and 1x2 images for each color type.
31     struct Images {
32         sk_sp<SkImage> imageX;
33         sk_sp<SkImage> imageY;
34     };
35 
36     Images images[2];
37     uint32_t colors[] {0xFFFF0000, 0xFF0000FF};
38     SkPixmap cpmx(SkImageInfo::Make({2, 1},
39                                     kRGBA_8888_SkColorType,
40                                     kPremul_SkAlphaType),
41                   colors,
42                   sizeof(colors));
43     SkPixmap cpmy(SkImageInfo::Make({1, 2},
44                                     kRGBA_8888_SkColorType,
45                                     kPremul_SkAlphaType),
46                   colors,
47                   sizeof(colors[0]));
48     images[0] = {SkImages::RasterFromPixmapCopy(cpmx), SkImages::RasterFromPixmapCopy(cpmy)};
49 
50     uint8_t alphas[] {0xFF, 0xAA};
51     SkPixmap apmx(SkImageInfo::Make({2, 1},
52                                     kAlpha_8_SkColorType,
53                                     kPremul_SkAlphaType),
54                   alphas,
55                   sizeof(alphas));
56     SkPixmap apmy(SkImageInfo::Make({1, 2},
57                                     kAlpha_8_SkColorType,
58                                     kPremul_SkAlphaType),
59                   alphas,
60                   sizeof(alphas[0]));
61     images[1] = {SkImages::RasterFromPixmapCopy(apmx), SkImages::RasterFromPixmapCopy(apmy)};
62 
63     // We draw offscreen and then zoom that up to make the result clear.
64     auto surf = canvas->makeSurface(canvas->imageInfo().makeWH(80, 80));
65     if (!surf) {
66         *errorMsg = "Test only works with SkSurface backed canvases";
67         return skiagm::DrawResult::kSkip;
68     }
69     auto* c = surf->getCanvas();
70     c->clear(SK_ColorWHITE);
71 
72     // We scale up in the direction not being tested, the one with image dimension of 1, to make the
73     // result more easily visible.
74     static const float kOffAxisScale = 4;
75 
__anon67dc9d240102(sk_sp<SkImage> image, bool shader, bool doX, bool mirror, uint8_t alpha) 76     auto draw = [&](sk_sp<SkImage> image, bool shader, bool doX, bool mirror, uint8_t alpha) {
77         c->save();
78         SkPaint paint;
79         paint.setAlpha(alpha);
80         if (shader) {
81             paint.setShader(image->makeShader(SkFilterMode::kNearest));
82         }
83         if (doX) {
84             c->scale(mirror ? -1 : 1, kOffAxisScale);
85             c->translate(mirror ? -2.5 : 0.5, 0);
86         } else {
87             c->scale(kOffAxisScale, mirror ? -1 : 1);
88             c->translate(0, mirror ? -2.5 : 0.5);
89         }
90 
91         if (shader) {
92             c->drawRect(SkRect::Make(image->dimensions()), paint);
93         } else {
94             c->drawImage(image, 0, 0, SkFilterMode::kNearest, &paint);
95         }
96         c->restore();
97     };
98 
99     for (bool shader : {false, true})
100     for (uint8_t alpha : {0xFF , 0x70}) {
101         c->save();
102         for (const auto& i : images)
103         for (auto mirror : {false, true}) {
104             draw(i.imageX, shader, /*doX=*/true, mirror, alpha);
105             c->save();
106             c->translate(4, 0);
107             draw(i.imageY, shader, /*doX=*/false, mirror, alpha);
108             c->restore();
109             c->translate(0, kOffAxisScale*2);
110         }
111         c->restore();
112         c->translate(kOffAxisScale*2, 0);
113     }
114     canvas->scale(8, 8);
115     canvas->drawImage(surf->makeImageSnapshot(), 0, 0);
116 
117     return skiagm::DrawResult::kOk;
118 }
119