1 /*
2 * Copyright (C) 2021 Collabora, Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include "pan_blend.h"
25
26 /* A test consists of a given blend mode and its translated form */
27 struct test {
28 const char *label;
29 struct pan_blend_equation eq;
30 unsigned constant_mask;
31 bool reads_dest;
32 bool opaque;
33 bool fixed_function;
34 bool alpha_zero_nop;
35 bool alpha_one_store;
36 uint32_t hardware;
37 };
38
39 /* clang-format off */
40 #define RGBA(key, value) \
41 .rgb_ ## key = value, \
42 .alpha_ ## key = value
43
44 static const struct test blend_tests[] = {
45 {
46 "Replace",
47 {
48 .blend_enable = false,
49 .color_mask = 0xF,
50 },
51 .constant_mask = 0x0,
52 .reads_dest = false,
53 .opaque = true,
54 .fixed_function = true,
55 .alpha_zero_nop = false,
56 .alpha_one_store = false,
57 .hardware = 0xF0122122
58 },
59 {
60 "Alpha",
61 {
62 .blend_enable = true,
63 .color_mask = 0xF,
64
65 RGBA(func, PIPE_BLEND_ADD),
66 RGBA(src_factor, PIPE_BLENDFACTOR_SRC_ALPHA),
67 RGBA(dst_factor, PIPE_BLENDFACTOR_INV_SRC_ALPHA),
68 },
69 .constant_mask = 0x0,
70 .reads_dest = true,
71 .opaque = false,
72 .fixed_function = true,
73 .alpha_zero_nop = true,
74 .alpha_one_store = true,
75 .hardware = 0xF0503503
76 },
77 {
78 "Additive",
79 {
80 .blend_enable = true,
81 .color_mask = 0xF,
82
83 RGBA(func, PIPE_BLEND_ADD),
84 RGBA(src_factor, PIPE_BLENDFACTOR_ONE),
85 RGBA(dst_factor, PIPE_BLENDFACTOR_ONE),
86 },
87 .constant_mask = 0x0,
88 .reads_dest = true,
89 .opaque = false,
90 .fixed_function = true,
91 .alpha_zero_nop = false,
92 .alpha_one_store = false,
93 .hardware = 0xF0932932 /* equivalently 0xF0923923 */
94 },
95 {
96 "Additive-Alpha",
97 {
98 .blend_enable = true,
99 .color_mask = 0xF,
100
101 RGBA(func, PIPE_BLEND_ADD),
102 RGBA(src_factor, PIPE_BLENDFACTOR_SRC_ALPHA),
103 RGBA(dst_factor, PIPE_BLENDFACTOR_ONE),
104 },
105 .constant_mask = 0x0,
106 .reads_dest = true,
107 .opaque = false,
108 .fixed_function = true,
109 .alpha_zero_nop = true,
110 .alpha_one_store = false,
111 .hardware = 0xF0523523
112 },
113 {
114 "Subtractive",
115 {
116 .blend_enable = true,
117 .color_mask = 0xF,
118
119 RGBA(func, PIPE_BLEND_SUBTRACT),
120 RGBA(src_factor, PIPE_BLENDFACTOR_ONE),
121 RGBA(dst_factor, PIPE_BLENDFACTOR_ONE),
122 },
123 .constant_mask = 0x0,
124 .reads_dest = true,
125 .opaque = false,
126 .fixed_function = true,
127 .alpha_zero_nop = false,
128 .alpha_one_store = false,
129 .hardware = 0xF09B29B2 /* equivalently 0xF09A39A3 */
130 },
131 {
132 "Subtractive-Alpha",
133 {
134 .blend_enable = true,
135 .color_mask = 0xF,
136
137 RGBA(func, PIPE_BLEND_SUBTRACT),
138 RGBA(src_factor, PIPE_BLENDFACTOR_SRC_ALPHA),
139 RGBA(dst_factor, PIPE_BLENDFACTOR_ONE),
140 },
141 .constant_mask = 0x0,
142 .reads_dest = true,
143 .opaque = false,
144 .fixed_function = true,
145 .alpha_zero_nop = false,
146 .alpha_one_store = false,
147 .hardware = 0xF052B52b /* equivalently 0xF05A35A3 */
148 },
149 {
150 "Modulate",
151 {
152 .blend_enable = true,
153 .color_mask = 0xF,
154
155 RGBA(func, PIPE_BLEND_ADD),
156 RGBA(src_factor, PIPE_BLENDFACTOR_ZERO),
157 RGBA(dst_factor, PIPE_BLENDFACTOR_SRC_COLOR),
158 },
159 .constant_mask = 0x0,
160 .reads_dest = true,
161 .opaque = false,
162 .fixed_function = true,
163 .alpha_zero_nop = false,
164 .alpha_one_store = false,
165 .hardware = 0xF0231231 /* equivalently 0xF0321321 */
166 },
167 {
168 "Replace masked",
169 {
170 .blend_enable = false,
171 .color_mask = 0x3,
172 },
173 .constant_mask = 0x0,
174 .reads_dest = true,
175 .opaque = false,
176 .fixed_function = true,
177 .alpha_zero_nop = false,
178 .alpha_one_store = false,
179 .hardware = 0x30122122
180 },
181 {
182 "Modulate masked",
183 {
184 .blend_enable = true,
185 .color_mask = 0xA,
186
187 RGBA(func, PIPE_BLEND_ADD),
188 RGBA(src_factor, PIPE_BLENDFACTOR_ZERO),
189 RGBA(dst_factor, PIPE_BLENDFACTOR_SRC_COLOR),
190 },
191 .constant_mask = 0x0,
192 .reads_dest = true,
193 .opaque = false,
194 .fixed_function = true,
195 .alpha_zero_nop = false,
196 .alpha_one_store = false,
197 .hardware = 0xA0231231 /* equivalently 0xA0321321 */
198 },
199 {
200 "src*dst + dst*src",
201 {
202 .blend_enable = true,
203 .color_mask = 0xF,
204
205 RGBA(func, PIPE_BLEND_ADD),
206 RGBA(src_factor, PIPE_BLENDFACTOR_DST_COLOR),
207 RGBA(dst_factor, PIPE_BLENDFACTOR_SRC_COLOR),
208 },
209 .constant_mask = 0x0,
210 .reads_dest = true,
211 .opaque = false,
212 .fixed_function = true,
213 .alpha_zero_nop = false,
214 .alpha_one_store = false,
215 .hardware = 0xF0431431 /* 0 + dest * (2*src) */
216 },
217 {
218 "Mixed src*dst + dst*src masked I",
219 {
220 .blend_enable = true,
221 .color_mask = 0xC,
222
223 .rgb_func = PIPE_BLEND_ADD,
224 .rgb_src_factor = PIPE_BLENDFACTOR_ONE,
225 .rgb_dst_factor= PIPE_BLENDFACTOR_ZERO,
226
227 .alpha_func = PIPE_BLEND_ADD,
228 .alpha_src_factor = PIPE_BLENDFACTOR_DST_COLOR,
229 .alpha_dst_factor= PIPE_BLENDFACTOR_SRC_COLOR,
230 },
231 .constant_mask = 0x0,
232 .reads_dest = true,
233 .opaque = false,
234 .fixed_function = true,
235 .alpha_zero_nop = false,
236 .alpha_one_store = false,
237 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
238 },
239 {
240 "Mixed src*dst + dst*src masked II",
241 {
242 .blend_enable = true,
243 .color_mask = 0xC,
244
245 .rgb_func = PIPE_BLEND_ADD,
246 .rgb_src_factor = PIPE_BLENDFACTOR_ONE,
247 .rgb_dst_factor = PIPE_BLENDFACTOR_ZERO,
248
249 .alpha_func = PIPE_BLEND_ADD,
250 .alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA,
251 .alpha_dst_factor= PIPE_BLENDFACTOR_SRC_COLOR,
252 },
253 .constant_mask = 0x0,
254 .reads_dest = true,
255 .opaque = false,
256 .fixed_function = true,
257 .alpha_zero_nop = false,
258 .alpha_one_store = false,
259 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
260 },
261 {
262 "Mixed src*dst + dst*src masked III",
263 {
264 .blend_enable = true,
265 .color_mask = 0xC,
266
267 .rgb_func = PIPE_BLEND_ADD,
268 .rgb_src_factor = PIPE_BLENDFACTOR_ONE,
269 .rgb_dst_factor = PIPE_BLENDFACTOR_ZERO,
270
271 .alpha_func = PIPE_BLEND_ADD,
272 .alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA,
273 .alpha_dst_factor= PIPE_BLENDFACTOR_SRC_ALPHA,
274 },
275 .constant_mask = 0x0,
276 .reads_dest = true,
277 .opaque = false,
278 .fixed_function = true,
279 .alpha_zero_nop = false,
280 .alpha_one_store = false,
281 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
282 }
283 };
284 /* clang-format on */
285
286 #define ASSERT_EQ(x, y) \
287 do { \
288 if (x == y) { \
289 nr_pass++; \
290 } else { \
291 nr_fail++; \
292 fprintf(stderr, "%s: Assertion failed %s (%x) != %s (%x)\n", T.label, \
293 #x, x, #y, y); \
294 } \
295 } while (0)
296
297 int
main(int argc,const char ** argv)298 main(int argc, const char **argv)
299 {
300 unsigned nr_pass = 0, nr_fail = 0;
301
302 for (unsigned i = 0; i < ARRAY_SIZE(blend_tests); ++i) {
303 struct test T = blend_tests[i];
304 ASSERT_EQ(T.constant_mask, pan_blend_constant_mask(T.eq));
305 ASSERT_EQ(T.reads_dest, pan_blend_reads_dest(T.eq));
306 ASSERT_EQ(T.opaque, pan_blend_is_opaque(T.eq));
307 ASSERT_EQ(T.fixed_function, pan_blend_can_fixed_function(T.eq, true));
308 ASSERT_EQ(T.alpha_zero_nop, pan_blend_alpha_zero_nop(T.eq));
309 ASSERT_EQ(T.alpha_one_store, pan_blend_alpha_one_store(T.eq));
310
311 if (pan_blend_can_fixed_function(T.eq, true)) {
312 ASSERT_EQ(T.hardware, pan_pack_blend(T.eq));
313 }
314 }
315
316 printf("Passed %u/%u\n", nr_pass, nr_pass + nr_fail);
317 return nr_fail ? 1 : 0;
318 }
319