1 /*
2 * Copyright 2021 Google LLC
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 "include/core/SkBitmap.h"
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkBlender.h" // IWYU pragma: keep
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkShader.h"
18 #include "include/core/SkSurface.h"
19 #include "include/core/SkTypes.h"
20 #include "include/gpu/GpuTypes.h"
21 #include "include/gpu/ganesh/GrDirectContext.h"
22 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
23 #include "tests/CtsEnforcement.h"
24 #include "tests/Test.h"
25 #include "tools/RuntimeBlendUtils.h"
26
27 #include <cmath>
28 #include <initializer_list>
29 #include <vector>
30
31 struct GrContextOptions;
32
nearly_equal(const SkColor & x,const SkColor & y)33 static bool nearly_equal(const SkColor& x, const SkColor& y) {
34 const int kTolerance = 1;
35 return abs((int)SkColorGetA(x) - (int)SkColorGetA(y)) <= kTolerance &&
36 abs((int)SkColorGetR(x) - (int)SkColorGetR(y)) <= kTolerance &&
37 abs((int)SkColorGetG(x) - (int)SkColorGetG(y)) <= kTolerance &&
38 abs((int)SkColorGetB(x) - (int)SkColorGetB(y)) <= kTolerance;
39 }
40
test_blend(skiatest::Reporter * r,SkSurface * surface)41 static void test_blend(skiatest::Reporter* r, SkSurface* surface) {
42 SkBitmap bitmap;
43 REPORTER_ASSERT(r, bitmap.tryAllocPixels(surface->imageInfo()));
44
45 for (int m = 0; m < kSkBlendModeCount; ++m) {
46 SkBlendMode mode = (SkBlendMode)m;
47 for (int alpha : {0x80, 0xFF}) {
48 for (bool useShader : {false, true}) {
49 std::vector<SkColor> colors;
50 for (bool useRuntimeBlend : {false, true}) {
51 // Draw a solid red pixel.
52 SkPaint paint;
53 paint.setColor(SK_ColorRED);
54 paint.setBlendMode(SkBlendMode::kSrc);
55 surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);
56
57 // Draw a blue pixel on top of it, using the passed-in blend mode.
58 if (useShader) {
59 // Install a different color in the paint, to ensure we're using the shader
60 paint.setColor(SK_ColorGREEN);
61 paint.setShader(SkShaders::Color(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF)));
62 } else {
63 paint.setColor(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF));
64 }
65 if (useRuntimeBlend) {
66 paint.setBlender(GetRuntimeBlendForBlendMode(mode));
67 } else {
68 paint.setBlendMode(mode);
69 }
70 surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);
71
72 // Read back the red/blue blended pixel.
73 REPORTER_ASSERT(r,
74 surface->readPixels(bitmap.info(),
75 bitmap.getPixels(),
76 bitmap.rowBytes(),
77 /*srcX=*/0,
78 /*srcY=*/0));
79 colors.push_back(bitmap.getColor(/*x=*/0, /*y=*/0));
80 }
81
82 REPORTER_ASSERT(r,
83 nearly_equal(colors[0], colors[1]),
84 "Expected: %s %s %s blend matches. Actual: Built-in "
85 "A=%02X R=%02X G=%02X B=%02X, Runtime A=%02X R=%02X G=%02X B=%02X",
86 SkBlendMode_Name(mode),
87 (alpha == 0xFF) ? "solid" : "transparent",
88 useShader ? "shader" : "paint",
89 SkColorGetA(colors[0]),
90 SkColorGetR(colors[0]),
91 SkColorGetG(colors[0]),
92 SkColorGetB(colors[0]),
93 SkColorGetA(colors[1]),
94 SkColorGetR(colors[1]),
95 SkColorGetG(colors[1]),
96 SkColorGetB(colors[1]));
97 }
98 }
99 }
100 }
101
DEF_TEST(SkRuntimeBlender_CPU,r)102 DEF_TEST(SkRuntimeBlender_CPU, r) {
103 const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
104 sk_sp<SkSurface> surface(SkSurfaces::Raster(info));
105
106 test_blend(r, surface.get());
107 }
108
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkRuntimeBlender_GPU,r,ctxInfo,CtsEnforcement::kApiLevel_T)109 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkRuntimeBlender_GPU,
110 r,
111 ctxInfo,
112 CtsEnforcement::kApiLevel_T) {
113 const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
114 sk_sp<SkSurface> surface(
115 SkSurfaces::RenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kNo, info));
116 test_blend(r, surface.get());
117 }
118