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