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