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