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