vbo_save_api.c revision b76f6d9557ff27140e18cf8aa2b57db8876d5d4d
11e57a46299244793beb27e74be171d1540606999oliviermartin/************************************************************************** 21e57a46299244793beb27e74be171d1540606999oliviermartin 3c26aa6f1d4d2612bccf10557a8a6b160f6d68b3foliviermartinCopyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas. 41e57a46299244793beb27e74be171d1540606999oliviermartin 51e57a46299244793beb27e74be171d1540606999oliviermartinAll Rights Reserved. 61e57a46299244793beb27e74be171d1540606999oliviermartin 71e57a46299244793beb27e74be171d1540606999oliviermartinPermission is hereby granted, free of charge, to any person obtaining a 81e57a46299244793beb27e74be171d1540606999oliviermartincopy of this software and associated documentation files (the "Software"), 91e57a46299244793beb27e74be171d1540606999oliviermartinto deal in the Software without restriction, including without limitation 101e57a46299244793beb27e74be171d1540606999oliviermartinon the rights to use, copy, modify, merge, publish, distribute, sub 111e57a46299244793beb27e74be171d1540606999oliviermartinlicense, and/or sell copies of the Software, and to permit persons to whom 121e57a46299244793beb27e74be171d1540606999oliviermartinthe Software is furnished to do so, subject to the following conditions: 131e57a46299244793beb27e74be171d1540606999oliviermartin 141e57a46299244793beb27e74be171d1540606999oliviermartinThe above copyright notice and this permission notice (including the next 151e57a46299244793beb27e74be171d1540606999oliviermartinparagraph) shall be included in all copies or substantial portions of the 161e57a46299244793beb27e74be171d1540606999oliviermartinSoftware. 171e57a46299244793beb27e74be171d1540606999oliviermartin 181e57a46299244793beb27e74be171d1540606999oliviermartinTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 191e57a46299244793beb27e74be171d1540606999oliviermartinIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 201e57a46299244793beb27e74be171d1540606999oliviermartinFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 211e57a46299244793beb27e74be171d1540606999oliviermartinTUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 221e57a46299244793beb27e74be171d1540606999oliviermartinDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 231e57a46299244793beb27e74be171d1540606999oliviermartinOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 241e57a46299244793beb27e74be171d1540606999oliviermartinUSE OR OTHER DEALINGS IN THE SOFTWARE. 251e57a46299244793beb27e74be171d1540606999oliviermartin 261e57a46299244793beb27e74be171d1540606999oliviermartin**************************************************************************/ 271e57a46299244793beb27e74be171d1540606999oliviermartin 281e57a46299244793beb27e74be171d1540606999oliviermartin/* 291e57a46299244793beb27e74be171d1540606999oliviermartin * Authors: 301e57a46299244793beb27e74be171d1540606999oliviermartin * Keith Whitwell <keith@tungstengraphics.com> 311e57a46299244793beb27e74be171d1540606999oliviermartin */ 321e57a46299244793beb27e74be171d1540606999oliviermartin 331e57a46299244793beb27e74be171d1540606999oliviermartin 341e57a46299244793beb27e74be171d1540606999oliviermartin 351e57a46299244793beb27e74be171d1540606999oliviermartin/* Display list compiler attempts to store lists of vertices with the 361e57a46299244793beb27e74be171d1540606999oliviermartin * same vertex layout. Additionally it attempts to minimize the need 371e57a46299244793beb27e74be171d1540606999oliviermartin * for execute-time fixup of these vertex lists, allowing them to be 381e57a46299244793beb27e74be171d1540606999oliviermartin * cached on hardware. 391e57a46299244793beb27e74be171d1540606999oliviermartin * 401e57a46299244793beb27e74be171d1540606999oliviermartin * There are still some circumstances where this can be thwarted, for 411e57a46299244793beb27e74be171d1540606999oliviermartin * example by building a list that consists of one very long primitive 421e57a46299244793beb27e74be171d1540606999oliviermartin * (eg Begin(Triangles), 1000 vertices, End), and calling that list 431e57a46299244793beb27e74be171d1540606999oliviermartin * from inside a different begin/end object (Begin(Lines), CallList, 441e57a46299244793beb27e74be171d1540606999oliviermartin * End). 451e57a46299244793beb27e74be171d1540606999oliviermartin * 461e57a46299244793beb27e74be171d1540606999oliviermartin * In that case the code will have to replay the list as individual 47c26aa6f1d4d2612bccf10557a8a6b160f6d68b3foliviermartin * commands through the Exec dispatch table, or fix up the copied 481e57a46299244793beb27e74be171d1540606999oliviermartin * vertices at execute-time. 491e57a46299244793beb27e74be171d1540606999oliviermartin * 501e57a46299244793beb27e74be171d1540606999oliviermartin * The other case where fixup is required is when a vertex attribute 511e57a46299244793beb27e74be171d1540606999oliviermartin * is introduced in the middle of a primitive. Eg: 52c0b2e4775dcb06d9016f17f5d22e6276d9b58397oliviermartin * Begin(Lines) 531e57a46299244793beb27e74be171d1540606999oliviermartin * TexCoord1f() Vertex2f() 541e57a46299244793beb27e74be171d1540606999oliviermartin * TexCoord1f() Color3f() Vertex2f() 551e57a46299244793beb27e74be171d1540606999oliviermartin * End() 561e57a46299244793beb27e74be171d1540606999oliviermartin * 571e57a46299244793beb27e74be171d1540606999oliviermartin * If the current value of Color isn't known at compile-time, this 581e57a46299244793beb27e74be171d1540606999oliviermartin * primitive will require fixup. 591e57a46299244793beb27e74be171d1540606999oliviermartin * 601e57a46299244793beb27e74be171d1540606999oliviermartin * 611e57a46299244793beb27e74be171d1540606999oliviermartin * The list compiler currently doesn't attempt to compile lists 621e57a46299244793beb27e74be171d1540606999oliviermartin * containing EvalCoord or EvalPoint commands. On encountering one of 631e57a46299244793beb27e74be171d1540606999oliviermartin * these, compilation falls back to opcodes. 641e57a46299244793beb27e74be171d1540606999oliviermartin * 651e57a46299244793beb27e74be171d1540606999oliviermartin * This could be improved to fallback only when a mix of EvalCoord and 661e57a46299244793beb27e74be171d1540606999oliviermartin * Vertex commands are issued within a single primitive. 671e57a46299244793beb27e74be171d1540606999oliviermartin */ 681e57a46299244793beb27e74be171d1540606999oliviermartin 691e57a46299244793beb27e74be171d1540606999oliviermartin 701e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/glheader.h" 711e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/bufferobj.h" 721e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/context.h" 731e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/dlist.h" 741e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/enums.h" 751e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/eval.h" 761e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/macros.h" 771e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/api_validate.h" 781e57a46299244793beb27e74be171d1540606999oliviermartin#include "main/api_arrayelt.h" 791e57a46299244793beb27e74be171d1540606999oliviermartin#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_validate_DrawArrays(ctx, mode, start, count)) 1236 return; 1237 1238 if (save->out_of_memory) 1239 return; 1240 1241 _ae_map_vbos(ctx); 1242 1243 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK 1244 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); 1245 1246 for (i = 0; i < count; i++) 1247 CALL_ArrayElement(GET_DISPATCH(), (start + i)); 1248 CALL_End(GET_DISPATCH(), ()); 1249 1250 _ae_unmap_vbos(ctx); 1251} 1252 1253 1254/* Could do better by copying the arrays and element list intact and 1255 * then emitting an indexed prim at runtime. 1256 */ 1257static void GLAPIENTRY 1258_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, 1259 const GLvoid * indices) 1260{ 1261 GET_CURRENT_CONTEXT(ctx); 1262 struct vbo_save_context *save = &vbo_context(ctx)->save; 1263 GLint i; 1264 1265 if (!_mesa_validate_DrawElements(ctx, mode, count, type, indices, 0)) 1266 return; 1267 1268 if (save->out_of_memory) 1269 return; 1270 1271 _ae_map_vbos(ctx); 1272 1273 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) 1274 indices = 1275 ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices); 1276 1277 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK | 1278 VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); 1279 1280 switch (type) { 1281 case GL_UNSIGNED_BYTE: 1282 for (i = 0; i < count; i++) 1283 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i])); 1284 break; 1285 case GL_UNSIGNED_SHORT: 1286 for (i = 0; i < count; i++) 1287 CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i])); 1288 break; 1289 case GL_UNSIGNED_INT: 1290 for (i = 0; i < count; i++) 1291 CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i])); 1292 break; 1293 default: 1294 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); 1295 break; 1296 } 1297 1298 CALL_End(GET_DISPATCH(), ()); 1299 1300 _ae_unmap_vbos(ctx); 1301} 1302 1303 1304static void GLAPIENTRY 1305_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 1306 GLsizei count, GLenum type, 1307 const GLvoid * indices) 1308{ 1309 GET_CURRENT_CONTEXT(ctx); 1310 struct vbo_save_context *save = &vbo_context(ctx)->save; 1311 1312 if (!_mesa_validate_DrawRangeElements(ctx, mode, 1313 start, end, count, type, indices, 0)) 1314 return; 1315 1316 if (save->out_of_memory) 1317 return; 1318 1319 _save_OBE_DrawElements(mode, count, type, indices); 1320} 1321 1322 1323static void GLAPIENTRY 1324_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, 1325 const GLvoid **indices, GLsizei primcount) 1326{ 1327 GLsizei i; 1328 1329 for (i = 0; i < primcount; i++) { 1330 if (count[i] > 0) { 1331 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i])); 1332 } 1333 } 1334} 1335 1336 1337static void GLAPIENTRY 1338_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, 1339 GLenum type, 1340 const GLvoid * const *indices, 1341 GLsizei primcount, 1342 const GLint *basevertex) 1343{ 1344 GLsizei i; 1345 1346 for (i = 0; i < primcount; i++) { 1347 if (count[i] > 0) { 1348 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type, 1349 indices[i], 1350 basevertex[i])); 1351 } 1352 } 1353} 1354 1355 1356static void 1357_save_vtxfmt_init(struct gl_context *ctx) 1358{ 1359 struct vbo_save_context *save = &vbo_context(ctx)->save; 1360 GLvertexformat *vfmt = &save->vtxfmt; 1361 1362 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); 1363 1364 vfmt->Begin = _save_Begin; 1365 vfmt->Color3f = _save_Color3f; 1366 vfmt->Color3fv = _save_Color3fv; 1367 vfmt->Color4f = _save_Color4f; 1368 vfmt->Color4fv = _save_Color4fv; 1369 vfmt->EdgeFlag = _save_EdgeFlag; 1370 vfmt->End = _save_End; 1371 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; 1372 vfmt->FogCoordfEXT = _save_FogCoordfEXT; 1373 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; 1374 vfmt->Indexf = _save_Indexf; 1375 vfmt->Indexfv = _save_Indexfv; 1376 vfmt->Materialfv = _save_Materialfv; 1377 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; 1378 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; 1379 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; 1380 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; 1381 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; 1382 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; 1383 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; 1384 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; 1385 vfmt->Normal3f = _save_Normal3f; 1386 vfmt->Normal3fv = _save_Normal3fv; 1387 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; 1388 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; 1389 vfmt->TexCoord1f = _save_TexCoord1f; 1390 vfmt->TexCoord1fv = _save_TexCoord1fv; 1391 vfmt->TexCoord2f = _save_TexCoord2f; 1392 vfmt->TexCoord2fv = _save_TexCoord2fv; 1393 vfmt->TexCoord3f = _save_TexCoord3f; 1394 vfmt->TexCoord3fv = _save_TexCoord3fv; 1395 vfmt->TexCoord4f = _save_TexCoord4f; 1396 vfmt->TexCoord4fv = _save_TexCoord4fv; 1397 vfmt->Vertex2f = _save_Vertex2f; 1398 vfmt->Vertex2fv = _save_Vertex2fv; 1399 vfmt->Vertex3f = _save_Vertex3f; 1400 vfmt->Vertex3fv = _save_Vertex3fv; 1401 vfmt->Vertex4f = _save_Vertex4f; 1402 vfmt->Vertex4fv = _save_Vertex4fv; 1403 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; 1404 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; 1405 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; 1406 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; 1407 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; 1408 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; 1409 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; 1410 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; 1411 1412 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; 1413 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; 1414 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; 1415 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; 1416 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; 1417 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; 1418 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; 1419 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; 1420 1421 /* integer-valued */ 1422 vfmt->VertexAttribI1i = _save_VertexAttribI1i; 1423 vfmt->VertexAttribI2i = _save_VertexAttribI2i; 1424 vfmt->VertexAttribI3i = _save_VertexAttribI3i; 1425 vfmt->VertexAttribI4i = _save_VertexAttribI4i; 1426 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; 1427 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; 1428 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; 1429 1430 /* unsigned integer-valued */ 1431 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; 1432 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; 1433 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; 1434 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; 1435 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; 1436 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; 1437 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; 1438 1439 vfmt->VertexP2ui = _save_VertexP2ui; 1440 vfmt->VertexP3ui = _save_VertexP3ui; 1441 vfmt->VertexP4ui = _save_VertexP4ui; 1442 vfmt->VertexP2uiv = _save_VertexP2uiv; 1443 vfmt->VertexP3uiv = _save_VertexP3uiv; 1444 vfmt->VertexP4uiv = _save_VertexP4uiv; 1445 1446 vfmt->TexCoordP1ui = _save_TexCoordP1ui; 1447 vfmt->TexCoordP2ui = _save_TexCoordP2ui; 1448 vfmt->TexCoordP3ui = _save_TexCoordP3ui; 1449 vfmt->TexCoordP4ui = _save_TexCoordP4ui; 1450 vfmt->TexCoordP1uiv = _save_TexCoordP1uiv; 1451 vfmt->TexCoordP2uiv = _save_TexCoordP2uiv; 1452 vfmt->TexCoordP3uiv = _save_TexCoordP3uiv; 1453 vfmt->TexCoordP4uiv = _save_TexCoordP4uiv; 1454 1455 vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui; 1456 vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui; 1457 vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui; 1458 vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui; 1459 vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv; 1460 vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv; 1461 vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv; 1462 vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv; 1463 1464 vfmt->NormalP3ui = _save_NormalP3ui; 1465 vfmt->NormalP3uiv = _save_NormalP3uiv; 1466 1467 vfmt->ColorP3ui = _save_ColorP3ui; 1468 vfmt->ColorP4ui = _save_ColorP4ui; 1469 vfmt->ColorP3uiv = _save_ColorP3uiv; 1470 vfmt->ColorP4uiv = _save_ColorP4uiv; 1471 1472 vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui; 1473 vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv; 1474 1475 vfmt->VertexAttribP1ui = _save_VertexAttribP1ui; 1476 vfmt->VertexAttribP2ui = _save_VertexAttribP2ui; 1477 vfmt->VertexAttribP3ui = _save_VertexAttribP3ui; 1478 vfmt->VertexAttribP4ui = _save_VertexAttribP4ui; 1479 1480 vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv; 1481 vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv; 1482 vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv; 1483 vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv; 1484 1485 /* This will all require us to fallback to saving the list as opcodes: 1486 */ 1487 _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */ 1488 1489 _MESA_INIT_EVAL_VTXFMT(vfmt, _save_); 1490 1491 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is 1492 * only used when we're inside a glBegin/End pair. 1493 */ 1494 vfmt->Begin = _save_Begin; 1495 vfmt->Rectf = _save_Rectf; 1496 vfmt->DrawArrays = _save_DrawArrays; 1497 vfmt->DrawElements = _save_DrawElements; 1498 vfmt->DrawRangeElements = _save_DrawRangeElements; 1499 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; 1500 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; 1501 vfmt->MultiDrawElementsEXT = _save_MultiDrawElements; 1502 vfmt->MultiDrawElementsBaseVertex = _save_MultiDrawElementsBaseVertex; 1503 vfmt->DrawTransformFeedback = _save_DrawTransformFeedback; 1504 vfmt->DrawTransformFeedbackStream = _save_DrawTransformFeedbackStream; 1505 vfmt->DrawTransformFeedbackInstanced = _save_DrawTransformFeedbackInstanced; 1506 vfmt->DrawTransformFeedbackStreamInstanced = 1507 _save_DrawTransformFeedbackStreamInstanced; 1508} 1509 1510 1511void 1512vbo_save_SaveFlushVertices(struct gl_context *ctx) 1513{ 1514 struct vbo_save_context *save = &vbo_context(ctx)->save; 1515 1516 /* Noop when we are actually active: 1517 */ 1518 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM || 1519 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON) 1520 return; 1521 1522 if (save->vert_count || save->prim_count) 1523 _save_compile_vertex_list(ctx); 1524 1525 _save_copy_to_current(ctx); 1526 _save_reset_vertex(ctx); 1527 _save_reset_counters(ctx); 1528 ctx->Driver.SaveNeedFlush = 0; 1529} 1530 1531 1532void 1533vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) 1534{ 1535 struct vbo_save_context *save = &vbo_context(ctx)->save; 1536 1537 (void) list; 1538 (void) mode; 1539 1540 if (!save->prim_store) 1541 save->prim_store = alloc_prim_store(ctx); 1542 1543 if (!save->vertex_store) 1544 save->vertex_store = alloc_vertex_store(ctx); 1545 1546 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); 1547 1548 _save_reset_vertex(ctx); 1549 _save_reset_counters(ctx); 1550 ctx->Driver.SaveNeedFlush = 0; 1551} 1552 1553 1554void 1555vbo_save_EndList(struct gl_context *ctx) 1556{ 1557 struct vbo_save_context *save = &vbo_context(ctx)->save; 1558 1559 /* EndList called inside a (saved) Begin/End pair? 1560 */ 1561 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) { 1562 1563 if (save->prim_count > 0) { 1564 GLint i = save->prim_count - 1; 1565 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 1566 save->prim[i].end = 0; 1567 save->prim[i].count = (save->vert_count - save->prim[i].start); 1568 } 1569 1570 /* Make sure this vertex list gets replayed by the "loopback" 1571 * mechanism: 1572 */ 1573 save->dangling_attr_ref = 1; 1574 vbo_save_SaveFlushVertices(ctx); 1575 1576 /* Swap out this vertex format while outside begin/end. Any color, 1577 * etc. received between here and the next begin will be compiled 1578 * as opcodes. 1579 */ 1580 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 1581 } 1582 1583 vbo_save_unmap_vertex_store(ctx, save->vertex_store); 1584 1585 assert(save->vertex_size == 0); 1586} 1587 1588 1589void 1590vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) 1591{ 1592 struct vbo_save_context *save = &vbo_context(ctx)->save; 1593 save->replay_flags |= dlist->Flags; 1594} 1595 1596 1597void 1598vbo_save_EndCallList(struct gl_context *ctx) 1599{ 1600 struct vbo_save_context *save = &vbo_context(ctx)->save; 1601 1602 if (ctx->ListState.CallDepth == 1) { 1603 /* This is correct: want to keep only the VBO_SAVE_FALLBACK 1604 * flag, if it is set: 1605 */ 1606 save->replay_flags &= VBO_SAVE_FALLBACK; 1607 } 1608} 1609 1610 1611static void 1612vbo_destroy_vertex_list(struct gl_context *ctx, void *data) 1613{ 1614 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; 1615 (void) ctx; 1616 1617 if (--node->vertex_store->refcount == 0) 1618 free_vertex_store(ctx, node->vertex_store); 1619 1620 if (--node->prim_store->refcount == 0) 1621 free(node->prim_store); 1622 1623 free(node->current_data); 1624 node->current_data = NULL; 1625} 1626 1627 1628static void 1629vbo_print_vertex_list(struct gl_context *ctx, void *data) 1630{ 1631 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; 1632 GLuint i; 1633 (void) ctx; 1634 1635 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", 1636 node->count, node->prim_count, node->vertex_size); 1637 1638 for (i = 0; i < node->prim_count; i++) { 1639 struct _mesa_prim *prim = &node->prim[i]; 1640 printf(" prim %d: %s%s %d..%d %s %s\n", 1641 i, 1642 _mesa_lookup_prim_by_nr(prim->mode), 1643 prim->weak ? " (weak)" : "", 1644 prim->start, 1645 prim->start + prim->count, 1646 (prim->begin) ? "BEGIN" : "(wrap)", 1647 (prim->end) ? "END" : "(wrap)"); 1648 } 1649} 1650 1651 1652/** 1653 * Called during context creation/init. 1654 */ 1655static void 1656_save_current_init(struct gl_context *ctx) 1657{ 1658 struct vbo_save_context *save = &vbo_context(ctx)->save; 1659 GLint i; 1660 1661 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { 1662 const GLuint j = i - VBO_ATTRIB_POS; 1663 ASSERT(j < VERT_ATTRIB_MAX); 1664 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; 1665 save->current[i] = ctx->ListState.CurrentAttrib[j]; 1666 } 1667 1668 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { 1669 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; 1670 ASSERT(j < MAT_ATTRIB_MAX); 1671 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; 1672 save->current[i] = ctx->ListState.CurrentMaterial[j]; 1673 } 1674} 1675 1676 1677/** 1678 * Initialize the display list compiler. Called during context creation. 1679 */ 1680void 1681vbo_save_api_init(struct vbo_save_context *save) 1682{ 1683 struct gl_context *ctx = save->ctx; 1684 GLuint i; 1685 1686 save->opcode_vertex_list = 1687 _mesa_dlist_alloc_opcode(ctx, 1688 sizeof(struct vbo_save_vertex_list), 1689 vbo_save_playback_vertex_list, 1690 vbo_destroy_vertex_list, 1691 vbo_print_vertex_list); 1692 1693 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; 1694 1695 _save_vtxfmt_init(ctx); 1696 _save_current_init(ctx); 1697 _mesa_noop_vtxfmt_init(&save->vtxfmt_noop); 1698 1699 /* These will actually get set again when binding/drawing */ 1700 for (i = 0; i < VBO_ATTRIB_MAX; i++) 1701 save->inputs[i] = &save->arrays[i]; 1702 1703 /* Hook our array functions into the outside-begin-end vtxfmt in 1704 * ctx->ListState. 1705 */ 1706 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; 1707 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; 1708 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; 1709 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; 1710 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _save_OBE_MultiDrawElements; 1711 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _save_OBE_MultiDrawElementsBaseVertex; 1712} 1713