Merge branch 'upstream-gallium-0.1' into darktama-gallium-0.1
[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_dma.h"
7 #include "nv40_state.h"
8
9 static INLINE int
10 nv40_vbo_ncomp(uint format)
11 {
12 int ncomp = 0;
13
14 if (pf_size_x(format)) ncomp++;
15 if (pf_size_y(format)) ncomp++;
16 if (pf_size_z(format)) ncomp++;
17 if (pf_size_w(format)) ncomp++;
18
19 return ncomp;
20 }
21
22 static INLINE int
23 nv40_vbo_type(uint format)
24 {
25 switch (pf_type(format)) {
26 case PIPE_FORMAT_TYPE_FLOAT:
27 return NV40TCL_VTXFMT_TYPE_FLOAT;
28 case PIPE_FORMAT_TYPE_UNORM:
29 return NV40TCL_VTXFMT_TYPE_UBYTE;
30 default:
31 assert(0);
32 }
33 }
34
35 static boolean
36 nv40_vbo_static_attrib(struct nv40_context *nv40, int attrib,
37 struct pipe_vertex_element *ve,
38 struct pipe_vertex_buffer *vb)
39 {
40 struct pipe_winsys *ws = nv40->pipe.winsys;
41 int type, ncomp;
42 void *map;
43
44 type = nv40_vbo_type(ve->src_format);
45 ncomp = nv40_vbo_ncomp(ve->src_format);
46
47 map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_FLAG_READ);
48 map += vb->buffer_offset + ve->src_offset;
49
50 switch (type) {
51 case NV40TCL_VTXFMT_TYPE_FLOAT:
52 {
53 float *v = map;
54
55 BEGIN_RING(curie, NV40TCL_VTX_ATTR_4F_X(attrib), 4);
56 switch (ncomp) {
57 case 4:
58 OUT_RINGf(v[0]);
59 OUT_RINGf(v[1]);
60 OUT_RINGf(v[2]);
61 OUT_RINGf(v[3]);
62 break;
63 case 3:
64 OUT_RINGf(v[0]);
65 OUT_RINGf(v[1]);
66 OUT_RINGf(v[2]);
67 OUT_RINGf(1.0);
68 break;
69 case 2:
70 OUT_RINGf(v[0]);
71 OUT_RINGf(v[1]);
72 OUT_RINGf(0.0);
73 OUT_RINGf(1.0);
74 break;
75 case 1:
76 OUT_RINGf(v[0]);
77 OUT_RINGf(0.0);
78 OUT_RINGf(0.0);
79 OUT_RINGf(1.0);
80 break;
81 default:
82 ws->buffer_unmap(ws, vb->buffer);
83 return FALSE;
84 }
85 }
86 break;
87 default:
88 ws->buffer_unmap(ws, vb->buffer);
89 return FALSE;
90 }
91
92 ws->buffer_unmap(ws, vb->buffer);
93
94 return TRUE;
95 }
96
97 static void
98 nv40_vbo_arrays_update(struct nv40_context *nv40)
99 {
100 struct nv40_vertex_program *vp = nv40->vertprog.active;
101 uint32_t inputs, vtxfmt[16];
102 int hw, num_hw;
103
104 inputs = vp->ir;
105 for (hw = 0; hw < 16 && inputs; hw++) {
106 if (inputs & (1 << hw)) {
107 num_hw = hw;
108 inputs &= ~(1 << hw);
109 }
110 }
111 num_hw++;
112
113 inputs = vp->ir;
114 for (hw = 0; hw < num_hw; hw++) {
115 struct pipe_vertex_element *ve;
116 struct pipe_vertex_buffer *vb;
117
118 if (!(inputs & (1 << hw))) {
119 vtxfmt[hw] = NV40TCL_VTXFMT_TYPE_FLOAT;
120 continue;
121 }
122
123 ve = &nv40->vtxelt[hw];
124 vb = &nv40->vtxbuf[ve->vertex_buffer_index];
125
126 if (vb->pitch == 0) {
127 vtxfmt[hw] = NV40TCL_VTXFMT_TYPE_FLOAT;
128 if (nv40_vbo_static_attrib(nv40, hw, ve, vb) == TRUE)
129 continue;
130 }
131
132 BEGIN_RING(curie, NV40TCL_VTXBUF_ADDRESS(hw), 1);
133 OUT_RELOC(vb->buffer, vb->buffer_offset + ve->src_offset,
134 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_LOW |
135 NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
136 NV40TCL_VTXBUF_ADDRESS_DMA1);
137 vtxfmt[hw] = ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
138 (nv40_vbo_ncomp(ve->src_format) <<
139 NV40TCL_VTXFMT_SIZE_SHIFT) |
140 nv40_vbo_type(ve->src_format));
141 }
142
143 BEGIN_RING(curie, 0x1710, 1);
144 OUT_RING (0); /* vtx cache flush */
145 BEGIN_RING(curie, NV40TCL_VTXFMT(0), num_hw);
146 OUT_RINGp (vtxfmt, num_hw);
147 }
148
149 static boolean
150 nv40_vbo_validate_state(struct nv40_context *nv40)
151 {
152 if (nv40->dirty & ~NV40_NEW_ARRAYS)
153 nv40_emit_hw_state(nv40);
154
155 if (nv40->dirty & NV40_NEW_ARRAYS) {
156 nv40_vbo_arrays_update(nv40);
157 nv40->dirty &= ~NV40_NEW_ARRAYS;
158 }
159
160 return TRUE;
161 }
162
163 boolean
164 nv40_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
165 unsigned count)
166 {
167 struct nv40_context *nv40 = (struct nv40_context *)pipe;
168 unsigned nr;
169
170 assert(nv40_vbo_validate_state(nv40));
171
172 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
173 OUT_RING (nvgl_primitive(mode));
174
175 nr = (count & 0xff);
176 if (nr) {
177 BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
178 OUT_RING (((nr - 1) << 24) | start);
179 start += nr;
180 }
181
182 nr = count >> 8;
183 while (nr) {
184 unsigned push = nr > 2047 ? 2047 : nr;
185
186 nr -= push;
187
188 BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push);
189 while (push--) {
190 OUT_RING(((0x100 - 1) << 24) | start);
191 start += 0x100;
192 }
193 }
194
195 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
196 OUT_RING (0);
197
198 pipe->flush(pipe, 0);
199 return TRUE;
200 }
201
202 static INLINE void
203 nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
204 unsigned start, unsigned count)
205 {
206 uint8_t *elts = (uint8_t *)ib + start;
207 int push, i;
208
209 if (count & 1) {
210 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
211 OUT_RING (elts[0]);
212 elts++; count--;
213 }
214
215 while (count) {
216 push = MIN2(count, 2046);
217
218 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
219 for (i = 0; i < push; i+=2)
220 OUT_RING((elts[i+1] << 16) | elts[i]);
221
222 count -= push;
223 elts += push;
224 }
225 }
226
227 static INLINE void
228 nv40_draw_elements_u16(struct nv40_context *nv40, void *ib,
229 unsigned start, unsigned count)
230 {
231 uint16_t *elts = (uint16_t *)ib + start;
232 int push, i;
233
234 if (count & 1) {
235 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
236 OUT_RING (elts[0]);
237 elts++; count--;
238 }
239
240 while (count) {
241 push = MIN2(count, 2046);
242
243 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
244 for (i = 0; i < push; i+=2)
245 OUT_RING((elts[i+1] << 16) | elts[i]);
246
247 count -= push;
248 elts += push;
249 }
250 }
251
252 static INLINE void
253 nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
254 unsigned start, unsigned count)
255 {
256 uint32_t *elts = (uint32_t *)ib + start;
257 int push;
258
259 while (count) {
260 push = MIN2(count, 2047);
261
262 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
263 OUT_RINGp (elts, push);
264
265 count -= push;
266 elts += push;
267 }
268 }
269
270 boolean
271 nv40_draw_elements(struct pipe_context *pipe,
272 struct pipe_buffer_handle *indexBuffer, unsigned indexSize,
273 unsigned mode, unsigned start, unsigned count)
274 {
275 struct nv40_context *nv40 = (struct nv40_context *)pipe;
276 void *ib;
277
278 assert(nv40_vbo_validate_state(nv40));
279
280 ib = pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
281 PIPE_BUFFER_FLAG_READ);
282 if (!ib) {
283 NOUVEAU_ERR("Couldn't map index buffer!!\n");
284 return FALSE;
285 }
286
287 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
288 OUT_RING (nvgl_primitive(mode));
289
290 switch (indexSize) {
291 case 1:
292 nv40_draw_elements_u08(nv40, ib, start, count);
293 break;
294 case 2:
295 nv40_draw_elements_u16(nv40, ib, start, count);
296 break;
297 case 4:
298 nv40_draw_elements_u32(nv40, ib, start, count);
299 break;
300 default:
301 NOUVEAU_ERR("unsupported elt size %d\n", indexSize);
302 break;
303 }
304
305 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
306 OUT_RING (0);
307
308 pipe->winsys->buffer_unmap(pipe->winsys, indexBuffer);
309 pipe->flush(pipe, 0);
310 return TRUE;
311 }
312
313