2 * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org>
3 * Copyright © 2018 Google, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * Rob Clark <robclark@freedesktop.org>
28 #include "pipe/p_state.h"
29 #include "util/u_blend.h"
30 #include "util/u_string.h"
31 #include "util/u_memory.h"
33 #include "fd6_blend.h"
34 #include "fd6_context.h"
35 #include "fd6_format.h"
38 // XXX move somewhere common.. same across a3xx/a4xx/a5xx..
39 static enum a3xx_rb_blend_opcode
40 blend_func(unsigned func
)
44 return BLEND_DST_PLUS_SRC
;
46 return BLEND_MIN_DST_SRC
;
48 return BLEND_MAX_DST_SRC
;
49 case PIPE_BLEND_SUBTRACT
:
50 return BLEND_SRC_MINUS_DST
;
51 case PIPE_BLEND_REVERSE_SUBTRACT
:
52 return BLEND_DST_MINUS_SRC
;
54 DBG("invalid blend func: %x", func
);
59 struct fd6_blend_variant
*
60 __fd6_setup_blend_variant(struct fd6_blend_stateobj
*blend
, unsigned sample_mask
)
62 const struct pipe_blend_state
*cso
= &blend
->base
;
63 struct fd6_blend_variant
*so
;
64 enum a3xx_rop_code rop
= ROP_COPY
;
65 bool reads_dest
= false;
66 unsigned mrt_blend
= 0;
68 if (cso
->logicop_enable
) {
69 rop
= cso
->logicop_func
; /* maps 1:1 */
70 reads_dest
= util_logicop_reads_dest(cso
->logicop_func
);
73 so
= rzalloc_size(blend
, sizeof(*so
));
77 struct fd_ringbuffer
*ring
= fd_ringbuffer_new_object(blend
->ctx
->pipe
,
78 ((A6XX_MAX_RENDER_TARGETS
* 4) + 6) * 4);
81 for (unsigned i
= 0; i
<= cso
->max_rt
; i
++) {
82 const struct pipe_rt_blend_state
*rt
;
84 if (cso
->independent_blend_enable
)
89 OUT_REG(ring
, A6XX_RB_MRT_BLEND_CONTROL(i
,
90 .rgb_src_factor
= fd_blend_factor(rt
->rgb_src_factor
),
91 .rgb_blend_opcode
= blend_func(rt
->rgb_func
),
92 .rgb_dest_factor
= fd_blend_factor(rt
->rgb_dst_factor
),
93 .alpha_src_factor
= fd_blend_factor(rt
->alpha_src_factor
),
94 .alpha_blend_opcode
= blend_func(rt
->alpha_func
),
95 .alpha_dest_factor
= fd_blend_factor(rt
->alpha_dst_factor
),
98 OUT_REG(ring
, A6XX_RB_MRT_CONTROL(i
,
100 .rop_enable
= cso
->logicop_enable
,
101 .component_enable
= rt
->colormask
,
102 .blend
= rt
->blend_enable
,
103 .blend2
= rt
->blend_enable
,
106 if (rt
->blend_enable
) {
107 mrt_blend
|= (1 << i
);
111 mrt_blend
|= (1 << i
);
115 OUT_REG(ring
, A6XX_RB_DITHER_CNTL(
116 .dither_mode_mrt0
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
117 .dither_mode_mrt1
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
118 .dither_mode_mrt2
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
119 .dither_mode_mrt3
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
120 .dither_mode_mrt4
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
121 .dither_mode_mrt5
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
122 .dither_mode_mrt6
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
123 .dither_mode_mrt7
= cso
->dither
? DITHER_ALWAYS
: DITHER_DISABLE
,
126 OUT_REG(ring
, A6XX_SP_BLEND_CNTL(
128 .alpha_to_coverage
= cso
->alpha_to_coverage
,
129 .enabled
= !!mrt_blend
,
132 OUT_REG(ring
, A6XX_RB_BLEND_CNTL(
133 .enable_blend
= mrt_blend
,
134 .alpha_to_coverage
= cso
->alpha_to_coverage
,
135 .alpha_to_one
= cso
->alpha_to_one
,
136 .independent_blend
= cso
->independent_blend_enable
,
137 .sample_mask
= sample_mask
140 so
->sample_mask
= sample_mask
;
142 util_dynarray_append(&blend
->variants
, struct fd6_blend_variant
*, so
);
148 fd6_blend_state_create(struct pipe_context
*pctx
,
149 const struct pipe_blend_state
*cso
)
151 struct fd6_blend_stateobj
*so
;
153 so
= rzalloc_size(NULL
, sizeof(*so
));
158 so
->ctx
= fd_context(pctx
);
160 if (cso
->logicop_enable
) {
161 so
->reads_dest
|= util_logicop_reads_dest(cso
->logicop_func
);
164 unsigned nr
= cso
->independent_blend_enable
? cso
->max_rt
: 0;
165 for (unsigned i
= 0; i
<= nr
; i
++) {
166 const struct pipe_rt_blend_state
*rt
= &cso
->rt
[i
];
168 so
->reads_dest
|= rt
->blend_enable
;
170 /* From the PoV of LRZ, having masked color channels is
171 * the same as having blend enabled, in that the draw will
172 * care about the fragments from an earlier draw.
174 * NOTE we actually don't care about masked color channels
175 * that don't actually exist in the render target, but we
176 * don't know the render target format here to determine
177 * that. It is probably not worth worrying about, but if
178 * we find a game/benchmark that goes out of it's way to
179 * mask off non-existent channels, we should fixup the
180 * pipe_blend_state to give us more info.
182 if (rt
->blend_enable
|| (rt
->colormask
!= 0xf)) {
183 so
->reads_dest
= true;
187 util_dynarray_init(&so
->variants
, so
);
193 fd6_blend_state_delete(struct pipe_context
*pctx
, void *hwcso
)
195 struct fd6_blend_stateobj
*so
= hwcso
;
197 util_dynarray_foreach(&so
->variants
, struct fd6_blend_variant
*, vp
) {
198 struct fd6_blend_variant
*v
= *vp
;
199 fd_ringbuffer_del(v
->stateobj
);