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