xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/freedreno/a6xx/fd6_blend.cc (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2016 Rob Clark <[email protected]>
3  * Copyright © 2018 Google, Inc.
4  * SPDX-License-Identifier: MIT
5  *
6  * Authors:
7  *    Rob Clark <[email protected]>
8  */
9 
10 #define FD_BO_NO_HARDPIN 1
11 
12 #include "pipe/p_state.h"
13 #include "util/u_blend.h"
14 #include "util/u_dual_blend.h"
15 #include "util/u_memory.h"
16 #include "util/u_string.h"
17 
18 #include "fd6_blend.h"
19 #include "fd6_context.h"
20 #include "fd6_pack.h"
21 
22 // XXX move somewhere common.. same across a3xx/a4xx/a5xx..
23 static enum a3xx_rb_blend_opcode
blend_func(unsigned func)24 blend_func(unsigned func)
25 {
26    switch (func) {
27    case PIPE_BLEND_ADD:
28       return BLEND_DST_PLUS_SRC;
29    case PIPE_BLEND_MIN:
30       return BLEND_MIN_DST_SRC;
31    case PIPE_BLEND_MAX:
32       return BLEND_MAX_DST_SRC;
33    case PIPE_BLEND_SUBTRACT:
34       return BLEND_SRC_MINUS_DST;
35    case PIPE_BLEND_REVERSE_SUBTRACT:
36       return BLEND_DST_MINUS_SRC;
37    default:
38       DBG("invalid blend func: %x", func);
39       return (enum a3xx_rb_blend_opcode)0;
40    }
41 }
42 
43 template <chip CHIP>
44 struct fd6_blend_variant *
__fd6_setup_blend_variant(struct fd6_blend_stateobj * blend,unsigned sample_mask)45 __fd6_setup_blend_variant(struct fd6_blend_stateobj *blend,
46                           unsigned sample_mask)
47 {
48    const struct pipe_blend_state *cso = &blend->base;
49    struct fd6_blend_variant *so;
50    enum a3xx_rop_code rop = ROP_COPY;
51    bool reads_dest = false;
52    unsigned mrt_blend = 0;
53 
54    if (cso->logicop_enable) {
55       rop = (enum a3xx_rop_code)cso->logicop_func; /* maps 1:1 */
56       reads_dest = util_logicop_reads_dest((enum pipe_logicop)cso->logicop_func);
57    }
58 
59    so = (struct fd6_blend_variant *)rzalloc_size(blend, sizeof(*so));
60    if (!so)
61       return NULL;
62 
63    struct fd_ringbuffer *ring = fd_ringbuffer_new_object(
64       blend->ctx->pipe, ((A6XX_MAX_RENDER_TARGETS * 4) + 6) * 4);
65    so->stateobj = ring;
66 
67    for (unsigned i = 0; i <= cso->max_rt; i++) {
68       const struct pipe_rt_blend_state *rt;
69 
70       if (cso->independent_blend_enable)
71          rt = &cso->rt[i];
72       else
73          rt = &cso->rt[0];
74 
75       OUT_REG(ring,
76               A6XX_RB_MRT_BLEND_CONTROL(
77                  i, .rgb_src_factor = fd_blend_factor(rt->rgb_src_factor),
78                  .rgb_blend_opcode = blend_func(rt->rgb_func),
79                  .rgb_dest_factor = fd_blend_factor(rt->rgb_dst_factor),
80                  .alpha_src_factor = fd_blend_factor(rt->alpha_src_factor),
81                  .alpha_blend_opcode = blend_func(rt->alpha_func),
82                  .alpha_dest_factor = fd_blend_factor(rt->alpha_dst_factor), ));
83 
84       OUT_REG(ring,
85               A6XX_RB_MRT_CONTROL(
86                     i,
87                     .blend = rt->blend_enable,
88                     .blend2 = rt->blend_enable,
89                     .rop_enable = cso->logicop_enable,
90                     .rop_code = rop,
91                     .component_enable = rt->colormask,
92               )
93       );
94 
95       if (rt->blend_enable) {
96          mrt_blend |= (1 << i);
97       }
98 
99       if (reads_dest) {
100          mrt_blend |= (1 << i);
101       }
102    }
103 
104    /* sRGB + dither on a7xx goes badly: */
105    bool dither = (CHIP < A7XX) ? cso->dither : false;
106 
107    OUT_REG(ring,
108       A6XX_RB_DITHER_CNTL(
109             .dither_mode_mrt0 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
110             .dither_mode_mrt1 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
111             .dither_mode_mrt2 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
112             .dither_mode_mrt3 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
113             .dither_mode_mrt4 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
114             .dither_mode_mrt5 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
115             .dither_mode_mrt6 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
116             .dither_mode_mrt7 = dither ? DITHER_ALWAYS : DITHER_DISABLE,
117       )
118    );
119 
120    OUT_REG(ring,
121            A6XX_SP_BLEND_CNTL(
122                  .enable_blend = mrt_blend,
123                  .unk8 = true,
124                  .dual_color_in_enable = blend->use_dual_src_blend,
125                  .alpha_to_coverage = cso->alpha_to_coverage,
126            ),
127    );
128 
129    OUT_REG(ring,
130            A6XX_RB_BLEND_CNTL(
131                  .enable_blend = mrt_blend,
132                  .independent_blend = cso->independent_blend_enable,
133                  .dual_color_in_enable = blend->use_dual_src_blend,
134                  .alpha_to_coverage = cso->alpha_to_coverage,
135                  .alpha_to_one = cso->alpha_to_one,
136                  .sample_mask = sample_mask,
137            ),
138    );
139 
140    so->sample_mask = sample_mask;
141 
142    util_dynarray_append(&blend->variants, struct fd6_blend_variant *, so);
143 
144    return so;
145 }
146 FD_GENX(__fd6_setup_blend_variant);
147 
148 void *
fd6_blend_state_create(struct pipe_context * pctx,const struct pipe_blend_state * cso)149 fd6_blend_state_create(struct pipe_context *pctx,
150                        const struct pipe_blend_state *cso)
151 {
152    struct fd6_blend_stateobj *so;
153 
154    so = (struct fd6_blend_stateobj *)rzalloc_size(NULL, sizeof(*so));
155    if (!so)
156       return NULL;
157 
158    so->base = *cso;
159    so->ctx = fd_context(pctx);
160 
161    if (cso->logicop_enable) {
162       so->reads_dest |= util_logicop_reads_dest((enum pipe_logicop)cso->logicop_func);
163    }
164 
165    so->use_dual_src_blend =
166       cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0);
167 
168    STATIC_ASSERT((4 * PIPE_MAX_COLOR_BUFS) == (8 * sizeof(so->all_mrt_write_mask)));
169    so->all_mrt_write_mask = 0;
170 
171    for (unsigned i = 0; i <= cso->max_rt; i++) {
172       const struct pipe_rt_blend_state *rt =
173          &cso->rt[cso->independent_blend_enable ? i : 0];
174 
175       so->reads_dest |= rt->blend_enable;
176 
177       so->all_mrt_write_mask |= rt->colormask << (4 * i);
178    }
179 
180    util_dynarray_init(&so->variants, so);
181 
182    return so;
183 }
184 
185 void
fd6_blend_state_delete(struct pipe_context * pctx,void * hwcso)186 fd6_blend_state_delete(struct pipe_context *pctx, void *hwcso)
187 {
188    struct fd6_blend_stateobj *so = (struct fd6_blend_stateobj *)hwcso;
189 
190    util_dynarray_foreach (&so->variants, struct fd6_blend_variant *, vp) {
191       struct fd6_blend_variant *v = *vp;
192       fd_ringbuffer_del(v->stateobj);
193    }
194 
195    ralloc_free(so);
196 }
197