79b5f3d81cc9f26c93d438e00d40c622a0702540
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_shader_state.c
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
31 nvc0_program_update_context_state(struct nvc0_context *nvc0,
32 struct nvc0_program *prog, int stage)
33 {
34 if (prog->hdr[1])
35 nvc0->state.tls_required |= 1 << stage;
36 else
37 nvc0->state.tls_required &= ~(1 << stage);
38 }
39
40 static boolean
41 nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
42 {
43 int ret;
44 unsigned size;
45
46 if (prog->translated)
47 return TRUE;
48
49 prog->translated = nvc0_program_translate(prog);
50 if (!prog->translated)
51 return FALSE;
52
53 size = align(prog->code_size + NVC0_SHADER_HEADER_SIZE, 0x100);
54
55 ret = nouveau_resource_alloc(nvc0->screen->text_heap, size, prog,
56 &prog->res);
57 if (ret)
58 return FALSE;
59
60 prog->code_base = prog->res->start;
61
62 nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->text, prog->code_base,
63 NOUVEAU_BO_VRAM, NVC0_SHADER_HEADER_SIZE, prog->hdr);
64 nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->text,
65 prog->code_base + NVC0_SHADER_HEADER_SIZE,
66 NOUVEAU_BO_VRAM, prog->code_size, prog->code);
67
68 BEGIN_RING(nvc0->screen->base.channel, RING_3D(MEM_BARRIER), 1);
69 OUT_RING (nvc0->screen->base.channel, 0x1111);
70
71 return TRUE;
72 }
73
74 void
75 nvc0_vertprog_validate(struct nvc0_context *nvc0)
76 {
77 struct nouveau_channel *chan = nvc0->screen->base.channel;
78 struct nvc0_program *vp = nvc0->vertprog;
79
80 if (nvc0->clip.nr > vp->vp.num_ucps) {
81 assert(nvc0->clip.nr <= 6);
82 vp->vp.num_ucps = 6;
83
84 if (vp->translated)
85 nvc0_program_destroy(nvc0, vp);
86 }
87
88 if (!nvc0_program_validate(nvc0, vp))
89 return;
90 nvc0_program_update_context_state(nvc0, vp, 0);
91
92 BEGIN_RING(chan, RING_3D(SP_SELECT(1)), 2);
93 OUT_RING (chan, 0x11);
94 OUT_RING (chan, vp->code_base);
95 BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(1)), 1);
96 OUT_RING (chan, vp->max_gpr);
97
98 // BEGIN_RING(chan, RING_3D_(0x163c), 1);
99 // OUT_RING (chan, 0);
100 BEGIN_RING(chan, RING_3D(VERT_COLOR_CLAMP_EN), 1);
101 OUT_RING (chan, 1);
102 }
103
104 void
105 nvc0_fragprog_validate(struct nvc0_context *nvc0)
106 {
107 struct nouveau_channel *chan = nvc0->screen->base.channel;
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 BEGIN_RING(chan, RING_3D(EARLY_FRAGMENT_TESTS), 1);
115 OUT_RING (chan, fp->fp.early_z);
116 BEGIN_RING(chan, RING_3D(SP_SELECT(5)), 2);
117 OUT_RING (chan, 0x51);
118 OUT_RING (chan, fp->code_base);
119 BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(5)), 1);
120 OUT_RING (chan, fp->max_gpr);
121
122 BEGIN_RING(chan, RING_3D_(0x0360), 2);
123 OUT_RING (chan, 0x20164010);
124 OUT_RING (chan, 0x20);
125 BEGIN_RING(chan, RING_3D_(0x196c), 1);
126 OUT_RING (chan, fp->flags[0]);
127 }
128
129 void
130 nvc0_tctlprog_validate(struct nvc0_context *nvc0)
131 {
132 struct nouveau_channel *chan = nvc0->screen->base.channel;
133 struct nvc0_program *tp = nvc0->tctlprog;
134
135 if (!tp) {
136 BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 1);
137 OUT_RING (chan, 0x20);
138 return;
139 }
140 if (!nvc0_program_validate(nvc0, tp))
141 return;
142 nvc0_program_update_context_state(nvc0, tp, 1);
143
144 BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 2);
145 OUT_RING (chan, 0x21);
146 OUT_RING (chan, tp->code_base);
147 BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(2)), 1);
148 OUT_RING (chan, tp->max_gpr);
149 }
150
151 void
152 nvc0_tevlprog_validate(struct nvc0_context *nvc0)
153 {
154 struct nouveau_channel *chan = nvc0->screen->base.channel;
155 struct nvc0_program *tp = nvc0->tevlprog;
156
157 if (!tp) {
158 BEGIN_RING(chan, RING_3D(TEP_SELECT), 1);
159 OUT_RING (chan, 0x30);
160 return;
161 }
162 if (!nvc0_program_validate(nvc0, tp))
163 return;
164 nvc0_program_update_context_state(nvc0, tp, 2);
165
166 BEGIN_RING(chan, RING_3D(TEP_SELECT), 1);
167 OUT_RING (chan, 0x31);
168 BEGIN_RING(chan, RING_3D(SP_START_ID(3)), 1);
169 OUT_RING (chan, tp->code_base);
170 BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(3)), 1);
171 OUT_RING (chan, tp->max_gpr);
172 }
173
174 void
175 nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
176 {
177 struct nouveau_channel *chan = nvc0->screen->base.channel;
178 struct nvc0_program *gp = nvc0->gmtyprog;
179
180 if (!gp) {
181 BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
182 OUT_RING (chan, 0x40);
183 return;
184 }
185 if (!nvc0_program_validate(nvc0, gp))
186 return;
187 nvc0_program_update_context_state(nvc0, gp, 3);
188
189 BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
190 OUT_RING (chan, 0x41);
191 BEGIN_RING(chan, RING_3D(SP_START_ID(4)), 1);
192 OUT_RING (chan, gp->code_base);
193 BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1);
194 OUT_RING (chan, gp->max_gpr);
195 }
196
197 /* It's *is* kind of shader related. We need to inspect the program
198 * to get the output locations right.
199 */
200 void
201 nvc0_tfb_validate(struct nvc0_context *nvc0)
202 {
203 struct nouveau_channel *chan = nvc0->screen->base.channel;
204 struct nvc0_program *vp;
205 struct nvc0_transform_feedback_state *tfb = nvc0->tfb;
206 int b;
207
208 BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
209 if (!tfb) {
210 OUT_RING(chan, 0);
211 return;
212 }
213 OUT_RING(chan, 1);
214
215 vp = nvc0->vertprog ? nvc0->vertprog : nvc0->gmtyprog;
216
217 for (b = 0; b < nvc0->num_tfbbufs; ++b) {
218 uint8_t idx, var[128];
219 int i, n;
220 struct nv04_resource *buf = nv04_resource(nvc0->tfbbuf[b]);
221
222 BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5);
223 OUT_RING (chan, 1);
224 OUT_RESRCh(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
225 OUT_RESRCl(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
226 OUT_RING (chan, buf->base.width0 - nvc0->tfb_offset[b]);
227 OUT_RING (chan, 0); /* TFB_PRIMITIVE_ID <- offset ? */
228
229 if (!(nvc0->dirty & NVC0_NEW_TFB))
230 continue;
231
232 BEGIN_RING(chan, RING_3D(TFB_UNK07X0(b)), 3);
233 OUT_RING (chan, 0);
234 OUT_RING (chan, tfb->varying_count[b]);
235 OUT_RING (chan, tfb->stride[b]);
236
237 n = b ? tfb->varying_count[b - 1] : 0;
238 i = 0;
239 for (; i < tfb->varying_count[b]; ++i) {
240 idx = tfb->varying_index[n + i];
241 var[i] = vp->vp.out_pos[idx >> 2] + (idx & 3);
242 }
243 for (; i & 3; ++i)
244 var[i] = 0;
245
246 BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4);
247 OUT_RINGp (chan, var, i / 4);
248 }
249 for (; b < 4; ++b)
250 IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0);
251 }