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 #define RGBA(key, value) \
40 .rgb_ ## key = value, \
41 .alpha_ ## key = value
42
43 static const struct test blend_tests[] = {
44 {
45 "Replace",
46 {
47 .blend_enable = false,
48 .color_mask = 0xF,
49 },
50 .constant_mask = 0x0,
51 .reads_dest = false,
52 .opaque = true,
53 .fixed_function = true,
54 .alpha_zero_nop = false,
55 .alpha_one_store = false,
56 .hardware = 0xF0122122
57 },
58 {
59 "Alpha",
60 {
61 .blend_enable = true,
62 .color_mask = 0xF,
63
64 RGBA(func, BLEND_FUNC_ADD),
65 RGBA(src_factor, BLEND_FACTOR_SRC_ALPHA),
66 RGBA(dst_factor, BLEND_FACTOR_SRC_ALPHA),
67 RGBA(invert_dst_factor, true),
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, BLEND_FUNC_ADD),
84 RGBA(src_factor, BLEND_FACTOR_ZERO),
85 RGBA(dst_factor, BLEND_FACTOR_ZERO),
86 RGBA(invert_src_factor, true),
87 RGBA(invert_dst_factor, true),
88 },
89 .constant_mask = 0x0,
90 .reads_dest = true,
91 .opaque = false,
92 .fixed_function = true,
93 .alpha_zero_nop = false,
94 .alpha_one_store = false,
95 .hardware = 0xF0932932 /* equivalently 0xF0923923 */
96 },
97 {
98 "Additive-Alpha",
99 {
100 .blend_enable = true,
101 .color_mask = 0xF,
102
103 RGBA(func, BLEND_FUNC_ADD),
104 RGBA(src_factor, BLEND_FACTOR_SRC_ALPHA),
105 RGBA(dst_factor, BLEND_FACTOR_ZERO),
106 RGBA(invert_dst_factor, true),
107 },
108 .constant_mask = 0x0,
109 .reads_dest = true,
110 .opaque = false,
111 .fixed_function = true,
112 .alpha_zero_nop = true,
113 .alpha_one_store = false,
114 .hardware = 0xF0523523
115 },
116 {
117 "Subtractive",
118 {
119 .blend_enable = true,
120 .color_mask = 0xF,
121
122 RGBA(func, BLEND_FUNC_SUBTRACT),
123 RGBA(src_factor, BLEND_FACTOR_ZERO),
124 RGBA(dst_factor, BLEND_FACTOR_ZERO),
125 RGBA(invert_src_factor, true),
126 RGBA(invert_dst_factor, true),
127 },
128 .constant_mask = 0x0,
129 .reads_dest = true,
130 .opaque = false,
131 .fixed_function = true,
132 .alpha_zero_nop = false,
133 .alpha_one_store = false,
134 .hardware = 0xF09B29B2 /* equivalently 0xF09A39A3 */
135 },
136 {
137 "Subtractive-Alpha",
138 {
139 .blend_enable = true,
140 .color_mask = 0xF,
141
142 RGBA(func, BLEND_FUNC_SUBTRACT),
143 RGBA(src_factor, BLEND_FACTOR_SRC_ALPHA),
144 RGBA(dst_factor, BLEND_FACTOR_ZERO),
145 RGBA(invert_dst_factor, true),
146 },
147 .constant_mask = 0x0,
148 .reads_dest = true,
149 .opaque = false,
150 .fixed_function = true,
151 .alpha_zero_nop = false,
152 .alpha_one_store = false,
153 .hardware = 0xF052B52b /* equivalently 0xF05A35A3 */
154 },
155 {
156 "Modulate",
157 {
158 .blend_enable = true,
159 .color_mask = 0xF,
160
161 RGBA(func, BLEND_FUNC_ADD),
162 RGBA(src_factor, BLEND_FACTOR_ZERO),
163 RGBA(dst_factor, BLEND_FACTOR_SRC_COLOR),
164 },
165 .constant_mask = 0x0,
166 .reads_dest = true,
167 .opaque = false,
168 .fixed_function = true,
169 .alpha_zero_nop = false,
170 .alpha_one_store = false,
171 .hardware = 0xF0231231 /* equivalently 0xF0321321 */
172 },
173 {
174 "Replace masked",
175 {
176 .blend_enable = false,
177 .color_mask = 0x3,
178 },
179 .constant_mask = 0x0,
180 .reads_dest = true,
181 .opaque = false,
182 .fixed_function = true,
183 .alpha_zero_nop = false,
184 .alpha_one_store = false,
185 .hardware = 0x30122122
186 },
187 {
188 "Modulate masked",
189 {
190 .blend_enable = true,
191 .color_mask = 0xA,
192
193 RGBA(func, BLEND_FUNC_ADD),
194 RGBA(src_factor, BLEND_FACTOR_ZERO),
195 RGBA(dst_factor, BLEND_FACTOR_SRC_COLOR),
196 },
197 .constant_mask = 0x0,
198 .reads_dest = true,
199 .opaque = false,
200 .fixed_function = true,
201 .alpha_zero_nop = false,
202 .alpha_one_store = false,
203 .hardware = 0xA0231231 /* equivalently 0xA0321321 */
204 },
205 {
206 "src*dst + dst*src",
207 {
208 .blend_enable = true,
209 .color_mask = 0xF,
210
211 RGBA(func, BLEND_FUNC_ADD),
212 RGBA(src_factor, BLEND_FACTOR_DST_COLOR),
213 RGBA(dst_factor, BLEND_FACTOR_SRC_COLOR),
214 },
215 .constant_mask = 0x0,
216 .reads_dest = true,
217 .opaque = false,
218 .fixed_function = true,
219 .alpha_zero_nop = false,
220 .alpha_one_store = false,
221 .hardware = 0xF0431431 /* 0 + dest * (2*src) */
222 },
223 {
224 "Mixed src*dst + dst*src masked I",
225 {
226 .blend_enable = true,
227 .color_mask = 0xC,
228
229 .rgb_func = BLEND_FUNC_ADD,
230 .rgb_src_factor = BLEND_FACTOR_ZERO,
231 .rgb_invert_src_factor = true,
232 .rgb_dst_factor= BLEND_FACTOR_ZERO,
233
234 .alpha_func = BLEND_FUNC_ADD,
235 .alpha_src_factor = BLEND_FACTOR_DST_COLOR,
236 .alpha_dst_factor= BLEND_FACTOR_SRC_COLOR,
237 },
238 .constant_mask = 0x0,
239 .reads_dest = true,
240 .opaque = false,
241 .fixed_function = true,
242 .alpha_zero_nop = false,
243 .alpha_one_store = false,
244 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
245 },
246 {
247 "Mixed src*dst + dst*src masked II",
248 {
249 .blend_enable = true,
250 .color_mask = 0xC,
251
252 .rgb_func = BLEND_FUNC_ADD,
253 .rgb_src_factor = BLEND_FACTOR_ZERO,
254 .rgb_invert_src_factor = true,
255 .rgb_dst_factor= BLEND_FACTOR_ZERO,
256
257 .alpha_func = BLEND_FUNC_ADD,
258 .alpha_src_factor = BLEND_FACTOR_DST_ALPHA,
259 .alpha_dst_factor= BLEND_FACTOR_SRC_COLOR,
260 },
261 .constant_mask = 0x0,
262 .reads_dest = true,
263 .opaque = false,
264 .fixed_function = true,
265 .alpha_zero_nop = false,
266 .alpha_one_store = false,
267 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
268 },
269 {
270 "Mixed src*dst + dst*src masked III",
271 {
272 .blend_enable = true,
273 .color_mask = 0xC,
274
275 .rgb_func = BLEND_FUNC_ADD,
276 .rgb_src_factor = BLEND_FACTOR_ZERO,
277 .rgb_invert_src_factor = true,
278 .rgb_dst_factor= BLEND_FACTOR_ZERO,
279
280 .alpha_func = BLEND_FUNC_ADD,
281 .alpha_src_factor = BLEND_FACTOR_DST_ALPHA,
282 .alpha_dst_factor= BLEND_FACTOR_SRC_ALPHA,
283 },
284 .constant_mask = 0x0,
285 .reads_dest = true,
286 .opaque = false,
287 .fixed_function = true,
288 .alpha_zero_nop = false,
289 .alpha_one_store = false,
290 .hardware = 0xC0431132 /* 0 + dest * (2*src); equivalent 0xC0431122 */
291 }
292 };
293
294 #define ASSERT_EQ(x, y) do { \
295 if (x == y) { \
296 nr_pass++; \
297 } else { \
298 nr_fail++; \
299 fprintf(stderr, "%s: Assertion failed %s (%x) != %s (%x)\n", \
300 T.label, #x, x, #y, y); \
301 } \
302 } while(0)
303
main(int argc,const char ** argv)304 int main(int argc, const char **argv)
305 {
306 unsigned nr_pass = 0, nr_fail = 0;
307
308 for (unsigned i = 0; i < ARRAY_SIZE(blend_tests); ++i) {
309 struct test T = blend_tests[i];
310 ASSERT_EQ(T.constant_mask, pan_blend_constant_mask(T.eq));
311 ASSERT_EQ(T.reads_dest, pan_blend_reads_dest(T.eq));
312 ASSERT_EQ(T.opaque, pan_blend_is_opaque(T.eq));
313 ASSERT_EQ(T.fixed_function, pan_blend_can_fixed_function(T.eq, true));
314 ASSERT_EQ(T.alpha_zero_nop, pan_blend_alpha_zero_nop(T.eq));
315 ASSERT_EQ(T.alpha_one_store, pan_blend_alpha_one_store(T.eq));
316
317 if (pan_blend_can_fixed_function(T.eq, true)) {
318 ASSERT_EQ(T.hardware, pan_pack_blend(T.eq));
319 }
320 }
321
322 printf("Passed %u/%u\n", nr_pass, nr_pass + nr_fail);
323 return nr_fail ? 1 : 0;
324 }
325