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