Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / gallium / drivers / nv30 / nv30_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "pipe/p_util.h"
4
5 #include "nv30_context.h"
6 #include "nv30_state.h"
7
8 #include "nouveau/nouveau_channel.h"
9 #include "nouveau/nouveau_pushbuf.h"
10
11 static INLINE int
12 nv30_vbo_ncomp(uint format)
13 {
14 int ncomp = 0;
15
16 if (pf_size_x(format)) ncomp++;
17 if (pf_size_y(format)) ncomp++;
18 if (pf_size_z(format)) ncomp++;
19 if (pf_size_w(format)) ncomp++;
20
21 return ncomp;
22 }
23
24 static INLINE int
25 nv30_vbo_type(uint format)
26 {
27 switch (pf_type(format)) {
28 case PIPE_FORMAT_TYPE_FLOAT:
29 return NV34TCL_VTXFMT_TYPE_FLOAT;
30 case PIPE_FORMAT_TYPE_UNORM:
31 return NV34TCL_VTXFMT_TYPE_UBYTE;
32 default:
33 NOUVEAU_ERR("Unknown format 0x%08x\n", format);
34 return NV34TCL_VTXFMT_TYPE_FLOAT;
35 }
36 }
37
38 static boolean
39 nv30_vbo_static_attrib(struct nv30_context *nv30, int attrib,
40 struct pipe_vertex_element *ve,
41 struct pipe_vertex_buffer *vb)
42 {
43 struct pipe_winsys *ws = nv30->pipe.winsys;
44 int type, ncomp;
45 void *map;
46
47 type = nv30_vbo_type(ve->src_format);
48 ncomp = nv30_vbo_ncomp(ve->src_format);
49
50 map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
51 map += vb->buffer_offset + ve->src_offset;
52
53 switch (type) {
54 case NV34TCL_VTXFMT_TYPE_FLOAT:
55 {
56 float *v = map;
57
58 BEGIN_RING(rankine, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
59 switch (ncomp) {
60 case 4:
61 OUT_RINGf(v[0]);
62 OUT_RINGf(v[1]);
63 OUT_RINGf(v[2]);
64 OUT_RINGf(v[3]);
65 break;
66 case 3:
67 OUT_RINGf(v[0]);
68 OUT_RINGf(v[1]);
69 OUT_RINGf(v[2]);
70 OUT_RINGf(1.0);
71 break;
72 case 2:
73 OUT_RINGf(v[0]);
74 OUT_RINGf(v[1]);
75 OUT_RINGf(0.0);
76 OUT_RINGf(1.0);
77 break;
78 case 1:
79 OUT_RINGf(v[0]);
80 OUT_RINGf(0.0);
81 OUT_RINGf(0.0);
82 OUT_RINGf(1.0);
83 break;
84 default:
85 ws->buffer_unmap(ws, vb->buffer);
86 return FALSE;
87 }
88 }
89 break;
90 default:
91 ws->buffer_unmap(ws, vb->buffer);
92 return FALSE;
93 }
94
95 ws->buffer_unmap(ws, vb->buffer);
96
97 return TRUE;
98 }
99
100 static void
101 nv30_vbo_arrays_update(struct nv30_context *nv30)
102 {
103 struct nv30_vertex_program *vp = nv30->vertprog.active;
104 uint32_t inputs, vtxfmt[16];
105 int hw, num_hw = 0;
106
107 nv30->vb_enable = 0;
108
109 inputs = vp->ir;
110 for (hw = 0; hw < 16 && inputs; hw++) {
111 if (inputs & (1 << hw)) {
112 num_hw = hw;
113 inputs &= ~(1 << hw);
114 }
115 }
116 num_hw++;
117
118 inputs = vp->ir;
119 for (hw = 0; hw < num_hw; hw++) {
120 struct pipe_vertex_element *ve;
121 struct pipe_vertex_buffer *vb;
122
123 if (!(inputs & (1 << hw))) {
124 vtxfmt[hw] = NV34TCL_VTXFMT_TYPE_FLOAT;
125 continue;
126 }
127
128 ve = &nv30->vtxelt[hw];
129 vb = &nv30->vtxbuf[ve->vertex_buffer_index];
130
131 if (vb->pitch == 0) {
132 vtxfmt[hw] = NV34TCL_VTXFMT_TYPE_FLOAT;
133 if (nv30_vbo_static_attrib(nv30, hw, ve, vb) == TRUE)
134 continue;
135 }
136
137 nv30->vb_enable |= (1 << hw);
138 nv30->vb[hw].delta = vb->buffer_offset + ve->src_offset;
139 nv30->vb[hw].buffer = vb->buffer;
140
141 vtxfmt[hw] = ((vb->pitch << NV34TCL_VTXFMT_STRIDE_SHIFT) |
142 (nv30_vbo_ncomp(ve->src_format) <<
143 NV34TCL_VTXFMT_SIZE_SHIFT) |
144 nv30_vbo_type(ve->src_format));
145 }
146
147 BEGIN_RING(rankine, NV34TCL_VTXFMT(0), num_hw);
148 OUT_RINGp (vtxfmt, num_hw);
149 }
150
151 static boolean
152 nv30_vbo_validate_state(struct nv30_context *nv30,
153 struct pipe_buffer *ib, unsigned ib_format)
154 {
155 unsigned inputs;
156
157 nv30_state_validate(nv30);
158
159 nv30_emit_hw_state(nv30);
160
161 if (nv30->dirty & NV30_NEW_ARRAYS) {
162 nv30_vbo_arrays_update(nv30);
163 nv30->dirty &= ~NV30_NEW_ARRAYS;
164 }
165
166 inputs = nv30->vb_enable;
167 while (inputs) {
168 unsigned a = ffs(inputs) - 1;
169
170 inputs &= ~(1 << a);
171
172 BEGIN_RING(rankine, NV34TCL_VTXBUF_ADDRESS(a), 1);
173 OUT_RELOC (nv30->vb[a].buffer, nv30->vb[a].delta,
174 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_LOW |
175 NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
176 NV34TCL_VTXBUF_ADDRESS_DMA1);
177 }
178
179 if (ib) {
180 BEGIN_RING(rankine, NV34TCL_IDXBUF_ADDRESS, 2);
181 OUT_RELOCl(ib, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
182 NOUVEAU_BO_RD);
183 OUT_RELOCd(ib, ib_format, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
184 NOUVEAU_BO_RD | NOUVEAU_BO_OR,
185 0, NV34TCL_IDXBUF_FORMAT_DMA1);
186 }
187
188 BEGIN_RING(rankine, 0x1710, 1);
189 OUT_RING (0); /* vtx cache flush */
190
191 return TRUE;
192 }
193
194 boolean
195 nv30_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
196 unsigned count)
197 {
198 struct nv30_context *nv30 = nv30_context(pipe);
199 unsigned nr;
200 boolean ret;
201
202 ret = nv30_vbo_validate_state(nv30, NULL, 0);
203 if (!ret) {
204 NOUVEAU_ERR("state validate failed\n");
205 return FALSE;
206 }
207
208 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
209 OUT_RING (nvgl_primitive(mode));
210
211 nr = (count & 0xff);
212 if (nr) {
213 BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
214 OUT_RING (((nr - 1) << 24) | start);
215 start += nr;
216 }
217
218 nr = count >> 8;
219 while (nr) {
220 unsigned push = nr > 2047 ? 2047 : nr;
221
222 nr -= push;
223
224 BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
225 while (push--) {
226 OUT_RING(((0x100 - 1) << 24) | start);
227 start += 0x100;
228 }
229 }
230
231 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
232 OUT_RING (0);
233
234 pipe->flush(pipe, 0, NULL);
235 return TRUE;
236 }
237
238 static INLINE void
239 nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
240 unsigned start, unsigned count)
241 {
242 uint8_t *elts = (uint8_t *)ib + start;
243 int push, i;
244
245 if (count & 1) {
246 BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
247 OUT_RING (elts[0]);
248 elts++; count--;
249 }
250
251 while (count) {
252 push = MIN2(count, 2047 * 2);
253
254 BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
255 for (i = 0; i < push; i+=2)
256 OUT_RING((elts[i+1] << 16) | elts[i]);
257
258 count -= push;
259 elts += push;
260 }
261 }
262
263 static INLINE void
264 nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
265 unsigned start, unsigned count)
266 {
267 uint16_t *elts = (uint16_t *)ib + start;
268 int push, i;
269
270 if (count & 1) {
271 BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
272 OUT_RING (elts[0]);
273 elts++; count--;
274 }
275
276 while (count) {
277 push = MIN2(count, 2047 * 2);
278
279 BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
280 for (i = 0; i < push; i+=2)
281 OUT_RING((elts[i+1] << 16) | elts[i]);
282
283 count -= push;
284 elts += push;
285 }
286 }
287
288 static INLINE void
289 nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
290 unsigned start, unsigned count)
291 {
292 uint32_t *elts = (uint32_t *)ib + start;
293 int push;
294
295 while (count) {
296 push = MIN2(count, 2047);
297
298 BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
299 OUT_RINGp (elts, push);
300
301 count -= push;
302 elts += push;
303 }
304 }
305
306 static boolean
307 nv30_draw_elements_inline(struct pipe_context *pipe,
308 struct pipe_buffer *ib, unsigned ib_size,
309 unsigned mode, unsigned start, unsigned count)
310 {
311 struct nv30_context *nv30 = nv30_context(pipe);
312 struct pipe_winsys *ws = pipe->winsys;
313 boolean ret;
314 void *map;
315
316 ret = nv30_vbo_validate_state(nv30, NULL, 0);
317 if (!ret) {
318 NOUVEAU_ERR("state validate failed\n");
319 return FALSE;
320 }
321
322 map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
323 if (!ib) {
324 NOUVEAU_ERR("failed mapping ib\n");
325 return FALSE;
326 }
327
328 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
329 OUT_RING (nvgl_primitive(mode));
330
331 switch (ib_size) {
332 case 1:
333 nv30_draw_elements_u08(nv30, map, start, count);
334 break;
335 case 2:
336 nv30_draw_elements_u16(nv30, map, start, count);
337 break;
338 case 4:
339 nv30_draw_elements_u32(nv30, map, start, count);
340 break;
341 default:
342 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
343 break;
344 }
345
346 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
347 OUT_RING (0);
348
349 ws->buffer_unmap(ws, ib);
350
351 return TRUE;
352 }
353
354 static boolean
355 nv30_draw_elements_vbo(struct pipe_context *pipe,
356 struct pipe_buffer *ib, unsigned ib_size,
357 unsigned mode, unsigned start, unsigned count)
358 {
359 struct nv30_context *nv30 = nv30_context(pipe);
360 unsigned nr, type;
361 boolean ret;
362
363 switch (ib_size) {
364 case 2:
365 type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
366 break;
367 case 4:
368 type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
369 break;
370 default:
371 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
372 return FALSE;
373 }
374
375 ret = nv30_vbo_validate_state(nv30, ib, type);
376 if (!ret) {
377 NOUVEAU_ERR("failed state validation\n");
378 return FALSE;
379 }
380
381 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
382 OUT_RING (nvgl_primitive(mode));
383
384 nr = (count & 0xff);
385 if (nr) {
386 BEGIN_RING(rankine, NV34TCL_VB_INDEX_BATCH, 1);
387 OUT_RING (((nr - 1) << 24) | start);
388 start += nr;
389 }
390
391 nr = count >> 8;
392 while (nr) {
393 unsigned push = nr > 2047 ? 2047 : nr;
394
395 nr -= push;
396
397 BEGIN_RING_NI(rankine, NV34TCL_VB_INDEX_BATCH, push);
398 while (push--) {
399 OUT_RING(((0x100 - 1) << 24) | start);
400 start += 0x100;
401 }
402 }
403
404 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
405 OUT_RING (0);
406
407 return TRUE;
408 }
409
410 boolean
411 nv30_draw_elements(struct pipe_context *pipe,
412 struct pipe_buffer *indexBuffer, unsigned indexSize,
413 unsigned mode, unsigned start, unsigned count)
414 {
415 /* if (indexSize != 1) {
416 nv30_draw_elements_vbo(pipe, indexBuffer, indexSize,
417 mode, start, count);
418 } else */{
419 nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
420 mode, start, count);
421 }
422
423 pipe->flush(pipe, 0, NULL);
424 return TRUE;
425 }
426
427