• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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