1/*
2 * Copyright 2010 Christoph Bumiller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#include "pipe/p_context.h"
24#include "pipe/p_defines.h"
25#include "pipe/p_state.h"
26#include "util/u_inlines.h"
27
28#include "nvc0_context.h"
29
30static INLINE void
31nvc0_program_update_context_state(struct nvc0_context *nvc0,
32                                  struct nvc0_program *prog, int stage)
33{
34   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
35
36   if (prog && prog->need_tls) {
37      const uint32_t flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR;
38      if (!nvc0->state.tls_required)
39         BCTX_REFN_bo(nvc0->bufctx_3d, TLS, flags, nvc0->screen->tls);
40      nvc0->state.tls_required |= 1 << stage;
41   } else {
42      if (nvc0->state.tls_required == (1 << stage))
43         nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TLS);
44      nvc0->state.tls_required &= ~(1 << stage);
45   }
46
47   if (prog && prog->immd_size) {
48      BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
49      /* NOTE: may overlap code of a different shader */
50      PUSH_DATA (push, align(prog->immd_size, 0x100));
51      PUSH_DATAh(push, nvc0->screen->text->offset + prog->immd_base);
52      PUSH_DATA (push, nvc0->screen->text->offset + prog->immd_base);
53      BEGIN_NVC0(push, NVC0_3D(CB_BIND(stage)), 1);
54      PUSH_DATA (push, (14 << 4) | 1);
55
56      nvc0->state.c14_bound |= 1 << stage;
57   } else
58   if (nvc0->state.c14_bound & (1 << stage)) {
59      BEGIN_NVC0(push, NVC0_3D(CB_BIND(stage)), 1);
60      PUSH_DATA (push, (14 << 4) | 0);
61
62      nvc0->state.c14_bound &= ~(1 << stage);
63   }
64}
65
66static INLINE boolean
67nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
68{
69   if (prog->mem)
70      return TRUE;
71
72   if (!prog->translated) {
73      prog->translated = nvc0_program_translate(
74         prog, nvc0->screen->base.device->chipset);
75      if (!prog->translated)
76         return FALSE;
77   }
78
79   if (likely(prog->code_size))
80      return nvc0_program_upload_code(nvc0, prog);
81   return TRUE; /* stream output info only */
82}
83
84void
85nvc0_vertprog_validate(struct nvc0_context *nvc0)
86{
87   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
88   struct nvc0_program *vp = nvc0->vertprog;
89
90   if (!nvc0_program_validate(nvc0, vp))
91         return;
92   nvc0_program_update_context_state(nvc0, vp, 0);
93
94   BEGIN_NVC0(push, NVC0_3D(SP_SELECT(1)), 2);
95   PUSH_DATA (push, 0x11);
96   PUSH_DATA (push, vp->code_base);
97   BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(1)), 1);
98   PUSH_DATA (push, vp->max_gpr);
99
100   // BEGIN_NVC0(push, NVC0_3D_(0x163c), 1);
101   // PUSH_DATA (push, 0);
102}
103
104void
105nvc0_fragprog_validate(struct nvc0_context *nvc0)
106{
107   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
108   struct nvc0_program *fp = nvc0->fragprog;
109
110   if (!nvc0_program_validate(nvc0, fp))
111         return;
112   nvc0_program_update_context_state(nvc0, fp, 4);
113
114   if (fp->fp.early_z != nvc0->state.early_z_forced) {
115      nvc0->state.early_z_forced = fp->fp.early_z;
116      IMMED_NVC0(push, NVC0_3D(FORCE_EARLY_FRAGMENT_TESTS), fp->fp.early_z);
117   }
118
119   BEGIN_NVC0(push, NVC0_3D(SP_SELECT(5)), 2);
120   PUSH_DATA (push, 0x51);
121   PUSH_DATA (push, fp->code_base);
122   BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(5)), 1);
123   PUSH_DATA (push, fp->max_gpr);
124
125   BEGIN_NVC0(push, SUBC_3D(0x0360), 2);
126   PUSH_DATA (push, 0x20164010);
127   PUSH_DATA (push, 0x20);
128   BEGIN_NVC0(push, NVC0_3D(ZCULL_TEST_MASK), 1);
129   PUSH_DATA (push, fp->flags[0]);
130}
131
132void
133nvc0_tctlprog_validate(struct nvc0_context *nvc0)
134{
135   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
136   struct nvc0_program *tp = nvc0->tctlprog;
137
138   if (tp && nvc0_program_validate(nvc0, tp)) {
139      if (tp->tp.tess_mode != ~0) {
140         BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1);
141         PUSH_DATA (push, tp->tp.tess_mode);
142      }
143      BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 2);
144      PUSH_DATA (push, 0x21);
145      PUSH_DATA (push, tp->code_base);
146      BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(2)), 1);
147      PUSH_DATA (push, tp->max_gpr);
148
149      if (tp->tp.input_patch_size <= 32)
150         IMMED_NVC0(push, NVC0_3D(PATCH_VERTICES), tp->tp.input_patch_size);
151   } else {
152      BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 1);
153      PUSH_DATA (push, 0x20);
154   }
155   nvc0_program_update_context_state(nvc0, tp, 1);
156}
157
158void
159nvc0_tevlprog_validate(struct nvc0_context *nvc0)
160{
161   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
162   struct nvc0_program *tp = nvc0->tevlprog;
163
164   if (tp && nvc0_program_validate(nvc0, tp)) {
165      if (tp->tp.tess_mode != ~0) {
166         BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1);
167         PUSH_DATA (push, tp->tp.tess_mode);
168      }
169      BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1);
170      PUSH_DATA (push, 0x31);
171      BEGIN_NVC0(push, NVC0_3D(SP_START_ID(3)), 1);
172      PUSH_DATA (push, tp->code_base);
173      BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(3)), 1);
174      PUSH_DATA (push, tp->max_gpr);
175   } else {
176      BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1);
177      PUSH_DATA (push, 0x30);
178   }
179   nvc0_program_update_context_state(nvc0, tp, 2);
180}
181
182void
183nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
184{
185   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
186   struct nvc0_program *gp = nvc0->gmtyprog;
187
188   if (gp)
189      nvc0_program_validate(nvc0, gp);
190
191   /* we allow GPs with no code for specifying stream output state only */
192   if (gp && gp->code_size) {
193      const boolean gp_selects_layer = gp->hdr[13] & (1 << 9);
194
195      BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1);
196      PUSH_DATA (push, 0x41);
197      BEGIN_NVC0(push, NVC0_3D(SP_START_ID(4)), 1);
198      PUSH_DATA (push, gp->code_base);
199      BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(4)), 1);
200      PUSH_DATA (push, gp->max_gpr);
201      BEGIN_NVC0(push, NVC0_3D(LAYER), 1);
202      PUSH_DATA (push, gp_selects_layer ? NVC0_3D_LAYER_USE_GP : 0);
203   } else {
204      IMMED_NVC0(push, NVC0_3D(LAYER), 0);
205      BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1);
206      PUSH_DATA (push, 0x40);
207   }
208   nvc0_program_update_context_state(nvc0, gp, 3);
209}
210
211void
212nvc0_tfb_validate(struct nvc0_context *nvc0)
213{
214   struct nouveau_pushbuf *push = nvc0->base.pushbuf;
215   struct nvc0_transform_feedback_state *tfb;
216   unsigned b;
217
218   if (nvc0->gmtyprog) tfb = nvc0->gmtyprog->tfb;
219   else
220   if (nvc0->tevlprog) tfb = nvc0->tevlprog->tfb;
221   else
222      tfb = nvc0->vertprog->tfb;
223
224   IMMED_NVC0(push, NVC0_3D(TFB_ENABLE), (tfb && nvc0->num_tfbbufs) ? 1 : 0);
225
226   if (tfb && tfb != nvc0->state.tfb) {
227      for (b = 0; b < 4; ++b) {
228         if (tfb->varying_count[b]) {
229            unsigned n = (tfb->varying_count[b] + 3) / 4;
230
231            BEGIN_NVC0(push, NVC0_3D(TFB_STREAM(b)), 3);
232            PUSH_DATA (push, 0);
233            PUSH_DATA (push, tfb->varying_count[b]);
234            PUSH_DATA (push, tfb->stride[b]);
235            BEGIN_NVC0(push, NVC0_3D(TFB_VARYING_LOCS(b, 0)), n);
236            PUSH_DATAp(push, tfb->varying_index[b], n);
237
238            if (nvc0->tfbbuf[b])
239               nvc0_so_target(nvc0->tfbbuf[b])->stride = tfb->stride[b];
240         } else {
241            IMMED_NVC0(push, NVC0_3D(TFB_VARYING_COUNT(b)), 0);
242         }
243      }
244   }
245   nvc0->state.tfb = tfb;
246
247   if (!(nvc0->dirty & NVC0_NEW_TFB_TARGETS))
248      return;
249   nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TFB);
250
251   for (b = 0; b < nvc0->num_tfbbufs; ++b) {
252      struct nvc0_so_target *targ = nvc0_so_target(nvc0->tfbbuf[b]);
253      struct nv04_resource *buf = nv04_resource(targ->pipe.buffer);
254
255      if (tfb)
256         targ->stride = tfb->stride[b];
257
258      if (!(nvc0->tfbbuf_dirty & (1 << b)))
259         continue;
260
261      if (!targ->clean)
262         nvc0_query_fifo_wait(push, targ->pq);
263      BEGIN_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 5);
264      PUSH_DATA (push, 1);
265      PUSH_DATAh(push, buf->address + targ->pipe.buffer_offset);
266      PUSH_DATA (push, buf->address + targ->pipe.buffer_offset);
267      PUSH_DATA (push, targ->pipe.buffer_size);
268      if (!targ->clean) {
269         nvc0_query_pushbuf_submit(push, targ->pq, 0x4);
270      } else {
271         PUSH_DATA(push, 0); /* TFB_BUFFER_OFFSET */
272         targ->clean = FALSE;
273      }
274      BCTX_REFN(nvc0->bufctx_3d, TFB, buf, WR);
275   }
276   for (; b < 4; ++b)
277      IMMED_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 0);
278}
279