nv40: implement user clip planes
[mesa.git] / src / gallium / drivers / nv40 / nv40_draw.c
1 #include "pipe/p_util.h"
2 #include "pipe/p_shader_tokens.h"
3
4 #include "draw/draw_context.h"
5 #include "draw/draw_vertex.h"
6 #include "draw/draw_private.h"
7
8 #include "nv40_context.h"
9 #define NV40_SHADER_NO_FUCKEDNESS
10 #include "nv40_shader.h"
11
12 /* Simple, but crappy, swtnl path, hopefully we wont need to hit this very
13 * often at all. Uses "quadro style" vertex submission + a fixed vertex
14 * layout to avoid the need to generate a vertex program or vtxfmt.
15 */
16
17 struct nv40_render_stage {
18 struct draw_stage stage;
19 struct nv40_context *nv40;
20 unsigned prim;
21 };
22
23 static INLINE struct nv40_render_stage *
24 nv40_render_stage(struct draw_stage *stage)
25 {
26 return (struct nv40_render_stage *)stage;
27 }
28
29 static INLINE void
30 nv40_render_vertex(struct nv40_context *nv40, const struct vertex_header *v)
31 {
32 unsigned i;
33
34 for (i = 0; i < nv40->swtnl.nr_attribs; i++) {
35 unsigned idx = nv40->swtnl.draw[i];
36 unsigned hw = nv40->swtnl.hw[i];
37
38 switch (nv40->swtnl.emit[i]) {
39 case EMIT_OMIT:
40 break;
41 case EMIT_1F:
42 BEGIN_RING(curie, 0x1e40 + (hw * 4), 1);
43 OUT_RING (fui(v->data[idx][0]));
44 break;
45 case EMIT_2F:
46 BEGIN_RING(curie, NV40TCL_VTX_ATTR_2F_X(hw), 2);
47 OUT_RING (fui(v->data[idx][0]));
48 OUT_RING (fui(v->data[idx][1]));
49 break;
50 case EMIT_3F:
51 BEGIN_RING(curie, NV40TCL_VTX_ATTR_3F_X(hw), 3);
52 OUT_RING (fui(v->data[idx][0]));
53 OUT_RING (fui(v->data[idx][1]));
54 OUT_RING (fui(v->data[idx][2]));
55 break;
56 case EMIT_4F:
57 BEGIN_RING(curie, NV40TCL_VTX_ATTR_4F_X(hw), 4);
58 OUT_RING (fui(v->data[idx][0]));
59 OUT_RING (fui(v->data[idx][1]));
60 OUT_RING (fui(v->data[idx][2]));
61 OUT_RING (fui(v->data[idx][3]));
62 break;
63 case EMIT_4UB:
64 BEGIN_RING(curie, 0x1940 + (hw * 4), 1);
65 OUT_RING (pack_ub4(float_to_ubyte(v->data[idx][0]),
66 float_to_ubyte(v->data[idx][1]),
67 float_to_ubyte(v->data[idx][2]),
68 float_to_ubyte(v->data[idx][3])));
69 break;
70 default:
71 assert(0);
72 break;
73 }
74 }
75 }
76
77 static INLINE void
78 nv40_render_prim(struct draw_stage *stage, struct prim_header *prim,
79 unsigned mode, unsigned count)
80 {
81 struct nv40_render_stage *rs = nv40_render_stage(stage);
82 struct nv40_context *nv40 = rs->nv40;
83 struct nouveau_pushbuf *pb = nv40->nvws->channel->pushbuf;
84 unsigned i;
85
86 /* Ensure there's room for 4xfloat32 + potentially 3 begin/end */
87 if (pb->remaining < ((count * 20) + 6)) {
88 if (rs->prim != NV40TCL_BEGIN_END_STOP) {
89 NOUVEAU_ERR("AIII, missed flush\n");
90 assert(0);
91 }
92 FIRE_RING(NULL);
93 nv40_state_emit(nv40);
94 }
95
96 /* Switch primitive modes if necessary */
97 if (rs->prim != mode) {
98 if (rs->prim != NV40TCL_BEGIN_END_STOP) {
99 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
100 OUT_RING (NV40TCL_BEGIN_END_STOP);
101 }
102
103 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
104 OUT_RING (mode);
105 rs->prim = mode;
106 }
107
108 /* Emit vertex data */
109 for (i = 0; i < count; i++)
110 nv40_render_vertex(nv40, prim->v[i]);
111
112 /* If it's likely we'll need to empty the push buffer soon, finish
113 * off the primitive now.
114 */
115 if (pb->remaining < ((count * 20) + 6)) {
116 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
117 OUT_RING (NV40TCL_BEGIN_END_STOP);
118 rs->prim = NV40TCL_BEGIN_END_STOP;
119 }
120 }
121
122 static void
123 nv40_render_point(struct draw_stage *draw, struct prim_header *prim)
124 {
125 nv40_render_prim(draw, prim, NV40TCL_BEGIN_END_POINTS, 1);
126 }
127
128 static void
129 nv40_render_line(struct draw_stage *draw, struct prim_header *prim)
130 {
131 nv40_render_prim(draw, prim, NV40TCL_BEGIN_END_LINES, 2);
132 }
133
134 static void
135 nv40_render_tri(struct draw_stage *draw, struct prim_header *prim)
136 {
137 nv40_render_prim(draw, prim, NV40TCL_BEGIN_END_TRIANGLES, 3);
138 }
139
140 static void
141 nv40_render_flush(struct draw_stage *draw, unsigned flags)
142 {
143 struct nv40_render_stage *rs = nv40_render_stage(draw);
144 struct nv40_context *nv40 = rs->nv40;
145
146 if (rs->prim != NV40TCL_BEGIN_END_STOP) {
147 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
148 OUT_RING (NV40TCL_BEGIN_END_STOP);
149 rs->prim = NV40TCL_BEGIN_END_STOP;
150 }
151 }
152
153 static void
154 nv40_render_reset_stipple_counter(struct draw_stage *draw)
155 {
156 }
157
158 static void
159 nv40_render_destroy(struct draw_stage *draw)
160 {
161 FREE(draw);
162 }
163
164 static INLINE void
165 emit_mov(struct nv40_vertex_program *vp,
166 unsigned dst, unsigned src, unsigned vor, unsigned mask)
167 {
168 struct nv40_vertex_program_exec *inst;
169
170 vp->insns = realloc(vp->insns,
171 sizeof(struct nv40_vertex_program_exec) *
172 ++vp->nr_insns);
173 inst = &vp->insns[vp->nr_insns - 1];
174
175 inst->data[0] = 0x401f9c6c;
176 inst->data[1] = 0x0040000d | (src << 8);
177 inst->data[2] = 0x8106c083;
178 inst->data[3] = 0x6041ff80 | (dst << 2) | (mask << 13);
179 inst->const_index = -1;
180 inst->has_branch_offset = FALSE;
181
182 vp->ir |= (1 << src);
183 if (vor != ~0)
184 vp->or |= (1 << vor);
185 }
186
187 static struct nv40_vertex_program *
188 create_drawvp(struct nv40_context *nv40)
189 {
190 struct nv40_vertex_program *vp = CALLOC_STRUCT(nv40_vertex_program);
191 unsigned i;
192
193 emit_mov(vp, NV40_VP_INST_DEST_POS, 0, ~0, 0xf);
194 emit_mov(vp, NV40_VP_INST_DEST_COL0, 3, 0, 0xf);
195 emit_mov(vp, NV40_VP_INST_DEST_COL1, 4, 1, 0xf);
196 emit_mov(vp, NV40_VP_INST_DEST_BFC0, 3, 2, 0xf);
197 emit_mov(vp, NV40_VP_INST_DEST_BFC1, 4, 3, 0xf);
198 emit_mov(vp, NV40_VP_INST_DEST_FOGC, 5, 4, 0x8);
199 for (i = 0; i < 8; i++)
200 emit_mov(vp, NV40_VP_INST_DEST_TC(i), 8 + i, 14 + i, 0xf);
201
202 vp->insns[vp->nr_insns - 1].data[3] |= 1;
203 vp->translated = TRUE;
204 return vp;
205 }
206
207 struct draw_stage *
208 nv40_draw_render_stage(struct nv40_context *nv40)
209 {
210 struct nv40_render_stage *render = CALLOC_STRUCT(nv40_render_stage);
211
212 if (!nv40->swtnl.vertprog)
213 nv40->swtnl.vertprog = create_drawvp(nv40);
214
215 render->nv40 = nv40;
216 render->stage.draw = nv40->draw;
217 render->stage.point = nv40_render_point;
218 render->stage.line = nv40_render_line;
219 render->stage.tri = nv40_render_tri;
220 render->stage.flush = nv40_render_flush;
221 render->stage.reset_stipple_counter = nv40_render_reset_stipple_counter;
222 render->stage.destroy = nv40_render_destroy;
223
224 return &render->stage;
225 }
226
227 boolean
228 nv40_draw_elements_swtnl(struct pipe_context *pipe,
229 struct pipe_buffer *idxbuf, unsigned idxbuf_size,
230 unsigned mode, unsigned start, unsigned count)
231 {
232 struct nv40_context *nv40 = nv40_context(pipe);
233 struct pipe_winsys *ws = pipe->winsys;
234 unsigned i;
235 void *map;
236
237 if (!nv40_state_validate_swtnl(nv40))
238 return FALSE;
239 nv40->state.dirty &= ~(1ULL << NV40_STATE_VTXBUF);
240 nv40_state_emit(nv40);
241
242 for (i = 0; i < PIPE_ATTRIB_MAX; i++) {
243 if (!nv40->vtxbuf[i].buffer)
244 continue;
245 map = ws->buffer_map(ws, nv40->vtxbuf[i].buffer,
246 PIPE_BUFFER_USAGE_CPU_READ);
247 draw_set_mapped_vertex_buffer(nv40->draw, i, map);
248 }
249
250 if (idxbuf) {
251 map = ws->buffer_map(ws, idxbuf, PIPE_BUFFER_USAGE_CPU_READ);
252 draw_set_mapped_element_buffer(nv40->draw, idxbuf_size, map);
253 } else {
254 draw_set_mapped_element_buffer(nv40->draw, 0, NULL);
255 }
256
257 if (nv40->constbuf[PIPE_SHADER_VERTEX]) {
258 map = ws->buffer_map(ws, nv40->constbuf[PIPE_SHADER_VERTEX],
259 PIPE_BUFFER_USAGE_CPU_READ);
260 draw_set_mapped_constant_buffer(nv40->draw, map);
261 }
262
263 draw_arrays(nv40->draw, mode, start, count);
264
265 for (i = 0; i < PIPE_ATTRIB_MAX; i++) {
266 if (!nv40->vtxbuf[i].buffer)
267 continue;
268 ws->buffer_unmap(ws, nv40->vtxbuf[i].buffer);
269 }
270
271 if (idxbuf)
272 ws->buffer_unmap(ws, idxbuf);
273
274 if (nv40->constbuf[PIPE_SHADER_VERTEX])
275 ws->buffer_unmap(ws, nv40->constbuf[PIPE_SHADER_VERTEX]);
276
277 draw_flush(nv40->draw);
278 pipe->flush(pipe, 0, NULL);
279
280 return TRUE;
281 }
282
283 static INLINE void
284 emit_attrib(struct nv40_context *nv40, unsigned hw, unsigned emit,
285 unsigned semantic, unsigned index)
286 {
287 unsigned draw_out = draw_find_vs_output(nv40->draw, semantic, index);
288 unsigned a = nv40->swtnl.nr_attribs++;
289
290 nv40->swtnl.hw[a] = hw;
291 nv40->swtnl.emit[a] = emit;
292 nv40->swtnl.draw[a] = draw_out;
293 }
294
295 static boolean
296 nv40_state_vtxfmt_validate(struct nv40_context *nv40)
297 {
298 struct nv40_fragment_program *fp = nv40->fragprog;
299 unsigned colour = 0, texcoords = 0, fog = 0, i;
300
301 /* Determine needed fragprog inputs */
302 for (i = 0; i < fp->info.num_inputs; i++) {
303 switch (fp->info.input_semantic_name[i]) {
304 case TGSI_SEMANTIC_POSITION:
305 break;
306 case TGSI_SEMANTIC_COLOR:
307 colour |= (1 << fp->info.input_semantic_index[i]);
308 break;
309 case TGSI_SEMANTIC_GENERIC:
310 texcoords |= (1 << fp->info.input_semantic_index[i]);
311 break;
312 case TGSI_SEMANTIC_FOG:
313 fog = 1;
314 break;
315 default:
316 assert(0);
317 }
318 }
319
320 nv40->swtnl.nr_attribs = 0;
321
322 /* Map draw vtxprog output to hw attribute IDs */
323 for (i = 0; i < 2; i++) {
324 if (!(colour & (1 << i)))
325 continue;
326 emit_attrib(nv40, 3 + i, EMIT_4UB, TGSI_SEMANTIC_COLOR, i);
327 }
328
329 for (i = 0; i < 8; i++) {
330 if (!(texcoords & (1 << i)))
331 continue;
332 emit_attrib(nv40, 8 + i, EMIT_4F, TGSI_SEMANTIC_GENERIC, i);
333 }
334
335 if (fog) {
336 emit_attrib(nv40, 5, EMIT_1F, TGSI_SEMANTIC_FOG, 0);
337 }
338
339 emit_attrib(nv40, 0, EMIT_3F, TGSI_SEMANTIC_POSITION, 0);
340
341 return FALSE;
342 }
343
344 struct nv40_state_entry nv40_state_vtxfmt = {
345 .validate = nv40_state_vtxfmt_validate,
346 .dirty = {
347 .pipe = NV40_NEW_ARRAYS | NV40_NEW_FRAGPROG,
348 .hw = 0
349 }
350 };
351