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 */
27struct 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
43static 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
304int 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