1/* 2 * Copyright 2012 Red Hat Inc. 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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 * 24 */ 25 26#include "util/format/u_format.h" 27#include "util/u_draw.h" 28#include "util/u_inlines.h" 29#include "util/u_prim.h" 30#include "translate/translate.h" 31 32#include "nouveau_fence.h" 33#include "nv_object.xml.h" 34#include "nv30/nv30-40_3d.xml.h" 35#include "nv30/nv30_context.h" 36#include "nv30/nv30_format.h" 37 38static void 39nv30_emit_vtxattr(struct nv30_context *nv30, struct pipe_vertex_buffer *vb, 40 struct pipe_vertex_element *ve, unsigned attr) 41{ 42 const unsigned nc = util_format_get_nr_components(ve->src_format); 43 struct nouveau_pushbuf *push = nv30->base.pushbuf; 44 struct nv04_resource *res = nv04_resource(vb->buffer.resource); 45 const void *data; 46 float v[4]; 47 48 data = nouveau_resource_map_offset(&nv30->base, res, vb->buffer_offset + 49 ve->src_offset, NOUVEAU_BO_RD); 50 51 util_format_unpack_rgba(ve->src_format, v, data, 1); 52 53 switch (nc) { 54 case 4: 55 BEGIN_NV04(push, NV30_3D(VTX_ATTR_4F(attr)), 4); 56 PUSH_DATAf(push, v[0]); 57 PUSH_DATAf(push, v[1]); 58 PUSH_DATAf(push, v[2]); 59 PUSH_DATAf(push, v[3]); 60 break; 61 case 3: 62 BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(attr)), 3); 63 PUSH_DATAf(push, v[0]); 64 PUSH_DATAf(push, v[1]); 65 PUSH_DATAf(push, v[2]); 66 break; 67 case 2: 68 BEGIN_NV04(push, NV30_3D(VTX_ATTR_2F(attr)), 2); 69 PUSH_DATAf(push, v[0]); 70 PUSH_DATAf(push, v[1]); 71 break; 72 case 1: 73 BEGIN_NV04(push, NV30_3D(VTX_ATTR_1F(attr)), 1); 74 PUSH_DATAf(push, v[0]); 75 break; 76 default: 77 assert(0); 78 break; 79 } 80} 81 82static inline void 83nv30_vbuf_range(struct nv30_context *nv30, int vbi, 84 uint32_t *base, uint32_t *size) 85{ 86 assert(nv30->vbo_max_index != ~0); 87 *base = nv30->vbo_min_index * nv30->vtxbuf[vbi].stride; 88 *size = (nv30->vbo_max_index - 89 nv30->vbo_min_index + 1) * nv30->vtxbuf[vbi].stride; 90} 91 92static void 93nv30_prevalidate_vbufs(struct nv30_context *nv30) 94{ 95 struct pipe_vertex_buffer *vb; 96 struct nv04_resource *buf; 97 int i; 98 uint32_t base, size; 99 100 nv30->vbo_fifo = nv30->vbo_user = 0; 101 102 for (i = 0; i < nv30->num_vtxbufs; i++) { 103 vb = &nv30->vtxbuf[i]; 104 if (!vb->stride || !vb->buffer.resource) /* NOTE: user_buffer not implemented */ 105 continue; 106 buf = nv04_resource(vb->buffer.resource); 107 108 /* NOTE: user buffers with temporary storage count as mapped by GPU */ 109 if (!nouveau_resource_mapped_by_gpu(vb->buffer.resource)) { 110 if (nv30->vbo_push_hint) { 111 nv30->vbo_fifo = ~0; 112 continue; 113 } else { 114 if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) { 115 nv30->vbo_user |= 1 << i; 116 assert(vb->stride > vb->buffer_offset); 117 nv30_vbuf_range(nv30, i, &base, &size); 118 nouveau_user_buffer_upload(&nv30->base, buf, base, size); 119 } else { 120 nouveau_buffer_migrate(&nv30->base, buf, NOUVEAU_BO_GART); 121 } 122 nv30->base.vbo_dirty = true; 123 } 124 } 125 } 126} 127 128static void 129nv30_update_user_vbufs(struct nv30_context *nv30) 130{ 131 struct nouveau_pushbuf *push = nv30->base.pushbuf; 132 uint32_t base, offset, size; 133 int i; 134 uint32_t written = 0; 135 136 for (i = 0; i < nv30->vertex->num_elements; i++) { 137 struct pipe_vertex_element *ve = &nv30->vertex->pipe[i]; 138 const int b = ve->vertex_buffer_index; 139 struct pipe_vertex_buffer *vb = &nv30->vtxbuf[b]; 140 struct nv04_resource *buf = nv04_resource(vb->buffer.resource); 141 142 if (!(nv30->vbo_user & (1 << b))) 143 continue; 144 145 if (!vb->stride) { 146 nv30_emit_vtxattr(nv30, vb, ve, i); 147 continue; 148 } 149 nv30_vbuf_range(nv30, b, &base, &size); 150 151 if (!(written & (1 << b))) { 152 written |= 1 << b; 153 nouveau_user_buffer_upload(&nv30->base, buf, base, size); 154 } 155 156 offset = vb->buffer_offset + ve->src_offset; 157 158 BEGIN_NV04(push, NV30_3D(VTXBUF(i)), 1); 159 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP, buf, offset, 160 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 161 0, NV30_3D_VTXBUF_DMA1); 162 } 163 nv30->base.vbo_dirty = true; 164} 165 166static inline void 167nv30_release_user_vbufs(struct nv30_context *nv30) 168{ 169 uint32_t vbo_user = nv30->vbo_user; 170 171 while (vbo_user) { 172 int i = ffs(vbo_user) - 1; 173 vbo_user &= ~(1 << i); 174 175 nouveau_buffer_release_gpu_storage(nv04_resource(nv30->vtxbuf[i].buffer.resource)); 176 } 177 178 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXTMP); 179} 180 181void 182nv30_vbo_validate(struct nv30_context *nv30) 183{ 184 struct nouveau_pushbuf *push = nv30->base.pushbuf; 185 struct nv30_vertex_stateobj *vertex = nv30->vertex; 186 struct pipe_vertex_element *ve; 187 struct pipe_vertex_buffer *vb; 188 unsigned i, redefine; 189 190 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF); 191 if (!nv30->vertex || nv30->draw_flags) 192 return; 193 194#if UTIL_ARCH_BIG_ENDIAN 195 if (1) { /* Figure out where the buffers are getting messed up */ 196#else 197 if (unlikely(vertex->need_conversion)) { 198#endif 199 nv30->vbo_fifo = ~0; 200 nv30->vbo_user = 0; 201 } else { 202 nv30_prevalidate_vbufs(nv30); 203 } 204 205 if (!PUSH_SPACE(push, 128)) 206 return; 207 208 redefine = MAX2(vertex->num_elements, nv30->state.num_vtxelts); 209 if (redefine == 0) 210 return; 211 212 BEGIN_NV04(push, NV30_3D(VTXFMT(0)), redefine); 213 214 for (i = 0; i < vertex->num_elements; i++) { 215 ve = &vertex->pipe[i]; 216 vb = &nv30->vtxbuf[ve->vertex_buffer_index]; 217 218 if (likely(vb->stride) || nv30->vbo_fifo) 219 PUSH_DATA (push, (vb->stride << 8) | vertex->element[i].state); 220 else 221 PUSH_DATA (push, NV30_3D_VTXFMT_TYPE_V32_FLOAT); 222 } 223 224 for (; i < nv30->state.num_vtxelts; i++) { 225 PUSH_DATA (push, NV30_3D_VTXFMT_TYPE_V32_FLOAT); 226 } 227 228 for (i = 0; i < vertex->num_elements; i++) { 229 struct nv04_resource *res; 230 unsigned offset; 231 bool user; 232 233 ve = &vertex->pipe[i]; 234 vb = &nv30->vtxbuf[ve->vertex_buffer_index]; 235 user = (nv30->vbo_user & (1 << ve->vertex_buffer_index)); 236 237 res = nv04_resource(vb->buffer.resource); 238 239 if (nv30->vbo_fifo || unlikely(vb->stride == 0)) { 240 if (!nv30->vbo_fifo) 241 nv30_emit_vtxattr(nv30, vb, ve, i); 242 continue; 243 } 244 245 offset = ve->src_offset + vb->buffer_offset; 246 247 BEGIN_NV04(push, NV30_3D(VTXBUF(i)), 1); 248 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), user ? BUFCTX_VTXTMP : BUFCTX_VTXBUF, 249 res, offset, NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 250 0, NV30_3D_VTXBUF_DMA1); 251 } 252 253 nv30->state.num_vtxelts = vertex->num_elements; 254} 255 256static void * 257nv30_vertex_state_create(struct pipe_context *pipe, unsigned num_elements, 258 const struct pipe_vertex_element *elements) 259{ 260 struct nv30_vertex_stateobj *so; 261 struct translate_key transkey; 262 unsigned i; 263 264 so = MALLOC(sizeof(*so) + sizeof(*so->element) * num_elements); 265 if (!so) 266 return NULL; 267 memcpy(so->pipe, elements, sizeof(*elements) * num_elements); 268 so->num_elements = num_elements; 269 so->need_conversion = false; 270 271 transkey.nr_elements = 0; 272 transkey.output_stride = 0; 273 274 for (i = 0; i < num_elements; i++) { 275 const struct pipe_vertex_element *ve = &elements[i]; 276 const unsigned vbi = ve->vertex_buffer_index; 277 enum pipe_format fmt = ve->src_format; 278 279 so->element[i].state = nv30_vtxfmt(pipe->screen, fmt)->hw; 280 if (!so->element[i].state) { 281 switch (util_format_get_nr_components(fmt)) { 282 case 1: fmt = PIPE_FORMAT_R32_FLOAT; break; 283 case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break; 284 case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break; 285 case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break; 286 default: 287 assert(0); 288 FREE(so); 289 return NULL; 290 } 291 so->element[i].state = nv30_vtxfmt(pipe->screen, fmt)->hw; 292 so->need_conversion = true; 293 } 294 295 if (1) { 296 unsigned j = transkey.nr_elements++; 297 298 transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL; 299 transkey.element[j].input_format = ve->src_format; 300 transkey.element[j].input_buffer = vbi; 301 transkey.element[j].input_offset = ve->src_offset; 302 transkey.element[j].instance_divisor = ve->instance_divisor; 303 304 transkey.element[j].output_format = fmt; 305 transkey.element[j].output_offset = transkey.output_stride; 306 transkey.output_stride += (util_format_get_stride(fmt, 1) + 3) & ~3; 307 } 308 } 309 310 so->translate = translate_create(&transkey); 311 so->vtx_size = transkey.output_stride / 4; 312 so->vtx_per_packet_max = NV04_PFIFO_MAX_PACKET_LEN / MAX2(so->vtx_size, 1); 313 return so; 314} 315 316static void 317nv30_vertex_state_delete(struct pipe_context *pipe, void *hwcso) 318{ 319 struct nv30_vertex_stateobj *so = hwcso; 320 321 if (so->translate) 322 so->translate->release(so->translate); 323 FREE(hwcso); 324} 325 326static void 327nv30_vertex_state_bind(struct pipe_context *pipe, void *hwcso) 328{ 329 struct nv30_context *nv30 = nv30_context(pipe); 330 331 nv30->vertex = hwcso; 332 nv30->dirty |= NV30_NEW_VERTEX; 333} 334 335static void 336nv30_draw_arrays(struct nv30_context *nv30, 337 unsigned mode, unsigned start, unsigned count, 338 unsigned instance_count) 339{ 340 struct nouveau_pushbuf *push = nv30->base.pushbuf; 341 unsigned prim; 342 343 prim = nv30_prim_gl(mode); 344 345 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 346 PUSH_DATA (push, prim); 347 while (count) { 348 const unsigned mpush = 2047 * 256; 349 unsigned npush = (count > mpush) ? mpush : count; 350 unsigned wpush = ((npush + 255) & ~255) >> 8; 351 352 count -= npush; 353 354 BEGIN_NI04(push, NV30_3D(VB_VERTEX_BATCH), wpush); 355 while (npush >= 256) { 356 PUSH_DATA (push, 0xff000000 | start); 357 start += 256; 358 npush -= 256; 359 } 360 361 if (npush) 362 PUSH_DATA (push, ((npush - 1) << 24) | start); 363 } 364 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 365 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 366} 367 368static void 369nv30_draw_elements_inline_u08(struct nouveau_pushbuf *push, const uint8_t *map, 370 unsigned start, unsigned count) 371{ 372 map += start; 373 374 if (count & 1) { 375 BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 376 PUSH_DATA (push, *map++); 377 } 378 379 count >>= 1; 380 while (count) { 381 unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 382 count -= npush; 383 384 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 385 while (npush--) { 386 PUSH_DATA (push, (map[1] << 16) | map[0]); 387 map += 2; 388 } 389 } 390 391} 392 393static void 394nv30_draw_elements_inline_u16(struct nouveau_pushbuf *push, const uint16_t *map, 395 unsigned start, unsigned count) 396{ 397 map += start; 398 399 if (count & 1) { 400 BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 401 PUSH_DATA (push, *map++); 402 } 403 404 count >>= 1; 405 while (count) { 406 unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 407 count -= npush; 408 409 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 410 while (npush--) { 411 PUSH_DATA (push, (map[1] << 16) | map[0]); 412 map += 2; 413 } 414 } 415} 416 417static void 418nv30_draw_elements_inline_u32(struct nouveau_pushbuf *push, const uint32_t *map, 419 unsigned start, unsigned count) 420{ 421 map += start; 422 423 while (count) { 424 const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 425 426 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U32), nr); 427 PUSH_DATAp(push, map, nr); 428 429 map += nr; 430 count -= nr; 431 } 432} 433 434static void 435nv30_draw_elements_inline_u32_short(struct nouveau_pushbuf *push, 436 const uint32_t *map, 437 unsigned start, unsigned count) 438{ 439 map += start; 440 441 if (count & 1) { 442 BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 443 PUSH_DATA (push, *map++); 444 } 445 446 count >>= 1; 447 while (count) { 448 unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 449 count -= npush; 450 451 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 452 while (npush--) { 453 PUSH_DATA (push, (map[1] << 16) | map[0]); 454 map += 2; 455 } 456 } 457} 458 459static void 460nv30_draw_elements(struct nv30_context *nv30, bool shorten, 461 const struct pipe_draw_info *info, 462 unsigned mode, unsigned start, unsigned count, 463 unsigned instance_count, int32_t index_bias, 464 unsigned index_size) 465{ 466 struct nouveau_pushbuf *push = nv30->base.pushbuf; 467 struct nouveau_object *eng3d = nv30->screen->eng3d; 468 unsigned prim = nv30_prim_gl(mode); 469 470 if (eng3d->oclass >= NV40_3D_CLASS && index_bias != nv30->state.index_bias) { 471 BEGIN_NV04(push, NV40_3D(VB_ELEMENT_BASE), 1); 472 PUSH_DATA (push, index_bias); 473 nv30->state.index_bias = index_bias; 474 } 475 476 if (eng3d->oclass == NV40_3D_CLASS && index_size > 1 && 477 !info->has_user_indices) { 478 struct nv04_resource *res = nv04_resource(info->index.resource); 479 unsigned offset = 0; 480 481 assert(nouveau_resource_mapped_by_gpu(&res->base)); 482 483 BEGIN_NV04(push, NV30_3D(IDXBUF_OFFSET), 2); 484 PUSH_RESRC(push, NV30_3D(IDXBUF_OFFSET), BUFCTX_IDXBUF, res, offset, 485 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0); 486 PUSH_MTHD (push, NV30_3D(IDXBUF_FORMAT), BUFCTX_IDXBUF, res->bo, 487 (index_size == 2) ? 0x00000010 : 0x00000000, 488 res->domain | NOUVEAU_BO_RD, 489 0, NV30_3D_IDXBUF_FORMAT_DMA1); 490 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 491 PUSH_DATA (push, prim); 492 while (count) { 493 const unsigned mpush = 2047 * 256; 494 unsigned npush = (count > mpush) ? mpush : count; 495 unsigned wpush = ((npush + 255) & ~255) >> 8; 496 497 count -= npush; 498 499 BEGIN_NI04(push, NV30_3D(VB_INDEX_BATCH), wpush); 500 while (npush >= 256) { 501 PUSH_DATA (push, 0xff000000 | start); 502 start += 256; 503 npush -= 256; 504 } 505 506 if (npush) 507 PUSH_DATA (push, ((npush - 1) << 24) | start); 508 } 509 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 510 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 511 PUSH_RESET(push, BUFCTX_IDXBUF); 512 } else { 513 const void *data; 514 if (!info->has_user_indices) 515 data = nouveau_resource_map_offset(&nv30->base, 516 nv04_resource(info->index.resource), 517 0, NOUVEAU_BO_RD); 518 else 519 data = info->index.user; 520 if (!data) 521 return; 522 523 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 524 PUSH_DATA (push, prim); 525 switch (index_size) { 526 case 1: 527 nv30_draw_elements_inline_u08(push, data, start, count); 528 break; 529 case 2: 530 nv30_draw_elements_inline_u16(push, data, start, count); 531 break; 532 case 4: 533 if (shorten) 534 nv30_draw_elements_inline_u32_short(push, data, start, count); 535 else 536 nv30_draw_elements_inline_u32(push, data, start, count); 537 break; 538 default: 539 assert(0); 540 return; 541 } 542 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 543 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 544 } 545} 546 547static void 548nv30_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info, 549 unsigned drawid_offset, 550 const struct pipe_draw_indirect_info *indirect, 551 const struct pipe_draw_start_count_bias *draws, 552 unsigned num_draws) 553{ 554 if (num_draws > 1) { 555 util_draw_multi(pipe, info, drawid_offset, indirect, draws, num_draws); 556 return; 557 } 558 559 if (!indirect && (!draws[0].count || !info->instance_count)) 560 return; 561 562 struct nv30_context *nv30 = nv30_context(pipe); 563 struct nouveau_pushbuf *push = nv30->base.pushbuf; 564 int i; 565 566 if (!info->primitive_restart && 567 !u_trim_pipe_prim(info->mode, (unsigned*)&draws[0].count)) 568 return; 569 570 /* For picking only a few vertices from a large user buffer, push is better, 571 * if index count is larger and we expect repeated vertices, suggest upload. 572 */ 573 nv30->vbo_push_hint = /* the 64 is heuristic */ 574 !(info->index_size && 575 info->index_bounds_valid && 576 ((info->max_index - info->min_index + 64) < draws[0].count)); 577 578 if (info->index_bounds_valid) { 579 nv30->vbo_min_index = info->min_index; 580 nv30->vbo_max_index = info->max_index; 581 } else { 582 nv30->vbo_min_index = 0; 583 nv30->vbo_max_index = ~0; 584 } 585 586 if (nv30->vbo_push_hint != !!nv30->vbo_fifo) 587 nv30->dirty |= NV30_NEW_ARRAYS; 588 589 push->user_priv = &nv30->bufctx; 590 if (nv30->vbo_user && !(nv30->dirty & (NV30_NEW_VERTEX | NV30_NEW_ARRAYS))) 591 nv30_update_user_vbufs(nv30); 592 593 nv30_state_validate(nv30, ~0, true); 594 if (nv30->draw_flags) { 595 nv30_render_vbo(pipe, info, drawid_offset, &draws[0]); 596 return; 597 } else 598 if (nv30->vbo_fifo) { 599 nv30_push_vbo(nv30, info, &draws[0]); 600 return; 601 } 602 603 for (i = 0; i < nv30->num_vtxbufs && !nv30->base.vbo_dirty; ++i) { 604 if (!nv30->vtxbuf[i].buffer.resource) 605 continue; 606 if (nv30->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) 607 nv30->base.vbo_dirty = true; 608 } 609 610 if (!nv30->base.vbo_dirty && info->index_size && !info->has_user_indices && 611 info->index.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) 612 nv30->base.vbo_dirty = true; 613 614 if (nv30->base.vbo_dirty) { 615 BEGIN_NV04(push, NV30_3D(VTX_CACHE_INVALIDATE_1710), 1); 616 PUSH_DATA (push, 0); 617 nv30->base.vbo_dirty = false; 618 } 619 620 if (!info->index_size) { 621 nv30_draw_arrays(nv30, 622 info->mode, draws[0].start, draws[0].count, 623 info->instance_count); 624 } else { 625 bool shorten = info->index_bounds_valid && info->max_index <= 65535; 626 627 if (info->primitive_restart != nv30->state.prim_restart) { 628 if (info->primitive_restart) { 629 BEGIN_NV04(push, NV40_3D(PRIM_RESTART_ENABLE), 2); 630 PUSH_DATA (push, 1); 631 PUSH_DATA (push, info->restart_index); 632 633 if (info->restart_index > 65535) 634 shorten = false; 635 } else { 636 BEGIN_NV04(push, NV40_3D(PRIM_RESTART_ENABLE), 1); 637 PUSH_DATA (push, 0); 638 } 639 nv30->state.prim_restart = info->primitive_restart; 640 } else 641 if (info->primitive_restart) { 642 BEGIN_NV04(push, NV40_3D(PRIM_RESTART_INDEX), 1); 643 PUSH_DATA (push, info->restart_index); 644 645 if (info->restart_index > 65535) 646 shorten = false; 647 } 648 649 nv30_draw_elements(nv30, shorten, info, 650 info->mode, draws[0].start, draws[0].count, 651 info->instance_count, draws[0].index_bias, info->index_size); 652 } 653 654 nv30_state_release(nv30); 655 nv30_release_user_vbufs(nv30); 656} 657 658void 659nv30_vbo_init(struct pipe_context *pipe) 660{ 661 pipe->create_vertex_elements_state = nv30_vertex_state_create; 662 pipe->delete_vertex_elements_state = nv30_vertex_state_delete; 663 pipe->bind_vertex_elements_state = nv30_vertex_state_bind; 664 pipe->draw_vbo = nv30_draw_vbo; 665} 666