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