c26536b0e77ca7ed824491068834d6c0599077ef
[profile/ivi/mesa.git] / src / gallium / drivers / nvfx / nvfx_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5
6 #include "nvfx_context.h"
7 #include "nvfx_state.h"
8
9 #include "nouveau/nouveau_channel.h"
10 #include "nouveau/nouveau_pushbuf.h"
11 #include "nouveau/nouveau_util.h"
12
13 static boolean
14 nvfx_force_swtnl(struct nvfx_context *nvfx)
15 {
16         static int force_swtnl = -1;
17         if(force_swtnl < 0)
18                 force_swtnl = debug_get_bool_option("NOUVEAU_SWTNL", 0);
19         return force_swtnl;
20 }
21
22 static INLINE int
23 nvfx_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
24 {
25         switch (pipe) {
26         case PIPE_FORMAT_R32_FLOAT:
27         case PIPE_FORMAT_R32G32_FLOAT:
28         case PIPE_FORMAT_R32G32B32_FLOAT:
29         case PIPE_FORMAT_R32G32B32A32_FLOAT:
30                 *fmt = NV34TCL_VTXFMT_TYPE_FLOAT;
31                 break;
32         case PIPE_FORMAT_R8_UNORM:
33         case PIPE_FORMAT_R8G8_UNORM:
34         case PIPE_FORMAT_R8G8B8_UNORM:
35         case PIPE_FORMAT_R8G8B8A8_UNORM:
36                 *fmt = NV34TCL_VTXFMT_TYPE_UBYTE;
37                 break;
38         case PIPE_FORMAT_R16_SSCALED:
39         case PIPE_FORMAT_R16G16_SSCALED:
40         case PIPE_FORMAT_R16G16B16_SSCALED:
41         case PIPE_FORMAT_R16G16B16A16_SSCALED:
42                 *fmt = NV34TCL_VTXFMT_TYPE_USHORT;
43                 break;
44         default:
45                 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
46                 return 1;
47         }
48
49         switch (pipe) {
50         case PIPE_FORMAT_R8_UNORM:
51         case PIPE_FORMAT_R32_FLOAT:
52         case PIPE_FORMAT_R16_SSCALED:
53                 *ncomp = 1;
54                 break;
55         case PIPE_FORMAT_R8G8_UNORM:
56         case PIPE_FORMAT_R32G32_FLOAT:
57         case PIPE_FORMAT_R16G16_SSCALED:
58                 *ncomp = 2;
59                 break;
60         case PIPE_FORMAT_R8G8B8_UNORM:
61         case PIPE_FORMAT_R32G32B32_FLOAT:
62         case PIPE_FORMAT_R16G16B16_SSCALED:
63                 *ncomp = 3;
64                 break;
65         case PIPE_FORMAT_R8G8B8A8_UNORM:
66         case PIPE_FORMAT_R32G32B32A32_FLOAT:
67         case PIPE_FORMAT_R16G16B16A16_SSCALED:
68                 *ncomp = 4;
69                 break;
70         default:
71                 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
72                 return 1;
73         }
74
75         return 0;
76 }
77
78 static boolean
79 nvfx_vbo_set_idxbuf(struct nvfx_context *nvfx, struct pipe_buffer *ib,
80                     unsigned ib_size)
81 {
82         struct pipe_screen *pscreen = &nvfx->screen->base.base;
83         unsigned type;
84
85         if (!ib) {
86                 nvfx->idxbuf = NULL;
87                 nvfx->idxbuf_format = 0xdeadbeef;
88                 return FALSE;
89         }
90
91         if (!pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF) || ib_size == 1)
92                 return FALSE;
93
94         switch (ib_size) {
95         case 2:
96                 type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
97                 break;
98         case 4:
99                 type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
100                 break;
101         default:
102                 return FALSE;
103         }
104
105         if (ib != nvfx->idxbuf ||
106             type != nvfx->idxbuf_format) {
107                 nvfx->dirty |= NVFX_NEW_ARRAYS;
108                 nvfx->idxbuf = ib;
109                 nvfx->idxbuf_format = type;
110         }
111
112         return TRUE;
113 }
114
115 static boolean
116 nvfx_vbo_static_attrib(struct nvfx_context *nvfx, struct nouveau_stateobj *so,
117                        int attrib, struct pipe_vertex_element *ve,
118                        struct pipe_vertex_buffer *vb)
119 {
120         struct pipe_screen *pscreen = nvfx->pipe.screen;
121         struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
122         unsigned type, ncomp;
123         void *map;
124
125         if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp))
126                 return FALSE;
127
128         map  = pipe_buffer_map(pscreen, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
129         map += vb->buffer_offset + ve->src_offset;
130
131         switch (type) {
132         case NV34TCL_VTXFMT_TYPE_FLOAT:
133         {
134                 float *v = map;
135
136                 switch (ncomp) {
137                 case 4:
138                         so_method(so, eng3d, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
139                         so_data  (so, fui(v[0]));
140                         so_data  (so, fui(v[1]));
141                         so_data  (so, fui(v[2]));
142                         so_data  (so, fui(v[3]));
143                         break;
144                 case 3:
145                         so_method(so, eng3d, NV34TCL_VTX_ATTR_3F_X(attrib), 3);
146                         so_data  (so, fui(v[0]));
147                         so_data  (so, fui(v[1]));
148                         so_data  (so, fui(v[2]));
149                         break;
150                 case 2:
151                         so_method(so, eng3d, NV34TCL_VTX_ATTR_2F_X(attrib), 2);
152                         so_data  (so, fui(v[0]));
153                         so_data  (so, fui(v[1]));
154                         break;
155                 case 1:
156                         so_method(so, eng3d, NV34TCL_VTX_ATTR_1F(attrib), 1);
157                         so_data  (so, fui(v[0]));
158                         break;
159                 default:
160                         pipe_buffer_unmap(pscreen, vb->buffer);
161                         return FALSE;
162                 }
163         }
164                 break;
165         default:
166                 pipe_buffer_unmap(pscreen, vb->buffer);
167                 return FALSE;
168         }
169
170         pipe_buffer_unmap(pscreen, vb->buffer);
171         return TRUE;
172 }
173
174 void
175 nvfx_draw_arrays(struct pipe_context *pipe,
176                  unsigned mode, unsigned start, unsigned count)
177 {
178         struct nvfx_context *nvfx = nvfx_context(pipe);
179         struct nvfx_screen *screen = nvfx->screen;
180         struct nouveau_channel *chan = screen->base.channel;
181         struct nouveau_grobj *eng3d = screen->eng3d;
182         unsigned restart = 0;
183
184         nvfx_vbo_set_idxbuf(nvfx, NULL, 0);
185         if (nvfx_force_swtnl(nvfx) || !nvfx_state_validate(nvfx)) {
186                 nvfx_draw_elements_swtnl(pipe, NULL, 0,
187                                            mode, start, count);
188                 return;
189         }
190
191         while (count) {
192                 unsigned vc, nr;
193
194                 nvfx_state_emit(nvfx);
195
196                 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 256,
197                                         mode, start, count, &restart);
198                 if (!vc) {
199                         FIRE_RING(chan);
200                         continue;
201                 }
202
203                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
204                 OUT_RING  (chan, nvgl_primitive(mode));
205
206                 nr = (vc & 0xff);
207                 if (nr) {
208                         BEGIN_RING(chan, eng3d, NV34TCL_VB_VERTEX_BATCH, 1);
209                         OUT_RING  (chan, ((nr - 1) << 24) | start);
210                         start += nr;
211                 }
212
213                 nr = vc >> 8;
214                 while (nr) {
215                         unsigned push = nr > 2047 ? 2047 : nr;
216
217                         nr -= push;
218
219                         BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_VERTEX_BATCH, push);
220                         while (push--) {
221                                 OUT_RING(chan, ((0x100 - 1) << 24) | start);
222                                 start += 0x100;
223                         }
224                 }
225
226                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
227                 OUT_RING  (chan, 0);
228
229                 count -= vc;
230                 start = restart;
231         }
232
233         pipe->flush(pipe, 0, NULL);
234 }
235
236 static INLINE void
237 nvfx_draw_elements_u08(struct nvfx_context *nvfx, void *ib,
238                        unsigned mode, unsigned start, unsigned count)
239 {
240         struct nvfx_screen *screen = nvfx->screen;
241         struct nouveau_channel *chan = screen->base.channel;
242         struct nouveau_grobj *eng3d = screen->eng3d;
243
244         while (count) {
245                 uint8_t *elts = (uint8_t *)ib + start;
246                 unsigned vc, push, restart = 0;
247
248                 nvfx_state_emit(nvfx);
249
250                 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 2,
251                                         mode, start, count, &restart);
252                 if (vc == 0) {
253                         FIRE_RING(chan);
254                         continue;
255                 }
256                 count -= vc;
257
258                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
259                 OUT_RING  (chan, nvgl_primitive(mode));
260
261                 if (vc & 1) {
262                         BEGIN_RING(chan, eng3d, NV34TCL_VB_ELEMENT_U32, 1);
263                         OUT_RING  (chan, elts[0]);
264                         elts++; vc--;
265                 }
266
267                 while (vc) {
268                         unsigned i;
269
270                         push = MIN2(vc, 2047 * 2);
271
272                         BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U16, push >> 1);
273                         for (i = 0; i < push; i+=2)
274                                 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
275
276                         vc -= push;
277                         elts += push;
278                 }
279
280                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
281                 OUT_RING  (chan, 0);
282
283                 start = restart;
284         }
285 }
286
287 static INLINE void
288 nvfx_draw_elements_u16(struct nvfx_context *nvfx, void *ib,
289                        unsigned mode, unsigned start, unsigned count)
290 {
291         struct nvfx_screen *screen = nvfx->screen;
292         struct nouveau_channel *chan = screen->base.channel;
293         struct nouveau_grobj *eng3d = screen->eng3d;
294
295         while (count) {
296                 uint16_t *elts = (uint16_t *)ib + start;
297                 unsigned vc, push, restart = 0;
298
299                 nvfx_state_emit(nvfx);
300
301                 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 2,
302                                         mode, start, count, &restart);
303                 if (vc == 0) {
304                         FIRE_RING(chan);
305                         continue;
306                 }
307                 count -= vc;
308
309                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
310                 OUT_RING  (chan, nvgl_primitive(mode));
311
312                 if (vc & 1) {
313                         BEGIN_RING(chan, eng3d, NV34TCL_VB_ELEMENT_U32, 1);
314                         OUT_RING  (chan, elts[0]);
315                         elts++; vc--;
316                 }
317
318                 while (vc) {
319                         unsigned i;
320
321                         push = MIN2(vc, 2047 * 2);
322
323                         BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U16, push >> 1);
324                         for (i = 0; i < push; i+=2)
325                                 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
326
327                         vc -= push;
328                         elts += push;
329                 }
330
331                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
332                 OUT_RING  (chan, 0);
333
334                 start = restart;
335         }
336 }
337
338 static INLINE void
339 nvfx_draw_elements_u32(struct nvfx_context *nvfx, void *ib,
340                        unsigned mode, unsigned start, unsigned count)
341 {
342         struct nvfx_screen *screen = nvfx->screen;
343         struct nouveau_channel *chan = screen->base.channel;
344         struct nouveau_grobj *eng3d = screen->eng3d;
345
346         while (count) {
347                 uint32_t *elts = (uint32_t *)ib + start;
348                 unsigned vc, push, restart = 0;
349
350                 nvfx_state_emit(nvfx);
351
352                 vc = nouveau_vbuf_split(AVAIL_RING(chan), 5, 1,
353                                         mode, start, count, &restart);
354                 if (vc == 0) {
355                         FIRE_RING(chan);
356                         continue;
357                 }
358                 count -= vc;
359
360                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
361                 OUT_RING  (chan, nvgl_primitive(mode));
362
363                 while (vc) {
364                         push = MIN2(vc, 2047);
365
366                         BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U32, push);
367                         OUT_RINGp    (chan, elts, push);
368
369                         vc -= push;
370                         elts += push;
371                 }
372
373                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
374                 OUT_RING  (chan, 0);
375
376                 start = restart;
377         }
378 }
379
380 static void
381 nvfx_draw_elements_inline(struct pipe_context *pipe,
382                           struct pipe_buffer *ib, unsigned ib_size,
383                           unsigned mode, unsigned start, unsigned count)
384 {
385         struct nvfx_context *nvfx = nvfx_context(pipe);
386         struct pipe_screen *pscreen = pipe->screen;
387         void *map;
388
389         map = pipe_buffer_map(pscreen, ib, PIPE_BUFFER_USAGE_CPU_READ);
390         if (!ib) {
391                 NOUVEAU_ERR("failed mapping ib\n");
392                 return;
393         }
394
395         switch (ib_size) {
396         case 1:
397                 nvfx_draw_elements_u08(nvfx, map, mode, start, count);
398                 break;
399         case 2:
400                 nvfx_draw_elements_u16(nvfx, map, mode, start, count);
401                 break;
402         case 4:
403                 nvfx_draw_elements_u32(nvfx, map, mode, start, count);
404                 break;
405         default:
406                 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
407                 break;
408         }
409
410         pipe_buffer_unmap(pscreen, ib);
411 }
412
413 static void
414 nvfx_draw_elements_vbo(struct pipe_context *pipe,
415                        unsigned mode, unsigned start, unsigned count)
416 {
417         struct nvfx_context *nvfx = nvfx_context(pipe);
418         struct nvfx_screen *screen = nvfx->screen;
419         struct nouveau_channel *chan = screen->base.channel;
420         struct nouveau_grobj *eng3d = screen->eng3d;
421         unsigned restart = 0;
422
423         while (count) {
424                 unsigned nr, vc;
425
426                 nvfx_state_emit(nvfx);
427
428                 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 256,
429                                         mode, start, count, &restart);
430                 if (!vc) {
431                         FIRE_RING(chan);
432                         continue;
433                 }
434
435                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
436                 OUT_RING  (chan, nvgl_primitive(mode));
437
438                 nr = (vc & 0xff);
439                 if (nr) {
440                         BEGIN_RING(chan, eng3d, NV34TCL_VB_INDEX_BATCH, 1);
441                         OUT_RING  (chan, ((nr - 1) << 24) | start);
442                         start += nr;
443                 }
444
445                 nr = vc >> 8;
446                 while (nr) {
447                         unsigned push = nr > 2047 ? 2047 : nr;
448
449                         nr -= push;
450
451                         BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_INDEX_BATCH, push);
452                         while (push--) {
453                                 OUT_RING(chan, ((0x100 - 1) << 24) | start);
454                                 start += 0x100;
455                         }
456                 }
457
458                 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
459                 OUT_RING  (chan, 0);
460
461                 count -= vc;
462                 start = restart;
463         }
464 }
465
466 void
467 nvfx_draw_elements(struct pipe_context *pipe,
468                    struct pipe_buffer *indexBuffer, unsigned indexSize,
469                    unsigned mode, unsigned start, unsigned count)
470 {
471         struct nvfx_context *nvfx = nvfx_context(pipe);
472         boolean idxbuf;
473
474         idxbuf = nvfx_vbo_set_idxbuf(nvfx, indexBuffer, indexSize);
475         if (nvfx_force_swtnl(nvfx) || !nvfx_state_validate(nvfx)) {
476                 nvfx_draw_elements_swtnl(pipe, indexBuffer, indexSize,
477                                            mode, start, count);
478                 return;
479         }
480
481         if (idxbuf) {
482                 nvfx_draw_elements_vbo(pipe, mode, start, count);
483         } else {
484                 nvfx_draw_elements_inline(pipe, indexBuffer, indexSize,
485                                           mode, start, count);
486         }
487
488         pipe->flush(pipe, 0, NULL);
489 }
490
491 static boolean
492 nvfx_vbo_validate(struct nvfx_context *nvfx)
493 {
494         struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
495         struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
496         struct pipe_buffer *ib = nvfx->idxbuf;
497         unsigned ib_format = nvfx->idxbuf_format;
498         unsigned vb_flags = nvfx->screen->vertex_buffer_flags | NOUVEAU_BO_RD;
499         int hw;
500
501         vtxbuf = so_new(3, 17, 18);
502         so_method(vtxbuf, eng3d, NV34TCL_VTXBUF_ADDRESS(0), nvfx->vtxelt->num_elements);
503         vtxfmt = so_new(1, 16, 0);
504         so_method(vtxfmt, eng3d, NV34TCL_VTXFMT(0), nvfx->vtxelt->num_elements);
505
506         for (hw = 0; hw < nvfx->vtxelt->num_elements; hw++) {
507                 struct pipe_vertex_element *ve;
508                 struct pipe_vertex_buffer *vb;
509                 unsigned type, ncomp;
510
511                 ve = &nvfx->vtxelt->pipe[hw];
512                 vb = &nvfx->vtxbuf[ve->vertex_buffer_index];
513
514                 if (!vb->stride) {
515                         if (!sattr)
516                                 sattr = so_new(16, 16 * 4, 0);
517
518                         if (nvfx_vbo_static_attrib(nvfx, sattr, hw, ve, vb)) {
519                                 so_data(vtxbuf, 0);
520                                 so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
521                                 continue;
522                         }
523                 }
524
525                 if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
526                         nvfx->fallback_swtnl |= NVFX_NEW_ARRAYS;
527                         so_ref(NULL, &vtxbuf);
528                         so_ref(NULL, &vtxfmt);
529                         return FALSE;
530                 }
531
532                 so_reloc(vtxbuf, nouveau_bo(vb->buffer),
533                                  vb->buffer_offset + ve->src_offset,
534                                  vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
535                                  0, NV34TCL_VTXBUF_ADDRESS_DMA1);
536                 so_data (vtxfmt, ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) |
537                                   (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
538         }
539
540         if (ib) {
541                 struct nouveau_bo *bo = nouveau_bo(ib);
542
543                 so_method(vtxbuf, eng3d, NV34TCL_IDXBUF_ADDRESS, 2);
544                 so_reloc (vtxbuf, bo, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
545                 so_reloc (vtxbuf, bo, ib_format, vb_flags | NOUVEAU_BO_OR,
546                                   0, NV34TCL_IDXBUF_FORMAT_DMA1);
547         }
548
549         so_method(vtxbuf, eng3d, 0x1710, 1);
550         so_data  (vtxbuf, 0);
551
552         so_ref(vtxbuf, &nvfx->state.hw[NVFX_STATE_VTXBUF]);
553         so_ref(NULL, &vtxbuf);
554         nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXBUF);
555         so_ref(vtxfmt, &nvfx->state.hw[NVFX_STATE_VTXFMT]);
556         so_ref(NULL, &vtxfmt);
557         nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXFMT);
558         so_ref(sattr, &nvfx->state.hw[NVFX_STATE_VTXATTR]);
559         so_ref(NULL, &sattr);
560         nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXATTR);
561         return FALSE;
562 }
563
564 struct nvfx_state_entry nvfx_state_vbo = {
565         .validate = nvfx_vbo_validate,
566         .dirty = {
567                 .pipe = NVFX_NEW_ARRAYS,
568                 .hw = 0,
569         }
570 };