nv50: move onto common linear buffer manager
[mesa.git] / src / gallium / drivers / nv50 / nv50_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 #include "pipe/p_context.h"
24 #include "pipe/p_state.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
27 #include "translate/translate.h"
28
29 #include "nv50_context.h"
30 #include "nv50_resource.h"
31
32 #include "nv50_3d.xml.h"
33
34 void
35 nv50_vertex_state_delete(struct pipe_context *pipe,
36 void *hwcso)
37 {
38 struct nv50_vertex_stateobj *so = hwcso;
39
40 if (so->translate)
41 so->translate->release(so->translate);
42 FREE(hwcso);
43 }
44
45 void *
46 nv50_vertex_state_create(struct pipe_context *pipe,
47 unsigned num_elements,
48 const struct pipe_vertex_element *elements)
49 {
50 struct nv50_vertex_stateobj *so;
51 struct translate_key transkey;
52 unsigned i;
53
54 assert(num_elements);
55
56 so = MALLOC(sizeof(*so) +
57 (num_elements - 1) * sizeof(struct nv50_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 = nv50_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 = nv50_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->vertex_size = transkey.output_stride / 4;
113 so->packet_vertex_limit = NV04_PFIFO_MAX_PACKET_LEN /
114 MAX2(so->vertex_size, 1);
115
116 return so;
117 }
118
119 #define NV50_3D_VERTEX_ATTRIB_INACTIVE \
120 NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT | \
121 NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 | \
122 NV50_3D_VERTEX_ARRAY_ATTRIB_CONST
123
124 static void
125 nv50_emit_vtxattr(struct nv50_context *nv50, struct pipe_vertex_buffer *vb,
126 struct pipe_vertex_element *ve, unsigned attr)
127 {
128 const void *data;
129 struct nouveau_channel *chan = nv50->screen->base.channel;
130 struct nv04_resource *res = nv04_resource(vb->buffer);
131 float v[4];
132 const unsigned nc = util_format_get_nr_components(ve->src_format);
133
134 data = nouveau_resource_map_offset(&nv50->pipe, res, vb->buffer_offset +
135 ve->src_offset, NOUVEAU_BO_RD);
136
137 util_format_read_4f(ve->src_format, v, 0, data, 0, 0, 0, 1, 1);
138
139 switch (nc) {
140 case 4:
141 BEGIN_RING(chan, RING_3D(VTX_ATTR_4F_X(attr)), 4);
142 OUT_RINGf (chan, v[0]);
143 OUT_RINGf (chan, v[1]);
144 OUT_RINGf (chan, v[2]);
145 OUT_RINGf (chan, v[3]);
146 break;
147 case 3:
148 BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(attr)), 3);
149 OUT_RINGf (chan, v[0]);
150 OUT_RINGf (chan, v[1]);
151 OUT_RINGf (chan, v[2]);
152 break;
153 case 2:
154 BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(attr)), 2);
155 OUT_RINGf (chan, v[0]);
156 OUT_RINGf (chan, v[1]);
157 break;
158 case 1:
159 if (attr == nv50->vertprog->vp.edgeflag) {
160 BEGIN_RING(chan, RING_3D(EDGEFLAG_ENABLE), 1);
161 OUT_RING (chan, v[0] ? 1 : 0);
162 }
163 BEGIN_RING(chan, RING_3D(VTX_ATTR_1F(attr)), 1);
164 OUT_RINGf (chan, v[0]);
165 break;
166 default:
167 assert(0);
168 break;
169 }
170 }
171
172 static INLINE void
173 nv50_vbuf_range(struct nv50_context *nv50, int vbi,
174 uint32_t *base, uint32_t *size)
175 {
176 if (unlikely(nv50->vertex->instance_bufs & (1 << vbi))) {
177 /* TODO: use min and max instance divisor to get a proper range */
178 *base = 0;
179 *size = nv50->vtxbuf[vbi].buffer->width0;
180 } else {
181 assert(nv50->vbo_max_index != ~0);
182 *base = nv50->vbo_min_index * nv50->vtxbuf[vbi].stride;
183 *size = (nv50->vbo_max_index -
184 nv50->vbo_min_index + 1) * nv50->vtxbuf[vbi].stride;
185 }
186 }
187
188 static void
189 nv50_prevalidate_vbufs(struct nv50_context *nv50)
190 {
191 struct pipe_vertex_buffer *vb;
192 struct nv04_resource *buf;
193 int i;
194 uint32_t base, size;
195
196 nv50->vbo_fifo = nv50->vbo_user = 0;
197
198 nv50_bufctx_reset(nv50, NV50_BUFCTX_VERTEX);
199
200 for (i = 0; i < nv50->num_vtxbufs; ++i) {
201 vb = &nv50->vtxbuf[i];
202 if (!vb->stride)
203 continue;
204 buf = nv04_resource(vb->buffer);
205
206 /* NOTE: user buffers with temporary storage count as mapped by GPU */
207 if (!nouveau_resource_mapped_by_gpu(vb->buffer)) {
208 if (nv50->vbo_push_hint) {
209 nv50->vbo_fifo = ~0;
210 continue;
211 } else {
212 if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) {
213 nv50->vbo_user |= 1 << i;
214 assert(vb->stride > vb->buffer_offset);
215 nv50_vbuf_range(nv50, i, &base, &size);
216 nouveau_user_buffer_upload(buf, base, size);
217 } else {
218 nouveau_buffer_migrate(&nv50->pipe, buf, NOUVEAU_BO_GART);
219 }
220 nv50->vbo_dirty = TRUE;
221 }
222 }
223 nv50_bufctx_add_resident(nv50, NV50_BUFCTX_VERTEX, buf, NOUVEAU_BO_RD);
224 nouveau_buffer_adjust_score(&nv50->pipe, buf, 1);
225 }
226 }
227
228 static void
229 nv50_update_user_vbufs(struct nv50_context *nv50)
230 {
231 struct nouveau_channel *chan = nv50->screen->base.channel;
232 uint32_t base, offset, size;
233 int i;
234 uint32_t written = 0;
235
236 for (i = 0; i < nv50->vertex->num_elements; ++i) {
237 struct pipe_vertex_element *ve = &nv50->vertex->element[i].pipe;
238 const int b = ve->vertex_buffer_index;
239 struct pipe_vertex_buffer *vb = &nv50->vtxbuf[b];
240 struct nv04_resource *buf = nv04_resource(vb->buffer);
241
242 if (!(nv50->vbo_user & (1 << b)))
243 continue;
244
245 if (!vb->stride) {
246 nv50_emit_vtxattr(nv50, vb, ve, i);
247 continue;
248 }
249 nv50_vbuf_range(nv50, b, &base, &size);
250
251 if (!(written & (1 << b))) {
252 written |= 1 << b;
253 nouveau_user_buffer_upload(buf, base, size);
254 }
255 offset = vb->buffer_offset + ve->src_offset;
256
257 MARK_RING (chan, 6, 4);
258 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2);
259 OUT_RESRCh(chan, buf, base + size - 1, NOUVEAU_BO_RD);
260 OUT_RESRCl(chan, buf, base + size - 1, NOUVEAU_BO_RD);
261 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_START_HIGH(i)), 2);
262 OUT_RESRCh(chan, buf, offset, NOUVEAU_BO_RD);
263 OUT_RESRCl(chan, buf, offset, NOUVEAU_BO_RD);
264 }
265 nv50->vbo_dirty = TRUE;
266 }
267
268 static INLINE void
269 nv50_release_user_vbufs(struct nv50_context *nv50)
270 {
271 uint32_t vbo_user = nv50->vbo_user;
272
273 while (vbo_user) {
274 int i = ffs(vbo_user) - 1;
275 vbo_user &= ~(1 << i);
276
277 nouveau_buffer_release_gpu_storage(nv04_resource(nv50->vtxbuf[i].buffer));
278 }
279 }
280
281 void
282 nv50_vertex_arrays_validate(struct nv50_context *nv50)
283 {
284 struct nouveau_channel *chan = nv50->screen->base.channel;
285 struct nv50_vertex_stateobj *vertex = nv50->vertex;
286 struct pipe_vertex_buffer *vb;
287 struct nv50_vertex_element *ve;
288 unsigned i;
289
290 if (unlikely(vertex->need_conversion)) {
291 nv50->vbo_fifo = ~0;
292 nv50->vbo_user = 0;
293 } else {
294 nv50_prevalidate_vbufs(nv50);
295 }
296
297 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_ATTRIB(0)), vertex->num_elements);
298 for (i = 0; i < vertex->num_elements; ++i) {
299 ve = &vertex->element[i];
300 vb = &nv50->vtxbuf[ve->pipe.vertex_buffer_index];
301
302 if (likely(vb->stride) || nv50->vbo_fifo) {
303 OUT_RING(chan, ve->state);
304 } else {
305 OUT_RING(chan, ve->state | NV50_3D_VERTEX_ARRAY_ATTRIB_CONST);
306 nv50->vbo_fifo &= ~(1 << i);
307 }
308 }
309
310 for (i = 0; i < vertex->num_elements; ++i) {
311 struct nv04_resource *res;
312 unsigned size, offset;
313
314 ve = &vertex->element[i];
315 vb = &nv50->vtxbuf[ve->pipe.vertex_buffer_index];
316
317 if (unlikely(ve->pipe.instance_divisor)) {
318 if (!(nv50->state.instance_elts & (1 << i))) {
319 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1);
320 OUT_RING (chan, 1);
321 }
322 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_DIVISOR(i)), 1);
323 OUT_RING (chan, ve->pipe.instance_divisor);
324 } else
325 if (unlikely(nv50->state.instance_elts & (1 << i))) {
326 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1);
327 OUT_RING (chan, 0);
328 }
329
330 res = nv04_resource(vb->buffer);
331
332 if (nv50->vbo_fifo || unlikely(vb->stride == 0)) {
333 if (!nv50->vbo_fifo)
334 nv50_emit_vtxattr(nv50, vb, &ve->pipe, i);
335 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
336 OUT_RING (chan, 0);
337 continue;
338 }
339
340 size = vb->buffer->width0;
341 offset = ve->pipe.src_offset + vb->buffer_offset;
342
343 MARK_RING (chan, 8, 4);
344 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
345 OUT_RING (chan, NV50_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
346 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2);
347 OUT_RESRCh(chan, res, size - 1, NOUVEAU_BO_RD);
348 OUT_RESRCl(chan, res, size - 1, NOUVEAU_BO_RD);
349 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_START_HIGH(i)), 2);
350 OUT_RESRCh(chan, res, offset, NOUVEAU_BO_RD);
351 OUT_RESRCl(chan, res, offset, NOUVEAU_BO_RD);
352 }
353 for (; i < nv50->state.num_vtxelts; ++i) {
354 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_ATTRIB(i)), 1);
355 OUT_RING (chan, NV50_3D_VERTEX_ATTRIB_INACTIVE);
356 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
357 OUT_RING (chan, 0);
358 }
359
360 nv50->state.num_vtxelts = vertex->num_elements;
361 nv50->state.instance_elts = vertex->instance_elts;
362 }
363
364 #define NV50_PRIM_GL_CASE(n) \
365 case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
366
367 static INLINE unsigned
368 nv50_prim_gl(unsigned prim)
369 {
370 switch (prim) {
371 NV50_PRIM_GL_CASE(POINTS);
372 NV50_PRIM_GL_CASE(LINES);
373 NV50_PRIM_GL_CASE(LINE_LOOP);
374 NV50_PRIM_GL_CASE(LINE_STRIP);
375 NV50_PRIM_GL_CASE(TRIANGLES);
376 NV50_PRIM_GL_CASE(TRIANGLE_STRIP);
377 NV50_PRIM_GL_CASE(TRIANGLE_FAN);
378 NV50_PRIM_GL_CASE(QUADS);
379 NV50_PRIM_GL_CASE(QUAD_STRIP);
380 NV50_PRIM_GL_CASE(POLYGON);
381 NV50_PRIM_GL_CASE(LINES_ADJACENCY);
382 NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
383 NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
384 NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
385 default:
386 return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
387 break;
388 }
389 }
390
391 static void
392 nv50_draw_vbo_flush_notify(struct nouveau_channel *chan)
393 {
394 struct nv50_context *nv50 = chan->user_private;
395
396 nouveau_fence_update(&nv50->screen->base, TRUE);
397
398 nv50_bufctx_emit_relocs(nv50);
399 }
400
401 static void
402 nv50_draw_arrays(struct nv50_context *nv50,
403 unsigned mode, unsigned start, unsigned count,
404 unsigned instance_count)
405 {
406 struct nouveau_channel *chan = nv50->screen->base.channel;
407 unsigned prim;
408
409 chan->flush_notify = nv50_draw_vbo_flush_notify;
410 chan->user_private = nv50;
411
412 prim = nv50_prim_gl(mode);
413
414 while (instance_count--) {
415 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
416 OUT_RING (chan, prim);
417 BEGIN_RING(chan, RING_3D(VERTEX_BUFFER_FIRST), 2);
418 OUT_RING (chan, start);
419 OUT_RING (chan, count);
420 BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1);
421 OUT_RING (chan, 0);
422
423 prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
424 }
425
426 chan->flush_notify = nv50_default_flush_notify;
427 }
428
429 static void
430 nv50_draw_elements_inline_u08(struct nouveau_channel *chan, uint8_t *map,
431 unsigned start, unsigned count)
432 {
433 map += start;
434
435 if (count & 3) {
436 unsigned i;
437 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U32), count & 3);
438 for (i = 0; i < (count & 3); ++i)
439 OUT_RING(chan, *map++);
440 count &= ~3;
441 }
442 while (count) {
443 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4;
444
445 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U8), nr);
446 for (i = 0; i < nr; ++i) {
447 OUT_RING(chan,
448 (map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]);
449 map += 4;
450 }
451 count -= nr * 4;
452 }
453 }
454
455 static void
456 nv50_draw_elements_inline_u16(struct nouveau_channel *chan, uint16_t *map,
457 unsigned start, unsigned count)
458 {
459 map += start;
460
461 if (count & 1) {
462 count &= ~1;
463 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32), 1);
464 OUT_RING (chan, *map++);
465 }
466 while (count) {
467 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
468
469 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U16), nr);
470 for (i = 0; i < nr; ++i) {
471 OUT_RING(chan, (map[1] << 16) | map[0]);
472 map += 2;
473 }
474 count -= nr * 2;
475 }
476 }
477
478 static void
479 nv50_draw_elements_inline_u32(struct nouveau_channel *chan, uint32_t *map,
480 unsigned start, unsigned count)
481 {
482 map += start;
483
484 while (count) {
485 const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
486
487 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U32), nr);
488 OUT_RINGp (chan, map, nr);
489
490 map += nr;
491 count -= nr;
492 }
493 }
494
495 static void
496 nv50_draw_elements_inline_u32_short(struct nouveau_channel *chan, uint32_t *map,
497 unsigned start, unsigned count)
498 {
499 map += start;
500
501 if (count & 1) {
502 count--;
503 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32), 1);
504 OUT_RING (chan, *map++);
505 }
506 while (count) {
507 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
508
509 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U16), nr);
510 for (i = 0; i < nr; ++i) {
511 OUT_RING(chan, (map[1] << 16) | map[0]);
512 map += 2;
513 }
514 count -= nr * 2;
515 }
516 }
517
518 static void
519 nv50_draw_elements(struct nv50_context *nv50, boolean shorten,
520 unsigned mode, unsigned start, unsigned count,
521 unsigned instance_count, int32_t index_bias)
522 {
523 struct nouveau_channel *chan = nv50->screen->base.channel;
524 void *data;
525 unsigned prim;
526 const unsigned index_size = nv50->idxbuf.index_size;
527
528 chan->flush_notify = nv50_draw_vbo_flush_notify;
529 chan->user_private = nv50;
530
531 prim = nv50_prim_gl(mode);
532
533 if (index_bias != nv50->state.index_bias) {
534 BEGIN_RING(chan, RING_3D(VB_ELEMENT_BASE), 1);
535 OUT_RING (chan, index_bias);
536 nv50->state.index_bias = index_bias;
537 }
538
539 if (nouveau_resource_mapped_by_gpu(nv50->idxbuf.buffer) && 0) {
540 struct nv04_resource *res = nv04_resource(nv50->idxbuf.buffer);
541 unsigned offset = res->offset + nv50->idxbuf.offset;
542
543 nouveau_buffer_adjust_score(&nv50->pipe, res, 1);
544
545 while (instance_count--) {
546 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
547 OUT_RING (chan, mode);
548
549 switch (index_size) {
550 case 4:
551 {
552 WAIT_RING (chan, 2);
553 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32) | 0x30000, 0);
554 OUT_RING (chan, count);
555 nouveau_pushbuf_submit(chan, res->bo,
556 (start << 2) + offset,
557 (count << 2));
558 }
559 break;
560 case 2:
561 {
562 unsigned pb_start = (start & ~1);
563 unsigned pb_words = (((start + count + 1) & ~1) - pb_start) >> 1;
564
565 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16_SETUP), 1);
566 OUT_RING (chan, (start << 31) | count);
567 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16) | 0x30000, 0);
568 OUT_RING (chan, pb_words);
569 nouveau_pushbuf_submit(chan, res->bo,
570 (pb_start << 1) + offset, pb_words << 2);
571 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16_SETUP), 1);
572 OUT_RING (chan, 0);
573 break;
574 }
575 case 1:
576 {
577 unsigned pb_start = (start & ~3);
578 unsigned pb_words = (((start + count + 3) & ~3) - pb_start) >> 1;
579
580 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8_SETUP), 1);
581 OUT_RING (chan, (start << 30) | count);
582 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8) | 0x30000, 0);
583 OUT_RING (chan, pb_words);
584 nouveau_pushbuf_submit(chan, res->bo,
585 pb_start + offset, pb_words << 2);
586 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8_SETUP), 1);
587 OUT_RING (chan, 0);
588 break;
589 }
590 default:
591 assert(0);
592 return;
593 }
594
595 nv50_resource_fence(res, NOUVEAU_BO_RD);
596
597 mode |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
598 }
599 } else {
600 data = nouveau_resource_map_offset(&nv50->pipe,
601 nv04_resource(nv50->idxbuf.buffer),
602 nv50->idxbuf.offset, NOUVEAU_BO_RD);
603 if (!data)
604 return;
605
606 while (instance_count--) {
607 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
608 OUT_RING (chan, prim);
609 switch (index_size) {
610 case 1:
611 nv50_draw_elements_inline_u08(chan, data, start, count);
612 break;
613 case 2:
614 nv50_draw_elements_inline_u16(chan, data, start, count);
615 break;
616 case 4:
617 if (shorten)
618 nv50_draw_elements_inline_u32_short(chan, data, start, count);
619 else
620 nv50_draw_elements_inline_u32(chan, data, start, count);
621 break;
622 default:
623 assert(0);
624 return;
625 }
626 BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1);
627 OUT_RING (chan, 0);
628
629 prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
630 }
631 }
632
633 chan->flush_notify = nv50_default_flush_notify;
634 }
635
636 void
637 nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
638 {
639 struct nv50_context *nv50 = nv50_context(pipe);
640 struct nouveau_channel *chan = nv50->screen->base.channel;
641
642 /* For picking only a few vertices from a large user buffer, push is better,
643 * if index count is larger and we expect repeated vertices, suggest upload.
644 */
645 nv50->vbo_push_hint = /* the 64 is heuristic */
646 !(info->indexed &&
647 ((info->max_index - info->min_index + 64) < info->count));
648
649 nv50->vbo_min_index = info->min_index;
650 nv50->vbo_max_index = info->max_index;
651
652 if (nv50->vbo_push_hint != !!nv50->vbo_fifo)
653 nv50->dirty |= NV50_NEW_ARRAYS;
654
655 if (nv50->vbo_user && !(nv50->dirty & (NV50_NEW_VERTEX | NV50_NEW_ARRAYS)))
656 nv50_update_user_vbufs(nv50);
657
658 nv50_state_validate(nv50);
659
660 if (nv50->vbo_fifo) {
661 nv50_push_vbo(nv50, info);
662 return;
663 }
664
665 if (nv50->state.instance_base != info->start_instance) {
666 nv50->state.instance_base = info->start_instance;
667 /* NOTE: this does not affect the shader input, should it ? */
668 BEGIN_RING(chan, RING_3D(VB_INSTANCE_BASE), 1);
669 OUT_RING (chan, info->start_instance);
670 }
671
672 if (nv50->vbo_dirty) {
673 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FLUSH), 1);
674 OUT_RING (chan, 0);
675 nv50->vbo_dirty = FALSE;
676 }
677
678 if (!info->indexed) {
679 nv50_draw_arrays(nv50,
680 info->mode, info->start, info->count,
681 info->instance_count);
682 } else {
683 boolean shorten = info->max_index <= 65535;
684
685 assert(nv50->idxbuf.buffer);
686
687 if (info->primitive_restart != nv50->state.prim_restart) {
688 if (info->primitive_restart) {
689 BEGIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 2);
690 OUT_RING (chan, 1);
691 OUT_RING (chan, info->restart_index);
692
693 if (info->restart_index > 65535)
694 shorten = FALSE;
695 } else {
696 BEGIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 1);
697 OUT_RING (chan, 0);
698 }
699 nv50->state.prim_restart = info->primitive_restart;
700 } else
701 if (info->primitive_restart) {
702 BEGIN_RING(chan, RING_3D(PRIM_RESTART_INDEX), 1);
703 OUT_RING (chan, info->restart_index);
704
705 if (info->restart_index > 65535)
706 shorten = FALSE;
707 }
708
709 nv50_draw_elements(nv50, shorten,
710 info->mode, info->start, info->count,
711 info->instance_count, info->index_bias);
712 }
713
714 nv50_release_user_vbufs(nv50);
715 }