nv50_vbo.c revision 2206a7f5132905bb1b53d8343d11847010f6b63a
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 so = MALLOC(sizeof(*so) + 55 num_elements * sizeof(struct nv50_vertex_element)); 56 if (!so) 57 return NULL; 58 so->num_elements = num_elements; 59 so->instance_elts = 0; 60 so->instance_bufs = 0; 61 so->need_conversion = FALSE; 62 63 transkey.nr_elements = 0; 64 transkey.output_stride = 0; 65 66 for (i = 0; i < num_elements; ++i) { 67 const struct pipe_vertex_element *ve = &elements[i]; 68 const unsigned vbi = ve->vertex_buffer_index; 69 enum pipe_format fmt = ve->src_format; 70 71 so->element[i].pipe = elements[i]; 72 so->element[i].state = nv50_format_table[fmt].vtx; 73 74 if (!so->element[i].state) { 75 switch (util_format_get_nr_components(fmt)) { 76 case 1: fmt = PIPE_FORMAT_R32_FLOAT; break; 77 case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break; 78 case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break; 79 case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break; 80 default: 81 assert(0); 82 return NULL; 83 } 84 so->element[i].state = nv50_format_table[fmt].vtx; 85 so->need_conversion = TRUE; 86 } 87 so->element[i].state |= i; 88 89 if (1) { 90 unsigned j = transkey.nr_elements++; 91 92 transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL; 93 transkey.element[j].input_format = ve->src_format; 94 transkey.element[j].input_buffer = vbi; 95 transkey.element[j].input_offset = ve->src_offset; 96 transkey.element[j].instance_divisor = ve->instance_divisor; 97 98 transkey.element[j].output_format = fmt; 99 transkey.element[j].output_offset = transkey.output_stride; 100 transkey.output_stride += (util_format_get_stride(fmt, 1) + 3) & ~3; 101 102 if (unlikely(ve->instance_divisor)) { 103 so->instance_elts |= 1 << i; 104 so->instance_bufs |= 1 << vbi; 105 } 106 } 107 } 108 109 so->translate = translate_create(&transkey); 110 so->vertex_size = transkey.output_stride / 4; 111 so->packet_vertex_limit = NV04_PFIFO_MAX_PACKET_LEN / 112 MAX2(so->vertex_size, 1); 113 114 return so; 115} 116 117#define NV50_3D_VERTEX_ATTRIB_INACTIVE \ 118 NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT | \ 119 NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 | \ 120 NV50_3D_VERTEX_ARRAY_ATTRIB_CONST 121 122static void 123nv50_emit_vtxattr(struct nv50_context *nv50, struct pipe_vertex_buffer *vb, 124 struct pipe_vertex_element *ve, unsigned attr) 125{ 126 const void *data; 127 struct nouveau_pushbuf *push = nv50->base.pushbuf; 128 struct nv04_resource *res = nv04_resource(vb->buffer); 129 float v[4]; 130 const unsigned nc = util_format_get_nr_components(ve->src_format); 131 132 data = nouveau_resource_map_offset(&nv50->base, res, vb->buffer_offset + 133 ve->src_offset, NOUVEAU_BO_RD); 134 135 util_format_read_4f(ve->src_format, v, 0, data, 0, 0, 0, 1, 1); 136 137 switch (nc) { 138 case 4: 139 BEGIN_NV04(push, NV50_3D(VTX_ATTR_4F_X(attr)), 4); 140 PUSH_DATAf(push, v[0]); 141 PUSH_DATAf(push, v[1]); 142 PUSH_DATAf(push, v[2]); 143 PUSH_DATAf(push, v[3]); 144 break; 145 case 3: 146 BEGIN_NV04(push, NV50_3D(VTX_ATTR_3F_X(attr)), 3); 147 PUSH_DATAf(push, v[0]); 148 PUSH_DATAf(push, v[1]); 149 PUSH_DATAf(push, v[2]); 150 break; 151 case 2: 152 BEGIN_NV04(push, NV50_3D(VTX_ATTR_2F_X(attr)), 2); 153 PUSH_DATAf(push, v[0]); 154 PUSH_DATAf(push, v[1]); 155 break; 156 case 1: 157 if (attr == nv50->vertprog->vp.edgeflag) { 158 BEGIN_NV04(push, NV50_3D(EDGEFLAG), 1); 159 PUSH_DATA (push, v[0] ? 1 : 0); 160 } 161 BEGIN_NV04(push, NV50_3D(VTX_ATTR_1F(attr)), 1); 162 PUSH_DATAf(push, v[0]); 163 break; 164 default: 165 assert(0); 166 break; 167 } 168} 169 170static INLINE void 171nv50_vbuf_range(struct nv50_context *nv50, int vbi, 172 uint32_t *base, uint32_t *size) 173{ 174 if (unlikely(nv50->vertex->instance_bufs & (1 << vbi))) { 175 /* TODO: use min and max instance divisor to get a proper range */ 176 *base = 0; 177 *size = nv50->vtxbuf[vbi].buffer->width0; 178 } else { 179 assert(nv50->vbo_max_index != ~0); 180 *base = nv50->vbo_min_index * nv50->vtxbuf[vbi].stride; 181 *size = (nv50->vbo_max_index - 182 nv50->vbo_min_index + 1) * nv50->vtxbuf[vbi].stride; 183 } 184} 185 186static void 187nv50_prevalidate_vbufs(struct nv50_context *nv50) 188{ 189 const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART; 190 struct nouveau_bo *bo; 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 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_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 if (nouveau_resource_mapped_by_gpu(vb->buffer)) { 207 BCTX_REFN(nv50->bufctx_3d, VERTEX, buf, RD); 208 } else { 209 if (nv50->vbo_push_hint) { 210 nv50->vbo_fifo = ~0; 211 return; 212 } 213 nv50->base.vbo_dirty = TRUE; 214 215 if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) { 216 assert(vb->stride > vb->buffer_offset); 217 nv50->vbo_user |= 1 << i; 218 nv50_vbuf_range(nv50, i, &base, &size); 219 bo = nouveau_scratch_data(&nv50->base, buf, base, size); 220 if (bo) 221 BCTX_REFN_bo(nv50->bufctx_3d, VERTEX_TMP, bo_flags, bo); 222 } else { 223 if (nouveau_buffer_migrate(&nv50->base, buf, NOUVEAU_BO_GART)) 224 BCTX_REFN(nv50->bufctx_3d, VERTEX, buf, RD); 225 } 226 } 227 } 228} 229 230static void 231nv50_update_user_vbufs(struct nv50_context *nv50) 232{ 233 const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART; 234 struct nouveau_bo *bo; 235 struct nouveau_pushbuf *push = nv50->base.pushbuf; 236 uint32_t base, offset, size; 237 int i; 238 uint32_t written = 0; 239 240 for (i = 0; i < nv50->vertex->num_elements; ++i) { 241 struct pipe_vertex_element *ve = &nv50->vertex->element[i].pipe; 242 const int b = ve->vertex_buffer_index; 243 struct pipe_vertex_buffer *vb = &nv50->vtxbuf[b]; 244 struct nv04_resource *buf = nv04_resource(vb->buffer); 245 246 if (!(nv50->vbo_user & (1 << b))) 247 continue; 248 249 if (!vb->stride) { 250 nv50_emit_vtxattr(nv50, vb, ve, i); 251 continue; 252 } 253 nv50_vbuf_range(nv50, b, &base, &size); 254 255 if (!(written & (1 << b))) { 256 written |= 1 << b; 257 bo = nouveau_scratch_data(&nv50->base, buf, base, size); 258 if (bo) 259 BCTX_REFN_bo(nv50->bufctx_3d, VERTEX_TMP, bo_flags, bo); 260 } 261 offset = vb->buffer_offset + ve->src_offset; 262 263 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2); 264 PUSH_DATAh(push, buf->address + base + size - 1); 265 PUSH_DATA (push, buf->address + base + size - 1); 266 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_START_HIGH(i)), 2); 267 PUSH_DATAh(push, buf->address + offset); 268 PUSH_DATA (push, buf->address + offset); 269 } 270 nv50->base.vbo_dirty = TRUE; 271} 272 273static INLINE void 274nv50_release_user_vbufs(struct nv50_context *nv50) 275{ 276 if (nv50->vbo_user) { 277 nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_VERTEX_TMP); 278 nouveau_scratch_done(&nv50->base); 279 } 280} 281 282void 283nv50_vertex_arrays_validate(struct nv50_context *nv50) 284{ 285 struct nouveau_pushbuf *push = nv50->base.pushbuf; 286 struct nv50_vertex_stateobj *vertex = nv50->vertex; 287 struct pipe_vertex_buffer *vb; 288 struct nv50_vertex_element *ve; 289 unsigned i; 290 291 if (unlikely(vertex->need_conversion)) { 292 nv50->vbo_fifo = ~0; 293 nv50->vbo_user = 0; 294 } else { 295 nv50_prevalidate_vbufs(nv50); 296 } 297 298 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_ATTRIB(0)), vertex->num_elements); 299 for (i = 0; i < vertex->num_elements; ++i) { 300 ve = &vertex->element[i]; 301 vb = &nv50->vtxbuf[ve->pipe.vertex_buffer_index]; 302 303 if (likely(vb->stride) || nv50->vbo_fifo) { 304 PUSH_DATA(push, ve->state); 305 } else { 306 PUSH_DATA(push, ve->state | NV50_3D_VERTEX_ARRAY_ATTRIB_CONST); 307 nv50->vbo_fifo &= ~(1 << i); 308 } 309 } 310 311 for (i = 0; i < vertex->num_elements; ++i) { 312 struct nv04_resource *res; 313 unsigned size, offset; 314 315 ve = &vertex->element[i]; 316 vb = &nv50->vtxbuf[ve->pipe.vertex_buffer_index]; 317 318 if (unlikely(ve->pipe.instance_divisor)) { 319 if (!(nv50->state.instance_elts & (1 << i))) { 320 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1); 321 PUSH_DATA (push, 1); 322 } 323 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_DIVISOR(i)), 1); 324 PUSH_DATA (push, ve->pipe.instance_divisor); 325 } else 326 if (unlikely(nv50->state.instance_elts & (1 << i))) { 327 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1); 328 PUSH_DATA (push, 0); 329 } 330 331 res = nv04_resource(vb->buffer); 332 333 if (nv50->vbo_fifo || unlikely(vb->stride == 0)) { 334 if (!nv50->vbo_fifo) 335 nv50_emit_vtxattr(nv50, vb, &ve->pipe, i); 336 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 1); 337 PUSH_DATA (push, 0); 338 continue; 339 } 340 341 size = vb->buffer->width0; 342 offset = ve->pipe.src_offset + vb->buffer_offset; 343 344 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 1); 345 PUSH_DATA (push, NV50_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride); 346 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2); 347 PUSH_DATAh(push, res->address + size - 1); 348 PUSH_DATA (push, res->address + size - 1); 349 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_START_HIGH(i)), 2); 350 PUSH_DATAh(push, res->address + offset); 351 PUSH_DATA (push, res->address + offset); 352 } 353 for (; i < nv50->state.num_vtxelts; ++i) { 354 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_ATTRIB(i)), 1); 355 PUSH_DATA (push, NV50_3D_VERTEX_ATTRIB_INACTIVE); 356 if (unlikely(nv50->state.instance_elts & (1 << i))) { 357 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1); 358 PUSH_DATA (push, 0); 359 } 360 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FETCH(i)), 1); 361 PUSH_DATA (push, 0); 362 } 363 364 nv50->state.num_vtxelts = vertex->num_elements; 365 nv50->state.instance_elts = vertex->instance_elts; 366} 367 368#define NV50_PRIM_GL_CASE(n) \ 369 case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n 370 371static INLINE unsigned 372nv50_prim_gl(unsigned prim) 373{ 374 switch (prim) { 375 NV50_PRIM_GL_CASE(POINTS); 376 NV50_PRIM_GL_CASE(LINES); 377 NV50_PRIM_GL_CASE(LINE_LOOP); 378 NV50_PRIM_GL_CASE(LINE_STRIP); 379 NV50_PRIM_GL_CASE(TRIANGLES); 380 NV50_PRIM_GL_CASE(TRIANGLE_STRIP); 381 NV50_PRIM_GL_CASE(TRIANGLE_FAN); 382 NV50_PRIM_GL_CASE(QUADS); 383 NV50_PRIM_GL_CASE(QUAD_STRIP); 384 NV50_PRIM_GL_CASE(POLYGON); 385 NV50_PRIM_GL_CASE(LINES_ADJACENCY); 386 NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY); 387 NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY); 388 NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY); 389 default: 390 return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS; 391 break; 392 } 393} 394 395static void 396nv50_draw_arrays(struct nv50_context *nv50, 397 unsigned mode, unsigned start, unsigned count, 398 unsigned instance_count) 399{ 400 struct nouveau_pushbuf *push = nv50->base.pushbuf; 401 unsigned prim; 402 403 if (nv50->state.index_bias) { 404 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_BASE), 1); 405 PUSH_DATA (push, 0); 406 nv50->state.index_bias = 0; 407 } 408 409 prim = nv50_prim_gl(mode); 410 411 while (instance_count--) { 412 BEGIN_NV04(push, NV50_3D(VERTEX_BEGIN_GL), 1); 413 PUSH_DATA (push, prim); 414 BEGIN_NV04(push, NV50_3D(VERTEX_BUFFER_FIRST), 2); 415 PUSH_DATA (push, start); 416 PUSH_DATA (push, count); 417 BEGIN_NV04(push, NV50_3D(VERTEX_END_GL), 1); 418 PUSH_DATA (push, 0); 419 420 prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 421 } 422} 423 424static void 425nv50_draw_elements_inline_u08(struct nouveau_pushbuf *push, uint8_t *map, 426 unsigned start, unsigned count) 427{ 428 map += start; 429 430 if (count & 3) { 431 unsigned i; 432 BEGIN_NI04(push, NV50_3D(VB_ELEMENT_U32), count & 3); 433 for (i = 0; i < (count & 3); ++i) 434 PUSH_DATA(push, *map++); 435 count &= ~3; 436 } 437 while (count) { 438 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4; 439 440 BEGIN_NI04(push, NV50_3D(VB_ELEMENT_U8), nr); 441 for (i = 0; i < nr; ++i) { 442 PUSH_DATA(push, 443 (map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]); 444 map += 4; 445 } 446 count -= nr * 4; 447 } 448} 449 450static void 451nv50_draw_elements_inline_u16(struct nouveau_pushbuf *push, uint16_t *map, 452 unsigned start, unsigned count) 453{ 454 map += start; 455 456 if (count & 1) { 457 count &= ~1; 458 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U32), 1); 459 PUSH_DATA (push, *map++); 460 } 461 while (count) { 462 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2; 463 464 BEGIN_NI04(push, NV50_3D(VB_ELEMENT_U16), nr); 465 for (i = 0; i < nr; ++i) { 466 PUSH_DATA(push, (map[1] << 16) | map[0]); 467 map += 2; 468 } 469 count -= nr * 2; 470 } 471} 472 473static void 474nv50_draw_elements_inline_u32(struct nouveau_pushbuf *push, uint32_t *map, 475 unsigned start, unsigned count) 476{ 477 map += start; 478 479 while (count) { 480 const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 481 482 BEGIN_NI04(push, NV50_3D(VB_ELEMENT_U32), nr); 483 PUSH_DATAp(push, map, nr); 484 485 map += nr; 486 count -= nr; 487 } 488} 489 490static void 491nv50_draw_elements_inline_u32_short(struct nouveau_pushbuf *push, uint32_t *map, 492 unsigned start, unsigned count) 493{ 494 map += start; 495 496 if (count & 1) { 497 count--; 498 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U32), 1); 499 PUSH_DATA (push, *map++); 500 } 501 while (count) { 502 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2; 503 504 BEGIN_NI04(push, NV50_3D(VB_ELEMENT_U16), nr); 505 for (i = 0; i < nr; ++i) { 506 PUSH_DATA(push, (map[1] << 16) | map[0]); 507 map += 2; 508 } 509 count -= nr * 2; 510 } 511} 512 513static void 514nv50_draw_elements(struct nv50_context *nv50, boolean shorten, 515 unsigned mode, unsigned start, unsigned count, 516 unsigned instance_count, int32_t index_bias) 517{ 518 struct nouveau_pushbuf *push = nv50->base.pushbuf; 519 void *data; 520 struct nv04_resource *buf = nv04_resource(nv50->idxbuf.buffer); 521 unsigned prim; 522 const unsigned index_size = nv50->idxbuf.index_size; 523 524 prim = nv50_prim_gl(mode); 525 526 if (index_bias != nv50->state.index_bias) { 527 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_BASE), 1); 528 PUSH_DATA (push, index_bias); 529 nv50->state.index_bias = index_bias; 530 } 531 532 if (nouveau_resource_mapped_by_gpu(nv50->idxbuf.buffer)) { 533 unsigned pb_start; 534 unsigned pb_bytes; 535 const unsigned base = buf->offset; 536 537 start += nv50->idxbuf.offset >> (index_size >> 1); 538 539 while (instance_count--) { 540 BEGIN_NV04(push, NV50_3D(VERTEX_BEGIN_GL), 1); 541 PUSH_DATA (push, prim); 542 543 nouveau_pushbuf_space(push, 8, 0, 1); 544 545 switch (index_size) { 546 case 4: 547 BEGIN_NL50(push, NV50_3D(VB_ELEMENT_U32), count); 548 nouveau_pushbuf_data(push, buf->bo, base + start * 4, count * 4); 549 break; 550 case 2: 551 pb_start = (start & ~1) * 2; 552 pb_bytes = ((start + count + 1) & ~1) * 2 - pb_start; 553 554 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U16_SETUP), 1); 555 PUSH_DATA (push, (start << 31) | count); 556 BEGIN_NL50(push, NV50_3D(VB_ELEMENT_U16), pb_bytes / 4); 557 nouveau_pushbuf_data(push, buf->bo, base + pb_start, pb_bytes); 558 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U16_SETUP), 1); 559 PUSH_DATA (push, 0); 560 break; 561 default: 562 assert(index_size == 1); 563 pb_start = start & ~3; 564 pb_bytes = ((start + count + 3) & ~3) - pb_start; 565 566 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U8_SETUP), 1); 567 PUSH_DATA (push, (start << 30) | count); 568 BEGIN_NL50(push, NV50_3D(VB_ELEMENT_U8), pb_bytes / 4); 569 nouveau_pushbuf_data(push, buf->bo, base + pb_start, pb_bytes); 570 BEGIN_NV04(push, NV50_3D(VB_ELEMENT_U8_SETUP), 1); 571 PUSH_DATA (push, 0); 572 break; 573 } 574 BEGIN_NV04(push, NV50_3D(VERTEX_END_GL), 1); 575 PUSH_DATA (push, 0); 576 577 prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 578 } 579 } else { 580 data = nouveau_resource_map_offset(&nv50->base, buf, 581 nv50->idxbuf.offset, NOUVEAU_BO_RD); 582 if (!data) 583 return; 584 585 while (instance_count--) { 586 BEGIN_NV04(push, NV50_3D(VERTEX_BEGIN_GL), 1); 587 PUSH_DATA (push, prim); 588 switch (index_size) { 589 case 1: 590 nv50_draw_elements_inline_u08(push, data, start, count); 591 break; 592 case 2: 593 nv50_draw_elements_inline_u16(push, data, start, count); 594 break; 595 case 4: 596 if (shorten) 597 nv50_draw_elements_inline_u32_short(push, data, start, count); 598 else 599 nv50_draw_elements_inline_u32(push, data, start, count); 600 break; 601 default: 602 assert(0); 603 return; 604 } 605 BEGIN_NV04(push, NV50_3D(VERTEX_END_GL), 1); 606 PUSH_DATA (push, 0); 607 608 prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 609 } 610 } 611} 612 613static void 614nv50_draw_vbo_kick_notify(struct nouveau_pushbuf *chan) 615{ 616 struct nv50_screen *screen = chan->user_priv; 617 618 nouveau_fence_update(&screen->base, TRUE); 619 620 nv50_bufctx_fence(screen->cur_ctx->bufctx_3d, TRUE); 621} 622 623void 624nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) 625{ 626 struct nv50_context *nv50 = nv50_context(pipe); 627 struct nouveau_pushbuf *push = nv50->base.pushbuf; 628 629 /* For picking only a few vertices from a large user buffer, push is better, 630 * if index count is larger and we expect repeated vertices, suggest upload. 631 */ 632 nv50->vbo_push_hint = /* the 64 is heuristic */ 633 !(info->indexed && 634 ((info->max_index - info->min_index + 64) < info->count)); 635 636 nv50->vbo_min_index = info->min_index; 637 nv50->vbo_max_index = info->max_index; 638 639 if (nv50->vbo_push_hint != !!nv50->vbo_fifo) 640 nv50->dirty |= NV50_NEW_ARRAYS; 641 642 if (nv50->vbo_user && !(nv50->dirty & (NV50_NEW_VERTEX | NV50_NEW_ARRAYS))) 643 nv50_update_user_vbufs(nv50); 644 645 nv50_state_validate(nv50, ~0, 8); /* 8 as minimum, we use flush_notify */ 646 647 push->kick_notify = nv50_draw_vbo_kick_notify; 648 649 if (nv50->vbo_fifo) { 650 nv50_push_vbo(nv50, info); 651 push->kick_notify = nv50_default_kick_notify; 652 nouveau_pushbuf_bufctx(push, NULL); 653 return; 654 } 655 656 if (nv50->state.instance_base != info->start_instance) { 657 nv50->state.instance_base = info->start_instance; 658 /* NOTE: this does not affect the shader input, should it ? */ 659 BEGIN_NV04(push, NV50_3D(VB_INSTANCE_BASE), 1); 660 PUSH_DATA (push, info->start_instance); 661 } 662 663 if (nv50->base.vbo_dirty) { 664 BEGIN_NV04(push, NV50_3D(VERTEX_ARRAY_FLUSH), 1); 665 PUSH_DATA (push, 0); 666 nv50->base.vbo_dirty = FALSE; 667 } 668 669 if (!info->indexed) { 670 nv50_draw_arrays(nv50, 671 info->mode, info->start, info->count, 672 info->instance_count); 673 } else { 674 boolean shorten = info->max_index <= 65535; 675 676 assert(nv50->idxbuf.buffer); 677 678 if (info->primitive_restart != nv50->state.prim_restart) { 679 if (info->primitive_restart) { 680 BEGIN_NV04(push, NV50_3D(PRIM_RESTART_ENABLE), 2); 681 PUSH_DATA (push, 1); 682 PUSH_DATA (push, info->restart_index); 683 684 if (info->restart_index > 65535) 685 shorten = FALSE; 686 } else { 687 BEGIN_NV04(push, NV50_3D(PRIM_RESTART_ENABLE), 1); 688 PUSH_DATA (push, 0); 689 } 690 nv50->state.prim_restart = info->primitive_restart; 691 } else 692 if (info->primitive_restart) { 693 BEGIN_NV04(push, NV50_3D(PRIM_RESTART_INDEX), 1); 694 PUSH_DATA (push, info->restart_index); 695 696 if (info->restart_index > 65535) 697 shorten = FALSE; 698 } 699 700 nv50_draw_elements(nv50, shorten, 701 info->mode, info->start, info->count, 702 info->instance_count, info->index_bias); 703 } 704 push->kick_notify = nv50_default_kick_notify; 705 706 nv50_release_user_vbufs(nv50); 707 708 nouveau_pushbuf_bufctx(push, NULL); 709} 710