1 2 #include "pipe/p_context.h" 3 #include "pipe/p_state.h" 4 #include "util/u_inlines.h" 5 #include "util/u_format.h" 6 #include "translate/translate.h" 7 8 #include "nvc0_context.h" 9 #include "nvc0_resource.h" 10 11 #include "nvc0_3d.xml.h" 12 13 struct push_context { 14 struct nouveau_pushbuf *push; 15 16 struct translate *translate; 17 void *dest; 18 const void *idxbuf; 19 20 uint32_t vertex_size; 21 uint32_t restart_index; 22 uint32_t instance_id; 23 24 boolean prim_restart; 25 boolean need_vertex_id; 26 27 struct { 28 boolean enabled; 29 boolean value; 30 unsigned stride; 31 const uint8_t *data; 32 } edgeflag; 33 }; 34 35 static void nvc0_push_upload_vertex_ids(struct push_context *, 36 struct nvc0_context *, 37 const struct pipe_draw_info *); 38 39 static void 40 nvc0_push_context_init(struct nvc0_context *nvc0, struct push_context *ctx) 41 { 42 ctx->push = nvc0->base.pushbuf; 43 44 ctx->translate = nvc0->vertex->translate; 45 ctx->vertex_size = nvc0->vertex->size; 46 47 ctx->need_vertex_id = 48 nvc0->vertprog->vp.need_vertex_id && (nvc0->vertex->num_elements < 32); 49 50 ctx->edgeflag.value = TRUE; 51 ctx->edgeflag.enabled = nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS; 52 53 /* silence warnings */ 54 ctx->edgeflag.data = NULL; 55 ctx->edgeflag.stride = 0; 56 } 57 58 static INLINE void 59 nvc0_vertex_configure_translate(struct nvc0_context *nvc0, int32_t index_bias) 60 { 61 struct translate *translate = nvc0->vertex->translate; 62 unsigned i; 63 64 for (i = 0; i < nvc0->num_vtxbufs; ++i) { 65 const uint8_t *map; 66 const struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i]; 67 68 if (likely(!vb->buffer)) 69 map = (const uint8_t *)vb->user_buffer; 70 else 71 map = nouveau_resource_map_offset(&nvc0->base, 72 nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD); 73 74 if (index_bias && !unlikely(nvc0->vertex->instance_bufs & (1 << i))) 75 map += (intptr_t)index_bias * vb->stride; 76 77 translate->set_buffer(translate, i, map, vb->stride, ~0); 78 } 79 } 80 81 static INLINE void 82 nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0) 83 { 84 if (nvc0->idxbuf.buffer) { 85 struct nv04_resource *buf = nv04_resource(nvc0->idxbuf.buffer); 86 ctx->idxbuf = nouveau_resource_map_offset(&nvc0->base, 87 buf, nvc0->idxbuf.offset, NOUVEAU_BO_RD); 88 } else { 89 ctx->idxbuf = nvc0->idxbuf.user_buffer; 90 } 91 } 92 93 static INLINE void 94 nvc0_push_map_edgeflag(struct push_context *ctx, struct nvc0_context *nvc0, 95 int32_t index_bias) 96 { 97 unsigned attr = nvc0->vertprog->vp.edgeflag; 98 struct pipe_vertex_element *ve = &nvc0->vertex->element[attr].pipe; 99 struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index]; 100 struct nv04_resource *buf = nv04_resource(vb->buffer); 101 unsigned offset = vb->buffer_offset + ve->src_offset; 102 103 ctx->edgeflag.stride = vb->stride; 104 ctx->edgeflag.data = nouveau_resource_map_offset(&nvc0->base, 105 buf, offset, NOUVEAU_BO_RD); 106 if (index_bias) 107 ctx->edgeflag.data += (intptr_t)index_bias * vb->stride; 108 } 109 110 static INLINE unsigned 111 prim_restart_search_i08(const uint8_t *elts, unsigned push, uint8_t index) 112 { 113 unsigned i; 114 for (i = 0; i < push && elts[i] != index; ++i); 115 return i; 116 } 117 118 static INLINE unsigned 119 prim_restart_search_i16(const uint16_t *elts, unsigned push, uint16_t index) 120 { 121 unsigned i; 122 for (i = 0; i < push && elts[i] != index; ++i); 123 return i; 124 } 125 126 static INLINE unsigned 127 prim_restart_search_i32(const uint32_t *elts, unsigned push, uint32_t index) 128 { 129 unsigned i; 130 for (i = 0; i < push && elts[i] != index; ++i); 131 return i; 132 } 133 134 static INLINE boolean 135 ef_value(const struct push_context *ctx, uint32_t index) 136 { 137 float *pf = (float *)&ctx->edgeflag.data[index * ctx->edgeflag.stride]; 138 return *pf ? TRUE : FALSE; 139 } 140 141 static INLINE boolean 142 ef_toggle(struct push_context *ctx) 143 { 144 ctx->edgeflag.value = !ctx->edgeflag.value; 145 return ctx->edgeflag.value; 146 } 147 148 static INLINE unsigned 149 ef_toggle_search_i08(struct push_context *ctx, const uint8_t *elts, unsigned n) 150 { 151 unsigned i; 152 for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i); 153 return i; 154 } 155 156 static INLINE unsigned 157 ef_toggle_search_i16(struct push_context *ctx, const uint16_t *elts, unsigned n) 158 { 159 unsigned i; 160 for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i); 161 return i; 162 } 163 164 static INLINE unsigned 165 ef_toggle_search_i32(struct push_context *ctx, const uint32_t *elts, unsigned n) 166 { 167 unsigned i; 168 for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i); 169 return i; 170 } 171 172 static INLINE unsigned 173 ef_toggle_search_seq(struct push_context *ctx, unsigned start, unsigned n) 174 { 175 unsigned i; 176 for (i = 0; i < n && ef_value(ctx, start++) == ctx->edgeflag.value; ++i); 177 return i; 178 } 179 180 static INLINE void * 181 nvc0_push_setup_vertex_array(struct nvc0_context *nvc0, const unsigned count) 182 { 183 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 184 struct nouveau_bo *bo; 185 uint64_t va; 186 const unsigned size = count * nvc0->vertex->size; 187 188 void *const dest = nouveau_scratch_get(&nvc0->base, size, &va, &bo); 189 190 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_START_HIGH(0)), 2); 191 PUSH_DATAh(push, va); 192 PUSH_DATA (push, va); 193 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(0)), 2); 194 PUSH_DATAh(push, va + size - 1); 195 PUSH_DATA (push, va + size - 1); 196 197 BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD, 198 bo); 199 nouveau_pushbuf_validate(push); 200 201 return dest; 202 } 203 204 static void 205 disp_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) 206 { 207 struct nouveau_pushbuf *push = ctx->push; 208 struct translate *translate = ctx->translate; 209 const uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start; 210 unsigned pos = 0; 211 212 do { 213 unsigned nR = count; 214 215 if (unlikely(ctx->prim_restart)) 216 nR = prim_restart_search_i08(elts, nR, ctx->restart_index); 217 218 translate->run_elts8(translate, elts, nR, ctx->instance_id, ctx->dest); 219 count -= nR; 220 ctx->dest += nR * ctx->vertex_size; 221 222 while (nR) { 223 unsigned nE = nR; 224 225 if (unlikely(ctx->edgeflag.enabled)) 226 nE = ef_toggle_search_i08(ctx, elts, nR); 227 228 PUSH_SPACE(push, 4); 229 if (likely(nE >= 2)) { 230 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2); 231 PUSH_DATA (push, pos); 232 PUSH_DATA (push, nE); 233 } else 234 if (nE) { 235 if (pos <= 0xff) { 236 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos); 237 } else { 238 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 239 PUSH_DATA (push, pos); 240 } 241 } 242 if (unlikely(nE != nR)) 243 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx)); 244 245 pos += nE; 246 elts += nE; 247 nR -= nE; 248 } 249 if (count) { 250 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 251 PUSH_DATA (push, ctx->restart_index); 252 ++elts; 253 ctx->dest += ctx->vertex_size; 254 ++pos; 255 --count; 256 } 257 } while (count); 258 } 259 260 static void 261 disp_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) 262 { 263 struct nouveau_pushbuf *push = ctx->push; 264 struct translate *translate = ctx->translate; 265 const uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start; 266 unsigned pos = 0; 267 268 do { 269 unsigned nR = count; 270 271 if (unlikely(ctx->prim_restart)) 272 nR = prim_restart_search_i16(elts, nR, ctx->restart_index); 273 274 translate->run_elts16(translate, elts, nR, ctx->instance_id, ctx->dest); 275 count -= nR; 276 ctx->dest += nR * ctx->vertex_size; 277 278 while (nR) { 279 unsigned nE = nR; 280 281 if (unlikely(ctx->edgeflag.enabled)) 282 nE = ef_toggle_search_i16(ctx, elts, nR); 283 284 PUSH_SPACE(push, 4); 285 if (likely(nE >= 2)) { 286 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2); 287 PUSH_DATA (push, pos); 288 PUSH_DATA (push, nE); 289 } else 290 if (nE) { 291 if (pos <= 0xff) { 292 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos); 293 } else { 294 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 295 PUSH_DATA (push, pos); 296 } 297 } 298 if (unlikely(nE != nR)) 299 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx)); 300 301 pos += nE; 302 elts += nE; 303 nR -= nE; 304 } 305 if (count) { 306 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 307 PUSH_DATA (push, ctx->restart_index); 308 ++elts; 309 ctx->dest += ctx->vertex_size; 310 ++pos; 311 --count; 312 } 313 } while (count); 314 } 315 316 static void 317 disp_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) 318 { 319 struct nouveau_pushbuf *push = ctx->push; 320 struct translate *translate = ctx->translate; 321 const uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start; 322 unsigned pos = 0; 323 324 do { 325 unsigned nR = count; 326 327 if (unlikely(ctx->prim_restart)) 328 nR = prim_restart_search_i32(elts, nR, ctx->restart_index); 329 330 translate->run_elts(translate, elts, nR, ctx->instance_id, ctx->dest); 331 count -= nR; 332 ctx->dest += nR * ctx->vertex_size; 333 334 while (nR) { 335 unsigned nE = nR; 336 337 if (unlikely(ctx->edgeflag.enabled)) 338 nE = ef_toggle_search_i32(ctx, elts, nR); 339 340 PUSH_SPACE(push, 4); 341 if (likely(nE >= 2)) { 342 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2); 343 PUSH_DATA (push, pos); 344 PUSH_DATA (push, nE); 345 } else 346 if (nE) { 347 if (pos <= 0xff) { 348 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos); 349 } else { 350 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 351 PUSH_DATA (push, pos); 352 } 353 } 354 if (unlikely(nE != nR)) 355 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx)); 356 357 pos += nE; 358 elts += nE; 359 nR -= nE; 360 } 361 if (count) { 362 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1); 363 PUSH_DATA (push, ctx->restart_index); 364 ++elts; 365 ctx->dest += ctx->vertex_size; 366 ++pos; 367 --count; 368 } 369 } while (count); 370 } 371 372 static void 373 disp_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) 374 { 375 struct nouveau_pushbuf *push = ctx->push; 376 struct translate *translate = ctx->translate; 377 unsigned pos = 0; 378 379 translate->run(translate, start, count, ctx->instance_id, ctx->dest); 380 do { 381 unsigned nr = count; 382 383 if (unlikely(ctx->edgeflag.enabled)) 384 nr = ef_toggle_search_seq(ctx, start + pos, nr); 385 386 PUSH_SPACE(push, 4); 387 if (likely(nr)) { 388 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2); 389 PUSH_DATA (push, pos); 390 PUSH_DATA (push, nr); 391 } 392 if (unlikely(nr != count)) 393 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx)); 394 395 pos += nr; 396 count -= nr; 397 } while (count); 398 } 399 400 401 #define NVC0_PRIM_GL_CASE(n) \ 402 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n 403 404 static INLINE unsigned 405 nvc0_prim_gl(unsigned prim) 406 { 407 switch (prim) { 408 NVC0_PRIM_GL_CASE(POINTS); 409 NVC0_PRIM_GL_CASE(LINES); 410 NVC0_PRIM_GL_CASE(LINE_LOOP); 411 NVC0_PRIM_GL_CASE(LINE_STRIP); 412 NVC0_PRIM_GL_CASE(TRIANGLES); 413 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP); 414 NVC0_PRIM_GL_CASE(TRIANGLE_FAN); 415 NVC0_PRIM_GL_CASE(QUADS); 416 NVC0_PRIM_GL_CASE(QUAD_STRIP); 417 NVC0_PRIM_GL_CASE(POLYGON); 418 NVC0_PRIM_GL_CASE(LINES_ADJACENCY); 419 NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY); 420 NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY); 421 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY); 422 /* 423 NVC0_PRIM_GL_CASE(PATCHES); */ 424 default: 425 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS; 426 } 427 } 428 429 void 430 nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info) 431 { 432 struct push_context ctx; 433 unsigned i, index_size; 434 unsigned inst_count = info->instance_count; 435 unsigned vert_count = info->count; 436 unsigned prim; 437 438 nvc0_push_context_init(nvc0, &ctx); 439 440 nvc0_vertex_configure_translate(nvc0, info->index_bias); 441 442 if (unlikely(ctx.edgeflag.enabled)) 443 nvc0_push_map_edgeflag(&ctx, nvc0, info->index_bias); 444 445 ctx.prim_restart = info->primitive_restart; 446 ctx.restart_index = info->restart_index; 447 448 if (info->indexed) { 449 nvc0_push_map_idxbuf(&ctx, nvc0); 450 index_size = nvc0->idxbuf.index_size; 451 452 if (info->primitive_restart) { 453 BEGIN_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 2); 454 PUSH_DATA (ctx.push, 1); 455 PUSH_DATA (ctx.push, info->restart_index); 456 } else 457 if (nvc0->state.prim_restart) { 458 IMMED_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 0); 459 } 460 nvc0->state.prim_restart = info->primitive_restart; 461 } else { 462 if (unlikely(info->count_from_stream_output)) { 463 struct pipe_context *pipe = &nvc0->base.pipe; 464 struct nvc0_so_target *targ; 465 targ = nvc0_so_target(info->count_from_stream_output); 466 pipe->get_query_result(pipe, targ->pq, TRUE, (void *)&vert_count); 467 vert_count /= targ->stride; 468 } 469 ctx.idxbuf = NULL; /* shut up warnings */ 470 index_size = 0; 471 } 472 473 ctx.instance_id = info->start_instance; 474 475 prim = nvc0_prim_gl(info->mode); 476 do { 477 PUSH_SPACE(ctx.push, 9); 478 479 ctx.dest = nvc0_push_setup_vertex_array(nvc0, vert_count); 480 if (unlikely(!ctx.dest)) 481 break; 482 483 if (unlikely(ctx.need_vertex_id)) 484 nvc0_push_upload_vertex_ids(&ctx, nvc0, info); 485 486 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0); 487 BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_BEGIN_GL), 1); 488 PUSH_DATA (ctx.push, prim); 489 switch (index_size) { 490 case 1: 491 disp_vertices_i08(&ctx, info->start, vert_count); 492 break; 493 case 2: 494 disp_vertices_i16(&ctx, info->start, vert_count); 495 break; 496 case 4: 497 disp_vertices_i32(&ctx, info->start, vert_count); 498 break; 499 default: 500 assert(index_size == 0); 501 disp_vertices_seq(&ctx, info->start, vert_count); 502 break; 503 } 504 PUSH_SPACE(ctx.push, 1); 505 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_END_GL), 0); 506 507 if (--inst_count) { 508 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 509 ++ctx.instance_id; 510 } 511 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX_TMP); 512 nouveau_scratch_done(&nvc0->base); 513 } while (inst_count); 514 515 516 /* reset state and unmap buffers (no-op) */ 517 518 if (unlikely(!ctx.edgeflag.value)) { 519 PUSH_SPACE(ctx.push, 1); 520 IMMED_NVC0(ctx.push, NVC0_3D(EDGEFLAG), 1); 521 } 522 523 if (unlikely(ctx.need_vertex_id)) { 524 PUSH_SPACE(ctx.push, 4); 525 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 0); 526 BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(1)), 1); 527 PUSH_DATA (ctx.push, 528 NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST | 529 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT | 530 NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32); 531 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 0); 532 } 533 534 if (info->indexed) 535 nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer)); 536 for (i = 0; i < nvc0->num_vtxbufs; ++i) 537 nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer)); 538 } 539 540 static INLINE void 541 copy_indices_u8(uint32_t *dst, const uint8_t *elts, uint32_t bias, unsigned n) 542 { 543 unsigned i; 544 for (i = 0; i < n; ++i) 545 dst[i] = elts[i] + bias; 546 } 547 548 static INLINE void 549 copy_indices_u16(uint32_t *dst, const uint16_t *elts, uint32_t bias, unsigned n) 550 { 551 unsigned i; 552 for (i = 0; i < n; ++i) 553 dst[i] = elts[i] + bias; 554 } 555 556 static INLINE void 557 copy_indices_u32(uint32_t *dst, const uint32_t *elts, uint32_t bias, unsigned n) 558 { 559 unsigned i; 560 for (i = 0; i < n; ++i) 561 dst[i] = elts[i] + bias; 562 } 563 564 static void 565 nvc0_push_upload_vertex_ids(struct push_context *ctx, 566 struct nvc0_context *nvc0, 567 const struct pipe_draw_info *info) 568 569 { 570 struct nouveau_pushbuf *push = ctx->push; 571 struct nouveau_bo *bo; 572 uint64_t va; 573 uint32_t *data; 574 uint32_t format; 575 unsigned index_size = nvc0->idxbuf.index_size; 576 unsigned i; 577 unsigned a = nvc0->vertex->num_elements; 578 579 if (!index_size || info->index_bias) 580 index_size = 4; 581 data = (uint32_t *)nouveau_scratch_get(&nvc0->base, 582 info->count * index_size, &va, &bo); 583 584 BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD, 585 bo); 586 nouveau_pushbuf_validate(push); 587 588 if (info->indexed) { 589 if (!info->index_bias) { 590 memcpy(data, ctx->idxbuf, info->count * index_size); 591 } else { 592 switch (nvc0->idxbuf.index_size) { 593 case 1: 594 copy_indices_u8(data, ctx->idxbuf, info->index_bias, info->count); 595 break; 596 case 2: 597 copy_indices_u16(data, ctx->idxbuf, info->index_bias, info->count); 598 break; 599 default: 600 copy_indices_u32(data, ctx->idxbuf, info->index_bias, info->count); 601 break; 602 } 603 } 604 } else { 605 for (i = 0; i < info->count; ++i) 606 data[i] = i + (info->start + info->index_bias); 607 } 608 609 format = (1 << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT) | 610 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_UINT; 611 612 switch (index_size) { 613 case 1: 614 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_8; 615 break; 616 case 2: 617 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_16; 618 break; 619 default: 620 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32; 621 break; 622 } 623 624 PUSH_SPACE(push, 12); 625 626 if (unlikely(nvc0->state.instance_elts & 2)) { 627 nvc0->state.instance_elts &= ~2; 628 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(1)), 0); 629 } 630 631 BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1); 632 PUSH_DATA (push, format); 633 634 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 3); 635 PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | index_size); 636 PUSH_DATAh(push, va); 637 PUSH_DATA (push, va); 638 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(1)), 2); 639 PUSH_DATAh(push, va + info->count * index_size - 1); 640 PUSH_DATA (push, va + info->count * index_size - 1); 641 642 #define NVC0_3D_VERTEX_ID_REPLACE_SOURCE_ATTR_X(a) \ 643 (((0x80 + (a) * 0x10) / 4) << NVC0_3D_VERTEX_ID_REPLACE_SOURCE__SHIFT) 644 645 BEGIN_NVC0(push, NVC0_3D(VERTEX_ID_REPLACE), 1); 646 PUSH_DATA (push, NVC0_3D_VERTEX_ID_REPLACE_SOURCE_ATTR_X(a) | 1); 647 } 648