vbo_save_api.c revision 69c6e21ceb6c2eb0c4b0fae0228027d665027b4e
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/mfeatures.h" 78#include "main/api_noop.h" 79#include "main/api_validate.h" 80#include "main/api_arrayelt.h" 81#include "main/vtxfmt.h" 82#include "main/dispatch.h" 83 84#include "vbo_context.h" 85 86 87#if FEATURE_dlist 88 89 90#ifdef ERROR 91#undef ERROR 92#endif 93 94 95/* An interesting VBO number/name to help with debugging */ 96#define VBO_BUF_ID 12345 97 98 99/* 100 * NOTE: Old 'parity' issue is gone, but copying can still be 101 * wrong-footed on replay. 102 */ 103static GLuint _save_copy_vertices( struct gl_context *ctx, 104 const struct vbo_save_vertex_list *node, 105 const GLfloat *src_buffer) 106{ 107 struct vbo_save_context *save = &vbo_context( ctx )->save; 108 const struct _mesa_prim *prim = &node->prim[node->prim_count-1]; 109 GLuint nr = prim->count; 110 GLuint sz = save->vertex_size; 111 const GLfloat *src = src_buffer + prim->start * sz; 112 GLfloat *dst = save->copied.buffer; 113 GLuint ovf, i; 114 115 if (prim->end) 116 return 0; 117 118 switch( prim->mode ) 119 { 120 case GL_POINTS: 121 return 0; 122 case GL_LINES: 123 ovf = nr&1; 124 for (i = 0 ; i < ovf ; i++) 125 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 126 return i; 127 case GL_TRIANGLES: 128 ovf = nr%3; 129 for (i = 0 ; i < ovf ; i++) 130 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, 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, sz*sizeof(GLfloat) ); 136 return i; 137 case GL_LINE_STRIP: 138 if (nr == 0) 139 return 0; 140 else { 141 memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) ); 142 return 1; 143 } 144 case GL_LINE_LOOP: 145 case GL_TRIANGLE_FAN: 146 case GL_POLYGON: 147 if (nr == 0) 148 return 0; 149 else if (nr == 1) { 150 memcpy( dst, src+0, sz*sizeof(GLfloat) ); 151 return 1; 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: ovf = 0; break; 161 case 1: ovf = 1; break; 162 default: ovf = 2 + (nr&1); break; 163 } 164 for (i = 0 ; i < ovf ; i++) 165 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 166 return i; 167 default: 168 assert(0); 169 return 0; 170 } 171} 172 173 174static struct vbo_save_vertex_store *alloc_vertex_store( struct gl_context *ctx ) 175{ 176 struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store); 177 178 /* obj->Name needs to be non-zero, but won't ever be examined more 179 * closely than that. In particular these buffers won't be entered 180 * into the hash and can never be confused with ones visible to the 181 * user. Perhaps there could be a special number for internal 182 * buffers: 183 */ 184 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, 185 VBO_BUF_ID, 186 GL_ARRAY_BUFFER_ARB); 187 188 ctx->Driver.BufferData( ctx, 189 GL_ARRAY_BUFFER_ARB, 190 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), 191 NULL, 192 GL_STATIC_DRAW_ARB, 193 vertex_store->bufferobj); 194 195 vertex_store->buffer = NULL; 196 vertex_store->used = 0; 197 vertex_store->refcount = 1; 198 199 return vertex_store; 200} 201 202static void free_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) 203{ 204 assert(!vertex_store->buffer); 205 206 if (vertex_store->bufferobj) { 207 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); 208 } 209 210 FREE( vertex_store ); 211} 212 213static GLfloat *map_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) 214{ 215 assert(vertex_store->bufferobj); 216 assert(!vertex_store->buffer); 217 vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, 218 GL_ARRAY_BUFFER_ARB, /* not used */ 219 GL_WRITE_ONLY, /* not used */ 220 vertex_store->bufferobj); 221 222 assert(vertex_store->buffer); 223 return vertex_store->buffer + vertex_store->used; 224} 225 226static void unmap_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) 227{ 228 ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj ); 229 vertex_store->buffer = NULL; 230} 231 232 233static struct vbo_save_primitive_store *alloc_prim_store( struct gl_context *ctx ) 234{ 235 struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store); 236 (void) ctx; 237 store->used = 0; 238 store->refcount = 1; 239 return store; 240} 241 242static void _save_reset_counters( struct gl_context *ctx ) 243{ 244 struct vbo_save_context *save = &vbo_context(ctx)->save; 245 246 save->prim = save->prim_store->buffer + save->prim_store->used; 247 save->buffer = (save->vertex_store->buffer + 248 save->vertex_store->used); 249 250 assert(save->buffer == save->buffer_ptr); 251 252 if (save->vertex_size) 253 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 254 save->vertex_size); 255 else 256 save->max_vert = 0; 257 258 save->vert_count = 0; 259 save->prim_count = 0; 260 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; 261 save->dangling_attr_ref = 0; 262} 263 264 265/* Insert the active immediate struct onto the display list currently 266 * being built. 267 */ 268static void _save_compile_vertex_list( struct gl_context *ctx ) 269{ 270 struct vbo_save_context *save = &vbo_context(ctx)->save; 271 struct vbo_save_vertex_list *node; 272 273 /* Allocate space for this structure in the display list currently 274 * being compiled. 275 */ 276 node = (struct vbo_save_vertex_list *) 277 _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); 278 279 if (!node) 280 return; 281 282 /* Duplicate our template, increment refcounts to the storage structs: 283 */ 284 memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); 285 node->vertex_size = save->vertex_size; 286 node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); 287 node->count = save->vert_count; 288 node->wrap_count = save->copied.nr; 289 node->dangling_attr_ref = save->dangling_attr_ref; 290 node->prim = save->prim; 291 node->prim_count = save->prim_count; 292 node->vertex_store = save->vertex_store; 293 node->prim_store = save->prim_store; 294 295 node->vertex_store->refcount++; 296 node->prim_store->refcount++; 297 298 if (node->prim[0].no_current_update) { 299 node->current_size = 0; 300 node->current_data = NULL; 301 } else { 302 node->current_size = node->vertex_size - node->attrsz[0]; 303 node->current_data = NULL; 304 305 if (node->current_size) { 306 /* If the malloc fails, we just pull the data out of the VBO 307 * later instead. 308 */ 309 node->current_data = MALLOC( node->current_size * sizeof(GLfloat) ); 310 if (node->current_data) { 311 const char *buffer = (const char *)save->vertex_store->buffer; 312 unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); 313 unsigned vertex_offset = 0; 314 315 if (node->count) 316 vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat); 317 318 memcpy( node->current_data, 319 buffer + node->buffer_offset + vertex_offset + attr_offset, 320 node->current_size * sizeof(GLfloat) ); 321 } 322 } 323 } 324 325 326 327 assert(node->attrsz[VBO_ATTRIB_POS] != 0 || 328 node->count == 0); 329 330 if (save->dangling_attr_ref) 331 ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; 332 333 save->vertex_store->used += save->vertex_size * node->count; 334 save->prim_store->used += node->prim_count; 335 336 337 /* Copy duplicated vertices 338 */ 339 save->copied.nr = _save_copy_vertices( ctx, node, save->buffer ); 340 341 342 /* Deal with GL_COMPILE_AND_EXECUTE: 343 */ 344 if (ctx->ExecuteFlag) { 345 struct _glapi_table *dispatch = GET_DISPATCH(); 346 347 _glapi_set_dispatch(ctx->Exec); 348 349 vbo_loopback_vertex_list( ctx, 350 (const GLfloat *)((const char *)save->vertex_store->buffer + 351 node->buffer_offset), 352 node->attrsz, 353 node->prim, 354 node->prim_count, 355 node->wrap_count, 356 node->vertex_size); 357 358 _glapi_set_dispatch(dispatch); 359 } 360 361 362 /* Decide whether the storage structs are full, or can be used for 363 * the next vertex lists as well. 364 */ 365 if (save->vertex_store->used > 366 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { 367 368 /* Unmap old store: 369 */ 370 unmap_vertex_store( ctx, save->vertex_store ); 371 372 /* Release old reference: 373 */ 374 save->vertex_store->refcount--; 375 assert(save->vertex_store->refcount != 0); 376 save->vertex_store = NULL; 377 378 /* Allocate and map new store: 379 */ 380 save->vertex_store = alloc_vertex_store( ctx ); 381 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store ); 382 } 383 384 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { 385 save->prim_store->refcount--; 386 assert(save->prim_store->refcount != 0); 387 save->prim_store = alloc_prim_store( ctx ); 388 } 389 390 /* Reset our structures for the next run of vertices: 391 */ 392 _save_reset_counters( ctx ); 393} 394 395 396/* TODO -- If no new vertices have been stored, don't bother saving 397 * it. 398 */ 399static void _save_wrap_buffers( struct gl_context *ctx ) 400{ 401 struct vbo_save_context *save = &vbo_context(ctx)->save; 402 GLint i = save->prim_count - 1; 403 GLenum mode; 404 GLboolean weak; 405 GLboolean no_current_update; 406 407 assert(i < (GLint) save->prim_max); 408 assert(i >= 0); 409 410 /* Close off in-progress primitive. 411 */ 412 save->prim[i].count = (save->vert_count - 413 save->prim[i].start); 414 mode = save->prim[i].mode; 415 weak = save->prim[i].weak; 416 no_current_update = save->prim[i].no_current_update; 417 418 /* store the copied vertices, and allocate a new list. 419 */ 420 _save_compile_vertex_list( ctx ); 421 422 /* Restart interrupted primitive 423 */ 424 save->prim[0].mode = mode; 425 save->prim[0].weak = weak; 426 save->prim[0].no_current_update = no_current_update; 427 save->prim[0].begin = 0; 428 save->prim[0].end = 0; 429 save->prim[0].pad = 0; 430 save->prim[0].start = 0; 431 save->prim[0].count = 0; 432 save->prim[0].num_instances = 1; 433 save->prim_count = 1; 434} 435 436 437 438/* Called only when buffers are wrapped as the result of filling the 439 * vertex_store struct. 440 */ 441static void _save_wrap_filled_vertex( struct gl_context *ctx ) 442{ 443 struct vbo_save_context *save = &vbo_context(ctx)->save; 444 GLfloat *data = save->copied.buffer; 445 GLuint i; 446 447 /* Emit a glEnd to close off the last vertex list. 448 */ 449 _save_wrap_buffers( ctx ); 450 451 /* Copy stored stored vertices to start of new list. 452 */ 453 assert(save->max_vert - save->vert_count > save->copied.nr); 454 455 for (i = 0 ; i < save->copied.nr ; i++) { 456 memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat)); 457 data += save->vertex_size; 458 save->buffer_ptr += save->vertex_size; 459 save->vert_count++; 460 } 461} 462 463 464static void _save_copy_to_current( struct gl_context *ctx ) 465{ 466 struct vbo_save_context *save = &vbo_context(ctx)->save; 467 GLuint i; 468 469 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 470 if (save->attrsz[i]) { 471 save->currentsz[i][0] = save->attrsz[i]; 472 COPY_CLEAN_4V(save->current[i], 473 save->attrsz[i], 474 save->attrptr[i]); 475 } 476 } 477} 478 479 480static void _save_copy_from_current( struct gl_context *ctx ) 481{ 482 struct vbo_save_context *save = &vbo_context(ctx)->save; 483 GLint i; 484 485 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 486 switch (save->attrsz[i]) { 487 case 4: save->attrptr[i][3] = save->current[i][3]; 488 case 3: save->attrptr[i][2] = save->current[i][2]; 489 case 2: save->attrptr[i][1] = save->current[i][1]; 490 case 1: save->attrptr[i][0] = save->current[i][0]; 491 case 0: break; 492 } 493 } 494} 495 496 497 498 499/* Flush existing data, set new attrib size, replay copied vertices. 500 */ 501static void _save_upgrade_vertex( struct gl_context *ctx, 502 GLuint attr, 503 GLuint newsz ) 504{ 505 struct vbo_save_context *save = &vbo_context(ctx)->save; 506 GLuint oldsz; 507 GLuint i; 508 GLfloat *tmp; 509 510 /* Store the current run of vertices, and emit a GL_END. Emit a 511 * BEGIN in the new buffer. 512 */ 513 if (save->vert_count) 514 _save_wrap_buffers( ctx ); 515 else 516 assert( save->copied.nr == 0 ); 517 518 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case 519 * when the attribute already exists in the vertex and is having 520 * its size increased. 521 */ 522 _save_copy_to_current( ctx ); 523 524 /* Fix up sizes: 525 */ 526 oldsz = save->attrsz[attr]; 527 save->attrsz[attr] = newsz; 528 529 save->vertex_size += newsz - oldsz; 530 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 531 save->vertex_size); 532 save->vert_count = 0; 533 534 /* Recalculate all the attrptr[] values: 535 */ 536 for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) { 537 if (save->attrsz[i]) { 538 save->attrptr[i] = tmp; 539 tmp += save->attrsz[i]; 540 } 541 else 542 save->attrptr[i] = NULL; /* will not be dereferenced. */ 543 } 544 545 /* Copy from current to repopulate the vertex with correct values. 546 */ 547 _save_copy_from_current( ctx ); 548 549 /* Replay stored vertices to translate them to new format here. 550 * 551 * If there are copied vertices and the new (upgraded) attribute 552 * has not been defined before, this list is somewhat degenerate, 553 * and will need fixup at runtime. 554 */ 555 if (save->copied.nr) 556 { 557 GLfloat *data = save->copied.buffer; 558 GLfloat *dest = save->buffer; 559 GLuint j; 560 561 /* Need to note this and fix up at runtime (or loopback): 562 */ 563 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { 564 assert(oldsz == 0); 565 save->dangling_attr_ref = GL_TRUE; 566 } 567 568 for (i = 0 ; i < save->copied.nr ; i++) { 569 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { 570 if (save->attrsz[j]) { 571 if (j == attr) { 572 if (oldsz) { 573 COPY_CLEAN_4V( dest, oldsz, data ); 574 data += oldsz; 575 dest += newsz; 576 } 577 else { 578 COPY_SZ_4V( dest, newsz, save->current[attr] ); 579 dest += newsz; 580 } 581 } 582 else { 583 GLint sz = save->attrsz[j]; 584 COPY_SZ_4V( dest, sz, data ); 585 data += sz; 586 dest += sz; 587 } 588 } 589 } 590 } 591 592 save->buffer_ptr = dest; 593 save->vert_count += save->copied.nr; 594 } 595} 596 597static void save_fixup_vertex( struct gl_context *ctx, GLuint attr, GLuint sz ) 598{ 599 struct vbo_save_context *save = &vbo_context(ctx)->save; 600 601 if (sz > save->attrsz[attr]) { 602 /* New size is larger. Need to flush existing vertices and get 603 * an enlarged vertex format. 604 */ 605 _save_upgrade_vertex( ctx, attr, sz ); 606 } 607 else if (sz < save->active_sz[attr]) { 608 static GLfloat id[4] = { 0, 0, 0, 1 }; 609 GLuint i; 610 611 /* New size is equal or smaller - just need to fill in some 612 * zeros. 613 */ 614 for (i = sz ; i <= save->attrsz[attr] ; i++) 615 save->attrptr[attr][i-1] = id[i-1]; 616 } 617 618 save->active_sz[attr] = sz; 619} 620 621static void _save_reset_vertex( struct gl_context *ctx ) 622{ 623 struct vbo_save_context *save = &vbo_context(ctx)->save; 624 GLuint i; 625 626 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 627 save->attrsz[i] = 0; 628 save->active_sz[i] = 0; 629 } 630 631 save->vertex_size = 0; 632} 633 634 635 636#define ERROR(err) _mesa_compile_error( ctx, err, __FUNCTION__ ); 637 638 639/* Only one size for each attribute may be active at once. Eg. if 640 * Color3f is installed/active, then Color4f may not be, even if the 641 * vertex actually contains 4 color coordinates. This is because the 642 * 3f version won't otherwise set color[3] to 1.0 -- this is the job 643 * of the chooser function when switching between Color4f and Color3f. 644 */ 645#define ATTR( A, N, V0, V1, V2, V3 ) \ 646do { \ 647 struct vbo_save_context *save = &vbo_context(ctx)->save; \ 648 \ 649 if (save->active_sz[A] != N) \ 650 save_fixup_vertex(ctx, A, N); \ 651 \ 652 { \ 653 GLfloat *dest = save->attrptr[A]; \ 654 if (N>0) dest[0] = V0; \ 655 if (N>1) dest[1] = V1; \ 656 if (N>2) dest[2] = V2; \ 657 if (N>3) dest[3] = V3; \ 658 } \ 659 \ 660 if ((A) == 0) { \ 661 GLuint i; \ 662 \ 663 for (i = 0; i < save->vertex_size; i++) \ 664 save->buffer_ptr[i] = save->vertex[i]; \ 665 \ 666 save->buffer_ptr += save->vertex_size; \ 667 \ 668 if (++save->vert_count >= save->max_vert) \ 669 _save_wrap_filled_vertex( ctx ); \ 670 } \ 671} while (0) 672 673#define TAG(x) _save_##x 674 675#include "vbo_attrib_tmp.h" 676 677 678 679 680/* Cope with EvalCoord/CallList called within a begin/end object: 681 * -- Flush current buffer 682 * -- Fallback to opcodes for the rest of the begin/end object. 683 */ 684static void DO_FALLBACK( struct gl_context *ctx ) 685{ 686 struct vbo_save_context *save = &vbo_context(ctx)->save; 687 688 if (save->vert_count || save->prim_count) { 689 GLint i = save->prim_count - 1; 690 691 /* Close off in-progress primitive. 692 */ 693 save->prim[i].count = (save->vert_count - 694 save->prim[i].start); 695 696 /* Need to replay this display list with loopback, 697 * unfortunately, otherwise this primitive won't be handled 698 * properly: 699 */ 700 save->dangling_attr_ref = 1; 701 702 _save_compile_vertex_list( ctx ); 703 } 704 705 _save_copy_to_current( ctx ); 706 _save_reset_vertex( ctx ); 707 _save_reset_counters( ctx ); 708 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 709 ctx->Driver.SaveNeedFlush = 0; 710} 711 712static void GLAPIENTRY _save_EvalCoord1f( GLfloat u ) 713{ 714 GET_CURRENT_CONTEXT(ctx); 715 DO_FALLBACK(ctx); 716 CALL_EvalCoord1f(ctx->Save, (u)); 717} 718 719static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v ) 720{ 721 GET_CURRENT_CONTEXT(ctx); 722 DO_FALLBACK(ctx); 723 CALL_EvalCoord1fv(ctx->Save, (v)); 724} 725 726static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v ) 727{ 728 GET_CURRENT_CONTEXT(ctx); 729 DO_FALLBACK(ctx); 730 CALL_EvalCoord2f(ctx->Save, (u, v)); 731} 732 733static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v ) 734{ 735 GET_CURRENT_CONTEXT(ctx); 736 DO_FALLBACK(ctx); 737 CALL_EvalCoord2fv(ctx->Save, (v)); 738} 739 740static void GLAPIENTRY _save_EvalPoint1( GLint i ) 741{ 742 GET_CURRENT_CONTEXT(ctx); 743 DO_FALLBACK(ctx); 744 CALL_EvalPoint1(ctx->Save, (i)); 745} 746 747static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j ) 748{ 749 GET_CURRENT_CONTEXT(ctx); 750 DO_FALLBACK(ctx); 751 CALL_EvalPoint2(ctx->Save, (i, j)); 752} 753 754static void GLAPIENTRY _save_CallList( GLuint l ) 755{ 756 GET_CURRENT_CONTEXT(ctx); 757 DO_FALLBACK(ctx); 758 CALL_CallList(ctx->Save, (l)); 759} 760 761static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v ) 762{ 763 GET_CURRENT_CONTEXT(ctx); 764 DO_FALLBACK(ctx); 765 CALL_CallLists(ctx->Save, (n, type, v)); 766} 767 768 769 770 771/* This begin is hooked into ... Updating of 772 * ctx->Driver.CurrentSavePrimitive is already taken care of. 773 */ 774GLboolean vbo_save_NotifyBegin( struct gl_context *ctx, GLenum mode ) 775{ 776 struct vbo_save_context *save = &vbo_context(ctx)->save; 777 778 GLuint i = save->prim_count++; 779 780 assert(i < save->prim_max); 781 save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; 782 save->prim[i].begin = 1; 783 save->prim[i].end = 0; 784 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; 785 save->prim[i].no_current_update = (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0; 786 save->prim[i].pad = 0; 787 save->prim[i].start = save->vert_count; 788 save->prim[i].count = 0; 789 save->prim[i].num_instances = 1; 790 791 _mesa_install_save_vtxfmt( ctx, &save->vtxfmt ); 792 ctx->Driver.SaveNeedFlush = 1; 793 return GL_TRUE; 794} 795 796 797 798static void GLAPIENTRY _save_End( void ) 799{ 800 GET_CURRENT_CONTEXT( ctx ); 801 struct vbo_save_context *save = &vbo_context(ctx)->save; 802 GLint i = save->prim_count - 1; 803 804 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 805 save->prim[i].end = 1; 806 save->prim[i].count = (save->vert_count - 807 save->prim[i].start); 808 809 if (i == (GLint) save->prim_max - 1) { 810 _save_compile_vertex_list( ctx ); 811 assert(save->copied.nr == 0); 812 } 813 814 /* Swap out this vertex format while outside begin/end. Any color, 815 * etc. received between here and the next begin will be compiled 816 * as opcodes. 817 */ 818 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 819} 820 821 822/* These are all errors as this vtxfmt is only installed inside 823 * begin/end pairs. 824 */ 825static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type, 826 const GLvoid *indices) 827{ 828 GET_CURRENT_CONTEXT(ctx); 829 (void) mode; (void) count; (void) type; (void) indices; 830 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); 831} 832 833 834static void GLAPIENTRY _save_DrawRangeElements(GLenum mode, 835 GLuint start, GLuint end, 836 GLsizei count, GLenum type, 837 const GLvoid *indices) 838{ 839 GET_CURRENT_CONTEXT(ctx); 840 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices; 841 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); 842} 843 844static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode, 845 GLsizei count, 846 GLenum type, 847 const GLvoid *indices, 848 GLint basevertex) 849{ 850 GET_CURRENT_CONTEXT(ctx); 851 (void) mode; (void) count; (void) type; (void) indices; (void)basevertex; 852 853 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); 854} 855 856static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode, 857 GLuint start, 858 GLuint end, 859 GLsizei count, 860 GLenum type, 861 const GLvoid *indices, 862 GLint basevertex) 863{ 864 GET_CURRENT_CONTEXT(ctx); 865 (void) mode; (void) start; (void) end; (void) count; (void) type; 866 (void) indices; (void)basevertex; 867 868 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); 869} 870 871static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count) 872{ 873 GET_CURRENT_CONTEXT(ctx); 874 (void) mode; (void) start; (void) count; 875 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" ); 876} 877 878static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) 879{ 880 GET_CURRENT_CONTEXT(ctx); 881 (void) x1; (void) y1; (void) x2; (void) y2; 882 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" ); 883} 884 885static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 ) 886{ 887 GET_CURRENT_CONTEXT(ctx); 888 (void) mode; (void) i1; (void) i2; 889 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" ); 890} 891 892static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2, 893 GLint j1, GLint j2 ) 894{ 895 GET_CURRENT_CONTEXT(ctx); 896 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2; 897 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" ); 898} 899 900static void GLAPIENTRY _save_Begin( GLenum mode ) 901{ 902 GET_CURRENT_CONTEXT( ctx ); 903 (void) mode; 904 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" ); 905} 906 907 908static void GLAPIENTRY _save_PrimitiveRestartNV( void ) 909{ 910 GLenum curPrim; 911 GET_CURRENT_CONTEXT( ctx ); 912 913 curPrim = ctx->Driver.CurrentSavePrimitive; 914 915 _save_End(); 916 _save_Begin(curPrim); 917} 918 919 920/* Unlike the functions above, these are to be hooked into the vtxfmt 921 * maintained in ctx->ListState, active when the list is known or 922 * suspected to be outside any begin/end primitive. 923 */ 924static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) 925{ 926 GET_CURRENT_CONTEXT(ctx); 927 vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK ); 928 CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 )); 929 CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 )); 930 CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 )); 931 CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 )); 932 CALL_End(GET_DISPATCH(), ()); 933} 934 935 936static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) 937{ 938 GET_CURRENT_CONTEXT(ctx); 939 GLint i; 940 941 if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) 942 return; 943 944 _ae_map_vbos( ctx ); 945 946 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK | VBO_SAVE_PRIM_NO_CURRENT_UPDATE); 947 948 for (i = 0; i < count; i++) 949 CALL_ArrayElement(GET_DISPATCH(), (start + i)); 950 CALL_End(GET_DISPATCH(), ()); 951 952 _ae_unmap_vbos( ctx ); 953} 954 955/* Could do better by copying the arrays and element list intact and 956 * then emitting an indexed prim at runtime. 957 */ 958static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, 959 const GLvoid *indices) 960{ 961 GET_CURRENT_CONTEXT(ctx); 962 GLint i; 963 964 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) 965 return; 966 967 _ae_map_vbos( ctx ); 968 969 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) 970 indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices); 971 972 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK | VBO_SAVE_PRIM_NO_CURRENT_UPDATE ); 973 974 switch (type) { 975 case GL_UNSIGNED_BYTE: 976 for (i = 0 ; i < count ; i++) 977 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] )); 978 break; 979 case GL_UNSIGNED_SHORT: 980 for (i = 0 ; i < count ; i++) 981 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] )); 982 break; 983 case GL_UNSIGNED_INT: 984 for (i = 0 ; i < count ; i++) 985 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] )); 986 break; 987 default: 988 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 989 break; 990 } 991 992 CALL_End(GET_DISPATCH(), ()); 993 994 _ae_unmap_vbos( ctx ); 995} 996 997static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode, 998 GLuint start, GLuint end, 999 GLsizei count, GLenum type, 1000 const GLvoid *indices) 1001{ 1002 GET_CURRENT_CONTEXT(ctx); 1003 if (_mesa_validate_DrawRangeElements( ctx, mode, 1004 start, end, 1005 count, type, indices, 0 )) 1006 _save_OBE_DrawElements( mode, count, type, indices ); 1007} 1008 1009 1010 1011 1012 1013static void _save_vtxfmt_init( struct gl_context *ctx ) 1014{ 1015 struct vbo_save_context *save = &vbo_context(ctx)->save; 1016 GLvertexformat *vfmt = &save->vtxfmt; 1017 1018 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); 1019 1020 vfmt->Begin = _save_Begin; 1021 vfmt->Color3f = _save_Color3f; 1022 vfmt->Color3fv = _save_Color3fv; 1023 vfmt->Color4f = _save_Color4f; 1024 vfmt->Color4fv = _save_Color4fv; 1025 vfmt->EdgeFlag = _save_EdgeFlag; 1026 vfmt->End = _save_End; 1027 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; 1028 vfmt->FogCoordfEXT = _save_FogCoordfEXT; 1029 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; 1030 vfmt->Indexf = _save_Indexf; 1031 vfmt->Indexfv = _save_Indexfv; 1032 vfmt->Materialfv = _save_Materialfv; 1033 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; 1034 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; 1035 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; 1036 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; 1037 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; 1038 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; 1039 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; 1040 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; 1041 vfmt->Normal3f = _save_Normal3f; 1042 vfmt->Normal3fv = _save_Normal3fv; 1043 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; 1044 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; 1045 vfmt->TexCoord1f = _save_TexCoord1f; 1046 vfmt->TexCoord1fv = _save_TexCoord1fv; 1047 vfmt->TexCoord2f = _save_TexCoord2f; 1048 vfmt->TexCoord2fv = _save_TexCoord2fv; 1049 vfmt->TexCoord3f = _save_TexCoord3f; 1050 vfmt->TexCoord3fv = _save_TexCoord3fv; 1051 vfmt->TexCoord4f = _save_TexCoord4f; 1052 vfmt->TexCoord4fv = _save_TexCoord4fv; 1053 vfmt->Vertex2f = _save_Vertex2f; 1054 vfmt->Vertex2fv = _save_Vertex2fv; 1055 vfmt->Vertex3f = _save_Vertex3f; 1056 vfmt->Vertex3fv = _save_Vertex3fv; 1057 vfmt->Vertex4f = _save_Vertex4f; 1058 vfmt->Vertex4fv = _save_Vertex4fv; 1059 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; 1060 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; 1061 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; 1062 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; 1063 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; 1064 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; 1065 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; 1066 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; 1067 1068 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; 1069 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; 1070 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; 1071 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; 1072 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; 1073 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; 1074 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; 1075 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; 1076 1077 /* integer-valued */ 1078 vfmt->VertexAttribI1i = _save_VertexAttribI1i; 1079 vfmt->VertexAttribI2i = _save_VertexAttribI2i; 1080 vfmt->VertexAttribI3i = _save_VertexAttribI3i; 1081 vfmt->VertexAttribI4i = _save_VertexAttribI4i; 1082 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; 1083 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; 1084 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; 1085 1086 /* unsigned integer-valued */ 1087 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; 1088 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; 1089 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; 1090 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; 1091 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; 1092 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; 1093 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; 1094 1095 /* This will all require us to fallback to saving the list as opcodes: 1096 */ 1097 _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */ 1098 1099 _MESA_INIT_EVAL_VTXFMT(vfmt, _save_); 1100 1101 /* These are all errors as we at least know we are in some sort of 1102 * begin/end pair: 1103 */ 1104 vfmt->Begin = _save_Begin; 1105 vfmt->Rectf = _save_Rectf; 1106 vfmt->DrawArrays = _save_DrawArrays; 1107 vfmt->DrawElements = _save_DrawElements; 1108 vfmt->DrawRangeElements = _save_DrawRangeElements; 1109 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; 1110 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; 1111 /* Loops back into vfmt->DrawElements */ 1112 vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; 1113 vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; 1114} 1115 1116 1117void vbo_save_SaveFlushVertices( struct gl_context *ctx ) 1118{ 1119 struct vbo_save_context *save = &vbo_context(ctx)->save; 1120 1121 /* Noop when we are actually active: 1122 */ 1123 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM || 1124 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON) 1125 return; 1126 1127 if (save->vert_count || 1128 save->prim_count) 1129 _save_compile_vertex_list( ctx ); 1130 1131 _save_copy_to_current( ctx ); 1132 _save_reset_vertex( ctx ); 1133 _save_reset_counters( ctx ); 1134 ctx->Driver.SaveNeedFlush = 0; 1135} 1136 1137void vbo_save_NewList( struct gl_context *ctx, GLuint list, GLenum mode ) 1138{ 1139 struct vbo_save_context *save = &vbo_context(ctx)->save; 1140 1141 (void) list; (void) mode; 1142 1143 if (!save->prim_store) 1144 save->prim_store = alloc_prim_store( ctx ); 1145 1146 if (!save->vertex_store) 1147 save->vertex_store = alloc_vertex_store( ctx ); 1148 1149 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store ); 1150 1151 _save_reset_vertex( ctx ); 1152 _save_reset_counters( ctx ); 1153 ctx->Driver.SaveNeedFlush = 0; 1154} 1155 1156void vbo_save_EndList( struct gl_context *ctx ) 1157{ 1158 struct vbo_save_context *save = &vbo_context(ctx)->save; 1159 1160 /* EndList called inside a (saved) Begin/End pair? 1161 */ 1162 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) { 1163 1164 if (save->prim_count > 0) { 1165 GLint i = save->prim_count - 1; 1166 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 1167 save->prim[i].end = 0; 1168 save->prim[i].count = (save->vert_count - 1169 save->prim[i].start); 1170 } 1171 1172 /* Make sure this vertex list gets replayed by the "loopback" 1173 * mechanism: 1174 */ 1175 save->dangling_attr_ref = 1; 1176 vbo_save_SaveFlushVertices( ctx ); 1177 1178 /* Swap out this vertex format while outside begin/end. Any color, 1179 * etc. received between here and the next begin will be compiled 1180 * as opcodes. 1181 */ 1182 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 1183 } 1184 1185 unmap_vertex_store( ctx, save->vertex_store ); 1186 1187 assert(save->vertex_size == 0); 1188} 1189 1190void vbo_save_BeginCallList( struct gl_context *ctx, struct gl_display_list *dlist ) 1191{ 1192 struct vbo_save_context *save = &vbo_context(ctx)->save; 1193 save->replay_flags |= dlist->Flags; 1194} 1195 1196void vbo_save_EndCallList( struct gl_context *ctx ) 1197{ 1198 struct vbo_save_context *save = &vbo_context(ctx)->save; 1199 1200 if (ctx->ListState.CallDepth == 1) { 1201 /* This is correct: want to keep only the VBO_SAVE_FALLBACK 1202 * flag, if it is set: 1203 */ 1204 save->replay_flags &= VBO_SAVE_FALLBACK; 1205 } 1206} 1207 1208 1209static void vbo_destroy_vertex_list( struct gl_context *ctx, void *data ) 1210{ 1211 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; 1212 (void) ctx; 1213 1214 if ( --node->vertex_store->refcount == 0 ) 1215 free_vertex_store( ctx, node->vertex_store ); 1216 1217 if ( --node->prim_store->refcount == 0 ) 1218 FREE( node->prim_store ); 1219 1220 if (node->current_data) { 1221 FREE(node->current_data); 1222 node->current_data = NULL; 1223 } 1224} 1225 1226 1227static void vbo_print_vertex_list( struct gl_context *ctx, void *data ) 1228{ 1229 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; 1230 GLuint i; 1231 (void) ctx; 1232 1233 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", 1234 node->count, 1235 node->prim_count, 1236 node->vertex_size); 1237 1238 for (i = 0 ; i < node->prim_count ; i++) { 1239 struct _mesa_prim *prim = &node->prim[i]; 1240 _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", 1241 i, 1242 _mesa_lookup_prim_by_nr(prim->mode), 1243 prim->weak ? " (weak)" : "", 1244 prim->start, 1245 prim->start + prim->count, 1246 (prim->begin) ? "BEGIN" : "(wrap)", 1247 (prim->end) ? "END" : "(wrap)"); 1248 } 1249} 1250 1251 1252static void _save_current_init( struct gl_context *ctx ) 1253{ 1254 struct vbo_save_context *save = &vbo_context(ctx)->save; 1255 GLint i; 1256 1257 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { 1258 const GLuint j = i - VBO_ATTRIB_POS; 1259 ASSERT(j < VERT_ATTRIB_MAX); 1260 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; 1261 save->current[i] = ctx->ListState.CurrentAttrib[j]; 1262 } 1263 1264 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { 1265 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; 1266 ASSERT(j < MAT_ATTRIB_MAX); 1267 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; 1268 save->current[i] = ctx->ListState.CurrentMaterial[j]; 1269 } 1270} 1271 1272/** 1273 * Initialize the display list compiler 1274 */ 1275void vbo_save_api_init( struct vbo_save_context *save ) 1276{ 1277 struct gl_context *ctx = save->ctx; 1278 GLuint i; 1279 1280 save->opcode_vertex_list = 1281 _mesa_dlist_alloc_opcode( ctx, 1282 sizeof(struct vbo_save_vertex_list), 1283 vbo_save_playback_vertex_list, 1284 vbo_destroy_vertex_list, 1285 vbo_print_vertex_list ); 1286 1287 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; 1288 1289 _save_vtxfmt_init( ctx ); 1290 _save_current_init( ctx ); 1291 1292 /* These will actually get set again when binding/drawing */ 1293 for (i = 0; i < VBO_ATTRIB_MAX; i++) 1294 save->inputs[i] = &save->arrays[i]; 1295 1296 /* Hook our array functions into the outside-begin-end vtxfmt in 1297 * ctx->ListState. 1298 */ 1299 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; 1300 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; 1301 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; 1302 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; 1303 /* loops back into _save_OBE_DrawElements */ 1304 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; 1305 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; 1306 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 1307} 1308 1309 1310#endif /* FEATURE_dlist */ 1311