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