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#include "pipe/p_state.h"
29#include "util/u_memory.h"
30#include "util/u_string.h"
31
32#include "fd6_context.h"
33#include "fd6_zsa.h"
34
35/* update lza state based on stencil-test func:
36 *
37 * Conceptually the order of the pipeline is:
38 *
39 *
40 *   FS -> Alpha-Test  ->  Stencil-Test  ->  Depth-Test
41 *                              |                |
42 *                       if wrmask != 0     if wrmask != 0
43 *                              |                |
44 *                              v                v
45 *                        Stencil-Write      Depth-Write
46 *
47 * Because Stencil-Test can have side effects (Stencil-Write) prior
48 * to depth test, in this case we potentially need to disable early
49 * lrz-test.  See:
50 *
51 * https://www.khronos.org/opengl/wiki/Per-Sample_Processing
52 */
53static void
54update_lrz_stencil(struct fd6_zsa_stateobj *so, enum pipe_compare_func func,
55                   bool stencil_write)
56{
57   switch (func) {
58   case PIPE_FUNC_ALWAYS:
59      /* nothing to do for LRZ, but for stencil test when stencil-
60       * write is enabled, we need to disable lrz-test, since
61       * conceptually stencil test and write happens before depth-
62       * test:
63       */
64      if (stencil_write) {
65         so->lrz.enable = false;
66         so->lrz.test = false;
67      }
68      break;
69   case PIPE_FUNC_NEVER:
70      /* fragment never passes, disable lrz_write for this draw: */
71      so->lrz.write = false;
72      break;
73   default:
74      /* whether the fragment passes or not depends on result
75       * of stencil test, which we cannot know when doing binning
76       * pass:
77       */
78      so->lrz.write = false;
79      /* similarly to the PIPE_FUNC_ALWAY case, if there are side-
80       * effects from stencil test we need to disable lrz-test.
81       */
82      if (stencil_write) {
83         so->lrz.enable = false;
84         so->lrz.test = false;
85      }
86      break;
87   }
88}
89
90void *
91fd6_zsa_state_create(struct pipe_context *pctx,
92                     const struct pipe_depth_stencil_alpha_state *cso)
93{
94   struct fd_context *ctx = fd_context(pctx);
95   struct fd6_zsa_stateobj *so;
96
97   so = CALLOC_STRUCT(fd6_zsa_stateobj);
98   if (!so)
99      return NULL;
100
101   so->base = *cso;
102
103   so->writes_zs = util_writes_depth_stencil(cso);
104
105   so->rb_depth_cntl |=
106      A6XX_RB_DEPTH_CNTL_ZFUNC(cso->depth_func); /* maps 1:1 */
107
108   if (cso->depth_enabled) {
109      so->rb_depth_cntl |=
110         A6XX_RB_DEPTH_CNTL_Z_TEST_ENABLE | A6XX_RB_DEPTH_CNTL_Z_READ_ENABLE;
111
112      so->lrz.test = true;
113
114      if (cso->depth_writemask) {
115         so->lrz.write = true;
116      }
117
118      switch (cso->depth_func) {
119      case PIPE_FUNC_LESS:
120      case PIPE_FUNC_LEQUAL:
121         so->lrz.enable = true;
122         so->lrz.direction = FD_LRZ_LESS;
123         break;
124
125      case PIPE_FUNC_GREATER:
126      case PIPE_FUNC_GEQUAL:
127         so->lrz.enable = true;
128         so->lrz.direction = FD_LRZ_GREATER;
129         break;
130
131      case PIPE_FUNC_NEVER:
132         so->lrz.enable = true;
133         so->lrz.write = false;
134         so->lrz.direction = FD_LRZ_LESS;
135         break;
136
137      /* TODO revisit these: */
138      case PIPE_FUNC_EQUAL:
139      case PIPE_FUNC_NOTEQUAL:
140      case PIPE_FUNC_ALWAYS:
141         so->lrz.write = false;
142         so->invalidate_lrz = true;
143         break;
144      }
145   }
146
147   if (cso->depth_writemask)
148      so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE;
149
150   if (cso->stencil[0].enabled) {
151      const struct pipe_stencil_state *s = &cso->stencil[0];
152
153      /* stencil test happens before depth test, so without performing
154       * stencil test we don't really know what the updates to the
155       * depth buffer will be.
156       */
157      update_lrz_stencil(so, s->func, !!s->writemask);
158
159      so->rb_stencil_control |=
160         A6XX_RB_STENCIL_CONTROL_STENCIL_READ |
161         A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE |
162         A6XX_RB_STENCIL_CONTROL_FUNC(s->func) | /* maps 1:1 */
163         A6XX_RB_STENCIL_CONTROL_FAIL(fd_stencil_op(s->fail_op)) |
164         A6XX_RB_STENCIL_CONTROL_ZPASS(fd_stencil_op(s->zpass_op)) |
165         A6XX_RB_STENCIL_CONTROL_ZFAIL(fd_stencil_op(s->zfail_op));
166
167      so->rb_stencilmask = A6XX_RB_STENCILMASK_MASK(s->valuemask);
168      so->rb_stencilwrmask = A6XX_RB_STENCILWRMASK_WRMASK(s->writemask);
169
170      if (cso->stencil[1].enabled) {
171         const struct pipe_stencil_state *bs = &cso->stencil[1];
172
173         update_lrz_stencil(so, bs->func, !!bs->writemask);
174
175         so->rb_stencil_control |=
176            A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF |
177            A6XX_RB_STENCIL_CONTROL_FUNC_BF(bs->func) | /* maps 1:1 */
178            A6XX_RB_STENCIL_CONTROL_FAIL_BF(fd_stencil_op(bs->fail_op)) |
179            A6XX_RB_STENCIL_CONTROL_ZPASS_BF(fd_stencil_op(bs->zpass_op)) |
180            A6XX_RB_STENCIL_CONTROL_ZFAIL_BF(fd_stencil_op(bs->zfail_op));
181
182         so->rb_stencilmask |= A6XX_RB_STENCILMASK_BFMASK(bs->valuemask);
183         so->rb_stencilwrmask |= A6XX_RB_STENCILWRMASK_BFWRMASK(bs->writemask);
184      }
185   }
186
187   if (cso->alpha_enabled) {
188      /* Alpha test is functionally a conditional discard, so we can't
189       * write LRZ before seeing if we end up discarding or not
190       */
191      if (cso->alpha_func != PIPE_FUNC_ALWAYS) {
192         so->lrz.write = false;
193         so->alpha_test = true;
194      }
195
196      uint32_t ref = cso->alpha_ref_value * 255.0f;
197      so->rb_alpha_control =
198         A6XX_RB_ALPHA_CONTROL_ALPHA_TEST |
199         A6XX_RB_ALPHA_CONTROL_ALPHA_REF(ref) |
200         A6XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(cso->alpha_func);
201   }
202
203   for (int i = 0; i < 4; i++) {
204      struct fd_ringbuffer *ring = fd_ringbuffer_new_object(ctx->pipe, 9 * 4);
205
206      OUT_PKT4(ring, REG_A6XX_RB_ALPHA_CONTROL, 1);
207      OUT_RING(ring,
208               (i & FD6_ZSA_NO_ALPHA)
209                  ? so->rb_alpha_control & ~A6XX_RB_ALPHA_CONTROL_ALPHA_TEST
210                  : so->rb_alpha_control);
211
212      OUT_PKT4(ring, REG_A6XX_RB_STENCIL_CONTROL, 1);
213      OUT_RING(ring, so->rb_stencil_control);
214
215      OUT_PKT4(ring, REG_A6XX_RB_DEPTH_CNTL, 1);
216      OUT_RING(ring,
217               so->rb_depth_cntl | COND(i & FD6_ZSA_DEPTH_CLIP_DISABLE,
218                                        A6XX_RB_DEPTH_CNTL_Z_CLIP_DISABLE));
219
220      OUT_PKT4(ring, REG_A6XX_RB_STENCILMASK, 2);
221      OUT_RING(ring, so->rb_stencilmask);
222      OUT_RING(ring, so->rb_stencilwrmask);
223
224      so->stateobj[i] = ring;
225   }
226
227   return so;
228}
229
230void
231fd6_zsa_state_delete(struct pipe_context *pctx, void *hwcso)
232{
233   struct fd6_zsa_stateobj *so = hwcso;
234
235   for (int i = 0; i < ARRAY_SIZE(so->stateobj); i++)
236      fd_ringbuffer_del(so->stateobj[i]);
237   FREE(hwcso);
238}
239