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