nv50_vbo.c revision d29f55546dec74ca77dce3a3bf581c251be1d397
1/* 2 * Copyright 2008 Ben Skeggs 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 "pipe/p_inlines.h" 26 27#include "util/u_format.h" 28 29#include "nv50_context.h" 30 31static boolean 32nv50_push_elements_u08(struct nv50_context *, uint8_t *, unsigned); 33 34static boolean 35nv50_push_elements_u16(struct nv50_context *, uint16_t *, unsigned); 36 37static boolean 38nv50_push_elements_u32(struct nv50_context *, uint32_t *, unsigned); 39 40static boolean 41nv50_push_arrays(struct nv50_context *, unsigned, unsigned); 42 43static INLINE unsigned 44nv50_prim(unsigned mode) 45{ 46 switch (mode) { 47 case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS; 48 case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES; 49 case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP; 50 case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP; 51 case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES; 52 case PIPE_PRIM_TRIANGLE_STRIP: 53 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP; 54 case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN; 55 case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS; 56 case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP; 57 case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON; 58 default: 59 break; 60 } 61 62 NOUVEAU_ERR("invalid primitive type %d\n", mode); 63 return NV50TCL_VERTEX_BEGIN_POINTS; 64} 65 66static INLINE uint32_t 67nv50_vbo_type_to_hw(enum pipe_format format) 68{ 69 const struct util_format_description *desc; 70 71 desc = util_format_description(format); 72 assert(desc); 73 74 switch (desc->channel[0].type) { 75 case UTIL_FORMAT_TYPE_FLOAT: 76 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT; 77 case UTIL_FORMAT_TYPE_UNSIGNED: 78 if (desc->channel[0].normalized) { 79 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UNORM; 80 } 81 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_USCALED; 82 case UTIL_FORMAT_TYPE_SIGNED: 83 if (desc->channel[0].normalized) { 84 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SNORM; 85 } 86 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SSCALED; 87 /* 88 case PIPE_FORMAT_TYPE_UINT: 89 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UINT; 90 case PIPE_FORMAT_TYPE_SINT: 91 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SINT; */ 92 default: 93 return 0; 94 } 95} 96 97static INLINE uint32_t 98nv50_vbo_size_to_hw(unsigned size, unsigned nr_c) 99{ 100 static const uint32_t hw_values[] = { 101 0, 0, 0, 0, 102 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8, 103 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8, 104 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8_8, 105 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8_8_8, 106 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16, 107 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16, 108 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16_16, 109 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16_16_16, 110 0, 0, 0, 0, 111 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32, 112 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32, 113 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32_32, 114 NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32_32_32 }; 115 116 /* we'd also have R11G11B10 and R10G10B10A2 */ 117 118 assert(nr_c > 0 && nr_c <= 4); 119 120 if (size > 32) 121 return 0; 122 size >>= (3 - 2); 123 124 return hw_values[size + (nr_c - 1)]; 125} 126 127static INLINE uint32_t 128nv50_vbo_vtxelt_to_hw(struct pipe_vertex_element *ve) 129{ 130 uint32_t hw_type, hw_size; 131 enum pipe_format pf = ve->src_format; 132 const struct util_format_description *desc; 133 unsigned size; 134 135 desc = util_format_description(pf); 136 assert(desc); 137 138 size = util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0); 139 140 hw_type = nv50_vbo_type_to_hw(pf); 141 hw_size = nv50_vbo_size_to_hw(size, ve->nr_components); 142 143 if (!hw_type || !hw_size) { 144 NOUVEAU_ERR("unsupported vbo format: %s\n", pf_name(pf)); 145 abort(); 146 return 0x24e80000; 147 } 148 149 if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z) /* BGRA */ 150 hw_size |= (1 << 31); /* no real swizzle bits :-( */ 151 152 return (hw_type | hw_size); 153} 154 155boolean 156nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start, 157 unsigned count) 158{ 159 struct nv50_context *nv50 = nv50_context(pipe); 160 struct nouveau_channel *chan = nv50->screen->tesla->channel; 161 struct nouveau_grobj *tesla = nv50->screen->tesla; 162 boolean ret; 163 164 nv50_state_validate(nv50); 165 166 BEGIN_RING(chan, tesla, 0x142c, 1); 167 OUT_RING (chan, 0); 168 BEGIN_RING(chan, tesla, 0x142c, 1); 169 OUT_RING (chan, 0); 170 171 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); 172 OUT_RING (chan, nv50_prim(mode)); 173 174 if (nv50->vbo_fifo) 175 ret = nv50_push_arrays(nv50, start, count); 176 else { 177 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2); 178 OUT_RING (chan, start); 179 OUT_RING (chan, count); 180 ret = TRUE; 181 } 182 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); 183 OUT_RING (chan, 0); 184 185 return ret; 186} 187 188static INLINE boolean 189nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map, 190 unsigned start, unsigned count) 191{ 192 struct nouveau_channel *chan = nv50->screen->tesla->channel; 193 struct nouveau_grobj *tesla = nv50->screen->tesla; 194 195 map += start; 196 197 if (nv50->vbo_fifo) 198 return nv50_push_elements_u08(nv50, map, count); 199 200 if (count & 1) { 201 BEGIN_RING(chan, tesla, 0x15e8, 1); 202 OUT_RING (chan, map[0]); 203 map++; 204 count--; 205 } 206 207 while (count) { 208 unsigned nr = count > 2046 ? 2046 : count; 209 int i; 210 211 BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1); 212 for (i = 0; i < nr; i += 2) 213 OUT_RING (chan, (map[i + 1] << 16) | map[i]); 214 215 count -= nr; 216 map += nr; 217 } 218 return TRUE; 219} 220 221static INLINE boolean 222nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map, 223 unsigned start, unsigned count) 224{ 225 struct nouveau_channel *chan = nv50->screen->tesla->channel; 226 struct nouveau_grobj *tesla = nv50->screen->tesla; 227 228 map += start; 229 230 if (nv50->vbo_fifo) 231 return nv50_push_elements_u16(nv50, map, count); 232 233 if (count & 1) { 234 BEGIN_RING(chan, tesla, 0x15e8, 1); 235 OUT_RING (chan, map[0]); 236 map++; 237 count--; 238 } 239 240 while (count) { 241 unsigned nr = count > 2046 ? 2046 : count; 242 int i; 243 244 BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1); 245 for (i = 0; i < nr; i += 2) 246 OUT_RING (chan, (map[i + 1] << 16) | map[i]); 247 248 count -= nr; 249 map += nr; 250 } 251 return TRUE; 252} 253 254static INLINE boolean 255nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint32_t *map, 256 unsigned start, unsigned count) 257{ 258 struct nouveau_channel *chan = nv50->screen->tesla->channel; 259 struct nouveau_grobj *tesla = nv50->screen->tesla; 260 261 map += start; 262 263 if (nv50->vbo_fifo) 264 return nv50_push_elements_u32(nv50, map, count); 265 266 while (count) { 267 unsigned nr = count > 2047 ? 2047 : count; 268 269 BEGIN_RING(chan, tesla, 0x400015e8, nr); 270 OUT_RINGp (chan, map, nr); 271 272 count -= nr; 273 map += nr; 274 } 275 return TRUE; 276} 277 278boolean 279nv50_draw_elements(struct pipe_context *pipe, 280 struct pipe_buffer *indexBuffer, unsigned indexSize, 281 unsigned mode, unsigned start, unsigned count) 282{ 283 struct nv50_context *nv50 = nv50_context(pipe); 284 struct nouveau_channel *chan = nv50->screen->tesla->channel; 285 struct nouveau_grobj *tesla = nv50->screen->tesla; 286 struct pipe_screen *pscreen = pipe->screen; 287 void *map; 288 boolean ret; 289 290 map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ); 291 292 nv50_state_validate(nv50); 293 294 BEGIN_RING(chan, tesla, 0x142c, 1); 295 OUT_RING (chan, 0); 296 BEGIN_RING(chan, tesla, 0x142c, 1); 297 OUT_RING (chan, 0); 298 299 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); 300 OUT_RING (chan, nv50_prim(mode)); 301 switch (indexSize) { 302 case 1: 303 ret = nv50_draw_elements_inline_u08(nv50, map, start, count); 304 break; 305 case 2: 306 ret = nv50_draw_elements_inline_u16(nv50, map, start, count); 307 break; 308 case 4: 309 ret = nv50_draw_elements_inline_u32(nv50, map, start, count); 310 break; 311 default: 312 assert(0); 313 ret = FALSE; 314 break; 315 } 316 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); 317 OUT_RING (chan, 0); 318 319 pipe_buffer_unmap(pscreen, indexBuffer); 320 321 return ret; 322} 323 324static INLINE boolean 325nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib, 326 struct nouveau_stateobj **pso, 327 struct pipe_vertex_element *ve, 328 struct pipe_vertex_buffer *vb) 329 330{ 331 struct nouveau_stateobj *so; 332 struct nouveau_grobj *tesla = nv50->screen->tesla; 333 struct nouveau_bo *bo = nouveau_bo(vb->buffer); 334 float *v; 335 int ret; 336 enum pipe_format pf = ve->src_format; 337 const struct util_format_description *desc; 338 339 desc = util_format_description(pf); 340 assert(desc); 341 342 if ((desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT) || 343 util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0) != 32) 344 return FALSE; 345 346 ret = nouveau_bo_map(bo, NOUVEAU_BO_RD); 347 if (ret) 348 return FALSE; 349 v = (float *)(bo->map + (vb->buffer_offset + ve->src_offset)); 350 351 so = *pso; 352 if (!so) 353 *pso = so = so_new(nv50->vtxelt_nr * 5, 0); 354 355 switch (ve->nr_components) { 356 case 4: 357 so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4); 358 so_data (so, fui(v[0])); 359 so_data (so, fui(v[1])); 360 so_data (so, fui(v[2])); 361 so_data (so, fui(v[3])); 362 break; 363 case 3: 364 so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3); 365 so_data (so, fui(v[0])); 366 so_data (so, fui(v[1])); 367 so_data (so, fui(v[2])); 368 break; 369 case 2: 370 so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2); 371 so_data (so, fui(v[0])); 372 so_data (so, fui(v[1])); 373 break; 374 case 1: 375 if (attrib == nv50->vertprog->cfg.edgeflag_in) { 376 so_method(so, tesla, 0x15e4, 1); 377 so_data (so, v[0] ? 1 : 0); 378 } 379 so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1); 380 so_data (so, fui(v[0])); 381 break; 382 default: 383 nouveau_bo_unmap(bo); 384 return FALSE; 385 } 386 387 nouveau_bo_unmap(bo); 388 return TRUE; 389} 390 391void 392nv50_vbo_validate(struct nv50_context *nv50) 393{ 394 struct nouveau_grobj *tesla = nv50->screen->tesla; 395 struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr; 396 unsigned i, n_ve; 397 398 /* don't validate if Gallium took away our buffers */ 399 if (nv50->vtxbuf_nr == 0) 400 return; 401 nv50->vbo_fifo = 0; 402 403 for (i = 0; i < nv50->vtxbuf_nr; ++i) 404 if (nv50->vtxbuf[i].stride && 405 !(nv50->vtxbuf[i].buffer->usage & PIPE_BUFFER_USAGE_VERTEX)) 406 nv50->vbo_fifo = 0xffff; 407 408 if (nv50->vertprog->cfg.edgeflag_in < 16) 409 nv50->vbo_fifo = 0xffff; /* vertprog can't set edgeflag */ 410 411 n_ve = MAX2(nv50->vtxelt_nr, nv50->state.vtxelt_nr); 412 413 vtxattr = NULL; 414 vtxbuf = so_new(n_ve * 7, nv50->vtxelt_nr * 4); 415 vtxfmt = so_new(n_ve + 1, 0); 416 so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve); 417 418 for (i = 0; i < nv50->vtxelt_nr; i++) { 419 struct pipe_vertex_element *ve = &nv50->vtxelt[i]; 420 struct pipe_vertex_buffer *vb = 421 &nv50->vtxbuf[ve->vertex_buffer_index]; 422 struct nouveau_bo *bo = nouveau_bo(vb->buffer); 423 uint32_t hw = nv50_vbo_vtxelt_to_hw(ve); 424 425 if (!vb->stride && 426 nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) { 427 so_data(vtxfmt, hw | (1 << 4)); 428 429 so_method(vtxbuf, tesla, 430 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1); 431 so_data (vtxbuf, 0); 432 433 nv50->vbo_fifo &= ~(1 << i); 434 continue; 435 } 436 so_data(vtxfmt, hw | i); 437 438 if (nv50->vbo_fifo) { 439 so_method(vtxbuf, tesla, 440 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1); 441 so_data (vtxbuf, 0); 442 continue; 443 } 444 445 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3); 446 so_data (vtxbuf, 0x20000000 | vb->stride); 447 so_reloc (vtxbuf, bo, vb->buffer_offset + 448 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | 449 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0); 450 so_reloc (vtxbuf, bo, vb->buffer_offset + 451 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | 452 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0); 453 454 /* vertex array limits */ 455 so_method(vtxbuf, tesla, 0x1080 + (i * 8), 2); 456 so_reloc (vtxbuf, bo, vb->buffer->size - 1, 457 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD | 458 NOUVEAU_BO_HIGH, 0, 0); 459 so_reloc (vtxbuf, bo, vb->buffer->size - 1, 460 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD | 461 NOUVEAU_BO_LOW, 0, 0); 462 } 463 for (; i < n_ve; ++i) { 464 so_data (vtxfmt, 0x7e080010); 465 466 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1); 467 so_data (vtxbuf, 0); 468 } 469 nv50->state.vtxelt_nr = nv50->vtxelt_nr; 470 471 so_ref (vtxfmt, &nv50->state.vtxfmt); 472 so_ref (vtxbuf, &nv50->state.vtxbuf); 473 so_ref (vtxattr, &nv50->state.vtxattr); 474 so_ref (NULL, &vtxbuf); 475 so_ref (NULL, &vtxfmt); 476 so_ref (NULL, &vtxattr); 477} 478 479typedef void (*pfn_push)(struct nouveau_channel *, void *); 480 481struct nv50_vbo_emitctx 482{ 483 pfn_push push[16]; 484 void *map[16]; 485 unsigned stride[16]; 486 unsigned nr_ve; 487 unsigned vtx_dwords; 488 unsigned vtx_max; 489 490 float edgeflag; 491 unsigned ve_edgeflag; 492}; 493 494static INLINE void 495emit_vtx_next(struct nouveau_channel *chan, struct nv50_vbo_emitctx *emit) 496{ 497 unsigned i; 498 499 for (i = 0; i < emit->nr_ve; ++i) { 500 emit->push[i](chan, emit->map[i]); 501 emit->map[i] += emit->stride[i]; 502 } 503} 504 505static INLINE void 506emit_vtx(struct nouveau_channel *chan, struct nv50_vbo_emitctx *emit, 507 uint32_t vi) 508{ 509 unsigned i; 510 511 for (i = 0; i < emit->nr_ve; ++i) 512 emit->push[i](chan, emit->map[i] + emit->stride[i] * vi); 513} 514 515static INLINE boolean 516nv50_map_vbufs(struct nv50_context *nv50) 517{ 518 int i; 519 520 for (i = 0; i < nv50->vtxbuf_nr; ++i) { 521 struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i]; 522 unsigned size, delta; 523 524 if (nouveau_bo(vb->buffer)->map) 525 continue; 526 527 size = vb->stride * (vb->max_index + 1); 528 delta = vb->buffer_offset; 529 530 if (!size) 531 size = vb->buffer->size - vb->buffer_offset; 532 533 if (nouveau_bo_map_range(nouveau_bo(vb->buffer), 534 delta, size, NOUVEAU_BO_RD)) 535 break; 536 } 537 538 if (i == nv50->vtxbuf_nr) 539 return TRUE; 540 for (; i >= 0; --i) 541 nouveau_bo_unmap(nouveau_bo(nv50->vtxbuf[i].buffer)); 542 return FALSE; 543} 544 545static INLINE void 546nv50_unmap_vbufs(struct nv50_context *nv50) 547{ 548 unsigned i; 549 550 for (i = 0; i < nv50->vtxbuf_nr; ++i) 551 if (nouveau_bo(nv50->vtxbuf[i].buffer)->map) 552 nouveau_bo_unmap(nouveau_bo(nv50->vtxbuf[i].buffer)); 553} 554 555static void 556emit_b32_1(struct nouveau_channel *chan, void *data) 557{ 558 uint32_t *v = data; 559 560 OUT_RING(chan, v[0]); 561} 562 563static void 564emit_b32_2(struct nouveau_channel *chan, void *data) 565{ 566 uint32_t *v = data; 567 568 OUT_RING(chan, v[0]); 569 OUT_RING(chan, v[1]); 570} 571 572static void 573emit_b32_3(struct nouveau_channel *chan, void *data) 574{ 575 uint32_t *v = data; 576 577 OUT_RING(chan, v[0]); 578 OUT_RING(chan, v[1]); 579 OUT_RING(chan, v[2]); 580} 581 582static void 583emit_b32_4(struct nouveau_channel *chan, void *data) 584{ 585 uint32_t *v = data; 586 587 OUT_RING(chan, v[0]); 588 OUT_RING(chan, v[1]); 589 OUT_RING(chan, v[2]); 590 OUT_RING(chan, v[3]); 591} 592 593static void 594emit_b16_1(struct nouveau_channel *chan, void *data) 595{ 596 uint16_t *v = data; 597 598 OUT_RING(chan, v[0]); 599} 600 601static void 602emit_b16_3(struct nouveau_channel *chan, void *data) 603{ 604 uint16_t *v = data; 605 606 OUT_RING(chan, (v[1] << 16) | v[0]); 607 OUT_RING(chan, v[2]); 608} 609 610static void 611emit_b08_1(struct nouveau_channel *chan, void *data) 612{ 613 uint8_t *v = data; 614 615 OUT_RING(chan, v[0]); 616} 617 618static void 619emit_b08_3(struct nouveau_channel *chan, void *data) 620{ 621 uint8_t *v = data; 622 623 OUT_RING(chan, (v[2] << 16) | (v[1] << 8) | v[0]); 624} 625 626static boolean 627emit_prepare(struct nv50_context *nv50, struct nv50_vbo_emitctx *emit, 628 unsigned start) 629{ 630 unsigned i; 631 632 if (nv50_map_vbufs(nv50) == FALSE) 633 return FALSE; 634 635 emit->ve_edgeflag = nv50->vertprog->cfg.edgeflag_in; 636 637 emit->edgeflag = 0.5f; 638 emit->nr_ve = 0; 639 emit->vtx_dwords = 0; 640 641 for (i = 0; i < nv50->vtxelt_nr; ++i) { 642 struct pipe_vertex_element *ve; 643 struct pipe_vertex_buffer *vb; 644 unsigned n, size; 645 const struct util_format_description *desc; 646 647 ve = &nv50->vtxelt[i]; 648 vb = &nv50->vtxbuf[ve->vertex_buffer_index]; 649 if (!(nv50->vbo_fifo & (1 << i))) 650 continue; 651 n = emit->nr_ve++; 652 653 emit->stride[n] = vb->stride; 654 emit->map[n] = nouveau_bo(vb->buffer)->map + 655 (start * vb->stride + ve->src_offset); 656 657 desc = util_format_description(ve->src_format); 658 assert(desc); 659 660 size = util_format_get_component_bits( 661 ve->src_format, UTIL_FORMAT_COLORSPACE_RGB, 0); 662 663 assert(ve->nr_components > 0 && ve->nr_components <= 4); 664 665 /* It shouldn't be necessary to push the implicit 1s 666 * for case 3 and size 8 cases 1, 2, 3. 667 */ 668 switch (size) { 669 default: 670 NOUVEAU_ERR("unsupported vtxelt size: %u\n", size); 671 return FALSE; 672 case 32: 673 switch (ve->nr_components) { 674 case 1: emit->push[n] = emit_b32_1; break; 675 case 2: emit->push[n] = emit_b32_2; break; 676 case 3: emit->push[n] = emit_b32_3; break; 677 case 4: emit->push[n] = emit_b32_4; break; 678 } 679 emit->vtx_dwords += ve->nr_components; 680 break; 681 case 16: 682 switch (ve->nr_components) { 683 case 1: emit->push[n] = emit_b16_1; break; 684 case 2: emit->push[n] = emit_b32_1; break; 685 case 3: emit->push[n] = emit_b16_3; break; 686 case 4: emit->push[n] = emit_b32_2; break; 687 } 688 emit->vtx_dwords += (ve->nr_components + 1) >> 1; 689 break; 690 case 8: 691 switch (ve->nr_components) { 692 case 1: emit->push[n] = emit_b08_1; break; 693 case 2: emit->push[n] = emit_b16_1; break; 694 case 3: emit->push[n] = emit_b08_3; break; 695 case 4: emit->push[n] = emit_b32_1; break; 696 } 697 emit->vtx_dwords += 1; 698 break; 699 } 700 } 701 702 emit->vtx_max = 512 / emit->vtx_dwords; 703 if (emit->ve_edgeflag < 16) 704 emit->vtx_max = 1; 705 706 return TRUE; 707} 708 709static INLINE void 710set_edgeflag(struct nouveau_channel *chan, 711 struct nouveau_grobj *tesla, 712 struct nv50_vbo_emitctx *emit, uint32_t index) 713{ 714 unsigned i = emit->ve_edgeflag; 715 716 if (i < 16) { 717 float f = *((float *)(emit->map[i] + index * emit->stride[i])); 718 719 if (emit->edgeflag != f) { 720 emit->edgeflag = f; 721 722 BEGIN_RING(chan, tesla, 0x15e4, 1); 723 OUT_RING (chan, f ? 1 : 0); 724 } 725 } 726} 727 728static boolean 729nv50_push_arrays(struct nv50_context *nv50, unsigned start, unsigned count) 730{ 731 struct nouveau_channel *chan = nv50->screen->base.channel; 732 struct nouveau_grobj *tesla = nv50->screen->tesla; 733 struct nv50_vbo_emitctx emit; 734 735 if (emit_prepare(nv50, &emit, start) == FALSE) 736 return FALSE; 737 738 while (count) { 739 unsigned i, dw, nr = MIN2(count, emit.vtx_max); 740 dw = nr * emit.vtx_dwords; 741 742 set_edgeflag(chan, tesla, &emit, 0); /* nr will be 1 */ 743 744 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw); 745 for (i = 0; i < nr; ++i) 746 emit_vtx_next(chan, &emit); 747 748 count -= nr; 749 } 750 nv50_unmap_vbufs(nv50); 751 752 return TRUE; 753} 754 755static boolean 756nv50_push_elements_u32(struct nv50_context *nv50, uint32_t *map, unsigned count) 757{ 758 struct nouveau_channel *chan = nv50->screen->base.channel; 759 struct nouveau_grobj *tesla = nv50->screen->tesla; 760 struct nv50_vbo_emitctx emit; 761 762 if (emit_prepare(nv50, &emit, 0) == FALSE) 763 return FALSE; 764 765 while (count) { 766 unsigned i, dw, nr = MIN2(count, emit.vtx_max); 767 dw = nr * emit.vtx_dwords; 768 769 set_edgeflag(chan, tesla, &emit, *map); 770 771 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw); 772 for (i = 0; i < nr; ++i) 773 emit_vtx(chan, &emit, *map++); 774 775 count -= nr; 776 } 777 nv50_unmap_vbufs(nv50); 778 779 return TRUE; 780} 781 782static boolean 783nv50_push_elements_u16(struct nv50_context *nv50, uint16_t *map, unsigned count) 784{ 785 struct nouveau_channel *chan = nv50->screen->base.channel; 786 struct nouveau_grobj *tesla = nv50->screen->tesla; 787 struct nv50_vbo_emitctx emit; 788 789 if (emit_prepare(nv50, &emit, 0) == FALSE) 790 return FALSE; 791 792 while (count) { 793 unsigned i, dw, nr = MIN2(count, emit.vtx_max); 794 dw = nr * emit.vtx_dwords; 795 796 set_edgeflag(chan, tesla, &emit, *map); 797 798 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw); 799 for (i = 0; i < nr; ++i) 800 emit_vtx(chan, &emit, *map++); 801 802 count -= nr; 803 } 804 nv50_unmap_vbufs(nv50); 805 806 return TRUE; 807} 808 809static boolean 810nv50_push_elements_u08(struct nv50_context *nv50, uint8_t *map, unsigned count) 811{ 812 struct nouveau_channel *chan = nv50->screen->base.channel; 813 struct nouveau_grobj *tesla = nv50->screen->tesla; 814 struct nv50_vbo_emitctx emit; 815 816 if (emit_prepare(nv50, &emit, 0) == FALSE) 817 return FALSE; 818 819 while (count) { 820 unsigned i, dw, nr = MIN2(count, emit.vtx_max); 821 dw = nr * emit.vtx_dwords; 822 823 set_edgeflag(chan, tesla, &emit, *map); 824 825 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw); 826 for (i = 0; i < nr; ++i) 827 emit_vtx(chan, &emit, *map++); 828 829 count -= nr; 830 } 831 nv50_unmap_vbufs(nv50); 832 833 return TRUE; 834} 835