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