1b8e80941Smrg/*
2b8e80941Smrg * © Copyright 2018 Alyssa Rosenzweig
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21b8e80941Smrg * SOFTWARE.
22b8e80941Smrg *
23b8e80941Smrg */
24b8e80941Smrg
25b8e80941Smrg#include <stdio.h>
26b8e80941Smrg#include "pan_blending.h"
27b8e80941Smrg
28b8e80941Smrg/*
29b8e80941Smrg * Implements fixed-function blending on Midgard.
30b8e80941Smrg *
31b8e80941Smrg * Midgard splits blending into a fixed-function fast path and a programmable
32b8e80941Smrg * slow path. The fixed function blending architecture is based on "dominant"
33b8e80941Smrg * blend factors. Blending is encoded separately (but identically) between RGB
34b8e80941Smrg * and alpha functions.
35b8e80941Smrg *
36b8e80941Smrg * Essentially, for a given blending operation, there is a single dominant
37b8e80941Smrg * factor. The following dominant factors are possible:
38b8e80941Smrg *
39b8e80941Smrg * 	- zero
40b8e80941Smrg * 	- source color
41b8e80941Smrg * 	- destination color
42b8e80941Smrg * 	- source alpha
43b8e80941Smrg * 	- destination alpha
44b8e80941Smrg * 	- constant float
45b8e80941Smrg *
46b8e80941Smrg * Further, a dominant factor's arithmetic compliment could be used. For
47b8e80941Smrg * instance, to encode GL_ONE_MINUS_SOURCE_ALPHA, the dominant factor would be
48b8e80941Smrg * MALI_DOMINANT_SRC_ALPHA with the complement_dominant bit set.
49b8e80941Smrg *
50b8e80941Smrg * A single constant float can be passed to the fixed-function hardware,
51b8e80941Smrg * allowing CONSTANT_ALPHA support. Further, if all components of the constant
52b8e80941Smrg * glBlendColor are identical, CONSTANT_COLOR can be implemented with the
53b8e80941Smrg * constant float mode. If the components differ, programmable blending is
54b8e80941Smrg * required.
55b8e80941Smrg *
56b8e80941Smrg * The nondominant factor can be either:
57b8e80941Smrg *
58b8e80941Smrg * 	- the same as the dominant factor (MALI_BLEND_NON_MIRROR)
59b8e80941Smrg * 	- zero (MALI_BLEND_NON_ZERO)
60b8e80941Smrg *
61b8e80941Smrg * Exactly one of the blend operation's source or destination can be used as
62b8e80941Smrg * the dominant factor; this is selected by the
63b8e80941Smrg * MALI_BLEND_DOM_SOURCE/DESTINATION flag.
64b8e80941Smrg *
65b8e80941Smrg * By default, all blending follows the standard OpenGL addition equation:
66b8e80941Smrg *
67b8e80941Smrg * 	out = source_value * source_factor + destination_value * destination_factor
68b8e80941Smrg *
69b8e80941Smrg * By setting the negate_source or negate_dest bits, other blend functions can
70b8e80941Smrg * be created. For instance, for SUBTRACT mode, set the "negate destination"
71b8e80941Smrg * flag, and similarly for REVERSE_SUBTRACT with "negate source".
72b8e80941Smrg *
73b8e80941Smrg * Finally, there is a "clip modifier" controlling the final blending
74b8e80941Smrg * behaviour, allowing for the following modes:
75b8e80941Smrg *
76b8e80941Smrg * 	- normal
77b8e80941Smrg * 	- force source factor to one (MALI_BLEND_MODE_SOURCE_ONE)
78b8e80941Smrg * 	- force destination factor to one (MALI_BLEND_MODE_DEST_ONE)
79b8e80941Smrg *
80b8e80941Smrg * The clipping flags can be used to encode blend modes where the nondominant
81b8e80941Smrg * factor is ONE.
82b8e80941Smrg *
83b8e80941Smrg * As an example putting it all together, to encode the following blend state:
84b8e80941Smrg *
85b8e80941Smrg * 	glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
86b8e80941Smrg * 	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
87b8e80941Smrg *
88b8e80941Smrg * We need the following configuration:
89b8e80941Smrg *
90b8e80941Smrg * 	- negate source (for REVERSE_SUBTRACT)
91b8e80941Smrg * 	- dominant factor "source alpha"
92b8e80941Smrg * 		- compliment dominant
93b8e80941Smrg * 		- source dominant
94b8e80941Smrg * 	- force destination to ONE
95b8e80941Smrg *
96b8e80941Smrg * The following routines implement this fixed function blending encoding
97b8e80941Smrg */
98b8e80941Smrg
99b8e80941Smrg/* Helper to find the uncomplemented Gallium blend factor corresponding to a
100b8e80941Smrg * complemented Gallium blend factor */
101b8e80941Smrg
102b8e80941Smrgstatic int
103b8e80941Smrgcomplement_factor(int factor)
104b8e80941Smrg{
105b8e80941Smrg        switch (factor) {
106b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
107b8e80941Smrg                return PIPE_BLENDFACTOR_SRC_COLOR;
108b8e80941Smrg
109b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
110b8e80941Smrg                return PIPE_BLENDFACTOR_SRC_ALPHA;
111b8e80941Smrg
112b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
113b8e80941Smrg                return PIPE_BLENDFACTOR_DST_ALPHA;
114b8e80941Smrg
115b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_COLOR:
116b8e80941Smrg                return PIPE_BLENDFACTOR_DST_COLOR;
117b8e80941Smrg
118b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
119b8e80941Smrg                return PIPE_BLENDFACTOR_CONST_COLOR;
120b8e80941Smrg
121b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
122b8e80941Smrg                return PIPE_BLENDFACTOR_CONST_ALPHA;
123b8e80941Smrg
124b8e80941Smrg        default:
125b8e80941Smrg                return -1;
126b8e80941Smrg        }
127b8e80941Smrg}
128b8e80941Smrg
129b8e80941Smrg/* Helper to strip the complement from any Gallium blend factor */
130b8e80941Smrg
131b8e80941Smrgstatic int
132b8e80941Smrguncomplement_factor(int factor)
133b8e80941Smrg{
134b8e80941Smrg        int complement = complement_factor(factor);
135b8e80941Smrg        return (complement == -1) ? factor : complement;
136b8e80941Smrg}
137b8e80941Smrg
138b8e80941Smrg
139b8e80941Smrg/* Attempt to find the dominant factor given a particular factor, complementing
140b8e80941Smrg * as necessary */
141b8e80941Smrg
142b8e80941Smrgstatic bool
143b8e80941Smrgpanfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *factor, bool *invert)
144b8e80941Smrg{
145b8e80941Smrg        switch (src_factor) {
146b8e80941Smrg        case PIPE_BLENDFACTOR_SRC_COLOR:
147b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
148b8e80941Smrg                *factor = MALI_DOMINANT_SRC_COLOR;
149b8e80941Smrg                break;
150b8e80941Smrg
151b8e80941Smrg        case PIPE_BLENDFACTOR_SRC_ALPHA:
152b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
153b8e80941Smrg                *factor = MALI_DOMINANT_SRC_ALPHA;
154b8e80941Smrg                break;
155b8e80941Smrg
156b8e80941Smrg        case PIPE_BLENDFACTOR_DST_COLOR:
157b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_COLOR:
158b8e80941Smrg                *factor = MALI_DOMINANT_DST_COLOR;
159b8e80941Smrg                break;
160b8e80941Smrg
161b8e80941Smrg        case PIPE_BLENDFACTOR_DST_ALPHA:
162b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
163b8e80941Smrg                *factor = MALI_DOMINANT_DST_ALPHA;
164b8e80941Smrg                break;
165b8e80941Smrg
166b8e80941Smrg        case PIPE_BLENDFACTOR_ONE:
167b8e80941Smrg        case PIPE_BLENDFACTOR_ZERO:
168b8e80941Smrg                *factor = MALI_DOMINANT_ZERO;
169b8e80941Smrg                break;
170b8e80941Smrg
171b8e80941Smrg        case PIPE_BLENDFACTOR_CONST_ALPHA:
172b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
173b8e80941Smrg        case PIPE_BLENDFACTOR_CONST_COLOR:
174b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
175b8e80941Smrg                *factor = MALI_DOMINANT_CONSTANT;
176b8e80941Smrg                break;
177b8e80941Smrg
178b8e80941Smrg        default:
179b8e80941Smrg                /* Fancy blend modes not supported */
180b8e80941Smrg                return false;
181b8e80941Smrg        }
182b8e80941Smrg
183b8e80941Smrg        /* Set invert flags */
184b8e80941Smrg
185b8e80941Smrg        switch (src_factor) {
186b8e80941Smrg        case PIPE_BLENDFACTOR_ONE:
187b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
188b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
189b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
190b8e80941Smrg        case PIPE_BLENDFACTOR_INV_DST_COLOR:
191b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
192b8e80941Smrg        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
193b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
194b8e80941Smrg        case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
195b8e80941Smrg                *invert = true;
196b8e80941Smrg
197b8e80941Smrg        default:
198b8e80941Smrg                break;
199b8e80941Smrg        }
200b8e80941Smrg
201b8e80941Smrg        return true;
202b8e80941Smrg}
203b8e80941Smrg
204b8e80941Smrg/* Check if this is a special edge case blend factor, which may require the use
205b8e80941Smrg * of clip modifiers */
206b8e80941Smrg
207b8e80941Smrgstatic bool
208b8e80941Smrgis_edge_blendfactor(unsigned factor)
209b8e80941Smrg{
210b8e80941Smrg        return factor == PIPE_BLENDFACTOR_ONE || factor == PIPE_BLENDFACTOR_ZERO;
211b8e80941Smrg}
212b8e80941Smrg
213b8e80941Smrg/* Perform the actual fixed function encoding. Encode the function with negate
214b8e80941Smrg * bits. Check for various cases to work out the dominant/nondominant split and
215b8e80941Smrg * accompanying flags. */
216b8e80941Smrg
217b8e80941Smrgstatic bool
218b8e80941Smrgpanfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_factor, unsigned *out)
219b8e80941Smrg{
220b8e80941Smrg        struct mali_blend_mode part = { 0 };
221b8e80941Smrg
222b8e80941Smrg        /* Make sure that the blend function is representible with negate flags */
223b8e80941Smrg
224b8e80941Smrg        if (func == PIPE_BLEND_ADD) {
225b8e80941Smrg                /* Default, no modifiers needed */
226b8e80941Smrg        } else if (func == PIPE_BLEND_SUBTRACT)
227b8e80941Smrg                part.negate_dest = true;
228b8e80941Smrg        else if (func == PIPE_BLEND_REVERSE_SUBTRACT)
229b8e80941Smrg                part.negate_source = true;
230b8e80941Smrg        else
231b8e80941Smrg                return false;
232b8e80941Smrg
233b8e80941Smrg        part.clip_modifier = MALI_BLEND_MOD_NORMAL;
234b8e80941Smrg
235b8e80941Smrg        /* Decide which is dominant, source or destination. If one is an edge
236b8e80941Smrg         * case, use the other as a factor. If they're the same, it doesn't
237b8e80941Smrg         * matter; we just mirror. If they're different non-edge-cases, you
238b8e80941Smrg         * need a blend shader (don't do that). */
239b8e80941Smrg
240b8e80941Smrg        if (is_edge_blendfactor(dst_factor)) {
241b8e80941Smrg                part.dominant = MALI_BLEND_DOM_SOURCE;
242b8e80941Smrg                part.nondominant_mode = MALI_BLEND_NON_ZERO;
243b8e80941Smrg
244b8e80941Smrg                if (dst_factor == PIPE_BLENDFACTOR_ONE)
245b8e80941Smrg                        part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
246b8e80941Smrg        } else if (is_edge_blendfactor(src_factor)) {
247b8e80941Smrg                part.dominant = MALI_BLEND_DOM_DESTINATION;
248b8e80941Smrg                part.nondominant_mode = MALI_BLEND_NON_ZERO;
249b8e80941Smrg
250b8e80941Smrg                if (src_factor == PIPE_BLENDFACTOR_ONE)
251b8e80941Smrg                        part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
252b8e80941Smrg
253b8e80941Smrg        } else if (src_factor == dst_factor) {
254b8e80941Smrg                part.dominant = MALI_BLEND_DOM_DESTINATION; /* Ought to be an arbitrary choice, but we need to set destination for some reason? Align with the blob until we understand more */
255b8e80941Smrg                part.nondominant_mode = MALI_BLEND_NON_MIRROR;
256b8e80941Smrg        } else if (src_factor == complement_factor(dst_factor)) {
257b8e80941Smrg                /* TODO: How does this work exactly? */
258b8e80941Smrg                part.dominant = MALI_BLEND_DOM_SOURCE;
259b8e80941Smrg                part.nondominant_mode = MALI_BLEND_NON_MIRROR;
260b8e80941Smrg                part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
261b8e80941Smrg        } else if (dst_factor == complement_factor(src_factor)) {
262b8e80941Smrg                part.dominant = MALI_BLEND_DOM_SOURCE;
263b8e80941Smrg                part.nondominant_mode = MALI_BLEND_NON_MIRROR;
264b8e80941Smrg                part.clip_modifier = /*MALI_BLEND_MOD_SOURCE_ONE*/MALI_BLEND_MOD_DEST_ONE; /* Which modifier should it be? */
265b8e80941Smrg        } else {
266b8e80941Smrg                printf("Failed to find dominant factor?\n");
267b8e80941Smrg                return false;
268b8e80941Smrg        }
269b8e80941Smrg
270b8e80941Smrg        unsigned in_dominant_factor =
271b8e80941Smrg                part.dominant == MALI_BLEND_DOM_SOURCE ? src_factor : dst_factor;
272b8e80941Smrg
273b8e80941Smrg        if (part.clip_modifier == MALI_BLEND_MOD_NORMAL && in_dominant_factor == PIPE_BLENDFACTOR_ONE) {
274b8e80941Smrg                part.clip_modifier = part.dominant == MALI_BLEND_DOM_SOURCE ? MALI_BLEND_MOD_SOURCE_ONE : MALI_BLEND_MOD_DEST_ONE;
275b8e80941Smrg                in_dominant_factor = PIPE_BLENDFACTOR_ZERO;
276b8e80941Smrg        }
277b8e80941Smrg
278b8e80941Smrg        bool invert_dominant = false;
279b8e80941Smrg        enum mali_dominant_factor dominant_factor;
280b8e80941Smrg
281b8e80941Smrg        if (!panfrost_make_dominant_factor(in_dominant_factor, &dominant_factor, &invert_dominant))
282b8e80941Smrg                return false;
283b8e80941Smrg
284b8e80941Smrg        part.dominant_factor = dominant_factor;
285b8e80941Smrg        part.complement_dominant = invert_dominant;
286b8e80941Smrg
287b8e80941Smrg        /* Write out mode */
288b8e80941Smrg        memcpy(out, &part, sizeof(part));
289b8e80941Smrg
290b8e80941Smrg        return true;
291b8e80941Smrg}
292b8e80941Smrg
293b8e80941Smrg/* We can upload a single constant for all of the factors. So, scan the factors
294b8e80941Smrg * for constants used, and scan the constants for the constants used. If there
295b8e80941Smrg * is a single unique constant, output that. If there are multiple,
296b8e80941Smrg * fixed-function operation breaks down. */
297b8e80941Smrg
298b8e80941Smrgstatic bool
299b8e80941Smrgpanfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, void *out)
300b8e80941Smrg{
301b8e80941Smrg        /* Color components used */
302b8e80941Smrg        bool cc[4] = { false };
303b8e80941Smrg
304b8e80941Smrg        for (unsigned i = 0; i < num_factors; ++i) {
305b8e80941Smrg                unsigned factor = uncomplement_factor(factors[i]);
306b8e80941Smrg
307b8e80941Smrg                if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
308b8e80941Smrg                        cc[0] = cc[1] = cc[2] = true;
309b8e80941Smrg                else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
310b8e80941Smrg                        cc[3] = true;
311b8e80941Smrg        }
312b8e80941Smrg
313b8e80941Smrg        /* Find the actual constant associated with the components used*/
314b8e80941Smrg
315b8e80941Smrg        float constant = 0.0;
316b8e80941Smrg        bool has_constant = false;
317b8e80941Smrg
318b8e80941Smrg        for (unsigned i = 0; i < 4; ++i) {
319b8e80941Smrg                /* If the component is unused, nothing to do */
320b8e80941Smrg                if (!cc[i]) continue;
321b8e80941Smrg
322b8e80941Smrg                float value = blend_color->color[i];
323b8e80941Smrg
324b8e80941Smrg                /* Either there's a second constant, in which case we fail, or
325b8e80941Smrg                 * there's no constant / a first constant, in which case we use
326b8e80941Smrg                 * that constant */
327b8e80941Smrg
328b8e80941Smrg                if (has_constant && constant != value) {
329b8e80941Smrg                        return false;
330b8e80941Smrg                } else {
331b8e80941Smrg                        has_constant = true;
332b8e80941Smrg                        constant = value;
333b8e80941Smrg                }
334b8e80941Smrg        }
335b8e80941Smrg
336b8e80941Smrg        /* We have the constant -- success! */
337b8e80941Smrg
338b8e80941Smrg        memcpy(out, &constant, sizeof(float));
339b8e80941Smrg        return true;
340b8e80941Smrg}
341b8e80941Smrg
342b8e80941Smrg/* Create the descriptor for a fixed blend mode given the corresponding Gallium
343b8e80941Smrg * state, if possible. Return true and write out the blend descriptor into
344b8e80941Smrg * blend_equation. If it is not possible with the fixed function
345b8e80941Smrg * representating, return false to handle degenerate cases with a blend shader
346b8e80941Smrg */
347b8e80941Smrg
348b8e80941Smrgstatic const struct pipe_rt_blend_state default_blend = {
349b8e80941Smrg        .blend_enable = 1,
350b8e80941Smrg
351b8e80941Smrg        .rgb_func = PIPE_BLEND_ADD,
352b8e80941Smrg        .rgb_src_factor = PIPE_BLENDFACTOR_ONE,
353b8e80941Smrg        .rgb_dst_factor = PIPE_BLENDFACTOR_ZERO,
354b8e80941Smrg
355b8e80941Smrg        .alpha_func = PIPE_BLEND_ADD,
356b8e80941Smrg        .alpha_src_factor = PIPE_BLENDFACTOR_ONE,
357b8e80941Smrg        .alpha_dst_factor = PIPE_BLENDFACTOR_ZERO,
358b8e80941Smrg
359b8e80941Smrg        .colormask = PIPE_MASK_RGBA
360b8e80941Smrg};
361b8e80941Smrg
362b8e80941Smrgbool
363b8e80941Smrgpanfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state *blend, struct mali_blend_equation *out, unsigned colormask, const struct pipe_blend_color *blend_color)
364b8e80941Smrg{
365b8e80941Smrg        /* If no blending is enabled, default back on `replace` mode */
366b8e80941Smrg
367b8e80941Smrg        if (!blend->blend_enable)
368b8e80941Smrg                return panfrost_make_fixed_blend_mode(&default_blend, out, colormask, blend_color);
369b8e80941Smrg
370b8e80941Smrg        /* We have room only for a single float32 constant between the four
371b8e80941Smrg         * components. If we need more, spill to the programmable pipeline. */
372b8e80941Smrg
373b8e80941Smrg        unsigned factors[] = {
374b8e80941Smrg                blend->rgb_src_factor, blend->rgb_dst_factor,
375b8e80941Smrg                blend->alpha_src_factor, blend->alpha_dst_factor,
376b8e80941Smrg        };
377b8e80941Smrg
378b8e80941Smrg        if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &out->constant))
379b8e80941Smrg                return false;
380b8e80941Smrg
381b8e80941Smrg        unsigned rgb_mode = 0;
382b8e80941Smrg        unsigned alpha_mode = 0;
383b8e80941Smrg
384b8e80941Smrg        if (!panfrost_make_fixed_blend_part(
385b8e80941Smrg                                blend->rgb_func, blend->rgb_src_factor, blend->rgb_dst_factor,
386b8e80941Smrg                                &rgb_mode))
387b8e80941Smrg                return false;
388b8e80941Smrg
389b8e80941Smrg        if (!panfrost_make_fixed_blend_part(
390b8e80941Smrg                                blend->alpha_func, blend->alpha_src_factor, blend->alpha_dst_factor,
391b8e80941Smrg                                &alpha_mode))
392b8e80941Smrg                return false;
393b8e80941Smrg
394b8e80941Smrg        out->rgb_mode = rgb_mode;
395b8e80941Smrg        out->alpha_mode = alpha_mode;
396b8e80941Smrg
397b8e80941Smrg        /* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */
398b8e80941Smrg        out->color_mask = colormask;
399b8e80941Smrg
400b8e80941Smrg        return true;
401b8e80941Smrg}
402