1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.1 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keith@tungstengraphics.com> 26 */ 27 28 29/** 30 * \file t_dd_dmatmp.h 31 * Template for render stages which build and emit vertices directly 32 * to fixed-size dma buffers. Useful for rendering strips and other 33 * native primitives where clipping and per-vertex tweaks such as 34 * those in t_dd_tritmp.h are not required. 35 * 36 * Produces code for both inline triangles and indexed triangles. 37 * Where various primitive types are unaccelerated by hardware, the 38 * code attempts to fallback to other primitive types (quadstrips to 39 * tristrips, lineloops to linestrips), or to indexed vertices. 40 */ 41 42#if !defined(HAVE_TRIANGLES) 43#error "must have at least triangles to use render template" 44#endif 45 46#if !HAVE_ELTS 47#define ELTS_VARS(buf) 48#define ALLOC_ELTS(nr) 0 49#define EMIT_ELT( offset, elt ) 50#define EMIT_TWO_ELTS( offset, elt0, elt1 ) 51#define INCR_ELTS( nr ) 52#define ELT_INIT(prim) 53#define GET_CURRENT_VB_MAX_ELTS() 0 54#define GET_SUBSEQUENT_VB_MAX_ELTS() 0 55#define RELEASE_ELT_VERTS() 56#define EMIT_INDEXED_VERTS( ctx, start, count ) 57#endif 58 59#ifndef EMIT_TWO_ELTS 60#define EMIT_TWO_ELTS( offset, elt0, elt1 ) \ 61do { \ 62 EMIT_ELT( offset, elt0 ); \ 63 EMIT_ELT( offset+1, elt1 ); \ 64} while (0) 65#endif 66 67 68/**********************************************************************/ 69/* Render whole begin/end objects */ 70/**********************************************************************/ 71 72 73 74 75#if (HAVE_ELTS) 76static void *TAG(emit_elts)( struct gl_context *ctx, GLuint *elts, GLuint nr, 77 void *buf) 78{ 79 GLint i; 80 LOCAL_VARS; 81 ELTS_VARS(buf); 82 83 for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) { 84 EMIT_TWO_ELTS( 0, elts[0], elts[1] ); 85 INCR_ELTS( 2 ); 86 } 87 88 if (i < nr) { 89 EMIT_ELT( 0, elts[0] ); 90 INCR_ELTS( 1 ); 91 } 92 93 return (void *)ELTPTR; 94} 95#endif 96 97static __inline void *TAG(emit_verts)( struct gl_context *ctx, GLuint start, 98 GLuint count, void *buf ) 99{ 100 return EMIT_VERTS(ctx, start, count, buf); 101} 102 103/*********************************************************************** 104 * Render non-indexed primitives. 105 ***********************************************************************/ 106 107static void TAG(render_points_verts)( struct gl_context *ctx, 108 GLuint start, 109 GLuint count, 110 GLuint flags ) 111{ 112 if (HAVE_POINTS) { 113 LOCAL_VARS; 114 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 115 int currentsz; 116 GLuint j, nr; 117 118 INIT( GL_POINTS ); 119 120 currentsz = GET_CURRENT_VB_MAX_VERTS(); 121 if (currentsz < 8) 122 currentsz = dmasz; 123 124 for (j = start; j < count; j += nr ) { 125 nr = MIN2( currentsz, count - j ); 126 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 127 currentsz = dmasz; 128 } 129 130 } else { 131 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 132 return; 133 } 134} 135 136static void TAG(render_lines_verts)( struct gl_context *ctx, 137 GLuint start, 138 GLuint count, 139 GLuint flags ) 140{ 141 if (HAVE_LINES) { 142 LOCAL_VARS; 143 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 144 int currentsz; 145 GLuint j, nr; 146 147 INIT( GL_LINES ); 148 149 /* Emit whole number of lines in total and in each buffer: 150 */ 151 count -= (count-start) & 1; 152 currentsz = GET_CURRENT_VB_MAX_VERTS(); 153 currentsz -= currentsz & 1; 154 dmasz -= dmasz & 1; 155 156 if (currentsz < 8) 157 currentsz = dmasz; 158 159 for (j = start; j < count; j += nr ) { 160 nr = MIN2( currentsz, count - j ); 161 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 162 currentsz = dmasz; 163 } 164 165 } else { 166 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 167 return; 168 } 169} 170 171 172static void TAG(render_line_strip_verts)( struct gl_context *ctx, 173 GLuint start, 174 GLuint count, 175 GLuint flags ) 176{ 177 if (HAVE_LINE_STRIPS) { 178 LOCAL_VARS; 179 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 180 int currentsz; 181 GLuint j, nr; 182 183 INIT( GL_LINE_STRIP ); 184 185 currentsz = GET_CURRENT_VB_MAX_VERTS(); 186 if (currentsz < 8) 187 currentsz = dmasz; 188 189 for (j = start; j + 1 < count; j += nr - 1 ) { 190 nr = MIN2( currentsz, count - j ); 191 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 192 currentsz = dmasz; 193 } 194 195 FLUSH(); 196 197 } else { 198 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 199 return; 200 } 201} 202 203 204static void TAG(render_line_loop_verts)( struct gl_context *ctx, 205 GLuint start, 206 GLuint count, 207 GLuint flags ) 208{ 209 if (HAVE_LINE_STRIPS) { 210 LOCAL_VARS; 211 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 212 int currentsz; 213 GLuint j, nr; 214 215 INIT( GL_LINE_STRIP ); 216 217 if (flags & PRIM_BEGIN) 218 j = start; 219 else 220 j = start + 1; 221 222 /* Ensure last vertex won't wrap buffers: 223 */ 224 currentsz = GET_CURRENT_VB_MAX_VERTS(); 225 currentsz--; 226 dmasz--; 227 228 if (currentsz < 8) { 229 currentsz = dmasz; 230 } 231 232 if (j + 1 < count) { 233 for ( ; j + 1 < count; j += nr - 1 ) { 234 nr = MIN2( currentsz, count - j ); 235 236 if (j + nr >= count && 237 start < count - 1 && 238 (flags & PRIM_END)) 239 { 240 void *tmp; 241 tmp = ALLOC_VERTS(nr+1); 242 tmp = TAG(emit_verts)( ctx, j, nr, tmp ); 243 tmp = TAG(emit_verts)( ctx, start, 1, tmp ); 244 (void) tmp; 245 } 246 else { 247 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 248 currentsz = dmasz; 249 } 250 } 251 252 } 253 else if (start + 1 < count && (flags & PRIM_END)) { 254 void *tmp; 255 tmp = ALLOC_VERTS(2); 256 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp ); 257 tmp = TAG(emit_verts)( ctx, start, 1, tmp ); 258 (void) tmp; 259 } 260 261 FLUSH(); 262 263 } else { 264 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 265 return; 266 } 267} 268 269 270static void TAG(render_triangles_verts)( struct gl_context *ctx, 271 GLuint start, 272 GLuint count, 273 GLuint flags ) 274{ 275 LOCAL_VARS; 276 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3; 277 int currentsz; 278 GLuint j, nr; 279 280 INIT(GL_TRIANGLES); 281 282 currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3; 283 284 /* Emit whole number of tris in total. dmasz is already a multiple 285 * of 3. 286 */ 287 count -= (count-start)%3; 288 289 if (currentsz < 8) 290 currentsz = dmasz; 291 292 for (j = start; j < count; j += nr) { 293 nr = MIN2( currentsz, count - j ); 294 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 295 currentsz = dmasz; 296 } 297} 298 299 300 301static void TAG(render_tri_strip_verts)( struct gl_context *ctx, 302 GLuint start, 303 GLuint count, 304 GLuint flags ) 305{ 306 if (HAVE_TRI_STRIPS) { 307 LOCAL_VARS; 308 GLuint j, nr; 309 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 310 int currentsz; 311 312 INIT(GL_TRIANGLE_STRIP); 313 314 currentsz = GET_CURRENT_VB_MAX_VERTS(); 315 316 if (currentsz < 8) { 317 currentsz = dmasz; 318 } 319 320 /* From here on emit even numbers of tris when wrapping over buffers: 321 */ 322 dmasz -= (dmasz & 1); 323 currentsz -= (currentsz & 1); 324 325 for (j = start ; j + 2 < count; j += nr - 2 ) { 326 nr = MIN2( currentsz, count - j ); 327 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 328 currentsz = dmasz; 329 } 330 331 FLUSH(); 332 333 } else { 334 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 335 return; 336 } 337} 338 339static void TAG(render_tri_fan_verts)( struct gl_context *ctx, 340 GLuint start, 341 GLuint count, 342 GLuint flags ) 343{ 344 if (HAVE_TRI_FANS) { 345 LOCAL_VARS; 346 GLuint j, nr; 347 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 348 int currentsz; 349 350 INIT(GL_TRIANGLE_FAN); 351 352 currentsz = GET_CURRENT_VB_MAX_VERTS(); 353 if (currentsz < 8) { 354 currentsz = dmasz; 355 } 356 357 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) { 358 void *tmp; 359 nr = MIN2( currentsz, count - j + 1 ); 360 tmp = ALLOC_VERTS( nr ); 361 tmp = TAG(emit_verts)( ctx, start, 1, tmp ); 362 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp ); 363 (void) tmp; 364 currentsz = dmasz; 365 } 366 367 FLUSH(); 368 } 369 else { 370 /* Could write code to emit these as indexed vertices (for the 371 * g400, for instance). 372 */ 373 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 374 return; 375 } 376} 377 378 379static void TAG(render_poly_verts)( struct gl_context *ctx, 380 GLuint start, 381 GLuint count, 382 GLuint flags ) 383{ 384 if (HAVE_POLYGONS) { 385 LOCAL_VARS; 386 GLuint j, nr; 387 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 388 int currentsz; 389 390 INIT(GL_POLYGON); 391 392 currentsz = GET_CURRENT_VB_MAX_VERTS(); 393 if (currentsz < 8) { 394 currentsz = dmasz; 395 } 396 397 for (j = start + 1 ; j + 1 < count ; j += nr - 2 ) { 398 void *tmp; 399 nr = MIN2( currentsz, count - j + 1 ); 400 tmp = ALLOC_VERTS( nr ); 401 tmp = TAG(emit_verts)( ctx, start, 1, tmp ); 402 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp ); 403 (void) tmp; 404 currentsz = dmasz; 405 } 406 407 FLUSH(); 408 } 409 else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) { 410 TAG(render_tri_fan_verts)( ctx, start, count, flags ); 411 } else { 412 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 413 return; 414 } 415} 416 417static void TAG(render_quad_strip_verts)( struct gl_context *ctx, 418 GLuint start, 419 GLuint count, 420 GLuint flags ) 421{ 422 GLuint j, nr; 423 424 if (HAVE_QUAD_STRIPS) { 425 LOCAL_VARS; 426 GLuint j, nr; 427 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 428 int currentsz; 429 430 INIT(GL_QUAD_STRIP); 431 432 currentsz = GET_CURRENT_VB_MAX_VERTS(); 433 if (currentsz < 8) { 434 currentsz = dmasz; 435 } 436 437 dmasz -= (dmasz & 2); 438 currentsz -= (currentsz & 2); 439 440 for (j = start ; j + 3 < count; j += nr - 2 ) { 441 nr = MIN2( currentsz, count - j ); 442 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 443 currentsz = dmasz; 444 } 445 446 FLUSH(); 447 448 } else if (HAVE_TRI_STRIPS && 449 ctx->Light.ShadeModel == GL_FLAT && 450 TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) { 451 if (HAVE_ELTS) { 452 LOCAL_VARS; 453 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 454 int currentsz; 455 GLuint j, nr; 456 457 EMIT_INDEXED_VERTS( ctx, start, count ); 458 459 /* Simulate flat-shaded quadstrips using indexed vertices: 460 */ 461 ELT_INIT( GL_TRIANGLES ); 462 463 currentsz = GET_CURRENT_VB_MAX_ELTS(); 464 465 /* Emit whole number of quads in total, and in each buffer. 466 */ 467 dmasz -= dmasz & 1; 468 count -= (count-start) & 1; 469 currentsz -= currentsz & 1; 470 471 if (currentsz < 12) 472 currentsz = dmasz; 473 474 currentsz = currentsz/6*2; 475 dmasz = dmasz/6*2; 476 477 for (j = start; j + 3 < count; j += nr - 2 ) { 478 nr = MIN2( currentsz, count - j ); 479 if (nr >= 4) { 480 GLint quads = (nr/2)-1; 481 GLint i; 482 ELTS_VARS( ALLOC_ELTS( quads*6 ) ); 483 484 for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) { 485 EMIT_TWO_ELTS( 0, (i+0), (i+1) ); 486 EMIT_TWO_ELTS( 2, (i+2), (i+1) ); 487 EMIT_TWO_ELTS( 4, (i+3), (i+2) ); 488 INCR_ELTS( 6 ); 489 } 490 491 FLUSH(); 492 } 493 currentsz = dmasz; 494 } 495 496 RELEASE_ELT_VERTS(); 497 FLUSH(); 498 } 499 else { 500 /* Vertices won't fit in a single buffer or elts not 501 * available - should never happen. 502 */ 503 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 504 return; 505 } 506 } 507 else if (HAVE_TRI_STRIPS) { 508 LOCAL_VARS; 509 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS(); 510 int currentsz; 511 512 /* Emit smooth-shaded quadstrips as tristrips: 513 */ 514 FLUSH(); 515 INIT( GL_TRIANGLE_STRIP ); 516 517 /* Emit whole number of quads in total, and in each buffer. 518 */ 519 dmasz -= dmasz & 1; 520 currentsz = GET_CURRENT_VB_MAX_VERTS(); 521 currentsz -= currentsz & 1; 522 count -= (count-start) & 1; 523 524 if (currentsz < 8) { 525 currentsz = dmasz; 526 } 527 528 for (j = start; j + 3 < count; j += nr - 2 ) { 529 nr = MIN2( currentsz, count - j ); 530 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 531 currentsz = dmasz; 532 } 533 534 FLUSH(); 535 536 } else { 537 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 538 return; 539 } 540} 541 542 543static void TAG(render_quads_verts)( struct gl_context *ctx, 544 GLuint start, 545 GLuint count, 546 GLuint flags ) 547{ 548 if (HAVE_QUADS) { 549 LOCAL_VARS; 550 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4; 551 int currentsz; 552 GLuint j, nr; 553 554 INIT(GL_QUADS); 555 556 /* Emit whole number of quads in total. dmasz is already a multiple 557 * of 4. 558 */ 559 count -= (count-start)%4; 560 561 currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4; 562 if (currentsz < 8) 563 currentsz = dmasz; 564 565 for (j = start; j < count; j += nr) { 566 nr = MIN2( currentsz, count - j ); 567 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) ); 568 currentsz = dmasz; 569 } 570 } 571 else if (HAVE_ELTS) { 572 /* Hardware doesn't have a quad primitive type -- try to 573 * simulate it using indexed vertices and the triangle 574 * primitive: 575 */ 576 LOCAL_VARS; 577 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 578 int currentsz; 579 GLuint j, nr; 580 581 EMIT_INDEXED_VERTS( ctx, start, count ); 582 583 FLUSH(); 584 ELT_INIT( GL_TRIANGLES ); 585 currentsz = GET_CURRENT_VB_MAX_ELTS(); 586 587 /* Emit whole number of quads in total, and in each buffer. 588 */ 589 dmasz -= dmasz & 3; 590 count -= (count-start) & 3; 591 currentsz -= currentsz & 3; 592 593 /* Adjust for rendering as triangles: 594 */ 595 currentsz = currentsz/6*4; 596 dmasz = dmasz/6*4; 597 598 if (currentsz < 8) 599 currentsz = dmasz; 600 601 for (j = start; j < count; j += nr ) { 602 nr = MIN2( currentsz, count - j ); 603 if (nr >= 4) { 604 GLint quads = nr/4; 605 GLint i; 606 ELTS_VARS( ALLOC_ELTS( quads*6 ) ); 607 608 for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) { 609 EMIT_TWO_ELTS( 0, (i+0), (i+1) ); 610 EMIT_TWO_ELTS( 2, (i+3), (i+1) ); 611 EMIT_TWO_ELTS( 4, (i+2), (i+3) ); 612 INCR_ELTS( 6 ); 613 } 614 615 FLUSH(); 616 } 617 currentsz = dmasz; 618 } 619 620 RELEASE_ELT_VERTS(); 621 } 622 else if (HAVE_TRIANGLES) { 623 /* Hardware doesn't have a quad primitive type -- try to 624 * simulate it using triangle primitive. This is a win for 625 * gears, but is it useful in the broader world? 626 */ 627 LOCAL_VARS; 628 GLuint j; 629 630 INIT(GL_TRIANGLES); 631 632 for (j = start; j < count-3; j += 4) { 633 void *tmp = ALLOC_VERTS( 6 ); 634 /* Send v0, v1, v3 635 */ 636 tmp = EMIT_VERTS(ctx, j, 2, tmp); 637 tmp = EMIT_VERTS(ctx, j + 3, 1, tmp); 638 /* Send v1, v2, v3 639 */ 640 tmp = EMIT_VERTS(ctx, j + 1, 3, tmp); 641 (void) tmp; 642 } 643 } 644 else { 645 /* Vertices won't fit in a single buffer, should never happen. 646 */ 647 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 648 return; 649 } 650} 651 652static void TAG(render_noop)( struct gl_context *ctx, 653 GLuint start, 654 GLuint count, 655 GLuint flags ) 656{ 657} 658 659 660 661 662static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] = 663{ 664 TAG(render_points_verts), 665 TAG(render_lines_verts), 666 TAG(render_line_loop_verts), 667 TAG(render_line_strip_verts), 668 TAG(render_triangles_verts), 669 TAG(render_tri_strip_verts), 670 TAG(render_tri_fan_verts), 671 TAG(render_quads_verts), 672 TAG(render_quad_strip_verts), 673 TAG(render_poly_verts), 674 TAG(render_noop), 675}; 676 677 678/**************************************************************************** 679 * Render elts using hardware indexed verts * 680 ****************************************************************************/ 681 682#if (HAVE_ELTS) 683static void TAG(render_points_elts)( struct gl_context *ctx, 684 GLuint start, 685 GLuint count, 686 GLuint flags ) 687{ 688 if (HAVE_POINTS) { 689 LOCAL_VARS; 690 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 691 int currentsz; 692 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 693 GLuint j, nr; 694 695 ELT_INIT( GL_POINTS ); 696 697 currentsz = GET_CURRENT_VB_MAX_ELTS(); 698 if (currentsz < 8) 699 currentsz = dmasz; 700 701 for (j = start; j < count; j += nr ) { 702 nr = MIN2( currentsz, count - j ); 703 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 704 FLUSH(); 705 currentsz = dmasz; 706 } 707 } else { 708 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 709 return; 710 } 711} 712 713 714 715static void TAG(render_lines_elts)( struct gl_context *ctx, 716 GLuint start, 717 GLuint count, 718 GLuint flags ) 719{ 720 if (HAVE_LINES) { 721 LOCAL_VARS; 722 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 723 int currentsz; 724 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 725 GLuint j, nr; 726 727 ELT_INIT( GL_LINES ); 728 729 /* Emit whole number of lines in total and in each buffer: 730 */ 731 count -= (count-start) & 1; 732 currentsz -= currentsz & 1; 733 dmasz -= dmasz & 1; 734 735 currentsz = GET_CURRENT_VB_MAX_ELTS(); 736 if (currentsz < 8) 737 currentsz = dmasz; 738 739 for (j = start; j < count; j += nr ) { 740 nr = MIN2( currentsz, count - j ); 741 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 742 FLUSH(); 743 currentsz = dmasz; 744 } 745 } else { 746 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 747 return; 748 } 749} 750 751 752static void TAG(render_line_strip_elts)( struct gl_context *ctx, 753 GLuint start, 754 GLuint count, 755 GLuint flags ) 756{ 757 if (HAVE_LINE_STRIPS) { 758 LOCAL_VARS; 759 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 760 int currentsz; 761 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 762 GLuint j, nr; 763 764 FLUSH(); /* always a new primitive */ 765 ELT_INIT( GL_LINE_STRIP ); 766 767 currentsz = GET_CURRENT_VB_MAX_ELTS(); 768 if (currentsz < 8) 769 currentsz = dmasz; 770 771 for (j = start; j + 1 < count; j += nr - 1 ) { 772 nr = MIN2( currentsz, count - j ); 773 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 774 FLUSH(); 775 currentsz = dmasz; 776 } 777 } else { 778 /* TODO: Try to emit as indexed lines. 779 */ 780 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 781 return; 782 } 783} 784 785 786static void TAG(render_line_loop_elts)( struct gl_context *ctx, 787 GLuint start, 788 GLuint count, 789 GLuint flags ) 790{ 791 if (HAVE_LINE_STRIPS) { 792 LOCAL_VARS; 793 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 794 int currentsz; 795 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 796 GLuint j, nr; 797 798 FLUSH(); 799 ELT_INIT( GL_LINE_STRIP ); 800 801 if (flags & PRIM_BEGIN) 802 j = start; 803 else 804 j = start + 1; 805 806 currentsz = GET_CURRENT_VB_MAX_ELTS(); 807 if (currentsz < 8) { 808 currentsz = dmasz; 809 } 810 811 /* Ensure last vertex doesn't wrap: 812 */ 813 currentsz--; 814 dmasz--; 815 816 if (j + 1 < count) { 817 for ( ; j + 1 < count; j += nr - 1 ) { 818 nr = MIN2( currentsz, count - j ); 819 820 if (j + nr >= count && 821 start < count - 1 && 822 (flags & PRIM_END)) 823 { 824 void *tmp; 825 tmp = ALLOC_ELTS(nr+1); 826 tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp ); 827 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp ); 828 (void) tmp; 829 } 830 else { 831 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 832 currentsz = dmasz; 833 } 834 } 835 836 } 837 else if (start + 1 < count && (flags & PRIM_END)) { 838 void *tmp; 839 tmp = ALLOC_ELTS(2); 840 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp ); 841 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp ); 842 (void) tmp; 843 } 844 845 FLUSH(); 846 } else { 847 /* TODO: Try to emit as indexed lines */ 848 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 849 return; 850 } 851} 852 853 854/* For verts, we still eliminate the copy from main memory to dma 855 * buffers. For elts, this is probably no better (worse?) than the 856 * standard path. 857 */ 858static void TAG(render_triangles_elts)( struct gl_context *ctx, 859 GLuint start, 860 GLuint count, 861 GLuint flags ) 862{ 863 LOCAL_VARS; 864 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 865 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3; 866 int currentsz; 867 GLuint j, nr; 868 869 FLUSH(); 870 ELT_INIT( GL_TRIANGLES ); 871 872 currentsz = GET_CURRENT_VB_MAX_ELTS(); 873 874 /* Emit whole number of tris in total. dmasz is already a multiple 875 * of 3. 876 */ 877 count -= (count-start)%3; 878 currentsz -= currentsz%3; 879 if (currentsz < 8) 880 currentsz = dmasz; 881 882 for (j = start; j < count; j += nr) { 883 nr = MIN2( currentsz, count - j ); 884 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 885 FLUSH(); 886 currentsz = dmasz; 887 } 888} 889 890 891 892static void TAG(render_tri_strip_elts)( struct gl_context *ctx, 893 GLuint start, 894 GLuint count, 895 GLuint flags ) 896{ 897 if (HAVE_TRI_STRIPS) { 898 LOCAL_VARS; 899 GLuint j, nr; 900 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 901 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 902 int currentsz; 903 904 FLUSH(); 905 ELT_INIT( GL_TRIANGLE_STRIP ); 906 907 currentsz = GET_CURRENT_VB_MAX_ELTS(); 908 if (currentsz < 8) { 909 currentsz = dmasz; 910 } 911 912 /* Keep the same winding over multiple buffers: 913 */ 914 dmasz -= (dmasz & 1); 915 currentsz -= (currentsz & 1); 916 917 for (j = start ; j + 2 < count; j += nr - 2 ) { 918 nr = MIN2( currentsz, count - j ); 919 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 920 FLUSH(); 921 currentsz = dmasz; 922 } 923 } else { 924 /* TODO: try to emit as indexed triangles */ 925 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 926 return; 927 } 928} 929 930static void TAG(render_tri_fan_elts)( struct gl_context *ctx, 931 GLuint start, 932 GLuint count, 933 GLuint flags ) 934{ 935 if (HAVE_TRI_FANS) { 936 LOCAL_VARS; 937 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 938 GLuint j, nr; 939 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 940 int currentsz; 941 942 FLUSH(); 943 ELT_INIT( GL_TRIANGLE_FAN ); 944 945 currentsz = GET_CURRENT_VB_MAX_ELTS(); 946 if (currentsz < 8) { 947 currentsz = dmasz; 948 } 949 950 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) { 951 void *tmp; 952 nr = MIN2( currentsz, count - j + 1 ); 953 tmp = ALLOC_ELTS( nr ); 954 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp ); 955 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp ); 956 (void) tmp; 957 FLUSH(); 958 currentsz = dmasz; 959 } 960 } else { 961 /* TODO: try to emit as indexed triangles */ 962 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 963 return; 964 } 965} 966 967 968static void TAG(render_poly_elts)( struct gl_context *ctx, 969 GLuint start, 970 GLuint count, 971 GLuint flags ) 972{ 973 if (HAVE_POLYGONS) { 974 LOCAL_VARS; 975 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 976 GLuint j, nr; 977 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 978 int currentsz; 979 980 FLUSH(); 981 ELT_INIT( GL_POLYGON ); 982 983 currentsz = GET_CURRENT_VB_MAX_ELTS(); 984 if (currentsz < 8) { 985 currentsz = dmasz; 986 } 987 988 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) { 989 void *tmp; 990 nr = MIN2( currentsz, count - j + 1 ); 991 tmp = ALLOC_ELTS( nr ); 992 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp ); 993 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp ); 994 (void) tmp; 995 FLUSH(); 996 currentsz = dmasz; 997 } 998 } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) { 999 TAG(render_tri_fan_verts)( ctx, start, count, flags ); 1000 } else { 1001 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__); 1002 return; 1003 } 1004} 1005 1006static void TAG(render_quad_strip_elts)( struct gl_context *ctx, 1007 GLuint start, 1008 GLuint count, 1009 GLuint flags ) 1010{ 1011 if (HAVE_QUAD_STRIPS && 0) { 1012 } 1013 else if (HAVE_TRI_STRIPS) { 1014 LOCAL_VARS; 1015 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 1016 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 1017 int currentsz; 1018 GLuint j, nr; 1019 1020 FLUSH(); 1021 currentsz = GET_CURRENT_VB_MAX_ELTS(); 1022 1023 /* Emit whole number of quads in total, and in each buffer. 1024 */ 1025 dmasz -= dmasz & 1; 1026 count -= (count-start) & 1; 1027 currentsz -= currentsz & 1; 1028 1029 if (currentsz < 12) 1030 currentsz = dmasz; 1031 1032 if (ctx->Light.ShadeModel == GL_FLAT) { 1033 ELT_INIT( GL_TRIANGLES ); 1034 1035 currentsz = currentsz/6*2; 1036 dmasz = dmasz/6*2; 1037 1038 for (j = start; j + 3 < count; j += nr - 2 ) { 1039 nr = MIN2( currentsz, count - j ); 1040 1041 if (nr >= 4) 1042 { 1043 GLint i; 1044 GLint quads = (nr/2)-1; 1045 ELTS_VARS( ALLOC_ELTS( quads*6 ) ); 1046 1047 for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) { 1048 EMIT_TWO_ELTS( 0, elts[0], elts[1] ); 1049 EMIT_TWO_ELTS( 2, elts[2], elts[1] ); 1050 EMIT_TWO_ELTS( 4, elts[3], elts[2] ); 1051 INCR_ELTS( 6 ); 1052 } 1053 1054 FLUSH(); 1055 } 1056 1057 currentsz = dmasz; 1058 } 1059 } 1060 else { 1061 ELT_INIT( GL_TRIANGLE_STRIP ); 1062 1063 for (j = start; j + 3 < count; j += nr - 2 ) { 1064 nr = MIN2( currentsz, count - j ); 1065 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 1066 FLUSH(); 1067 currentsz = dmasz; 1068 } 1069 } 1070 } 1071} 1072 1073 1074static void TAG(render_quads_elts)( struct gl_context *ctx, 1075 GLuint start, 1076 GLuint count, 1077 GLuint flags ) 1078{ 1079 if (HAVE_QUADS) { 1080 LOCAL_VARS; 1081 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 1082 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4; 1083 int currentsz; 1084 GLuint j, nr; 1085 1086 FLUSH(); 1087 ELT_INIT( GL_TRIANGLES ); 1088 1089 currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4; 1090 1091 count -= (count-start)%4; 1092 1093 if (currentsz < 8) 1094 currentsz = dmasz; 1095 1096 for (j = start; j < count; j += nr) { 1097 nr = MIN2( currentsz, count - j ); 1098 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) ); 1099 FLUSH(); 1100 currentsz = dmasz; 1101 } 1102 } else { 1103 LOCAL_VARS; 1104 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts; 1105 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS(); 1106 int currentsz; 1107 GLuint j, nr; 1108 1109 ELT_INIT( GL_TRIANGLES ); 1110 currentsz = GET_CURRENT_VB_MAX_ELTS(); 1111 1112 /* Emit whole number of quads in total, and in each buffer. 1113 */ 1114 dmasz -= dmasz & 3; 1115 count -= (count-start) & 3; 1116 currentsz -= currentsz & 3; 1117 1118 /* Adjust for rendering as triangles: 1119 */ 1120 currentsz = currentsz/6*4; 1121 dmasz = dmasz/6*4; 1122 1123 if (currentsz < 8) 1124 currentsz = dmasz; 1125 1126 for (j = start; j + 3 < count; j += nr - 2 ) { 1127 nr = MIN2( currentsz, count - j ); 1128 1129 if (nr >= 4) 1130 { 1131 GLint quads = nr/4; 1132 GLint i; 1133 ELTS_VARS( ALLOC_ELTS( quads * 6 ) ); 1134 1135 for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) { 1136 EMIT_TWO_ELTS( 0, elts[0], elts[1] ); 1137 EMIT_TWO_ELTS( 2, elts[3], elts[1] ); 1138 EMIT_TWO_ELTS( 4, elts[2], elts[3] ); 1139 INCR_ELTS( 6 ); 1140 } 1141 1142 FLUSH(); 1143 } 1144 1145 currentsz = dmasz; 1146 } 1147 } 1148} 1149 1150 1151 1152static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] = 1153{ 1154 TAG(render_points_elts), 1155 TAG(render_lines_elts), 1156 TAG(render_line_loop_elts), 1157 TAG(render_line_strip_elts), 1158 TAG(render_triangles_elts), 1159 TAG(render_tri_strip_elts), 1160 TAG(render_tri_fan_elts), 1161 TAG(render_quads_elts), 1162 TAG(render_quad_strip_elts), 1163 TAG(render_poly_elts), 1164 TAG(render_noop), 1165}; 1166 1167 1168 1169#endif 1170 1171 1172 1173/* Pre-check the primitives in the VB to prevent the need for 1174 * fallbacks later on. 1175 */ 1176static GLboolean TAG(validate_render)( struct gl_context *ctx, 1177 struct vertex_buffer *VB ) 1178{ 1179 GLint i; 1180 1181 if (VB->ClipOrMask & ~CLIP_CULL_BIT) 1182 return GL_FALSE; 1183 1184 if (VB->Elts && !HAVE_ELTS) 1185 return GL_FALSE; 1186 1187 for (i = 0 ; i < VB->PrimitiveCount ; i++) { 1188 GLuint prim = VB->Primitive[i].mode; 1189 GLuint count = VB->Primitive[i].count; 1190 GLboolean ok = GL_FALSE; 1191 1192 if (!count) 1193 continue; 1194 1195 switch (prim & PRIM_MODE_MASK) { 1196 case GL_POINTS: 1197 ok = HAVE_POINTS; 1198 break; 1199 case GL_LINES: 1200 ok = HAVE_LINES && !ctx->Line.StippleFlag; 1201 break; 1202 case GL_LINE_STRIP: 1203 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag; 1204 break; 1205 case GL_LINE_LOOP: 1206 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag; 1207 break; 1208 case GL_TRIANGLES: 1209 ok = HAVE_TRIANGLES; 1210 break; 1211 case GL_TRIANGLE_STRIP: 1212 ok = HAVE_TRI_STRIPS; 1213 break; 1214 case GL_TRIANGLE_FAN: 1215 ok = HAVE_TRI_FANS; 1216 break; 1217 case GL_POLYGON: 1218 if (HAVE_POLYGONS) { 1219 ok = GL_TRUE; 1220 } 1221 else { 1222 ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH); 1223 } 1224 break; 1225 case GL_QUAD_STRIP: 1226 if (VB->Elts) { 1227 ok = HAVE_TRI_STRIPS; 1228 } 1229 else if (HAVE_QUAD_STRIPS) { 1230 ok = GL_TRUE; 1231 } else if (HAVE_TRI_STRIPS && 1232 ctx->Light.ShadeModel == GL_FLAT && 1233 VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) { 1234 if (HAVE_ELTS) { 1235 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS(); 1236 } 1237 else { 1238 ok = GL_FALSE; 1239 } 1240 } 1241 else 1242 ok = HAVE_TRI_STRIPS; 1243 break; 1244 case GL_QUADS: 1245 if (HAVE_QUADS) { 1246 ok = GL_TRUE; 1247 } else if (HAVE_ELTS) { 1248 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS(); 1249 } 1250 else { 1251 ok = HAVE_TRIANGLES; /* flatshading is ok. */ 1252 } 1253 break; 1254 default: 1255 break; 1256 } 1257 1258 if (!ok) { 1259/* fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */ 1260 return GL_FALSE; 1261 } 1262 } 1263 1264 return GL_TRUE; 1265} 1266 1267