nouveau: switch to libdrm_nouveau-2.0
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_vbo.c
1 /*
2 * Copyright 2010 Christoph Bumiller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define NVC0_PUSH_EXPLICIT_SPACE_CHECKING
24
25 #include "pipe/p_context.h"
26 #include "pipe/p_state.h"
27 #include "util/u_inlines.h"
28 #include "util/u_format.h"
29 #include "translate/translate.h"
30
31 #include "nvc0_context.h"
32 #include "nvc0_resource.h"
33
34 #include "nvc0_3d.xml.h"
35
36 void
37 nvc0_vertex_state_delete(struct pipe_context *pipe,
38 void *hwcso)
39 {
40 struct nvc0_vertex_stateobj *so = hwcso;
41
42 if (so->translate)
43 so->translate->release(so->translate);
44 FREE(hwcso);
45 }
46
47 void *
48 nvc0_vertex_state_create(struct pipe_context *pipe,
49 unsigned num_elements,
50 const struct pipe_vertex_element *elements)
51 {
52 struct nvc0_vertex_stateobj *so;
53 struct translate_key transkey;
54 unsigned i;
55
56 so = MALLOC(sizeof(*so) +
57 num_elements * sizeof(struct nvc0_vertex_element));
58 if (!so)
59 return NULL;
60 so->num_elements = num_elements;
61 so->instance_elts = 0;
62 so->instance_bufs = 0;
63 so->need_conversion = FALSE;
64
65 transkey.nr_elements = 0;
66 transkey.output_stride = 0;
67
68 for (i = 0; i < num_elements; ++i) {
69 const struct pipe_vertex_element *ve = &elements[i];
70 const unsigned vbi = ve->vertex_buffer_index;
71 enum pipe_format fmt = ve->src_format;
72
73 so->element[i].pipe = elements[i];
74 so->element[i].state = nvc0_format_table[fmt].vtx;
75
76 if (!so->element[i].state) {
77 switch (util_format_get_nr_components(fmt)) {
78 case 1: fmt = PIPE_FORMAT_R32_FLOAT; break;
79 case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break;
80 case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break;
81 case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break;
82 default:
83 assert(0);
84 return NULL;
85 }
86 so->element[i].state = nvc0_format_table[fmt].vtx;
87 so->need_conversion = TRUE;
88 }
89 so->element[i].state |= i;
90
91 if (1) {
92 unsigned j = transkey.nr_elements++;
93
94 transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL;
95 transkey.element[j].input_format = ve->src_format;
96 transkey.element[j].input_buffer = vbi;
97 transkey.element[j].input_offset = ve->src_offset;
98 transkey.element[j].instance_divisor = ve->instance_divisor;
99
100 transkey.element[j].output_format = fmt;
101 transkey.element[j].output_offset = transkey.output_stride;
102 transkey.output_stride += (util_format_get_stride(fmt, 1) + 3) & ~3;
103
104 if (unlikely(ve->instance_divisor)) {
105 so->instance_elts |= 1 << i;
106 so->instance_bufs |= 1 << vbi;
107 }
108 }
109 }
110
111 so->translate = translate_create(&transkey);
112 so->vtx_size = transkey.output_stride / 4;
113 so->vtx_per_packet_max = NV04_PFIFO_MAX_PACKET_LEN / MAX2(so->vtx_size, 1);
114
115 return so;
116 }
117
118 #define NVC0_3D_VERTEX_ATTRIB_INACTIVE \
119 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT | \
120 NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32 | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST
121
122 #define VTX_ATTR(a, c, t, s) \
123 ((NVC0_3D_VTX_ATTR_DEFINE_TYPE_##t) | \
124 (NVC0_3D_VTX_ATTR_DEFINE_SIZE_##s) | \
125 ((a) << NVC0_3D_VTX_ATTR_DEFINE_ATTR__SHIFT) | \
126 ((c) << NVC0_3D_VTX_ATTR_DEFINE_COMP__SHIFT))
127
128 static void
129 nvc0_emit_vtxattr(struct nvc0_context *nvc0, struct pipe_vertex_buffer *vb,
130 struct pipe_vertex_element *ve, unsigned attr)
131 {
132 const void *data;
133 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
134 struct nv04_resource *res = nv04_resource(vb->buffer);
135 float v[4];
136 int i;
137 const unsigned nc = util_format_get_nr_components(ve->src_format);
138
139 data = nouveau_resource_map_offset(&nvc0->base, res, vb->buffer_offset +
140 ve->src_offset, NOUVEAU_BO_RD);
141
142 util_format_read_4f(ve->src_format, v, 0, data, 0, 0, 0, 1, 1);
143
144 PUSH_SPACE(push, 6);
145 BEGIN_NVC0(push, NVC0_3D(VTX_ATTR_DEFINE), nc + 1);
146 PUSH_DATA (push, VTX_ATTR(attr, nc, FLOAT, 32));
147 for (i = 0; i < nc; ++i)
148 PUSH_DATAf(push, v[i]);
149 }
150
151 static INLINE void
152 nvc0_vbuf_range(struct nvc0_context *nvc0, int vbi,
153 uint32_t *base, uint32_t *size)
154 {
155 if (unlikely(nvc0->vertex->instance_bufs & (1 << vbi))) {
156 /* TODO: use min and max instance divisor to get a proper range */
157 *base = 0;
158 *size = nvc0->vtxbuf[vbi].buffer->width0;
159 } else {
160 assert(nvc0->vbo_max_index != ~0);
161 *base = nvc0->vbo_min_index * nvc0->vtxbuf[vbi].stride;
162 *size = (nvc0->vbo_max_index -
163 nvc0->vbo_min_index + 1) * nvc0->vtxbuf[vbi].stride;
164 }
165 }
166
167 static void
168 nvc0_prevalidate_vbufs(struct nvc0_context *nvc0)
169 {
170 struct pipe_vertex_buffer *vb;
171 struct nv04_resource *buf;
172 int i;
173 uint32_t base, size;
174
175 nvc0->vbo_fifo = nvc0->vbo_user = 0;
176
177 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX);
178
179 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
180 vb = &nvc0->vtxbuf[i];
181 if (!vb->stride)
182 continue;
183 buf = nv04_resource(vb->buffer);
184
185 /* NOTE: user buffers with temporary storage count as mapped by GPU */
186 if (!nouveau_resource_mapped_by_gpu(vb->buffer)) {
187 if (nvc0->vbo_push_hint) {
188 nvc0->vbo_fifo = ~0;
189 continue;
190 } else {
191 if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) {
192 nvc0->vbo_user |= 1 << i;
193 assert(vb->stride > vb->buffer_offset);
194 nvc0_vbuf_range(nvc0, i, &base, &size);
195 nouveau_user_buffer_upload(&nvc0->base, buf, base, size);
196 } else {
197 nouveau_buffer_migrate(&nvc0->base, buf, NOUVEAU_BO_GART);
198 }
199 nvc0->base.vbo_dirty = TRUE;
200 }
201 }
202 BCTX_REFN(nvc0->bufctx_3d, VTX, buf, RD);
203 }
204 }
205
206 static void
207 nvc0_update_user_vbufs(struct nvc0_context *nvc0)
208 {
209 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
210 uint32_t base, offset, size;
211 int i;
212 uint32_t written = 0;
213
214 /* TODO: use separate bufctx bin for user buffers
215 */
216 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX);
217
218 PUSH_SPACE(push, nvc0->vertex->num_elements * 8);
219
220 for (i = 0; i < nvc0->vertex->num_elements; ++i) {
221 struct pipe_vertex_element *ve = &nvc0->vertex->element[i].pipe;
222 const int b = ve->vertex_buffer_index;
223 struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[b];
224 struct nv04_resource *buf = nv04_resource(vb->buffer);
225
226 if (!(nvc0->vbo_user & (1 << b))) {
227 BCTX_REFN(nvc0->bufctx_3d, VTX, buf, RD);
228 continue;
229 }
230
231 if (!vb->stride) {
232 nvc0_emit_vtxattr(nvc0, vb, ve, i);
233 continue;
234 }
235 nvc0_vbuf_range(nvc0, b, &base, &size);
236
237 if (!(written & (1 << b))) {
238 written |= 1 << b;
239 nouveau_user_buffer_upload(&nvc0->base, buf, base, size);
240 }
241 offset = vb->buffer_offset + ve->src_offset;
242
243 BEGIN_1IC0(push, NVC0_3D(VERTEX_ARRAY_SELECT), 5);
244 PUSH_DATA (push, i);
245 PUSH_DATAh(push, buf->address + base + size - 1);
246 PUSH_DATA (push, buf->address + base + size - 1);
247 PUSH_DATAh(push, buf->address + offset);
248 PUSH_DATA (push, buf->address + offset);
249
250 BCTX_REFN(nvc0->bufctx_3d, VTX, buf, RD);
251 }
252 nvc0->base.vbo_dirty = TRUE;
253 }
254
255 static INLINE void
256 nvc0_release_user_vbufs(struct nvc0_context *nvc0)
257 {
258 uint32_t vbo_user = nvc0->vbo_user;
259
260 while (vbo_user) {
261 int i = ffs(vbo_user) - 1;
262 vbo_user &= ~(1 << i);
263
264 nouveau_buffer_release_gpu_storage(nv04_resource(nvc0->vtxbuf[i].buffer));
265 }
266 }
267
268 void
269 nvc0_vertex_arrays_validate(struct nvc0_context *nvc0)
270 {
271 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
272 struct nvc0_vertex_stateobj *vertex = nvc0->vertex;
273 struct pipe_vertex_buffer *vb;
274 struct nvc0_vertex_element *ve;
275 unsigned i;
276
277 if (unlikely(vertex->need_conversion) ||
278 unlikely(nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS)) {
279 nvc0->vbo_fifo = ~0;
280 nvc0->vbo_user = 0;
281 } else {
282 nvc0_prevalidate_vbufs(nvc0);
283 }
284
285 PUSH_SPACE(push, vertex->num_elements + 1);
286 BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(0)), vertex->num_elements);
287 for (i = 0; i < vertex->num_elements; ++i) {
288 ve = &vertex->element[i];
289 vb = &nvc0->vtxbuf[ve->pipe.vertex_buffer_index];
290
291 if (likely(vb->stride) || nvc0->vbo_fifo) {
292 PUSH_DATA(push, ve->state);
293 } else {
294 PUSH_DATA(push, ve->state | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST);
295 nvc0->vbo_fifo &= ~(1 << i);
296 }
297 }
298
299 PUSH_SPACE(push, vertex->num_elements * 16);
300 for (i = 0; i < vertex->num_elements; ++i) {
301 struct nv04_resource *res;
302 unsigned size, offset;
303
304 ve = &vertex->element[i];
305 vb = &nvc0->vtxbuf[ve->pipe.vertex_buffer_index];
306
307 if (unlikely(ve->pipe.instance_divisor)) {
308 if (!(nvc0->state.instance_elts & (1 << i))) {
309 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1);
310 }
311 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_DIVISOR(i)), 1);
312 PUSH_DATA (push, ve->pipe.instance_divisor);
313 } else
314 if (unlikely(nvc0->state.instance_elts & (1 << i))) {
315 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 0);
316 }
317
318 res = nv04_resource(vb->buffer);
319
320 if (nvc0->vbo_fifo || unlikely(vb->stride == 0)) {
321 if (!nvc0->vbo_fifo)
322 nvc0_emit_vtxattr(nvc0, vb, &ve->pipe, i);
323 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);
324 PUSH_DATA (push, 0);
325 continue;
326 }
327
328 size = vb->buffer->width0;
329 offset = ve->pipe.src_offset + vb->buffer_offset;
330
331 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);
332 PUSH_DATA (push, (1 << 12) | vb->stride);
333 BEGIN_1IC0(push, NVC0_3D(VERTEX_ARRAY_SELECT), 5);
334 PUSH_DATA (push, i);
335 PUSH_DATAh(push, res->address + size - 1);
336 PUSH_DATA (push, res->address + size - 1);
337 PUSH_DATAh(push, res->address + offset);
338 PUSH_DATA (push, res->address + offset);
339 }
340 for (; i < nvc0->state.num_vtxelts; ++i) {
341 PUSH_SPACE(push, 5);
342 BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(i)), 1);
343 PUSH_DATA (push, NVC0_3D_VERTEX_ATTRIB_INACTIVE);
344 if (unlikely(nvc0->state.instance_elts & (1 << i)))
345 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 0);
346 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);
347 PUSH_DATA (push, 0);
348 }
349
350 nvc0->state.num_vtxelts = vertex->num_elements;
351 nvc0->state.instance_elts = vertex->instance_elts;
352 }
353
354 void
355 nvc0_idxbuf_validate(struct nvc0_context *nvc0)
356 {
357 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
358 struct nv04_resource *buf = nv04_resource(nvc0->idxbuf.buffer);
359
360 assert(buf);
361 if (!nouveau_resource_mapped_by_gpu(&buf->base))
362 return;
363
364 PUSH_SPACE(push, 6);
365 BEGIN_NVC0(push, NVC0_3D(INDEX_ARRAY_START_HIGH), 5);
366 PUSH_DATAh(push, buf->address + nvc0->idxbuf.offset);
367 PUSH_DATA (push, buf->address + nvc0->idxbuf.offset);
368 PUSH_DATAh(push, buf->address + buf->base.width0 - 1);
369 PUSH_DATA (push, buf->address + buf->base.width0 - 1);
370 PUSH_DATA (push, nvc0->idxbuf.index_size >> 1);
371
372 BCTX_REFN(nvc0->bufctx_3d, IDX, buf, RD);
373 }
374
375 #define NVC0_PRIM_GL_CASE(n) \
376 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
377
378 static INLINE unsigned
379 nvc0_prim_gl(unsigned prim)
380 {
381 switch (prim) {
382 NVC0_PRIM_GL_CASE(POINTS);
383 NVC0_PRIM_GL_CASE(LINES);
384 NVC0_PRIM_GL_CASE(LINE_LOOP);
385 NVC0_PRIM_GL_CASE(LINE_STRIP);
386 NVC0_PRIM_GL_CASE(TRIANGLES);
387 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
388 NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
389 NVC0_PRIM_GL_CASE(QUADS);
390 NVC0_PRIM_GL_CASE(QUAD_STRIP);
391 NVC0_PRIM_GL_CASE(POLYGON);
392 NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
393 NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
394 NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
395 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
396 /*
397 NVC0_PRIM_GL_CASE(PATCHES); */
398 default:
399 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
400 break;
401 }
402 }
403
404 static void
405 nvc0_draw_vbo_kick_notify(struct nouveau_pushbuf *push)
406 {
407 struct nvc0_screen *screen = push->user_priv;
408
409 nouveau_fence_update(&screen->base, TRUE);
410 }
411
412 static void
413 nvc0_draw_arrays(struct nvc0_context *nvc0,
414 unsigned mode, unsigned start, unsigned count,
415 unsigned instance_count)
416 {
417 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
418 unsigned prim;
419
420 if (nvc0->state.index_bias) {
421 PUSH_SPACE(push, 1);
422 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 0);
423 nvc0->state.index_bias = 0;
424 }
425
426 prim = nvc0_prim_gl(mode);
427
428 while (instance_count--) {
429 PUSH_SPACE(push, 6);
430 BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
431 PUSH_DATA (push, prim);
432 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
433 PUSH_DATA (push, start);
434 PUSH_DATA (push, count);
435 IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
436
437 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
438 }
439 }
440
441 static void
442 nvc0_draw_elements_inline_u08(struct nouveau_pushbuf *push, uint8_t *map,
443 unsigned start, unsigned count)
444 {
445 map += start;
446
447 if (count & 3) {
448 unsigned i;
449 PUSH_SPACE(push, 4);
450 BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), count & 3);
451 for (i = 0; i < (count & 3); ++i)
452 PUSH_DATA(push, *map++);
453 count &= ~3;
454 }
455 while (count) {
456 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4;
457
458 PUSH_SPACE(push, nr + 1);
459 BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U8), nr);
460 for (i = 0; i < nr; ++i) {
461 PUSH_DATA(push,
462 (map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]);
463 map += 4;
464 }
465 count -= nr * 4;
466 }
467 }
468
469 static void
470 nvc0_draw_elements_inline_u16(struct nouveau_pushbuf *push, uint16_t *map,
471 unsigned start, unsigned count)
472 {
473 map += start;
474
475 if (count & 1) {
476 count &= ~1;
477 PUSH_SPACE(push, 2);
478 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
479 PUSH_DATA (push, *map++);
480 }
481 while (count) {
482 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
483
484 PUSH_SPACE(push, nr + 1);
485 BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);
486 for (i = 0; i < nr; ++i) {
487 PUSH_DATA(push, (map[1] << 16) | map[0]);
488 map += 2;
489 }
490 count -= nr * 2;
491 }
492 }
493
494 static void
495 nvc0_draw_elements_inline_u32(struct nouveau_pushbuf *push, uint32_t *map,
496 unsigned start, unsigned count)
497 {
498 map += start;
499
500 while (count) {
501 const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
502
503 PUSH_SPACE(push, nr + 1);
504 BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), nr);
505 PUSH_DATAp(push, map, nr);
506
507 map += nr;
508 count -= nr;
509 }
510 }
511
512 static void
513 nvc0_draw_elements_inline_u32_short(struct nouveau_pushbuf *push, uint32_t *map,
514 unsigned start, unsigned count)
515 {
516 map += start;
517
518 if (count & 1) {
519 count--;
520 PUSH_SPACE(push, 1);
521 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
522 PUSH_DATA (push, *map++);
523 }
524 while (count) {
525 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
526
527 PUSH_SPACE(push, nr + 1);
528 BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);
529 for (i = 0; i < nr; ++i) {
530 PUSH_DATA(push, (map[1] << 16) | map[0]);
531 map += 2;
532 }
533 count -= nr * 2;
534 }
535 }
536
537 static void
538 nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten,
539 unsigned mode, unsigned start, unsigned count,
540 unsigned instance_count, int32_t index_bias)
541 {
542 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
543 void *data;
544 unsigned prim;
545 const unsigned index_size = nvc0->idxbuf.index_size;
546
547 prim = nvc0_prim_gl(mode);
548
549 if (index_bias != nvc0->state.index_bias) {
550 PUSH_SPACE(push, 2);
551 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 1);
552 PUSH_DATA (push, index_bias);
553 nvc0->state.index_bias = index_bias;
554 }
555
556 if (nouveau_resource_mapped_by_gpu(nvc0->idxbuf.buffer)) {
557 PUSH_SPACE(push, 1);
558 IMMED_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), prim);
559 do {
560 PUSH_SPACE(push, 7);
561 BEGIN_NVC0(push, NVC0_3D(INDEX_BATCH_FIRST), 2);
562 PUSH_DATA (push, start);
563 PUSH_DATA (push, count);
564 if (--instance_count) {
565 BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 2);
566 PUSH_DATA (push, 0);
567 PUSH_DATA (push, prim | NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT);
568 }
569 } while (instance_count);
570 IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
571 } else {
572 data = nouveau_resource_map_offset(&nvc0->base,
573 nv04_resource(nvc0->idxbuf.buffer),
574 nvc0->idxbuf.offset, NOUVEAU_BO_RD);
575 if (!data)
576 return;
577
578 while (instance_count--) {
579 PUSH_SPACE(push, 2);
580 BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
581 PUSH_DATA (push, prim);
582 switch (index_size) {
583 case 1:
584 nvc0_draw_elements_inline_u08(push, data, start, count);
585 break;
586 case 2:
587 nvc0_draw_elements_inline_u16(push, data, start, count);
588 break;
589 case 4:
590 if (shorten)
591 nvc0_draw_elements_inline_u32_short(push, data, start, count);
592 else
593 nvc0_draw_elements_inline_u32(push, data, start, count);
594 break;
595 default:
596 assert(0);
597 return;
598 }
599 PUSH_SPACE(push, 1);
600 IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
601
602 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
603 }
604 }
605 }
606
607 static void
608 nvc0_draw_stream_output(struct nvc0_context *nvc0,
609 const struct pipe_draw_info *info)
610 {
611 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
612 struct nvc0_so_target *so = nvc0_so_target(info->count_from_stream_output);
613 struct nv04_resource *res = nv04_resource(so->pipe.buffer);
614 unsigned mode = nvc0_prim_gl(info->mode);
615 unsigned num_instances = info->instance_count;
616
617 if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
618 res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
619 PUSH_SPACE(push, 2);
620 IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);
621 nvc0_query_fifo_wait(push, so->pq);
622 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
623 }
624
625 while (num_instances--) {
626 PUSH_SPACE(push, 8);
627 BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
628 PUSH_DATA (push, mode);
629 BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BASE), 1);
630 PUSH_DATA (push, 0);
631 BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_STRIDE), 1);
632 PUSH_DATA (push, so->stride);
633 BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BYTES), 1);
634 nvc0_query_pushbuf_submit(push, so->pq, 0x4);
635 IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
636
637 mode |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
638 }
639 }
640
641 void
642 nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
643 {
644 struct nvc0_context *nvc0 = nvc0_context(pipe);
645 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
646
647 /* For picking only a few vertices from a large user buffer, push is better,
648 * if index count is larger and we expect repeated vertices, suggest upload.
649 */
650 nvc0->vbo_push_hint = /* the 64 is heuristic */
651 !(info->indexed &&
652 ((info->max_index - info->min_index + 64) < info->count));
653
654 nvc0->vbo_min_index = info->min_index;
655 nvc0->vbo_max_index = info->max_index;
656
657 if (nvc0->vbo_push_hint != !!nvc0->vbo_fifo)
658 nvc0->dirty |= NVC0_NEW_ARRAYS;
659
660 if (nvc0->vbo_user && !(nvc0->dirty & (NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS)))
661 nvc0_update_user_vbufs(nvc0);
662
663 /* 8 as minimum to avoid immediate double validation of new buffers */
664 nvc0_state_validate(nvc0, ~0, 8);
665
666 push->kick_notify = nvc0_draw_vbo_kick_notify;
667
668 if (nvc0->vbo_fifo) {
669 nvc0_push_vbo(nvc0, info);
670 push->kick_notify = nvc0_default_kick_notify;
671 return;
672 }
673
674 /* space for base instance, flush, and prim restart */
675 PUSH_SPACE(push, 8);
676
677 if (nvc0->state.instance_base != info->start_instance) {
678 nvc0->state.instance_base = info->start_instance;
679 /* NOTE: this does not affect the shader input, should it ? */
680 BEGIN_NVC0(push, NVC0_3D(VB_INSTANCE_BASE), 1);
681 PUSH_DATA (push, info->start_instance);
682 }
683
684 if (nvc0->base.vbo_dirty) {
685 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 1);
686 PUSH_DATA (push, 0);
687 nvc0->base.vbo_dirty = FALSE;
688 }
689
690 if (unlikely(info->count_from_stream_output)) {
691 nvc0_draw_stream_output(nvc0, info);
692 } else
693 if (!info->indexed) {
694 nvc0_draw_arrays(nvc0,
695 info->mode, info->start, info->count,
696 info->instance_count);
697 } else {
698 boolean shorten = info->max_index <= 65535;
699
700 assert(nvc0->idxbuf.buffer);
701
702 if (info->primitive_restart != nvc0->state.prim_restart) {
703 if (info->primitive_restart) {
704 BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 2);
705 PUSH_DATA (push, 1);
706 PUSH_DATA (push, info->restart_index);
707
708 if (info->restart_index > 65535)
709 shorten = FALSE;
710 } else {
711 IMMED_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 0);
712 }
713 nvc0->state.prim_restart = info->primitive_restart;
714 } else
715 if (info->primitive_restart) {
716 BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_INDEX), 1);
717 PUSH_DATA (push, info->restart_index);
718
719 if (info->restart_index > 65535)
720 shorten = FALSE;
721 }
722
723 nvc0_draw_elements(nvc0, shorten,
724 info->mode, info->start, info->count,
725 info->instance_count, info->index_bias);
726 }
727 push->kick_notify = nvc0_default_kick_notify;
728
729 nvc0_release_user_vbufs(nvc0);
730 }