Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / gallium / drivers / nv40 / nv40_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "pipe/p_util.h"
4
5 #include "nv40_context.h"
6 #include "nv40_state.h"
7
8 #include "nouveau/nouveau_channel.h"
9 #include "nouveau/nouveau_pushbuf.h"
10
11 static INLINE int
12 nv40_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
13 {
14 char fs[128];
15
16 switch (pipe) {
17 case PIPE_FORMAT_R32_FLOAT:
18 case PIPE_FORMAT_R32G32_FLOAT:
19 case PIPE_FORMAT_R32G32B32_FLOAT:
20 case PIPE_FORMAT_R32G32B32A32_FLOAT:
21 *fmt = NV40TCL_VTXFMT_TYPE_FLOAT;
22 break;
23 case PIPE_FORMAT_R8_UNORM:
24 case PIPE_FORMAT_R8G8_UNORM:
25 case PIPE_FORMAT_R8G8B8_UNORM:
26 case PIPE_FORMAT_R8G8B8A8_UNORM:
27 *fmt = NV40TCL_VTXFMT_TYPE_UBYTE;
28 break;
29 default:
30 pf_sprint_name(fs, pipe);
31 NOUVEAU_ERR("Unknown format %s\n", fs);
32 return 1;
33 }
34
35 switch (pipe) {
36 case PIPE_FORMAT_R8_UNORM:
37 case PIPE_FORMAT_R32_FLOAT:
38 *ncomp = 1;
39 break;
40 case PIPE_FORMAT_R8G8_UNORM:
41 case PIPE_FORMAT_R32G32_FLOAT:
42 *ncomp = 2;
43 break;
44 case PIPE_FORMAT_R8G8B8_UNORM:
45 case PIPE_FORMAT_R32G32B32_FLOAT:
46 *ncomp = 3;
47 break;
48 case PIPE_FORMAT_R8G8B8A8_UNORM:
49 case PIPE_FORMAT_R32G32B32A32_FLOAT:
50 *ncomp = 4;
51 break;
52 default:
53 pf_sprint_name(fs, pipe);
54 NOUVEAU_ERR("Unknown format %s\n", fs);
55 return 1;
56 }
57
58 return 0;
59 }
60
61 static boolean
62 nv40_vbo_set_idxbuf(struct nv40_context *nv40, struct pipe_buffer *ib,
63 unsigned ib_size)
64 {
65 unsigned type;
66
67 if (!ib) {
68 nv40->idxbuf = NULL;
69 nv40->idxbuf_format = 0xdeadbeef;
70 return FALSE;
71 }
72
73 /* No support for 8bit indices, no support at all on 0x4497 chips */
74 if (nv40->screen->curie->grclass == NV44TCL || ib_size == 1)
75 return FALSE;
76
77 switch (ib_size) {
78 case 2:
79 type = NV40TCL_IDXBUF_FORMAT_TYPE_U16;
80 break;
81 case 4:
82 type = NV40TCL_IDXBUF_FORMAT_TYPE_U32;
83 break;
84 default:
85 return FALSE;
86 }
87
88 if (ib != nv40->idxbuf ||
89 type != nv40->idxbuf_format) {
90 nv40->dirty |= NV40_NEW_ARRAYS;
91 nv40->idxbuf = ib;
92 nv40->idxbuf_format = type;
93 }
94
95 return TRUE;
96 }
97
98 static boolean
99 nv40_vbo_static_attrib(struct nv40_context *nv40, int attrib,
100 struct pipe_vertex_element *ve,
101 struct pipe_vertex_buffer *vb)
102 {
103 struct pipe_winsys *ws = nv40->pipe.winsys;
104 unsigned type, ncomp;
105 void *map;
106
107 if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp))
108 return FALSE;
109
110 map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
111 map += vb->buffer_offset + ve->src_offset;
112
113 switch (type) {
114 case NV40TCL_VTXFMT_TYPE_FLOAT:
115 {
116 float *v = map;
117
118 BEGIN_RING(curie, NV40TCL_VTX_ATTR_4F_X(attrib), 4);
119 switch (ncomp) {
120 case 4:
121 OUT_RINGf(v[0]);
122 OUT_RINGf(v[1]);
123 OUT_RINGf(v[2]);
124 OUT_RINGf(v[3]);
125 break;
126 case 3:
127 OUT_RINGf(v[0]);
128 OUT_RINGf(v[1]);
129 OUT_RINGf(v[2]);
130 OUT_RINGf(1.0);
131 break;
132 case 2:
133 OUT_RINGf(v[0]);
134 OUT_RINGf(v[1]);
135 OUT_RINGf(0.0);
136 OUT_RINGf(1.0);
137 break;
138 case 1:
139 OUT_RINGf(v[0]);
140 OUT_RINGf(0.0);
141 OUT_RINGf(0.0);
142 OUT_RINGf(1.0);
143 break;
144 default:
145 ws->buffer_unmap(ws, vb->buffer);
146 return FALSE;
147 }
148 }
149 break;
150 default:
151 ws->buffer_unmap(ws, vb->buffer);
152 return FALSE;
153 }
154
155 ws->buffer_unmap(ws, vb->buffer);
156
157 return TRUE;
158 }
159
160 boolean
161 nv40_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
162 unsigned count)
163 {
164 struct nv40_context *nv40 = nv40_context(pipe);
165 unsigned nr;
166
167 nv40_vbo_set_idxbuf(nv40, NULL, 0);
168 nv40_emit_hw_state(nv40);
169
170 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
171 OUT_RING (nvgl_primitive(mode));
172
173 nr = (count & 0xff);
174 if (nr) {
175 BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
176 OUT_RING (((nr - 1) << 24) | start);
177 start += nr;
178 }
179
180 nr = count >> 8;
181 while (nr) {
182 unsigned push = nr > 2047 ? 2047 : nr;
183
184 nr -= push;
185
186 BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push);
187 while (push--) {
188 OUT_RING(((0x100 - 1) << 24) | start);
189 start += 0x100;
190 }
191 }
192
193 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
194 OUT_RING (0);
195
196 pipe->flush(pipe, 0);
197 return TRUE;
198 }
199
200 static INLINE void
201 nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
202 unsigned start, unsigned count)
203 {
204 uint8_t *elts = (uint8_t *)ib + start;
205 int push, i;
206
207 if (count & 1) {
208 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
209 OUT_RING (elts[0]);
210 elts++; count--;
211 }
212
213 while (count) {
214 push = MIN2(count, 2047 * 2);
215
216 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
217 for (i = 0; i < push; i+=2)
218 OUT_RING((elts[i+1] << 16) | elts[i]);
219
220 count -= push;
221 elts += push;
222 }
223 }
224
225 static INLINE void
226 nv40_draw_elements_u16(struct nv40_context *nv40, void *ib,
227 unsigned start, unsigned count)
228 {
229 uint16_t *elts = (uint16_t *)ib + start;
230 int push, i;
231
232 if (count & 1) {
233 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
234 OUT_RING (elts[0]);
235 elts++; count--;
236 }
237
238 while (count) {
239 push = MIN2(count, 2047 * 2);
240
241 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
242 for (i = 0; i < push; i+=2)
243 OUT_RING((elts[i+1] << 16) | elts[i]);
244
245 count -= push;
246 elts += push;
247 }
248 }
249
250 static INLINE void
251 nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
252 unsigned start, unsigned count)
253 {
254 uint32_t *elts = (uint32_t *)ib + start;
255 int push;
256
257 while (count) {
258 push = MIN2(count, 2047);
259
260 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
261 OUT_RINGp (elts, push);
262
263 count -= push;
264 elts += push;
265 }
266 }
267
268 static boolean
269 nv40_draw_elements_inline(struct pipe_context *pipe,
270 struct pipe_buffer *ib, unsigned ib_size,
271 unsigned mode, unsigned start, unsigned count)
272 {
273 struct nv40_context *nv40 = nv40_context(pipe);
274 struct pipe_winsys *ws = pipe->winsys;
275 void *map;
276
277 nv40_emit_hw_state(nv40);
278
279 map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
280 if (!ib) {
281 NOUVEAU_ERR("failed mapping ib\n");
282 return FALSE;
283 }
284
285 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
286 OUT_RING (nvgl_primitive(mode));
287
288 switch (ib_size) {
289 case 1:
290 nv40_draw_elements_u08(nv40, map, start, count);
291 break;
292 case 2:
293 nv40_draw_elements_u16(nv40, map, start, count);
294 break;
295 case 4:
296 nv40_draw_elements_u32(nv40, map, start, count);
297 break;
298 default:
299 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
300 break;
301 }
302
303 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
304 OUT_RING (0);
305
306 ws->buffer_unmap(ws, ib);
307
308 return TRUE;
309 }
310
311 static boolean
312 nv40_draw_elements_vbo(struct pipe_context *pipe,
313 unsigned mode, unsigned start, unsigned count)
314 {
315 struct nv40_context *nv40 = nv40_context(pipe);
316 unsigned nr;
317
318 nv40_emit_hw_state(nv40);
319
320 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
321 OUT_RING (nvgl_primitive(mode));
322
323 nr = (count & 0xff);
324 if (nr) {
325 BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1);
326 OUT_RING (((nr - 1) << 24) | start);
327 start += nr;
328 }
329
330 nr = count >> 8;
331 while (nr) {
332 unsigned push = nr > 2047 ? 2047 : nr;
333
334 nr -= push;
335
336 BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push);
337 while (push--) {
338 OUT_RING(((0x100 - 1) << 24) | start);
339 start += 0x100;
340 }
341 }
342
343 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
344 OUT_RING (0);
345
346 return TRUE;
347 }
348
349 boolean
350 nv40_draw_elements(struct pipe_context *pipe,
351 struct pipe_buffer *indexBuffer, unsigned indexSize,
352 unsigned mode, unsigned start, unsigned count)
353 {
354 struct nv40_context *nv40 = nv40_context(pipe);
355
356 if (nv40_vbo_set_idxbuf(nv40, indexBuffer, indexSize)) {
357 nv40_draw_elements_vbo(pipe, mode, start, count);
358 } else {
359 nv40_draw_elements_inline(pipe, indexBuffer, indexSize,
360 mode, start, count);
361 }
362
363 pipe->flush(pipe, 0);
364 return TRUE;
365 }
366
367 static boolean
368 nv40_vbo_validate(struct nv40_context *nv40)
369 {
370 struct nv40_vertex_program *vp = nv40->vertprog;
371 struct nouveau_stateobj *vtxbuf, *vtxfmt;
372 struct pipe_buffer *ib = nv40->idxbuf;
373 unsigned ib_format = nv40->idxbuf_format;
374 unsigned inputs, hw, num_hw;
375 unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
376
377 inputs = vp->ir;
378 for (hw = 0; hw < 16 && inputs; hw++) {
379 if (inputs & (1 << hw)) {
380 num_hw = hw;
381 inputs &= ~(1 << hw);
382 }
383 }
384 num_hw++;
385
386 vtxbuf = so_new(20, 18);
387 so_method(vtxbuf, nv40->screen->curie, NV40TCL_VTXBUF_ADDRESS(0), num_hw);
388 vtxfmt = so_new(17, 0);
389 so_method(vtxfmt, nv40->screen->curie, NV40TCL_VTXFMT(0), num_hw);
390
391 inputs = vp->ir;
392 for (hw = 0; hw < num_hw; hw++) {
393 struct pipe_vertex_element *ve;
394 struct pipe_vertex_buffer *vb;
395 unsigned type, ncomp;
396
397 if (!(inputs & (1 << hw))) {
398 so_data(vtxbuf, 0);
399 so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
400 continue;
401 }
402
403 ve = &nv40->vtxelt[hw];
404 vb = &nv40->vtxbuf[ve->vertex_buffer_index];
405
406 if (!vb->pitch && nv40_vbo_static_attrib(nv40, hw, ve, vb)) {
407 so_data(vtxbuf, 0);
408 so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
409 continue;
410 }
411
412 if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp))
413 assert(0);
414
415 so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
416 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
417 0, NV40TCL_VTXBUF_ADDRESS_DMA1);
418 so_data (vtxfmt, ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
419 (ncomp << NV40TCL_VTXFMT_SIZE_SHIFT) | type));
420 }
421
422 if (ib) {
423 so_method(vtxbuf, nv40->screen->curie, NV40TCL_IDXBUF_ADDRESS, 2);
424 so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
425 so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
426 0, NV40TCL_IDXBUF_FORMAT_DMA1);
427 }
428
429 so_method(vtxbuf, nv40->screen->curie, 0x1710, 1);
430 so_data (vtxbuf, 0);
431
432 so_ref(vtxbuf, &nv40->state.hw[NV40_STATE_VTXBUF]);
433 nv40->state.dirty |= (1ULL << NV40_STATE_VTXBUF);
434 so_ref(vtxfmt, &nv40->state.hw[NV40_STATE_VTXFMT]);
435 nv40->state.dirty |= (1ULL << NV40_STATE_VTXFMT);
436 return FALSE;
437 }
438
439 struct nv40_state_entry nv40_state_vbo = {
440 .validate = nv40_vbo_validate,
441 .dirty = {
442 .pipe = NV40_NEW_ARRAYS,
443 .hw = 0,
444 }
445 };
446