vbo_save_api.c revision 79679e258b7aa4b1dc672c03795d47456893f881
1/************************************************************************** 2 3Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas. 4 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the "Software"), 9to deal in the Software without restriction, including without limitation 10on the rights to use, copy, modify, merge, publish, distribute, sub 11license, and/or sell copies of the Software, and to permit persons to whom 12the Software is furnished to do so, subject to the following conditions: 13 14The above copyright notice and this permission notice (including the next 15paragraph) shall be included in all copies or substantial portions of the 16Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26**************************************************************************/ 27 28/* 29 * Authors: 30 * Keith Whitwell <keith@tungstengraphics.com> 31 */ 32 33 34 35/* Display list compiler attempts to store lists of vertices with the 36 * same vertex layout. Additionally it attempts to minimize the need 37 * for execute-time fixup of these vertex lists, allowing them to be 38 * cached on hardware. 39 * 40 * There are still some circumstances where this can be thwarted, for 41 * example by building a list that consists of one very long primitive 42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list 43 * from inside a different begin/end object (Begin(Lines), CallList, 44 * End). 45 * 46 * In that case the code will have to replay the list as individual 47 * commands through the Exec dispatch table, or fix up the copied 48 * vertices at execute-time. 49 * 50 * The other case where fixup is required is when a vertex attribute 51 * is introduced in the middle of a primitive. Eg: 52 * Begin(Lines) 53 * TexCoord1f() Vertex2f() 54 * TexCoord1f() Color3f() Vertex2f() 55 * End() 56 * 57 * If the current value of Color isn't known at compile-time, this 58 * primitive will require fixup. 59 * 60 * 61 * The list compiler currently doesn't attempt to compile lists 62 * containing EvalCoord or EvalPoint commands. On encountering one of 63 * these, compilation falls back to opcodes. 64 * 65 * This could be improved to fallback only when a mix of EvalCoord and 66 * Vertex commands are issued within a single primitive. 67 */ 68 69 70#include "main/glheader.h" 71#include "main/bufferobj.h" 72#include "main/context.h" 73#include "main/dlist.h" 74#include "main/enums.h" 75#include "main/eval.h" 76#include "main/macros.h" 77#include "main/api_validate.h" 78#include "main/api_arrayelt.h" 79#include "main/vtxfmt.h" 80#include "main/dispatch.h" 81 82#include "vbo_context.h" 83#include "vbo_noop.h" 84 85 86#ifdef ERROR 87#undef ERROR 88#endif 89 90 91/* An interesting VBO number/name to help with debugging */ 92#define VBO_BUF_ID 12345 93 94 95/* 96 * NOTE: Old 'parity' issue is gone, but copying can still be 97 * wrong-footed on replay. 98 */ 99static GLuint 100_save_copy_vertices(struct gl_context *ctx, 101 const struct vbo_save_vertex_list *node, 102 const GLfloat * src_buffer) 103{ 104 struct vbo_save_context *save = &vbo_context(ctx)->save; 105 const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; 106 GLuint nr = prim->count; 107 GLuint sz = save->vertex_size; 108 const GLfloat *src = src_buffer + prim->start * sz; 109 GLfloat *dst = save->copied.buffer; 110 GLuint ovf, i; 111 112 if (prim->end) 113 return 0; 114 115 switch (prim->mode) { 116 case GL_POINTS: 117 return 0; 118 case GL_LINES: 119 ovf = nr & 1; 120 for (i = 0; i < ovf; i++) 121 memcpy(dst + i * sz, src + (nr - ovf + i) * sz, 122 sz * sizeof(GLfloat)); 123 return i; 124 case GL_TRIANGLES: 125 ovf = nr % 3; 126 for (i = 0; i < ovf; i++) 127 memcpy(dst + i * sz, src + (nr - ovf + i) * sz, 128 sz * sizeof(GLfloat)); 129 return i; 130 case GL_QUADS: 131 ovf = nr & 3; 132 for (i = 0; i < ovf; i++) 133 memcpy(dst + i * sz, src + (nr - ovf + i) * sz, 134 sz * sizeof(GLfloat)); 135 return i; 136 case GL_LINE_STRIP: 137 if (nr == 0) 138 return 0; 139 else { 140 memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat)); 141 return 1; 142 } 143 case GL_LINE_LOOP: 144 case GL_TRIANGLE_FAN: 145 case GL_POLYGON: 146 if (nr == 0) 147 return 0; 148 else if (nr == 1) { 149 memcpy(dst, src + 0, sz * sizeof(GLfloat)); 150 return 1; 151 } 152 else { 153 memcpy(dst, src + 0, sz * sizeof(GLfloat)); 154 memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat)); 155 return 2; 156 } 157 case GL_TRIANGLE_STRIP: 158 case GL_QUAD_STRIP: 159 switch (nr) { 160 case 0: 161 ovf = 0; 162 break; 163 case 1: 164 ovf = 1; 165 break; 166 default: 167 ovf = 2 + (nr & 1); 168 break; 169 } 170 for (i = 0; i < ovf; i++) 171 memcpy(dst + i * sz, src + (nr - ovf + i) * sz, 172 sz * sizeof(GLfloat)); 173 return i; 174 default: 175 assert(0); 176 return 0; 177 } 178} 179 180 181static struct vbo_save_vertex_store * 182alloc_vertex_store(struct gl_context *ctx) 183{ 184 struct vbo_save_context *save = &vbo_context(ctx)->save; 185 struct vbo_save_vertex_store *vertex_store = 186 CALLOC_STRUCT(vbo_save_vertex_store); 187 188 /* obj->Name needs to be non-zero, but won't ever be examined more 189 * closely than that. In particular these buffers won't be entered 190 * into the hash and can never be confused with ones visible to the 191 * user. Perhaps there could be a special number for internal 192 * buffers: 193 */ 194 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, 195 VBO_BUF_ID, 196 GL_ARRAY_BUFFER_ARB); 197 if (vertex_store->bufferobj) { 198 save->out_of_memory = 199 !ctx->Driver.BufferData(ctx, 200 GL_ARRAY_BUFFER_ARB, 201 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), 202 NULL, GL_STATIC_DRAW_ARB, 203 vertex_store->bufferobj); 204 } 205 else { 206 save->out_of_memory = GL_TRUE; 207 } 208 209 if (save->out_of_memory) { 210 _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation"); 211 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); 212 } 213 214 vertex_store->buffer = NULL; 215 vertex_store->used = 0; 216 vertex_store->refcount = 1; 217 218 return vertex_store; 219} 220 221 222static void 223free_vertex_store(struct gl_context *ctx, 224 struct vbo_save_vertex_store *vertex_store) 225{ 226 assert(!vertex_store->buffer); 227 228 if (vertex_store->bufferobj) { 229 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); 230 } 231 232 free(vertex_store); 233} 234 235 236GLfloat * 237vbo_save_map_vertex_store(struct gl_context *ctx, 238 struct vbo_save_vertex_store *vertex_store) 239{ 240 assert(vertex_store->bufferobj); 241 assert(!vertex_store->buffer); 242 if (vertex_store->bufferobj->Size > 0) { 243 vertex_store->buffer = 244 (GLfloat *) ctx->Driver.MapBufferRange(ctx, 0, 245 vertex_store->bufferobj->Size, 246 GL_MAP_WRITE_BIT, /* not used */ 247 vertex_store->bufferobj); 248 assert(vertex_store->buffer); 249 return vertex_store->buffer + vertex_store->used; 250 } 251 else { 252 /* probably ran out of memory for buffers */ 253 return NULL; 254 } 255} 256 257 258void 259vbo_save_unmap_vertex_store(struct gl_context *ctx, 260 struct vbo_save_vertex_store *vertex_store) 261{ 262 if (vertex_store->bufferobj->Size > 0) { 263 ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj); 264 } 265 vertex_store->buffer = NULL; 266} 267 268 269static struct vbo_save_primitive_store * 270alloc_prim_store(struct gl_context *ctx) 271{ 272 struct vbo_save_primitive_store *store = 273 CALLOC_STRUCT(vbo_save_primitive_store); 274 (void) ctx; 275 store->used = 0; 276 store->refcount = 1; 277 return store; 278} 279 280 281static void 282_save_reset_counters(struct gl_context *ctx) 283{ 284 struct vbo_save_context *save = &vbo_context(ctx)->save; 285 286 save->prim = save->prim_store->buffer + save->prim_store->used; 287 save->buffer = save->vertex_store->buffer + save->vertex_store->used; 288 289 assert(save->buffer == save->buffer_ptr); 290 291 if (save->vertex_size) 292 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 293 save->vertex_size); 294 else 295 save->max_vert = 0; 296 297 save->vert_count = 0; 298 save->prim_count = 0; 299 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; 300 save->dangling_attr_ref = 0; 301} 302 303/** 304 * For a list of prims, try merging prims that can just be extensions of the 305 * previous prim. 306 */ 307static void 308vbo_merge_prims(struct gl_context *ctx, 309 struct _mesa_prim *prim_list, 310 GLuint *prim_count) 311{ 312 GLuint i; 313 struct _mesa_prim *prev_prim = prim_list; 314 315 for (i = 1; i < *prim_count; i++) { 316 struct _mesa_prim *this_prim = prim_list + i; 317 318 if (this_prim->mode == prev_prim->mode && 319 this_prim->mode == GL_QUADS && 320 this_prim->count % 4 == 0 && 321 prev_prim->count % 4 == 0 && 322 this_prim->start == prev_prim->start + prev_prim->count && 323 this_prim->basevertex == prev_prim->basevertex && 324 this_prim->num_instances == prev_prim->num_instances && 325 this_prim->base_instance == prev_prim->base_instance) { 326 /* We've found a prim that just extend the previous one. Tack it 327 * onto the previous one, and let this primitive struct get dropped. 328 */ 329 prev_prim->count += this_prim->count; 330 prev_prim->end = this_prim->end; 331 continue; 332 } 333 334 /* If any previous primitives have been dropped, then we need to copy 335 * this later one into the next available slot. 336 */ 337 prev_prim++; 338 if (prev_prim != this_prim) 339 *prev_prim = *this_prim; 340 } 341 342 *prim_count = prev_prim - prim_list + 1; 343} 344 345/** 346 * Insert the active immediate struct onto the display list currently 347 * being built. 348 */ 349static void 350_save_compile_vertex_list(struct gl_context *ctx) 351{ 352 struct vbo_save_context *save = &vbo_context(ctx)->save; 353 struct vbo_save_vertex_list *node; 354 355 /* Allocate space for this structure in the display list currently 356 * being compiled. 357 */ 358 node = (struct vbo_save_vertex_list *) 359 _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); 360 361 if (!node) 362 return; 363 364 /* Duplicate our template, increment refcounts to the storage structs: 365 */ 366 memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); 367 memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype)); 368 node->vertex_size = save->vertex_size; 369 node->buffer_offset = 370 (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); 371 node->count = save->vert_count; 372 node->wrap_count = save->copied.nr; 373 node->dangling_attr_ref = save->dangling_attr_ref; 374 node->prim = save->prim; 375 node->prim_count = save->prim_count; 376 node->vertex_store = save->vertex_store; 377 node->prim_store = save->prim_store; 378 379 node->vertex_store->refcount++; 380 node->prim_store->refcount++; 381 382 if (node->prim[0].no_current_update) { 383 node->current_size = 0; 384 node->current_data = NULL; 385 } 386 else { 387 node->current_size = node->vertex_size - node->attrsz[0]; 388 node->current_data = NULL; 389 390 if (node->current_size) { 391 /* If the malloc fails, we just pull the data out of the VBO 392 * later instead. 393 */ 394 node->current_data = malloc(node->current_size * sizeof(GLfloat)); 395 if (node->current_data) { 396 const char *buffer = (const char *) save->vertex_store->buffer; 397 unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); 398 unsigned vertex_offset = 0; 399 400 if (node->count) 401 vertex_offset = 402 (node->count - 1) * node->vertex_size * sizeof(GLfloat); 403 404 memcpy(node->current_data, 405 buffer + node->buffer_offset + vertex_offset + attr_offset, 406 node->current_size * sizeof(GLfloat)); 407 } 408 } 409 } 410 411 assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0); 412 413 if (save->dangling_attr_ref) 414 ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; 415 416 save->vertex_store->used += save->vertex_size * node->count; 417 save->prim_store->used += node->prim_count; 418 419 /* Copy duplicated vertices 420 */ 421 save->copied.nr = _save_copy_vertices(ctx, node, save->buffer); 422 423 vbo_merge_prims(ctx, node->prim, &node->prim_count); 424 425 /* Deal with GL_COMPILE_AND_EXECUTE: 426 */ 427 if (ctx->ExecuteFlag) { 428 struct _glapi_table *dispatch = GET_DISPATCH(); 429 430 _glapi_set_dispatch(ctx->Exec); 431 432 vbo_loopback_vertex_list(ctx, 433 (const GLfloat *) ((const char *) save-> 434 vertex_store->buffer + 435 node->buffer_offset), 436 node->attrsz, node->prim, node->prim_count, 437 node->wrap_count, node->vertex_size); 438 439 _glapi_set_dispatch(dispatch); 440 } 441 442 /* Decide whether the storage structs are full, or can be used for 443 * the next vertex lists as well. 444 */ 445 if (save->vertex_store->used > 446 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { 447 448 /* Unmap old store: 449 */ 450 vbo_save_unmap_vertex_store(ctx, save->vertex_store); 451 452 /* Release old reference: 453 */ 454 save->vertex_store->refcount--; 455 assert(save->vertex_store->refcount != 0); 456 save->vertex_store = NULL; 457 458 /* Allocate and map new store: 459 */ 460 save->vertex_store = alloc_vertex_store(ctx); 461 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); 462 save->out_of_memory = save->buffer_ptr == NULL; 463 } 464 465 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { 466 save->prim_store->refcount--; 467 assert(save->prim_store->refcount != 0); 468 save->prim_store = alloc_prim_store(ctx); 469 } 470 471 /* Reset our structures for the next run of vertices: 472 */ 473 _save_reset_counters(ctx); 474} 475 476 477/** 478 * TODO -- If no new vertices have been stored, don't bother saving it. 479 */ 480static void 481_save_wrap_buffers(struct gl_context *ctx) 482{ 483 struct vbo_save_context *save = &vbo_context(ctx)->save; 484 GLint i = save->prim_count - 1; 485 GLenum mode; 486 GLboolean weak; 487 GLboolean no_current_update; 488 489 assert(i < (GLint) save->prim_max); 490 assert(i >= 0); 491 492 /* Close off in-progress primitive. 493 */ 494 save->prim[i].count = (save->vert_count - save->prim[i].start); 495 mode = save->prim[i].mode; 496 weak = save->prim[i].weak; 497 no_current_update = save->prim[i].no_current_update; 498 499 /* store the copied vertices, and allocate a new list. 500 */ 501 _save_compile_vertex_list(ctx); 502 503 /* Restart interrupted primitive 504 */ 505 save->prim[0].mode = mode; 506 save->prim[0].weak = weak; 507 save->prim[0].no_current_update = no_current_update; 508 save->prim[0].begin = 0; 509 save->prim[0].end = 0; 510 save->prim[0].pad = 0; 511 save->prim[0].start = 0; 512 save->prim[0].count = 0; 513 save->prim[0].num_instances = 1; 514 save->prim[0].base_instance = 0; 515 save->prim_count = 1; 516} 517 518 519/** 520 * Called only when buffers are wrapped as the result of filling the 521 * vertex_store struct. 522 */ 523static void 524_save_wrap_filled_vertex(struct gl_context *ctx) 525{ 526 struct vbo_save_context *save = &vbo_context(ctx)->save; 527 GLfloat *data = save->copied.buffer; 528 GLuint i; 529 530 /* Emit a glEnd to close off the last vertex list. 531 */ 532 _save_wrap_buffers(ctx); 533 534 /* Copy stored stored vertices to start of new list. 535 */ 536 assert(save->max_vert - save->vert_count > save->copied.nr); 537 538 for (i = 0; i < save->copied.nr; i++) { 539 memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat)); 540 data += save->vertex_size; 541 save->buffer_ptr += save->vertex_size; 542 save->vert_count++; 543 } 544} 545 546 547static void 548_save_copy_to_current(struct gl_context *ctx) 549{ 550 struct vbo_save_context *save = &vbo_context(ctx)->save; 551 GLuint i; 552 553 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { 554 if (save->attrsz[i]) { 555 save->currentsz[i][0] = save->attrsz[i]; 556 COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i], 557 save->attrptr[i], save->attrtype[i]); 558 } 559 } 560} 561 562 563static void 564_save_copy_from_current(struct gl_context *ctx) 565{ 566 struct vbo_save_context *save = &vbo_context(ctx)->save; 567 GLint i; 568 569 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { 570 switch (save->attrsz[i]) { 571 case 4: 572 save->attrptr[i][3] = save->current[i][3]; 573 case 3: 574 save->attrptr[i][2] = save->current[i][2]; 575 case 2: 576 save->attrptr[i][1] = save->current[i][1]; 577 case 1: 578 save->attrptr[i][0] = save->current[i][0]; 579 case 0: 580 break; 581 } 582 } 583} 584 585 586/* Flush existing data, set new attrib size, replay copied vertices. 587 */ 588static void 589_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) 590{ 591 struct vbo_save_context *save = &vbo_context(ctx)->save; 592 GLuint oldsz; 593 GLuint i; 594 GLfloat *tmp; 595 596 /* Store the current run of vertices, and emit a GL_END. Emit a 597 * BEGIN in the new buffer. 598 */ 599 if (save->vert_count) 600 _save_wrap_buffers(ctx); 601 else 602 assert(save->copied.nr == 0); 603 604 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case 605 * when the attribute already exists in the vertex and is having 606 * its size increased. 607 */ 608 _save_copy_to_current(ctx); 609 610 /* Fix up sizes: 611 */ 612 oldsz = save->attrsz[attr]; 613 save->attrsz[attr] = newsz; 614 615 save->vertex_size += newsz - oldsz; 616 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 617 save->vertex_size); 618 save->vert_count = 0; 619 620 /* Recalculate all the attrptr[] values: 621 */ 622 for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) { 623 if (save->attrsz[i]) { 624 save->attrptr[i] = tmp; 625 tmp += save->attrsz[i]; 626 } 627 else { 628 save->attrptr[i] = NULL; /* will not be dereferenced. */ 629 } 630 } 631 632 /* Copy from current to repopulate the vertex with correct values. 633 */ 634 _save_copy_from_current(ctx); 635 636 /* Replay stored vertices to translate them to new format here. 637 * 638 * If there are copied vertices and the new (upgraded) attribute 639 * has not been defined before, this list is somewhat degenerate, 640 * and will need fixup at runtime. 641 */ 642 if (save->copied.nr) { 643 GLfloat *data = save->copied.buffer; 644 GLfloat *dest = save->buffer; 645 GLuint j; 646 647 /* Need to note this and fix up at runtime (or loopback): 648 */ 649 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { 650 assert(oldsz == 0); 651 save->dangling_attr_ref = GL_TRUE; 652 } 653 654 for (i = 0; i < save->copied.nr; i++) { 655 for (j = 0; j < VBO_ATTRIB_MAX; j++) { 656 if (save->attrsz[j]) { 657 if (j == attr) { 658 if (oldsz) { 659 COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data, 660 save->attrtype[j]); 661 data += oldsz; 662 dest += newsz; 663 } 664 else { 665 COPY_SZ_4V(dest, newsz, save->current[attr]); 666 dest += newsz; 667 } 668 } 669 else { 670 GLint sz = save->attrsz[j]; 671 COPY_SZ_4V(dest, sz, data); 672 data += sz; 673 dest += sz; 674 } 675 } 676 } 677 } 678 679 save->buffer_ptr = dest; 680 save->vert_count += save->copied.nr; 681 } 682} 683 684 685static void 686save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz) 687{ 688 struct vbo_save_context *save = &vbo_context(ctx)->save; 689 690 if (sz > save->attrsz[attr]) { 691 /* New size is larger. Need to flush existing vertices and get 692 * an enlarged vertex format. 693 */ 694 _save_upgrade_vertex(ctx, attr, sz); 695 } 696 else if (sz < save->active_sz[attr]) { 697 GLuint i; 698 const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]); 699 700 /* New size is equal or smaller - just need to fill in some 701 * zeros. 702 */ 703 for (i = sz; i <= save->attrsz[attr]; i++) 704 save->attrptr[attr][i - 1] = id[i - 1]; 705 } 706 707 save->active_sz[attr] = sz; 708} 709 710 711static void 712_save_reset_vertex(struct gl_context *ctx) 713{ 714 struct vbo_save_context *save = &vbo_context(ctx)->save; 715 GLuint i; 716 717 for (i = 0; i < VBO_ATTRIB_MAX; i++) { 718 save->attrsz[i] = 0; 719 save->active_sz[i] = 0; 720 } 721 722 save->vertex_size = 0; 723} 724 725 726 727#define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__); 728 729 730/* Only one size for each attribute may be active at once. Eg. if 731 * Color3f is installed/active, then Color4f may not be, even if the 732 * vertex actually contains 4 color coordinates. This is because the 733 * 3f version won't otherwise set color[3] to 1.0 -- this is the job 734 * of the chooser function when switching between Color4f and Color3f. 735 */ 736#define ATTR(A, N, T, V0, V1, V2, V3) \ 737do { \ 738 struct vbo_save_context *save = &vbo_context(ctx)->save; \ 739 \ 740 if (save->active_sz[A] != N) \ 741 save_fixup_vertex(ctx, A, N); \ 742 \ 743 { \ 744 GLfloat *dest = save->attrptr[A]; \ 745 if (N>0) dest[0] = V0; \ 746 if (N>1) dest[1] = V1; \ 747 if (N>2) dest[2] = V2; \ 748 if (N>3) dest[3] = V3; \ 749 save->attrtype[A] = T; \ 750 } \ 751 \ 752 if ((A) == 0) { \ 753 GLuint i; \ 754 \ 755 for (i = 0; i < save->vertex_size; i++) \ 756 save->buffer_ptr[i] = save->vertex[i]; \ 757 \ 758 save->buffer_ptr += save->vertex_size; \ 759 \ 760 if (++save->vert_count >= save->max_vert) \ 761 _save_wrap_filled_vertex(ctx); \ 762 } \ 763} while (0) 764 765#define TAG(x) _save_##x 766 767#include "vbo_attrib_tmp.h" 768 769 770 771#define MAT( ATTR, N, face, params ) \ 772do { \ 773 if (face != GL_BACK) \ 774 MAT_ATTR( ATTR, N, params ); /* front */ \ 775 if (face != GL_FRONT) \ 776 MAT_ATTR( ATTR + 1, N, params ); /* back */ \ 777} while (0) 778 779 780/** 781 * Save a glMaterial call found between glBegin/End. 782 * glMaterial calls outside Begin/End are handled in dlist.c. 783 */ 784static void GLAPIENTRY 785_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 786{ 787 GET_CURRENT_CONTEXT(ctx); 788 789 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 790 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)"); 791 return; 792 } 793 794 switch (pname) { 795 case GL_EMISSION: 796 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params); 797 break; 798 case GL_AMBIENT: 799 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); 800 break; 801 case GL_DIFFUSE: 802 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); 803 break; 804 case GL_SPECULAR: 805 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params); 806 break; 807 case GL_SHININESS: 808 if (*params < 0 || *params > ctx->Const.MaxShininess) { 809 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)"); 810 } 811 else { 812 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params); 813 } 814 break; 815 case GL_COLOR_INDEXES: 816 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params); 817 break; 818 case GL_AMBIENT_AND_DIFFUSE: 819 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); 820 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); 821 break; 822 default: 823 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)"); 824 return; 825 } 826} 827 828 829/* Cope with EvalCoord/CallList called within a begin/end object: 830 * -- Flush current buffer 831 * -- Fallback to opcodes for the rest of the begin/end object. 832 */ 833static void 834dlist_fallback(struct gl_context *ctx) 835{ 836 struct vbo_save_context *save = &vbo_context(ctx)->save; 837 838 if (save->vert_count || save->prim_count) { 839 if (save->prim_count > 0) { 840 /* Close off in-progress primitive. */ 841 GLint i = save->prim_count - 1; 842 save->prim[i].count = save->vert_count - save->prim[i].start; 843 } 844 845 /* Need to replay this display list with loopback, 846 * unfortunately, otherwise this primitive won't be handled 847 * properly: 848 */ 849 save->dangling_attr_ref = 1; 850 851 _save_compile_vertex_list(ctx); 852 } 853 854 _save_copy_to_current(ctx); 855 _save_reset_vertex(ctx); 856 _save_reset_counters(ctx); 857 if (save->out_of_memory) { 858 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); 859 } 860 else { 861 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 862 } 863 ctx->Driver.SaveNeedFlush = 0; 864} 865 866 867static void GLAPIENTRY 868_save_EvalCoord1f(GLfloat u) 869{ 870 GET_CURRENT_CONTEXT(ctx); 871 dlist_fallback(ctx); 872 CALL_EvalCoord1f(ctx->Save, (u)); 873} 874 875static void GLAPIENTRY 876_save_EvalCoord1fv(const GLfloat * v) 877{ 878 GET_CURRENT_CONTEXT(ctx); 879 dlist_fallback(ctx); 880 CALL_EvalCoord1fv(ctx->Save, (v)); 881} 882 883static void GLAPIENTRY 884_save_EvalCoord2f(GLfloat u, GLfloat v) 885{ 886 GET_CURRENT_CONTEXT(ctx); 887 dlist_fallback(ctx); 888 CALL_EvalCoord2f(ctx->Save, (u, v)); 889} 890 891static void GLAPIENTRY 892_save_EvalCoord2fv(const GLfloat * v) 893{ 894 GET_CURRENT_CONTEXT(ctx); 895 dlist_fallback(ctx); 896 CALL_EvalCoord2fv(ctx->Save, (v)); 897} 898 899static void GLAPIENTRY 900_save_EvalPoint1(GLint i) 901{ 902 GET_CURRENT_CONTEXT(ctx); 903 dlist_fallback(ctx); 904 CALL_EvalPoint1(ctx->Save, (i)); 905} 906 907static void GLAPIENTRY 908_save_EvalPoint2(GLint i, GLint j) 909{ 910 GET_CURRENT_CONTEXT(ctx); 911 dlist_fallback(ctx); 912 CALL_EvalPoint2(ctx->Save, (i, j)); 913} 914 915static void GLAPIENTRY 916_save_CallList(GLuint l) 917{ 918 GET_CURRENT_CONTEXT(ctx); 919 dlist_fallback(ctx); 920 CALL_CallList(ctx->Save, (l)); 921} 922 923static void GLAPIENTRY 924_save_CallLists(GLsizei n, GLenum type, const GLvoid * v) 925{ 926 GET_CURRENT_CONTEXT(ctx); 927 dlist_fallback(ctx); 928 CALL_CallLists(ctx->Save, (n, type, v)); 929} 930 931 932 933/* This begin is hooked into ... Updating of 934 * ctx->Driver.CurrentSavePrimitive is already taken care of. 935 */ 936GLboolean 937vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) 938{ 939 struct vbo_save_context *save = &vbo_context(ctx)->save; 940 941 GLuint i = save->prim_count++; 942 943 assert(i < save->prim_max); 944 save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; 945 save->prim[i].begin = 1; 946 save->prim[i].end = 0; 947 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; 948 save->prim[i].no_current_update = 949 (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0; 950 save->prim[i].pad = 0; 951 save->prim[i].start = save->vert_count; 952 save->prim[i].count = 0; 953 save->prim[i].num_instances = 1; 954 save->prim[i].base_instance = 0; 955 956 if (save->out_of_memory) { 957 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); 958 } 959 else { 960 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); 961 } 962 ctx->Driver.SaveNeedFlush = 1; 963 return GL_TRUE; 964} 965 966 967static void GLAPIENTRY 968_save_End(void) 969{ 970 GET_CURRENT_CONTEXT(ctx); 971 struct vbo_save_context *save = &vbo_context(ctx)->save; 972 GLint i = save->prim_count - 1; 973 974 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 975 save->prim[i].end = 1; 976 save->prim[i].count = (save->vert_count - save->prim[i].start); 977 978 if (i == (GLint) save->prim_max - 1) { 979 _save_compile_vertex_list(ctx); 980 assert(save->copied.nr == 0); 981 } 982 983 /* Swap out this vertex format while outside begin/end. Any color, 984 * etc. received between here and the next begin will be compiled 985 * as opcodes. 986 */ 987 if (save->out_of_memory) { 988 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); 989 } 990 else { 991 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 992 } 993} 994 995 996/* These are all errors as this vtxfmt is only installed inside 997 * begin/end pairs. 998 */ 999static void GLAPIENTRY 1000_save_DrawElements(GLenum mode, GLsizei count, GLenum type, 1001 const GLvoid * indices) 1002{ 1003 GET_CURRENT_CONTEXT(ctx); 1004 (void) mode; 1005 (void) count; 1006 (void) type; 1007 (void) indices; 1008 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements"); 1009} 1010 1011 1012static void GLAPIENTRY 1013_save_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 1014 GLsizei count, GLenum type, const GLvoid * indices) 1015{ 1016 GET_CURRENT_CONTEXT(ctx); 1017 (void) mode; 1018 (void) start; 1019 (void) end; 1020 (void) count; 1021 (void) type; 1022 (void) indices; 1023 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawRangeElements"); 1024} 1025 1026 1027static void GLAPIENTRY 1028_save_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 1029 const GLvoid * indices, GLint basevertex) 1030{ 1031 GET_CURRENT_CONTEXT(ctx); 1032 (void) mode; 1033 (void) count; 1034 (void) type; 1035 (void) indices; 1036 (void) basevertex; 1037 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements"); 1038} 1039 1040 1041static void GLAPIENTRY 1042_save_DrawRangeElementsBaseVertex(GLenum mode, 1043 GLuint start, 1044 GLuint end, 1045 GLsizei count, 1046 GLenum type, 1047 const GLvoid * indices, GLint basevertex) 1048{ 1049 GET_CURRENT_CONTEXT(ctx); 1050 (void) mode; 1051 (void) start; 1052 (void) end; 1053 (void) count; 1054 (void) type; 1055 (void) indices; 1056 (void) basevertex; 1057 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawRangeElements"); 1058} 1059 1060 1061static void GLAPIENTRY 1062_save_DrawArrays(GLenum mode, GLint start, GLsizei count) 1063{ 1064 GET_CURRENT_CONTEXT(ctx); 1065 (void) mode; 1066 (void) start; 1067 (void) count; 1068 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawArrays"); 1069} 1070 1071 1072static void GLAPIENTRY 1073_save_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, 1074 const GLvoid **indices, GLsizei primcount) 1075{ 1076 GET_CURRENT_CONTEXT(ctx); 1077 (void) mode; 1078 (void) count; 1079 (void) type; 1080 (void) indices; 1081 (void) primcount; 1082 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glMultiDrawElements"); 1083} 1084 1085 1086static void GLAPIENTRY 1087_save_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, 1088 GLenum type, const GLvoid * const *indices, 1089 GLsizei primcount, const GLint *basevertex) 1090{ 1091 GET_CURRENT_CONTEXT(ctx); 1092 (void) mode; 1093 (void) count; 1094 (void) type; 1095 (void) indices; 1096 (void) primcount; 1097 (void) basevertex; 1098 _mesa_compile_error(ctx, GL_INVALID_OPERATION, 1099 "glMultiDrawElementsBaseVertex"); 1100} 1101 1102 1103static void GLAPIENTRY 1104_save_DrawTransformFeedback(GLenum mode, GLuint name) 1105{ 1106 GET_CURRENT_CONTEXT(ctx); 1107 (void) mode; 1108 (void) name; 1109 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback"); 1110} 1111 1112 1113static void GLAPIENTRY 1114_save_DrawTransformFeedbackStream(GLenum mode, GLuint name, GLuint stream) 1115{ 1116 GET_CURRENT_CONTEXT(ctx); 1117 (void) mode; 1118 (void) name; 1119 (void) stream; 1120 _mesa_compile_error(ctx, GL_INVALID_OPERATION, 1121 "glDrawTransformFeedbackStream"); 1122} 1123 1124 1125static void GLAPIENTRY 1126_save_DrawTransformFeedbackInstanced(GLenum mode, GLuint name, 1127 GLsizei primcount) 1128{ 1129 GET_CURRENT_CONTEXT(ctx); 1130 (void) mode; 1131 (void) name; 1132 (void) primcount; 1133 _mesa_compile_error(ctx, GL_INVALID_OPERATION, 1134 "glDrawTransformFeedbackInstanced"); 1135} 1136 1137 1138static void GLAPIENTRY 1139_save_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, 1140 GLuint stream, GLsizei primcount) 1141{ 1142 GET_CURRENT_CONTEXT(ctx); 1143 (void) mode; 1144 (void) name; 1145 (void) stream; 1146 (void) primcount; 1147 _mesa_compile_error(ctx, GL_INVALID_OPERATION, 1148 "glDrawTransformFeedbackStreamInstanced"); 1149} 1150 1151 1152static void GLAPIENTRY 1153_save_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) 1154{ 1155 GET_CURRENT_CONTEXT(ctx); 1156 (void) x1; 1157 (void) y1; 1158 (void) x2; 1159 (void) y2; 1160 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glRectf"); 1161} 1162 1163 1164static void GLAPIENTRY 1165_save_EvalMesh1(GLenum mode, GLint i1, GLint i2) 1166{ 1167 GET_CURRENT_CONTEXT(ctx); 1168 (void) mode; 1169 (void) i1; 1170 (void) i2; 1171 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glEvalMesh1"); 1172} 1173 1174 1175static void GLAPIENTRY 1176_save_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) 1177{ 1178 GET_CURRENT_CONTEXT(ctx); 1179 (void) mode; 1180 (void) i1; 1181 (void) i2; 1182 (void) j1; 1183 (void) j2; 1184 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glEvalMesh2"); 1185} 1186 1187 1188static void GLAPIENTRY 1189_save_Begin(GLenum mode) 1190{ 1191 GET_CURRENT_CONTEXT(ctx); 1192 (void) mode; 1193 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin"); 1194} 1195 1196 1197static void GLAPIENTRY 1198_save_PrimitiveRestartNV(void) 1199{ 1200 GLenum curPrim; 1201 GET_CURRENT_CONTEXT(ctx); 1202 1203 curPrim = ctx->Driver.CurrentSavePrimitive; 1204 1205 _save_End(); 1206 _save_Begin(curPrim); 1207} 1208 1209 1210/* Unlike the functions above, these are to be hooked into the vtxfmt 1211 * maintained in ctx->ListState, active when the list is known or 1212 * suspected to be outside any begin/end primitive. 1213 * Note: OBE = Outside Begin/End 1214 */ 1215static void GLAPIENTRY 1216_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) 1217{ 1218 GET_CURRENT_CONTEXT(ctx); 1219 vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK); 1220 CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); 1221 CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); 1222 CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); 1223 CALL_Vertex2f(GET_DISPATCH(), (x1, y2)); 1224 CALL_End(GET_DISPATCH(), ()); 1225} 1226 1227 1228static void GLAPIENTRY 1229_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) 1230{ 1231 GET_CURRENT_CONTEXT(ctx); 1232 struct vbo_save_context *save = &vbo_context(ctx)->save; 1233 GLint i; 1234 1235 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1236 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)"); 1237 return; 1238 } 1239 if (count < 0) { 1240 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)"); 1241 return; 1242 } 1243 1244 if (save->out_of_memory) 1245 return; 1246 1247 _ae_map_vbos(ctx); 1248 1249 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK 1250 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); 1251 1252 for (i = 0; i < count; i++) 1253 CALL_ArrayElement(GET_DISPATCH(), (start + i)); 1254 CALL_End(GET_DISPATCH(), ()); 1255 1256 _ae_unmap_vbos(ctx); 1257} 1258 1259 1260/* Could do better by copying the arrays and element list intact and 1261 * then emitting an indexed prim at runtime. 1262 */ 1263static void GLAPIENTRY 1264_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, 1265 const GLvoid * indices) 1266{ 1267 GET_CURRENT_CONTEXT(ctx); 1268 struct vbo_save_context *save = &vbo_context(ctx)->save; 1269 GLint i; 1270 1271 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1272 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)"); 1273 return; 1274 } 1275 if (count < 0) { 1276 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); 1277 return; 1278 } 1279 if (type != GL_UNSIGNED_BYTE && 1280 type != GL_UNSIGNED_SHORT && 1281 type != GL_UNSIGNED_INT) { 1282 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); 1283 return; 1284 } 1285 1286 if (save->out_of_memory) 1287 return; 1288 1289 _ae_map_vbos(ctx); 1290 1291 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) 1292 indices = 1293 ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices); 1294 1295 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK | 1296 VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); 1297 1298 switch (type) { 1299 case GL_UNSIGNED_BYTE: 1300 for (i = 0; i < count; i++) 1301 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i])); 1302 break; 1303 case GL_UNSIGNED_SHORT: 1304 for (i = 0; i < count; i++) 1305 CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i])); 1306 break; 1307 case GL_UNSIGNED_INT: 1308 for (i = 0; i < count; i++) 1309 CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i])); 1310 break; 1311 default: 1312 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); 1313 break; 1314 } 1315 1316 CALL_End(GET_DISPATCH(), ()); 1317 1318 _ae_unmap_vbos(ctx); 1319} 1320 1321 1322static void GLAPIENTRY 1323_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 1324 GLsizei count, GLenum type, 1325 const GLvoid * indices) 1326{ 1327 GET_CURRENT_CONTEXT(ctx); 1328 struct vbo_save_context *save = &vbo_context(ctx)->save; 1329 1330 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1331 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)"); 1332 return; 1333 } 1334 if (count < 0) { 1335 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1336 "glDrawRangeElements(count<0)"); 1337 return; 1338 } 1339 if (type != GL_UNSIGNED_BYTE && 1340 type != GL_UNSIGNED_SHORT && 1341 type != GL_UNSIGNED_INT) { 1342 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)"); 1343 return; 1344 } 1345 if (end < start) { 1346 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1347 "glDrawRangeElements(end < start)"); 1348 return; 1349 } 1350 1351 if (save->out_of_memory) 1352 return; 1353 1354 _save_OBE_DrawElements(mode, count, type, indices); 1355} 1356 1357 1358static void GLAPIENTRY 1359_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, 1360 const GLvoid **indices, GLsizei primcount) 1361{ 1362 GLsizei i; 1363 1364 for (i = 0; i < primcount; i++) { 1365 if (count[i] > 0) { 1366 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i])); 1367 } 1368 } 1369} 1370 1371 1372static void GLAPIENTRY 1373_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, 1374 GLenum type, 1375 const GLvoid * const *indices, 1376 GLsizei primcount, 1377 const GLint *basevertex) 1378{ 1379 GLsizei i; 1380 1381 for (i = 0; i < primcount; i++) { 1382 if (count[i] > 0) { 1383 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type, 1384 indices[i], 1385 basevertex[i])); 1386 } 1387 } 1388} 1389 1390 1391static void 1392_save_vtxfmt_init(struct gl_context *ctx) 1393{ 1394 struct vbo_save_context *save = &vbo_context(ctx)->save; 1395 GLvertexformat *vfmt = &save->vtxfmt; 1396 1397 vfmt->ArrayElement = _ae_ArrayElement; 1398 1399 vfmt->Color3f = _save_Color3f; 1400 vfmt->Color3fv = _save_Color3fv; 1401 vfmt->Color4f = _save_Color4f; 1402 vfmt->Color4fv = _save_Color4fv; 1403 vfmt->EdgeFlag = _save_EdgeFlag; 1404 vfmt->End = _save_End; 1405 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; 1406 vfmt->FogCoordfEXT = _save_FogCoordfEXT; 1407 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; 1408 vfmt->Indexf = _save_Indexf; 1409 vfmt->Indexfv = _save_Indexfv; 1410 vfmt->Materialfv = _save_Materialfv; 1411 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; 1412 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; 1413 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; 1414 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; 1415 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; 1416 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; 1417 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; 1418 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; 1419 vfmt->Normal3f = _save_Normal3f; 1420 vfmt->Normal3fv = _save_Normal3fv; 1421 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; 1422 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; 1423 vfmt->TexCoord1f = _save_TexCoord1f; 1424 vfmt->TexCoord1fv = _save_TexCoord1fv; 1425 vfmt->TexCoord2f = _save_TexCoord2f; 1426 vfmt->TexCoord2fv = _save_TexCoord2fv; 1427 vfmt->TexCoord3f = _save_TexCoord3f; 1428 vfmt->TexCoord3fv = _save_TexCoord3fv; 1429 vfmt->TexCoord4f = _save_TexCoord4f; 1430 vfmt->TexCoord4fv = _save_TexCoord4fv; 1431 vfmt->Vertex2f = _save_Vertex2f; 1432 vfmt->Vertex2fv = _save_Vertex2fv; 1433 vfmt->Vertex3f = _save_Vertex3f; 1434 vfmt->Vertex3fv = _save_Vertex3fv; 1435 vfmt->Vertex4f = _save_Vertex4f; 1436 vfmt->Vertex4fv = _save_Vertex4fv; 1437 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; 1438 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; 1439 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; 1440 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; 1441 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; 1442 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; 1443 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; 1444 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; 1445 1446 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; 1447 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; 1448 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; 1449 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; 1450 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; 1451 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; 1452 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; 1453 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; 1454 1455 /* integer-valued */ 1456 vfmt->VertexAttribI1i = _save_VertexAttribI1i; 1457 vfmt->VertexAttribI2i = _save_VertexAttribI2i; 1458 vfmt->VertexAttribI3i = _save_VertexAttribI3i; 1459 vfmt->VertexAttribI4i = _save_VertexAttribI4i; 1460 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; 1461 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; 1462 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; 1463 1464 /* unsigned integer-valued */ 1465 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; 1466 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; 1467 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; 1468 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; 1469 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; 1470 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; 1471 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; 1472 1473 vfmt->VertexP2ui = _save_VertexP2ui; 1474 vfmt->VertexP3ui = _save_VertexP3ui; 1475 vfmt->VertexP4ui = _save_VertexP4ui; 1476 vfmt->VertexP2uiv = _save_VertexP2uiv; 1477 vfmt->VertexP3uiv = _save_VertexP3uiv; 1478 vfmt->VertexP4uiv = _save_VertexP4uiv; 1479 1480 vfmt->TexCoordP1ui = _save_TexCoordP1ui; 1481 vfmt->TexCoordP2ui = _save_TexCoordP2ui; 1482 vfmt->TexCoordP3ui = _save_TexCoordP3ui; 1483 vfmt->TexCoordP4ui = _save_TexCoordP4ui; 1484 vfmt->TexCoordP1uiv = _save_TexCoordP1uiv; 1485 vfmt->TexCoordP2uiv = _save_TexCoordP2uiv; 1486 vfmt->TexCoordP3uiv = _save_TexCoordP3uiv; 1487 vfmt->TexCoordP4uiv = _save_TexCoordP4uiv; 1488 1489 vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui; 1490 vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui; 1491 vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui; 1492 vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui; 1493 vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv; 1494 vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv; 1495 vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv; 1496 vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv; 1497 1498 vfmt->NormalP3ui = _save_NormalP3ui; 1499 vfmt->NormalP3uiv = _save_NormalP3uiv; 1500 1501 vfmt->ColorP3ui = _save_ColorP3ui; 1502 vfmt->ColorP4ui = _save_ColorP4ui; 1503 vfmt->ColorP3uiv = _save_ColorP3uiv; 1504 vfmt->ColorP4uiv = _save_ColorP4uiv; 1505 1506 vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui; 1507 vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv; 1508 1509 vfmt->VertexAttribP1ui = _save_VertexAttribP1ui; 1510 vfmt->VertexAttribP2ui = _save_VertexAttribP2ui; 1511 vfmt->VertexAttribP3ui = _save_VertexAttribP3ui; 1512 vfmt->VertexAttribP4ui = _save_VertexAttribP4ui; 1513 1514 vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv; 1515 vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv; 1516 vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv; 1517 vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv; 1518 1519 /* This will all require us to fallback to saving the list as opcodes: 1520 */ 1521 vfmt->CallList = _save_CallList; 1522 vfmt->CallLists = _save_CallLists; 1523 1524 vfmt->EvalCoord1f = _save_EvalCoord1f; 1525 vfmt->EvalCoord1fv = _save_EvalCoord1fv; 1526 vfmt->EvalCoord2f = _save_EvalCoord2f; 1527 vfmt->EvalCoord2fv = _save_EvalCoord2fv; 1528 vfmt->EvalPoint1 = _save_EvalPoint1; 1529 vfmt->EvalPoint2 = _save_EvalPoint2; 1530 vfmt->EvalMesh1 = _save_EvalMesh1; 1531 vfmt->EvalMesh2 = _save_EvalMesh2; 1532 1533 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is 1534 * only used when we're inside a glBegin/End pair. 1535 */ 1536 vfmt->Begin = _save_Begin; 1537 vfmt->Rectf = _save_Rectf; 1538 vfmt->DrawArrays = _save_DrawArrays; 1539 vfmt->DrawElements = _save_DrawElements; 1540 vfmt->DrawRangeElements = _save_DrawRangeElements; 1541 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; 1542 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; 1543 vfmt->MultiDrawElementsEXT = _save_MultiDrawElements; 1544 vfmt->MultiDrawElementsBaseVertex = _save_MultiDrawElementsBaseVertex; 1545 vfmt->DrawTransformFeedback = _save_DrawTransformFeedback; 1546 vfmt->DrawTransformFeedbackStream = _save_DrawTransformFeedbackStream; 1547 vfmt->DrawTransformFeedbackInstanced = _save_DrawTransformFeedbackInstanced; 1548 vfmt->DrawTransformFeedbackStreamInstanced = 1549 _save_DrawTransformFeedbackStreamInstanced; 1550} 1551 1552 1553/** 1554 * Initialize the dispatch table with the VBO functions for display 1555 * list compilation. 1556 */ 1557void 1558vbo_initialize_save_dispatch(const struct gl_context *ctx, 1559 struct _glapi_table *exec) 1560{ 1561 SET_DrawArrays(exec, _save_OBE_DrawArrays); 1562 SET_DrawElements(exec, _save_OBE_DrawElements); 1563 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements); 1564 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements); 1565 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex); 1566 /* Note: other glDraw functins aren't compiled into display lists */ 1567} 1568 1569 1570 1571void 1572vbo_save_SaveFlushVertices(struct gl_context *ctx) 1573{ 1574 struct vbo_save_context *save = &vbo_context(ctx)->save; 1575 1576 /* Noop when we are actually active: 1577 */ 1578 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX) 1579 return; 1580 1581 if (save->vert_count || save->prim_count) 1582 _save_compile_vertex_list(ctx); 1583 1584 _save_copy_to_current(ctx); 1585 _save_reset_vertex(ctx); 1586 _save_reset_counters(ctx); 1587 ctx->Driver.SaveNeedFlush = 0; 1588} 1589 1590 1591void 1592vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) 1593{ 1594 struct vbo_save_context *save = &vbo_context(ctx)->save; 1595 1596 (void) list; 1597 (void) mode; 1598 1599 if (!save->prim_store) 1600 save->prim_store = alloc_prim_store(ctx); 1601 1602 if (!save->vertex_store) 1603 save->vertex_store = alloc_vertex_store(ctx); 1604 1605 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); 1606 1607 _save_reset_vertex(ctx); 1608 _save_reset_counters(ctx); 1609 ctx->Driver.SaveNeedFlush = 0; 1610} 1611 1612 1613void 1614vbo_save_EndList(struct gl_context *ctx) 1615{ 1616 struct vbo_save_context *save = &vbo_context(ctx)->save; 1617 1618 /* EndList called inside a (saved) Begin/End pair? 1619 */ 1620 if (_mesa_inside_dlist_begin_end(ctx)) { 1621 if (save->prim_count > 0) { 1622 GLint i = save->prim_count - 1; 1623 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 1624 save->prim[i].end = 0; 1625 save->prim[i].count = (save->vert_count - save->prim[i].start); 1626 } 1627 1628 /* Make sure this vertex list gets replayed by the "loopback" 1629 * mechanism: 1630 */ 1631 save->dangling_attr_ref = 1; 1632 vbo_save_SaveFlushVertices(ctx); 1633 1634 /* Swap out this vertex format while outside begin/end. Any color, 1635 * etc. received between here and the next begin will be compiled 1636 * as opcodes. 1637 */ 1638 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 1639 } 1640 1641 vbo_save_unmap_vertex_store(ctx, save->vertex_store); 1642 1643 assert(save->vertex_size == 0); 1644} 1645 1646 1647void 1648vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) 1649{ 1650 struct vbo_save_context *save = &vbo_context(ctx)->save; 1651 save->replay_flags |= dlist->Flags; 1652} 1653 1654 1655void 1656vbo_save_EndCallList(struct gl_context *ctx) 1657{ 1658 struct vbo_save_context *save = &vbo_context(ctx)->save; 1659 1660 if (ctx->ListState.CallDepth == 1) { 1661 /* This is correct: want to keep only the VBO_SAVE_FALLBACK 1662 * flag, if it is set: 1663 */ 1664 save->replay_flags &= VBO_SAVE_FALLBACK; 1665 } 1666} 1667 1668 1669static void 1670vbo_destroy_vertex_list(struct gl_context *ctx, void *data) 1671{ 1672 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; 1673 (void) ctx; 1674 1675 if (--node->vertex_store->refcount == 0) 1676 free_vertex_store(ctx, node->vertex_store); 1677 1678 if (--node->prim_store->refcount == 0) 1679 free(node->prim_store); 1680 1681 free(node->current_data); 1682 node->current_data = NULL; 1683} 1684 1685 1686static void 1687vbo_print_vertex_list(struct gl_context *ctx, void *data) 1688{ 1689 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; 1690 GLuint i; 1691 (void) ctx; 1692 1693 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", 1694 node->count, node->prim_count, node->vertex_size); 1695 1696 for (i = 0; i < node->prim_count; i++) { 1697 struct _mesa_prim *prim = &node->prim[i]; 1698 printf(" prim %d: %s%s %d..%d %s %s\n", 1699 i, 1700 _mesa_lookup_prim_by_nr(prim->mode), 1701 prim->weak ? " (weak)" : "", 1702 prim->start, 1703 prim->start + prim->count, 1704 (prim->begin) ? "BEGIN" : "(wrap)", 1705 (prim->end) ? "END" : "(wrap)"); 1706 } 1707} 1708 1709 1710/** 1711 * Called during context creation/init. 1712 */ 1713static void 1714_save_current_init(struct gl_context *ctx) 1715{ 1716 struct vbo_save_context *save = &vbo_context(ctx)->save; 1717 GLint i; 1718 1719 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { 1720 const GLuint j = i - VBO_ATTRIB_POS; 1721 ASSERT(j < VERT_ATTRIB_MAX); 1722 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; 1723 save->current[i] = ctx->ListState.CurrentAttrib[j]; 1724 } 1725 1726 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { 1727 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; 1728 ASSERT(j < MAT_ATTRIB_MAX); 1729 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; 1730 save->current[i] = ctx->ListState.CurrentMaterial[j]; 1731 } 1732} 1733 1734 1735/** 1736 * Initialize the display list compiler. Called during context creation. 1737 */ 1738void 1739vbo_save_api_init(struct vbo_save_context *save) 1740{ 1741 struct gl_context *ctx = save->ctx; 1742 GLuint i; 1743 1744 save->opcode_vertex_list = 1745 _mesa_dlist_alloc_opcode(ctx, 1746 sizeof(struct vbo_save_vertex_list), 1747 vbo_save_playback_vertex_list, 1748 vbo_destroy_vertex_list, 1749 vbo_print_vertex_list); 1750 1751 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; 1752 1753 _save_vtxfmt_init(ctx); 1754 _save_current_init(ctx); 1755 _mesa_noop_vtxfmt_init(&save->vtxfmt_noop); 1756 1757 /* These will actually get set again when binding/drawing */ 1758 for (i = 0; i < VBO_ATTRIB_MAX; i++) 1759 save->inputs[i] = &save->arrays[i]; 1760 1761 /* Hook our array functions into the outside-begin-end vtxfmt in 1762 * ctx->ListState. 1763 */ 1764 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; 1765 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; 1766 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; 1767 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; 1768 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _save_OBE_MultiDrawElements; 1769 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _save_OBE_MultiDrawElementsBaseVertex; 1770} 1771