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 
30 static INLINE void
nvc0_program_update_context_state(struct nvc0_context * nvc0,struct nvc0_program * prog,int stage)31 nvc0_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 
66 static INLINE boolean
nvc0_program_validate(struct nvc0_context * nvc0,struct nvc0_program * prog)67 nvc0_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 
84 void
nvc0_vertprog_validate(struct nvc0_context * nvc0)85 nvc0_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 
104 void
nvc0_fragprog_validate(struct nvc0_context * nvc0)105 nvc0_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 
132 void
nvc0_tctlprog_validate(struct nvc0_context * nvc0)133 nvc0_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 
158 void
nvc0_tevlprog_validate(struct nvc0_context * nvc0)159 nvc0_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 
182 void
nvc0_gmtyprog_validate(struct nvc0_context * nvc0)183 nvc0_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 
211 void
nvc0_tfb_validate(struct nvc0_context * nvc0)212 nvc0_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