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