1 /*
2 * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "pipe/p_defines.h"
9 #include "util/u_bitmask.h"
10 #include "util/u_inlines.h"
11 #include "util/u_math.h"
12 #include "util/u_memory.h"
13
14 #include "svga_context.h"
15 #include "svga_hw_reg.h"
16 #include "svga_cmd.h"
17
18
19 static inline unsigned
svga_translate_compare_func(unsigned func)20 svga_translate_compare_func(unsigned func)
21 {
22 switch (func) {
23 case PIPE_FUNC_NEVER: return SVGA3D_CMP_NEVER;
24 case PIPE_FUNC_LESS: return SVGA3D_CMP_LESS;
25 case PIPE_FUNC_LEQUAL: return SVGA3D_CMP_LESSEQUAL;
26 case PIPE_FUNC_GREATER: return SVGA3D_CMP_GREATER;
27 case PIPE_FUNC_GEQUAL: return SVGA3D_CMP_GREATEREQUAL;
28 case PIPE_FUNC_NOTEQUAL: return SVGA3D_CMP_NOTEQUAL;
29 case PIPE_FUNC_EQUAL: return SVGA3D_CMP_EQUAL;
30 case PIPE_FUNC_ALWAYS: return SVGA3D_CMP_ALWAYS;
31 default:
32 assert(0);
33 return SVGA3D_CMP_ALWAYS;
34 }
35 }
36
37 static inline unsigned
svga_translate_stencil_op(unsigned op)38 svga_translate_stencil_op(unsigned op)
39 {
40 switch (op) {
41 case PIPE_STENCIL_OP_KEEP: return SVGA3D_STENCILOP_KEEP;
42 case PIPE_STENCIL_OP_ZERO: return SVGA3D_STENCILOP_ZERO;
43 case PIPE_STENCIL_OP_REPLACE: return SVGA3D_STENCILOP_REPLACE;
44 case PIPE_STENCIL_OP_INCR: return SVGA3D_STENCILOP_INCRSAT;
45 case PIPE_STENCIL_OP_DECR: return SVGA3D_STENCILOP_DECRSAT;
46 case PIPE_STENCIL_OP_INCR_WRAP: return SVGA3D_STENCILOP_INCR;
47 case PIPE_STENCIL_OP_DECR_WRAP: return SVGA3D_STENCILOP_DECR;
48 case PIPE_STENCIL_OP_INVERT: return SVGA3D_STENCILOP_INVERT;
49 default:
50 assert(0);
51 return SVGA3D_STENCILOP_KEEP;
52 }
53 }
54
55
56 /**
57 * Define a vgpu10 depth/stencil state object for the given
58 * svga depth/stencil state.
59 */
60 static void
define_depth_stencil_state_object(struct svga_context * svga,struct svga_depth_stencil_state * ds)61 define_depth_stencil_state_object(struct svga_context *svga,
62 struct svga_depth_stencil_state *ds)
63 {
64 assert(svga_have_vgpu10(svga));
65
66 ds->id = util_bitmask_add(svga->ds_object_id_bm);
67
68 /* spot check that these comparision tokens are the same */
69 STATIC_ASSERT(SVGA3D_COMPARISON_NEVER == SVGA3D_CMP_NEVER);
70 STATIC_ASSERT(SVGA3D_COMPARISON_LESS == SVGA3D_CMP_LESS);
71 STATIC_ASSERT(SVGA3D_COMPARISON_NOT_EQUAL == SVGA3D_CMP_NOTEQUAL);
72
73 /* Note: we use the ds->stencil[0].enabled value for both the front
74 * and back-face enables. If single-side stencil is used, we'll have
75 * set the back state the same as the front state.
76 */
77 SVGA_RETRY(svga, SVGA3D_vgpu10_DefineDepthStencilState
78 (svga->swc,
79 ds->id,
80 /* depth/Z */
81 ds->zenable,
82 ds->zwriteenable,
83 ds->zfunc,
84 /* Stencil */
85 ds->stencil[0].enabled, /*f|b*/
86 ds->stencil[0].enabled, /*f*/
87 ds->stencil[0].enabled, /*b*/
88 ds->stencil_mask,
89 ds->stencil_writemask,
90 /* front stencil */
91 ds->stencil[0].fail,
92 ds->stencil[0].zfail,
93 ds->stencil[0].pass,
94 ds->stencil[0].func,
95 /* back stencil */
96 ds->stencil[1].fail,
97 ds->stencil[1].zfail,
98 ds->stencil[1].pass,
99 ds->stencil[1].func));
100 }
101
102
103 static void *
svga_create_depth_stencil_state(struct pipe_context * pipe,const struct pipe_depth_stencil_alpha_state * templ)104 svga_create_depth_stencil_state(struct pipe_context *pipe,
105 const struct pipe_depth_stencil_alpha_state *templ)
106 {
107 struct svga_context *svga = svga_context(pipe);
108 struct svga_depth_stencil_state *ds = CALLOC_STRUCT(svga_depth_stencil_state);
109
110 if (!ds)
111 return NULL;
112
113 /* Don't try to figure out CW/CCW correspondence with
114 * stencil[0]/[1] at this point. Presumably this can change as
115 * back/front face are modified.
116 */
117 ds->stencil[0].enabled = templ->stencil[0].enabled;
118 if (ds->stencil[0].enabled) {
119 ds->stencil[0].func = svga_translate_compare_func(templ->stencil[0].func);
120 ds->stencil[0].fail = svga_translate_stencil_op(templ->stencil[0].fail_op);
121 ds->stencil[0].zfail = svga_translate_stencil_op(templ->stencil[0].zfail_op);
122 ds->stencil[0].pass = svga_translate_stencil_op(templ->stencil[0].zpass_op);
123
124 /* SVGA3D has one ref/mask/writemask triple shared between front &
125 * back face stencil. We really need two:
126 */
127 ds->stencil_mask = templ->stencil[0].valuemask & 0xff;
128 ds->stencil_writemask = templ->stencil[0].writemask & 0xff;
129 }
130 else {
131 ds->stencil[0].func = SVGA3D_CMP_ALWAYS;
132 ds->stencil[0].fail = SVGA3D_STENCILOP_KEEP;
133 ds->stencil[0].zfail = SVGA3D_STENCILOP_KEEP;
134 ds->stencil[0].pass = SVGA3D_STENCILOP_KEEP;
135 }
136
137 ds->stencil[1].enabled = templ->stencil[1].enabled;
138 if (templ->stencil[1].enabled) {
139 assert(templ->stencil[0].enabled);
140 /* two-sided stencil */
141 ds->stencil[1].func = svga_translate_compare_func(templ->stencil[1].func);
142 ds->stencil[1].fail = svga_translate_stencil_op(templ->stencil[1].fail_op);
143 ds->stencil[1].zfail = svga_translate_stencil_op(templ->stencil[1].zfail_op);
144 ds->stencil[1].pass = svga_translate_stencil_op(templ->stencil[1].zpass_op);
145
146 ds->stencil_mask = templ->stencil[1].valuemask & 0xff;
147 ds->stencil_writemask = templ->stencil[1].writemask & 0xff;
148
149 if (templ->stencil[1].valuemask != templ->stencil[0].valuemask) {
150 util_debug_message(&svga->debug.callback, CONFORMANCE,
151 "two-sided stencil mask not supported "
152 "(front=0x%x, back=0x%x)",
153 templ->stencil[0].valuemask,
154 templ->stencil[1].valuemask);
155 }
156 if (templ->stencil[1].writemask != templ->stencil[0].writemask) {
157 util_debug_message(&svga->debug.callback, CONFORMANCE,
158 "two-sided stencil writemask not supported "
159 "(front=0x%x, back=0x%x)",
160 templ->stencil[0].writemask,
161 templ->stencil[1].writemask);
162 }
163 }
164 else {
165 /* back face state is same as front-face state */
166 ds->stencil[1].func = ds->stencil[0].func;
167 ds->stencil[1].fail = ds->stencil[0].fail;
168 ds->stencil[1].zfail = ds->stencil[0].zfail;
169 ds->stencil[1].pass = ds->stencil[0].pass;
170 }
171
172
173 ds->zenable = templ->depth_enabled;
174 if (ds->zenable) {
175 ds->zfunc = svga_translate_compare_func(templ->depth_func);
176 ds->zwriteenable = templ->depth_writemask;
177 }
178 else {
179 ds->zfunc = SVGA3D_CMP_ALWAYS;
180 }
181
182 ds->alphatestenable = templ->alpha_enabled;
183 if (ds->alphatestenable) {
184 ds->alphafunc = svga_translate_compare_func(templ->alpha_func);
185 ds->alpharef = templ->alpha_ref_value;
186 }
187 else {
188 ds->alphafunc = SVGA3D_CMP_ALWAYS;
189 }
190
191 if (svga_have_vgpu10(svga)) {
192 define_depth_stencil_state_object(svga, ds);
193 }
194
195 svga->hud.num_depthstencil_objects++;
196
197 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
198 SVGA_STATS_COUNT_DEPTHSTENCILSTATE);
199
200 return ds;
201 }
202
203
204 static void
svga_bind_depth_stencil_state(struct pipe_context * pipe,void * depth_stencil)205 svga_bind_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
206 {
207 struct svga_context *svga = svga_context(pipe);
208
209 if (svga_have_vgpu10(svga)) {
210 /* flush any previously queued drawing before changing state */
211 svga_hwtnl_flush_retry(svga);
212 }
213
214 svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil;
215 svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA;
216 }
217
218
219 static void
svga_delete_depth_stencil_state(struct pipe_context * pipe,void * depth_stencil)220 svga_delete_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
221 {
222 struct svga_context *svga = svga_context(pipe);
223 struct svga_depth_stencil_state *ds =
224 (struct svga_depth_stencil_state *) depth_stencil;
225
226 if (svga_have_vgpu10(svga)) {
227 svga_hwtnl_flush_retry(svga);
228
229 assert(ds->id != SVGA3D_INVALID_ID);
230
231 SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc,
232 ds->id));
233
234 if (ds->id == svga->state.hw_draw.depth_stencil_id)
235 svga->state.hw_draw.depth_stencil_id = SVGA3D_INVALID_ID;
236
237 util_bitmask_clear(svga->ds_object_id_bm, ds->id);
238 ds->id = SVGA3D_INVALID_ID;
239 }
240
241 FREE(depth_stencil);
242 svga->hud.num_depthstencil_objects--;
243 }
244
245
246 static void
svga_set_stencil_ref(struct pipe_context * pipe,const struct pipe_stencil_ref stencil_ref)247 svga_set_stencil_ref(struct pipe_context *pipe,
248 const struct pipe_stencil_ref stencil_ref)
249 {
250 struct svga_context *svga = svga_context(pipe);
251
252 if (svga_have_vgpu10(svga)) {
253 /* flush any previously queued drawing before changing state */
254 svga_hwtnl_flush_retry(svga);
255 }
256
257 svga->curr.stencil_ref = stencil_ref;
258
259 svga->dirty |= SVGA_NEW_STENCIL_REF;
260 }
261
262
263 static void
svga_set_sample_mask(struct pipe_context * pipe,unsigned sample_mask)264 svga_set_sample_mask(struct pipe_context *pipe,
265 unsigned sample_mask)
266 {
267 struct svga_context *svga = svga_context(pipe);
268
269 svga->curr.sample_mask = sample_mask;
270
271 svga->dirty |= SVGA_NEW_BLEND; /* See emit_rss_vgpu10() */
272 }
273
274
275 static void
svga_set_min_samples(struct pipe_context * pipe,unsigned min_samples)276 svga_set_min_samples(struct pipe_context *pipe, unsigned min_samples)
277 {
278 /* This specifies the minimum number of times the fragment shader
279 * must run when doing per-sample shading for a MSAA render target.
280 * For our SVGA3D device, the FS is automatically run in per-sample
281 * mode if it uses the sample ID or sample position registers.
282 */
283 }
284
285
286 void
svga_init_depth_stencil_functions(struct svga_context * svga)287 svga_init_depth_stencil_functions(struct svga_context *svga)
288 {
289 svga->pipe.create_depth_stencil_alpha_state = svga_create_depth_stencil_state;
290 svga->pipe.bind_depth_stencil_alpha_state = svga_bind_depth_stencil_state;
291 svga->pipe.delete_depth_stencil_alpha_state = svga_delete_depth_stencil_state;
292
293 svga->pipe.set_stencil_ref = svga_set_stencil_ref;
294 svga->pipe.set_sample_mask = svga_set_sample_mask;
295 svga->pipe.set_min_samples = svga_set_min_samples;
296 }
297