1 /*
2 * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org>
3 * Copyright © 2018 Google, Inc.
4 *
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:
11 *
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
14 * Software.
15 *
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
22 * SOFTWARE.
23 *
24 * Authors:
25 * Rob Clark <robclark@freedesktop.org>
26 */
27
28 #define FD_BO_NO_HARDPIN 1
29
30 #include "pipe/p_state.h"
31 #include "util/u_memory.h"
32 #include "util/u_string.h"
33
34 #include "fd6_context.h"
35 #include "fd6_pack.h"
36 #include "fd6_zsa.h"
37
38 /* update lza state based on stencil-test func:
39 *
40 * Conceptually the order of the pipeline is:
41 *
42 *
43 * FS -> Alpha-Test -> Stencil-Test -> Depth-Test
44 * | |
45 * if wrmask != 0 if wrmask != 0
46 * | |
47 * v v
48 * Stencil-Write Depth-Write
49 *
50 * Because Stencil-Test can have side effects (Stencil-Write) prior
51 * to depth test, in this case we potentially need to disable early
52 * lrz-test. See:
53 *
54 * https://www.khronos.org/opengl/wiki/Per-Sample_Processing
55 */
56 static void
update_lrz_stencil(struct fd6_zsa_stateobj * so,enum pipe_compare_func func,bool stencil_write)57 update_lrz_stencil(struct fd6_zsa_stateobj *so, enum pipe_compare_func func,
58 bool stencil_write)
59 {
60 switch (func) {
61 case PIPE_FUNC_ALWAYS:
62 /* nothing to do for LRZ, but for stencil test when stencil-
63 * write is enabled, we need to disable lrz-test, since
64 * conceptually stencil test and write happens before depth-
65 * test:
66 */
67 if (stencil_write) {
68 so->lrz.enable = false;
69 so->lrz.test = false;
70 }
71 break;
72 case PIPE_FUNC_NEVER:
73 /* fragment never passes, disable lrz_write for this draw: */
74 so->lrz.write = false;
75 break;
76 default:
77 /* whether the fragment passes or not depends on result
78 * of stencil test, which we cannot know when doing binning
79 * pass:
80 */
81 so->lrz.write = false;
82 /* similarly to the PIPE_FUNC_ALWAY case, if there are side-
83 * effects from stencil test we need to disable lrz-test.
84 */
85 if (stencil_write) {
86 so->lrz.enable = false;
87 so->lrz.test = false;
88 }
89 break;
90 }
91 }
92
93 void *
fd6_zsa_state_create(struct pipe_context * pctx,const struct pipe_depth_stencil_alpha_state * cso)94 fd6_zsa_state_create(struct pipe_context *pctx,
95 const struct pipe_depth_stencil_alpha_state *cso)
96 {
97 struct fd_context *ctx = fd_context(pctx);
98 struct fd6_zsa_stateobj *so;
99
100 so = CALLOC_STRUCT(fd6_zsa_stateobj);
101 if (!so)
102 return NULL;
103
104 so->base = *cso;
105
106 so->writes_zs = util_writes_depth_stencil(cso);
107 so->writes_z = util_writes_depth(cso);
108
109 enum adreno_compare_func depth_func =
110 (enum adreno_compare_func)cso->depth_func; /* maps 1:1 */
111
112 /* On some GPUs it is necessary to enable z test for depth bounds test
113 * when UBWC is enabled. Otherwise, the GPU would hang. FUNC_ALWAYS is
114 * required to pass z test. Relevant tests:
115 * dEQP-VK.pipeline.extended_dynamic_state.two_draws_dynamic.depth_bounds_test_disable
116 * dEQP-VK.dynamic_state.ds_state.depth_bounds_1
117 */
118 if (cso->depth_bounds_test && !cso->depth_enabled &&
119 ctx->screen->info->a6xx.depth_bounds_require_depth_test_quirk) {
120 so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_TEST_ENABLE;
121 depth_func = FUNC_ALWAYS;
122 }
123
124 so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_ZFUNC(depth_func);
125
126 if (cso->depth_enabled) {
127 so->rb_depth_cntl |=
128 A6XX_RB_DEPTH_CNTL_Z_TEST_ENABLE | A6XX_RB_DEPTH_CNTL_Z_READ_ENABLE;
129
130 so->lrz.test = true;
131
132 if (cso->depth_writemask) {
133 so->lrz.write = true;
134 }
135
136 switch (cso->depth_func) {
137 case PIPE_FUNC_LESS:
138 case PIPE_FUNC_LEQUAL:
139 so->lrz.enable = true;
140 so->lrz.direction = FD_LRZ_LESS;
141 break;
142
143 case PIPE_FUNC_GREATER:
144 case PIPE_FUNC_GEQUAL:
145 so->lrz.enable = true;
146 so->lrz.direction = FD_LRZ_GREATER;
147 break;
148
149 case PIPE_FUNC_NEVER:
150 so->lrz.enable = true;
151 so->lrz.write = false;
152 so->lrz.direction = FD_LRZ_LESS;
153 break;
154
155 case PIPE_FUNC_ALWAYS:
156 case PIPE_FUNC_NOTEQUAL:
157 if (cso->depth_writemask) {
158 perf_debug_ctx(ctx, "Invalidating LRZ due to ALWAYS/NOTEQUAL with depth write");
159 so->lrz.write = false;
160 so->invalidate_lrz = true;
161 } else {
162 perf_debug_ctx(ctx, "Skipping LRZ due to ALWAYS/NOTEQUAL");
163 so->lrz.enable = false;
164 so->lrz.write = false;
165 }
166 break;
167
168 case PIPE_FUNC_EQUAL:
169 so->lrz.enable = false;
170 so->lrz.write = false;
171 break;
172 }
173 }
174
175 if (cso->depth_writemask)
176 so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE;
177
178 if (cso->stencil[0].enabled) {
179 const struct pipe_stencil_state *s = &cso->stencil[0];
180
181 /* stencil test happens before depth test, so without performing
182 * stencil test we don't really know what the updates to the
183 * depth buffer will be.
184 */
185 update_lrz_stencil(so, (enum pipe_compare_func)s->func, util_writes_stencil(s));
186
187 so->rb_stencil_control |=
188 A6XX_RB_STENCIL_CONTROL_STENCIL_READ |
189 A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE |
190 A6XX_RB_STENCIL_CONTROL_FUNC((enum adreno_compare_func)s->func) | /* maps 1:1 */
191 A6XX_RB_STENCIL_CONTROL_FAIL(fd_stencil_op(s->fail_op)) |
192 A6XX_RB_STENCIL_CONTROL_ZPASS(fd_stencil_op(s->zpass_op)) |
193 A6XX_RB_STENCIL_CONTROL_ZFAIL(fd_stencil_op(s->zfail_op));
194
195 so->rb_stencilmask = A6XX_RB_STENCILMASK_MASK(s->valuemask);
196 so->rb_stencilwrmask = A6XX_RB_STENCILWRMASK_WRMASK(s->writemask);
197
198 if (cso->stencil[1].enabled) {
199 const struct pipe_stencil_state *bs = &cso->stencil[1];
200
201 update_lrz_stencil(so, (enum pipe_compare_func)bs->func, util_writes_stencil(bs));
202
203 so->rb_stencil_control |=
204 A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF |
205 A6XX_RB_STENCIL_CONTROL_FUNC_BF((enum adreno_compare_func)bs->func) | /* maps 1:1 */
206 A6XX_RB_STENCIL_CONTROL_FAIL_BF(fd_stencil_op(bs->fail_op)) |
207 A6XX_RB_STENCIL_CONTROL_ZPASS_BF(fd_stencil_op(bs->zpass_op)) |
208 A6XX_RB_STENCIL_CONTROL_ZFAIL_BF(fd_stencil_op(bs->zfail_op));
209
210 so->rb_stencilmask |= A6XX_RB_STENCILMASK_BFMASK(bs->valuemask);
211 so->rb_stencilwrmask |= A6XX_RB_STENCILWRMASK_BFWRMASK(bs->writemask);
212 }
213 }
214
215 if (cso->alpha_enabled) {
216 /* Alpha test is functionally a conditional discard, so we can't
217 * write LRZ before seeing if we end up discarding or not
218 */
219 if (cso->alpha_func != PIPE_FUNC_ALWAYS) {
220 so->lrz.write = false;
221 so->alpha_test = true;
222 }
223
224 uint32_t ref = cso->alpha_ref_value * 255.0f;
225 so->rb_alpha_control =
226 A6XX_RB_ALPHA_CONTROL_ALPHA_TEST |
227 A6XX_RB_ALPHA_CONTROL_ALPHA_REF(ref) |
228 A6XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(
229 (enum adreno_compare_func)cso->alpha_func);
230 }
231
232 if (cso->depth_bounds_test) {
233 so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_BOUNDS_ENABLE |
234 A6XX_RB_DEPTH_CNTL_Z_READ_ENABLE;
235 so->lrz.z_bounds_enable = true;
236 }
237
238 /* Build the four state permutations (with/without alpha/depth-clamp)*/
239 for (int i = 0; i < 4; i++) {
240 struct fd_ringbuffer *ring = fd_ringbuffer_new_object(ctx->pipe, 12 * 4);
241
242 OUT_PKT4(ring, REG_A6XX_RB_ALPHA_CONTROL, 1);
243 OUT_RING(ring,
244 (i & FD6_ZSA_NO_ALPHA)
245 ? so->rb_alpha_control & ~A6XX_RB_ALPHA_CONTROL_ALPHA_TEST
246 : so->rb_alpha_control);
247
248 OUT_PKT4(ring, REG_A6XX_RB_STENCIL_CONTROL, 1);
249 OUT_RING(ring, so->rb_stencil_control);
250
251 OUT_PKT4(ring, REG_A6XX_RB_DEPTH_CNTL, 1);
252 OUT_RING(ring,
253 so->rb_depth_cntl | COND(i & FD6_ZSA_DEPTH_CLAMP,
254 A6XX_RB_DEPTH_CNTL_Z_CLAMP_ENABLE));
255
256 OUT_PKT4(ring, REG_A6XX_RB_STENCILMASK, 2);
257 OUT_RING(ring, so->rb_stencilmask);
258 OUT_RING(ring, so->rb_stencilwrmask);
259
260 OUT_REG(ring, A6XX_RB_Z_BOUNDS_MIN(cso->depth_bounds_min),
261 A6XX_RB_Z_BOUNDS_MAX(cso->depth_bounds_max));
262
263 so->stateobj[i] = ring;
264 }
265
266 return so;
267 }
268
269 void
fd6_zsa_state_delete(struct pipe_context * pctx,void * hwcso)270 fd6_zsa_state_delete(struct pipe_context *pctx, void *hwcso)
271 {
272 struct fd6_zsa_stateobj *so = (struct fd6_zsa_stateobj *)hwcso;
273
274 for (int i = 0; i < ARRAY_SIZE(so->stateobj); i++)
275 fd_ringbuffer_del(so->stateobj[i]);
276 FREE(hwcso);
277 }
278