nv50_vbo.c revision dbdbbce066de9af2856c207f5de8be7f10c74597
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 34void 35nv50_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 45void * 46nv50_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 124static void 125nv50_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->base, 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 172static INLINE void 173nv50_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 188static void 189nv50_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->base, buf, NOUVEAU_BO_GART); 219 } 220 nv50->base.vbo_dirty = TRUE; 221 } 222 } 223 nv50_bufctx_add_resident(nv50, NV50_BUFCTX_VERTEX, buf, NOUVEAU_BO_RD); 224 nouveau_buffer_adjust_score(&nv50->base, buf, 1); 225 } 226} 227 228static void 229nv50_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->base.vbo_dirty = TRUE; 266} 267 268static INLINE void 269nv50_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 281void 282nv50_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 367static INLINE unsigned 368nv50_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 391static void 392nv50_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 401static void 402nv50_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 429static void 430nv50_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 455static void 456nv50_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 478static void 479nv50_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 495static void 496nv50_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 518static void 519nv50_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)) { 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->base, 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->base, 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 636void 637nv50_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->base.vbo_dirty) { 673 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FLUSH), 1); 674 OUT_RING (chan, 0); 675 nv50->base.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} 716