vbo_save_api.c revision 7ec681f3
1/************************************************************************** 2 3Copyright 2002-2008 VMware, Inc. 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 21VMWARE 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 <keithw@vmware.com> 31 */ 32 33 34 35/* Display list compiler attempts to store lists of vertices with the 36 * same vertex layout. Additionally it attempts to minimize the need 37 * for execute-time fixup of these vertex lists, allowing them to be 38 * cached on hardware. 39 * 40 * There are still some circumstances where this can be thwarted, for 41 * example by building a list that consists of one very long primitive 42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list 43 * from inside a different begin/end object (Begin(Lines), CallList, 44 * End). 45 * 46 * In that case the code will have to replay the list as individual 47 * commands through the Exec dispatch table, or fix up the copied 48 * vertices at execute-time. 49 * 50 * The other case where fixup is required is when a vertex attribute 51 * is introduced in the middle of a primitive. Eg: 52 * Begin(Lines) 53 * TexCoord1f() Vertex2f() 54 * TexCoord1f() Color3f() Vertex2f() 55 * End() 56 * 57 * If the current value of Color isn't known at compile-time, this 58 * primitive will require fixup. 59 * 60 * 61 * The list compiler currently doesn't attempt to compile lists 62 * containing EvalCoord or EvalPoint commands. On encountering one of 63 * these, compilation falls back to opcodes. 64 * 65 * This could be improved to fallback only when a mix of EvalCoord and 66 * Vertex commands are issued within a single primitive. 67 * 68 * The compilation process works as follows. All vertex attributes 69 * except position are copied to vbo_save_context::attrptr (see ATTR_UNION). 70 * 'attrptr' are pointers to vbo_save_context::vertex ordered according to the enabled 71 * attributes (se upgrade_vertex). 72 * When the position attribute is received, all the attributes are then 73 * copied to the vertex_store (see the end of ATTR_UNION). 74 * The vertex_store is simply an extensible float array. 75 * When the vertex list needs to be compiled (see compile_vertex_list), 76 * several transformations are performed: 77 * - some primitives are merged together (eg: two consecutive GL_TRIANGLES 78 * with 3 vertices can be merged in a single GL_TRIANGLES with 6 vertices). 79 * - an index buffer is built. 80 * - identical vertices are detected and only one is kept. 81 * At the end of this transformation, the index buffer and the vertex buffer 82 * are uploaded in vRAM in the same buffer object. 83 * This buffer object is shared between multiple display list to allow 84 * draw calls merging later. 85 * 86 * The layout of this buffer for two display lists is: 87 * V0A0|V0A1|V1A0|V1A1|P0I0|P0I1|V0A0V0A1V0A2|V1A1V1A1V1A2|... 88 * ` new list starts 89 * - VxAy: vertex x, attributes y 90 * - PxIy: draw x, index y 91 * 92 * To allow draw call merging, display list must use the same VAO, including 93 * the same Offset in the buffer object. To achieve this, the start values of 94 * the primitive are shifted and the indices adjusted (see offset_diff and 95 * start_offset in compile_vertex_list). 96 * 97 * Display list using the loopback code (see vbo_save_playback_vertex_list_loopback), 98 * can't be drawn with an index buffer so this transformation is disabled 99 * in this case. 100 */ 101 102 103#include "main/glheader.h" 104#include "main/arrayobj.h" 105#include "main/bufferobj.h" 106#include "main/context.h" 107#include "main/dlist.h" 108#include "main/enums.h" 109#include "main/eval.h" 110#include "main/macros.h" 111#include "main/draw_validate.h" 112#include "main/api_arrayelt.h" 113#include "main/vtxfmt.h" 114#include "main/dispatch.h" 115#include "main/state.h" 116#include "main/varray.h" 117#include "util/bitscan.h" 118#include "util/u_memory.h" 119#include "util/hash_table.h" 120#include "util/u_prim.h" 121 122#include "gallium/include/pipe/p_state.h" 123 124#include "vbo_noop.h" 125#include "vbo_private.h" 126 127 128#ifdef ERROR 129#undef ERROR 130#endif 131 132/* An interesting VBO number/name to help with debugging */ 133#define VBO_BUF_ID 12345 134 135static void GLAPIENTRY 136_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params); 137 138static void GLAPIENTRY 139_save_EvalCoord1f(GLfloat u); 140 141static void GLAPIENTRY 142_save_EvalCoord2f(GLfloat u, GLfloat v); 143 144static void 145handle_out_of_memory(struct gl_context *ctx) 146{ 147 struct vbo_save_context *save = &vbo_context(ctx)->save; 148 _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt); 149 save->out_of_memory = true; 150} 151 152/* 153 * NOTE: Old 'parity' issue is gone, but copying can still be 154 * wrong-footed on replay. 155 */ 156static GLuint 157copy_vertices(struct gl_context *ctx, 158 const struct vbo_save_vertex_list *node, 159 const fi_type * src_buffer) 160{ 161 struct vbo_save_context *save = &vbo_context(ctx)->save; 162 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1]; 163 GLuint sz = save->vertex_size; 164 165 if (prim->end || !prim->count || !sz) 166 return 0; 167 168 const fi_type *src = src_buffer + prim->start * sz; 169 assert(save->copied.buffer == NULL); 170 save->copied.buffer = malloc(sizeof(fi_type) * sz * prim->count); 171 172 unsigned r = vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count, 173 prim->begin, sz, true, save->copied.buffer, src); 174 if (!r) { 175 free(save->copied.buffer); 176 save->copied.buffer = NULL; 177 } 178 return r; 179} 180 181 182static struct vbo_save_primitive_store * 183realloc_prim_store(struct vbo_save_primitive_store *store, int prim_count) 184{ 185 if (store == NULL) 186 store = CALLOC_STRUCT(vbo_save_primitive_store); 187 188 uint32_t old_size = store->size; 189 store->size = prim_count; 190 assert (old_size < store->size); 191 store->prims = realloc(store->prims, store->size * sizeof(struct _mesa_prim)); 192 memset(&store->prims[old_size], 0, (store->size - old_size) * sizeof(struct _mesa_prim)); 193 194 return store; 195} 196 197 198static void 199reset_counters(struct gl_context *ctx) 200{ 201 struct vbo_save_context *save = &vbo_context(ctx)->save; 202 203 save->vertex_store->used = 0; 204 save->prim_store->used = 0; 205 save->dangling_attr_ref = GL_FALSE; 206} 207 208/** 209 * For a list of prims, try merging prims that can just be extensions of the 210 * previous prim. 211 */ 212static void 213merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list, 214 GLuint *prim_count) 215{ 216 GLuint i; 217 struct _mesa_prim *prev_prim = prim_list; 218 219 for (i = 1; i < *prim_count; i++) { 220 struct _mesa_prim *this_prim = prim_list + i; 221 222 vbo_try_prim_conversion(&this_prim->mode, &this_prim->count); 223 224 if (vbo_merge_draws(ctx, true, 225 prev_prim->mode, this_prim->mode, 226 prev_prim->start, this_prim->start, 227 &prev_prim->count, this_prim->count, 228 prev_prim->basevertex, this_prim->basevertex, 229 &prev_prim->end, 230 this_prim->begin, this_prim->end)) { 231 /* We've found a prim that just extend the previous one. Tack it 232 * onto the previous one, and let this primitive struct get dropped. 233 */ 234 continue; 235 } 236 237 /* If any previous primitives have been dropped, then we need to copy 238 * this later one into the next available slot. 239 */ 240 prev_prim++; 241 if (prev_prim != this_prim) 242 *prev_prim = *this_prim; 243 } 244 245 *prim_count = prev_prim - prim_list + 1; 246} 247 248 249/** 250 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers 251 * don't have to worry about handling the _mesa_prim::begin/end flags. 252 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174 253 */ 254static void 255convert_line_loop_to_strip(struct vbo_save_context *save, 256 struct vbo_save_vertex_list *node) 257{ 258 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1]; 259 260 assert(prim->mode == GL_LINE_LOOP); 261 262 if (prim->end) { 263 /* Copy the 0th vertex to end of the buffer and extend the 264 * vertex count by one to finish the line loop. 265 */ 266 const GLuint sz = save->vertex_size; 267 /* 0th vertex: */ 268 const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz; 269 /* end of buffer: */ 270 fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz; 271 272 memcpy(dst, src, sz * sizeof(float)); 273 274 prim->count++; 275 node->cold->vertex_count++; 276 save->vertex_store->used += sz; 277 } 278 279 if (!prim->begin) { 280 /* Drawing the second or later section of a long line loop. 281 * Skip the 0th vertex. 282 */ 283 prim->start++; 284 prim->count--; 285 } 286 287 prim->mode = GL_LINE_STRIP; 288} 289 290 291/* Compare the present vao if it has the same setup. */ 292static bool 293compare_vao(gl_vertex_processing_mode mode, 294 const struct gl_vertex_array_object *vao, 295 const struct gl_buffer_object *bo, GLintptr buffer_offset, 296 GLuint stride, GLbitfield64 vao_enabled, 297 const GLubyte size[VBO_ATTRIB_MAX], 298 const GLenum16 type[VBO_ATTRIB_MAX], 299 const GLuint offset[VBO_ATTRIB_MAX]) 300{ 301 if (!vao) 302 return false; 303 304 /* If the enabled arrays are not the same we are not equal. */ 305 if (vao_enabled != vao->Enabled) 306 return false; 307 308 /* Check the buffer binding at 0 */ 309 if (vao->BufferBinding[0].BufferObj != bo) 310 return false; 311 /* BufferBinding[0].Offset != buffer_offset is checked per attribute */ 312 if (vao->BufferBinding[0].Stride != stride) 313 return false; 314 assert(vao->BufferBinding[0].InstanceDivisor == 0); 315 316 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */ 317 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; 318 319 /* Now check the enabled arrays */ 320 GLbitfield mask = vao_enabled; 321 while (mask) { 322 const int attr = u_bit_scan(&mask); 323 const unsigned char vbo_attr = vao_to_vbo_map[attr]; 324 const GLenum16 tp = type[vbo_attr]; 325 const GLintptr off = offset[vbo_attr] + buffer_offset; 326 const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr]; 327 if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off) 328 return false; 329 if (attrib->Format.Type != tp) 330 return false; 331 if (attrib->Format.Size != size[vbo_attr]) 332 return false; 333 assert(attrib->Format.Format == GL_RGBA); 334 assert(attrib->Format.Normalized == GL_FALSE); 335 assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp)); 336 assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp)); 337 assert(attrib->BufferBindingIndex == 0); 338 } 339 340 return true; 341} 342 343 344/* Create or reuse the vao for the vertex processing mode. */ 345static void 346update_vao(struct gl_context *ctx, 347 gl_vertex_processing_mode mode, 348 struct gl_vertex_array_object **vao, 349 struct gl_buffer_object *bo, GLintptr buffer_offset, 350 GLuint stride, GLbitfield64 vbo_enabled, 351 const GLubyte size[VBO_ATTRIB_MAX], 352 const GLenum16 type[VBO_ATTRIB_MAX], 353 const GLuint offset[VBO_ATTRIB_MAX]) 354{ 355 /* Compute the bitmasks of vao_enabled arrays */ 356 GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled); 357 358 /* 359 * Check if we can possibly reuse the exisiting one. 360 * In the long term we should reset them when something changes. 361 */ 362 if (compare_vao(mode, *vao, bo, buffer_offset, stride, 363 vao_enabled, size, type, offset)) 364 return; 365 366 /* The initial refcount is 1 */ 367 _mesa_reference_vao(ctx, vao, NULL); 368 *vao = _mesa_new_vao(ctx, ~((GLuint)0)); 369 370 /* 371 * assert(stride <= ctx->Const.MaxVertexAttribStride); 372 * MaxVertexAttribStride is not set for drivers that does not 373 * expose GL 44 or GLES 31. 374 */ 375 376 /* Bind the buffer object at binding point 0 */ 377 _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false, 378 false); 379 380 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space 381 * Note that the position/generic0 aliasing is done in the VAO. 382 */ 383 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; 384 /* Now set the enable arrays */ 385 GLbitfield mask = vao_enabled; 386 while (mask) { 387 const int vao_attr = u_bit_scan(&mask); 388 const GLubyte vbo_attr = vao_to_vbo_map[vao_attr]; 389 assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset); 390 391 _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset, 392 size[vbo_attr], type[vbo_attr], offset[vbo_attr]); 393 _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0); 394 } 395 _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled); 396 assert(vao_enabled == (*vao)->Enabled); 397 assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0); 398 399 /* Finalize and freeze the VAO */ 400 _mesa_set_vao_immutable(ctx, *vao); 401} 402 403static void wrap_filled_vertex(struct gl_context *ctx); 404 405/* Grow the vertex storage to accomodate for vertex_count new vertices */ 406static void 407grow_vertex_storage(struct gl_context *ctx, int vertex_count) 408{ 409 struct vbo_save_context *save = &vbo_context(ctx)->save; 410 assert (save->vertex_store); 411 412 int new_size = (save->vertex_store->used + 413 vertex_count * save->vertex_size) * sizeof(GLfloat); 414 415 /* Limit how much memory we allocate. */ 416 if (save->prim_store->used > 0 && 417 vertex_count > 0 && 418 new_size > VBO_SAVE_BUFFER_SIZE) { 419 wrap_filled_vertex(ctx); 420 new_size = VBO_SAVE_BUFFER_SIZE; 421 } 422 423 if (new_size > save->vertex_store->buffer_in_ram_size) { 424 save->vertex_store->buffer_in_ram_size = new_size; 425 save->vertex_store->buffer_in_ram = realloc(save->vertex_store->buffer_in_ram, 426 save->vertex_store->buffer_in_ram_size); 427 if (save->vertex_store->buffer_in_ram == NULL) 428 handle_out_of_memory(ctx); 429 } 430 431} 432 433struct vertex_key { 434 unsigned vertex_size; 435 fi_type *vertex_attributes; 436}; 437 438static uint32_t _hash_vertex_key(const void *key) 439{ 440 struct vertex_key *k = (struct vertex_key*)key; 441 unsigned sz = k->vertex_size; 442 assert(sz); 443 return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float)); 444} 445 446static bool _compare_vertex_key(const void *key1, const void *key2) 447{ 448 struct vertex_key *k1 = (struct vertex_key*)key1; 449 struct vertex_key *k2 = (struct vertex_key*)key2; 450 /* All the compared vertices are going to be drawn with the same VAO, 451 * so we can compare the attributes. */ 452 assert (k1->vertex_size == k2->vertex_size); 453 return memcmp(k1->vertex_attributes, 454 k2->vertex_attributes, 455 k1->vertex_size * sizeof(float)) == 0; 456} 457 458static void _free_entry(struct hash_entry *entry) 459{ 460 free((void*)entry->key); 461} 462 463/* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate 464 * of an existing vertex, return the original index instead. 465 */ 466static uint32_t 467add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index, 468 uint32_t index, fi_type *new_buffer, uint32_t *max_index) 469{ 470 /* If vertex deduplication is disabled return the original index. */ 471 if (!hash_to_index) 472 return index; 473 474 fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index; 475 476 struct vertex_key *key = malloc(sizeof(struct vertex_key)); 477 key->vertex_size = save->vertex_size; 478 key->vertex_attributes = vert; 479 480 struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key); 481 if (entry) { 482 free(key); 483 /* We found an existing vertex with the same hash, return its index. */ 484 return (uintptr_t) entry->data; 485 } else { 486 /* This is a new vertex. Determine a new index and copy its attributes to the vertex 487 * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices 488 * starting at index 0. 489 */ 490 uint32_t n = _mesa_hash_table_num_entries(hash_to_index); 491 *max_index = MAX2(n, *max_index); 492 493 memcpy(&new_buffer[save->vertex_size * n], 494 vert, 495 save->vertex_size * sizeof(fi_type)); 496 497 _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n)); 498 499 /* The index buffer is shared between list compilations, so add the base index to get 500 * the final index. 501 */ 502 return n; 503 } 504} 505 506 507static uint32_t 508get_vertex_count(struct vbo_save_context *save) 509{ 510 if (!save->vertex_size) 511 return 0; 512 return save->vertex_store->used / save->vertex_size; 513} 514 515 516/** 517 * Insert the active immediate struct onto the display list currently 518 * being built. 519 */ 520static void 521compile_vertex_list(struct gl_context *ctx) 522{ 523 struct vbo_save_context *save = &vbo_context(ctx)->save; 524 struct vbo_save_vertex_list *node; 525 526 /* Allocate space for this structure in the display list currently 527 * being compiled. 528 */ 529 node = (struct vbo_save_vertex_list *) 530 _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update); 531 532 if (!node) 533 return; 534 535 memset(node, 0, sizeof(struct vbo_save_vertex_list)); 536 node->cold = calloc(1, sizeof(*node->cold)); 537 538 /* Make sure the pointer is aligned to the size of a pointer */ 539 assert((GLintptr) node % sizeof(void *) == 0); 540 541 const GLsizei stride = save->vertex_size*sizeof(GLfloat); 542 543 node->cold->vertex_count = get_vertex_count(save); 544 node->cold->wrap_count = save->copied.nr; 545 node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used); 546 memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used); 547 node->cold->ib.obj = NULL; 548 node->cold->prim_count = save->prim_store->used; 549 550 if (save->no_current_update) { 551 node->cold->current_data = NULL; 552 } 553 else { 554 GLuint current_size = save->vertex_size - save->attrsz[0]; 555 node->cold->current_data = NULL; 556 557 if (current_size) { 558 node->cold->current_data = malloc(current_size * sizeof(GLfloat)); 559 if (node->cold->current_data) { 560 const char *buffer = (const char *)save->vertex_store->buffer_in_ram; 561 unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat); 562 unsigned vertex_offset = 0; 563 564 if (node->cold->vertex_count) 565 vertex_offset = (node->cold->vertex_count - 1) * stride; 566 567 memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset, 568 current_size * sizeof(GLfloat)); 569 } else { 570 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation"); 571 handle_out_of_memory(ctx); 572 } 573 } 574 } 575 576 assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0); 577 578 if (save->dangling_attr_ref) 579 ctx->ListState.Current.UseLoopback = true; 580 581 /* Copy duplicated vertices 582 */ 583 save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram); 584 585 if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) { 586 convert_line_loop_to_strip(save, node); 587 } 588 589 merge_prims(ctx, node->cold->prims, &node->cold->prim_count); 590 591 GLintptr buffer_offset = 0; 592 GLuint start_offset = 0; 593 594 /* Create an index buffer. */ 595 node->cold->min_index = node->cold->max_index = 0; 596 if (node->cold->vertex_count == 0 || node->cold->prim_count == 0) 597 goto end; 598 599 /* We won't modify node->prims, so use a const alias to avoid unintended 600 * writes to it. */ 601 const struct _mesa_prim *original_prims = node->cold->prims; 602 603 int end = original_prims[node->cold->prim_count - 1].start + 604 original_prims[node->cold->prim_count - 1].count; 605 int total_vert_count = end - original_prims[0].start; 606 607 node->cold->min_index = node->cold->prims[0].start; 608 node->cold->max_index = end - 1; 609 610 int max_index_count = total_vert_count * 2; 611 uint32_t* indices = (uint32_t*) malloc(max_index_count * sizeof(uint32_t)); 612 struct _mesa_prim *merged_prims = NULL; 613 614 int idx = 0; 615 struct hash_table *vertex_to_index = NULL; 616 fi_type *temp_vertices_buffer = NULL; 617 618 /* The loopback replay code doesn't use the index buffer, so we can't 619 * dedup vertices in this case. 620 */ 621 if (!ctx->ListState.Current.UseLoopback) { 622 vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key); 623 temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size); 624 } 625 626 uint32_t max_index = 0; 627 628 int last_valid_prim = -1; 629 /* Construct indices array. */ 630 for (unsigned i = 0; i < node->cold->prim_count; i++) { 631 assert(original_prims[i].basevertex == 0); 632 GLubyte mode = original_prims[i].mode; 633 634 int vertex_count = original_prims[i].count; 635 if (!vertex_count) { 636 continue; 637 } 638 639 /* Increase indices storage if the original estimation was too small. */ 640 if (idx + 3 * vertex_count > max_index_count) { 641 max_index_count = max_index_count + 3 * vertex_count; 642 indices = (uint32_t*) realloc(indices, max_index_count * sizeof(uint32_t)); 643 } 644 645 /* Line strips may get converted to lines */ 646 if (mode == GL_LINE_STRIP) 647 mode = GL_LINES; 648 649 /* If 2 consecutive prims use the same mode => merge them. */ 650 bool merge_prims = last_valid_prim >= 0 && 651 mode == merged_prims[last_valid_prim].mode && 652 mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN && 653 mode != GL_QUAD_STRIP && mode != GL_POLYGON && 654 mode != GL_PATCHES; 655 656 /* To be able to merge consecutive triangle strips we need to insert 657 * a degenerate triangle. 658 */ 659 if (merge_prims && 660 mode == GL_TRIANGLE_STRIP) { 661 /* Insert a degenerate triangle */ 662 assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP); 663 unsigned tri_count = merged_prims[last_valid_prim].count - 2; 664 665 indices[idx] = indices[idx - 1]; 666 indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start, 667 temp_vertices_buffer, &max_index); 668 idx += 2; 669 merged_prims[last_valid_prim].count += 2; 670 671 if (tri_count % 2) { 672 /* Add another index to preserve winding order */ 673 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start, 674 temp_vertices_buffer, &max_index); 675 merged_prims[last_valid_prim].count++; 676 } 677 } 678 679 int start = idx; 680 681 /* Convert line strips to lines if it'll allow if the previous 682 * prim mode is GL_LINES (so merge_prims is true) or if the next 683 * primitive mode is GL_LINES or GL_LINE_LOOP. 684 */ 685 if (original_prims[i].mode == GL_LINE_STRIP && 686 (merge_prims || 687 (i < node->cold->prim_count - 1 && 688 (original_prims[i + 1].mode == GL_LINE_STRIP || 689 original_prims[i + 1].mode == GL_LINES)))) { 690 for (unsigned j = 0; j < vertex_count; j++) { 691 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j, 692 temp_vertices_buffer, &max_index); 693 /* Repeat all but the first/last indices. */ 694 if (j && j != vertex_count - 1) { 695 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j, 696 temp_vertices_buffer, &max_index); 697 } 698 } 699 } else { 700 /* We didn't convert to LINES, so restore the original mode */ 701 mode = original_prims[i].mode; 702 703 for (unsigned j = 0; j < vertex_count; j++) { 704 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j, 705 temp_vertices_buffer, &max_index); 706 } 707 } 708 709 /* Duplicate the last vertex for incomplete primitives */ 710 unsigned min_vert = u_prim_vertex_count(mode)->min; 711 for (unsigned j = vertex_count; j < min_vert; j++) { 712 indices[idx++] = add_vertex(save, vertex_to_index, 713 original_prims[i].start + vertex_count - 1, 714 temp_vertices_buffer, &max_index); 715 } 716 717 if (merge_prims) { 718 /* Update vertex count. */ 719 merged_prims[last_valid_prim].count += idx - start; 720 } else { 721 /* Keep this primitive */ 722 last_valid_prim += 1; 723 assert(last_valid_prim <= i); 724 merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim)); 725 merged_prims[last_valid_prim] = original_prims[i]; 726 merged_prims[last_valid_prim].start = start; 727 merged_prims[last_valid_prim].count = idx - start; 728 } 729 merged_prims[last_valid_prim].mode = mode; 730 } 731 732 assert(idx > 0 && idx <= max_index_count); 733 734 unsigned merged_prim_count = last_valid_prim + 1; 735 node->cold->ib.ptr = NULL; 736 node->cold->ib.count = idx; 737 node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1; 738 739 /* How many bytes do we need to store the indices and the vertices */ 740 total_vert_count = vertex_to_index ? (max_index + 1) : idx; 741 unsigned total_bytes_needed = idx * sizeof(uint32_t) + 742 total_vert_count * save->vertex_size * sizeof(fi_type); 743 744 const GLintptr old_offset = save->VAO[0] ? 745 save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0; 746 if (old_offset != save->current_bo_bytes_used && stride > 0) { 747 GLintptr offset_diff = save->current_bo_bytes_used - old_offset; 748 while (offset_diff > 0 && 749 save->current_bo_bytes_used < save->current_bo->Size && 750 offset_diff % stride != 0) { 751 save->current_bo_bytes_used++; 752 offset_diff = save->current_bo_bytes_used - old_offset; 753 } 754 } 755 buffer_offset = save->current_bo_bytes_used; 756 757 /* Can we reuse the previous bo or should we allocate a new one? */ 758 int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0; 759 if (total_bytes_needed > available_bytes) { 760 if (save->current_bo) 761 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL); 762 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1); 763 bool success = ctx->Driver.BufferData(ctx, 764 GL_ELEMENT_ARRAY_BUFFER_ARB, 765 MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE), 766 NULL, 767 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT, 768 save->current_bo); 769 if (!success) { 770 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL); 771 _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation"); 772 handle_out_of_memory(ctx); 773 } else { 774 save->current_bo_bytes_used = 0; 775 available_bytes = save->current_bo->Size; 776 } 777 buffer_offset = 0; 778 } else { 779 assert(old_offset <= buffer_offset); 780 const GLintptr offset_diff = buffer_offset - old_offset; 781 if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) { 782 /* The vertex size is an exact multiple of the buffer offset. 783 * This means that we can use zero-based vertex attribute pointers 784 * and specify the start of the primitive with the _mesa_prim::start 785 * field. This results in issuing several draw calls with identical 786 * vertex attribute information. This can result in fewer state 787 * changes in drivers. In particular, the Gallium CSO module will 788 * filter out redundant vertex buffer changes. 789 */ 790 /* We cannot immediately update the primitives as some methods below 791 * still need the uncorrected start vertices 792 */ 793 start_offset = offset_diff/stride; 794 assert(old_offset == buffer_offset - offset_diff); 795 buffer_offset = old_offset; 796 } 797 798 /* Correct the primitive starts, we can only do this here as copy_vertices 799 * and convert_line_loop_to_strip above consume the uncorrected starts. 800 * On the other hand the _vbo_loopback_vertex_list call below needs the 801 * primitives to be corrected already. 802 */ 803 for (unsigned i = 0; i < node->cold->prim_count; i++) { 804 node->cold->prims[i].start += start_offset; 805 } 806 /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have 807 * to apply this transformation to all indices and max_index. 808 */ 809 for (unsigned i = 0; i < idx; i++) 810 indices[i] += start_offset; 811 max_index += start_offset; 812 } 813 814 _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo); 815 816 /* Upload the vertices first (see buffer_offset) */ 817 ctx->Driver.BufferSubData(ctx, 818 save->current_bo_bytes_used, 819 total_vert_count * save->vertex_size * sizeof(fi_type), 820 vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram, 821 node->cold->ib.obj); 822 save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type); 823 824 if (vertex_to_index) { 825 _mesa_hash_table_destroy(vertex_to_index, _free_entry); 826 free(temp_vertices_buffer); 827 } 828 829 /* Since we append the indices to an existing buffer, we need to adjust the start value of each 830 * primitive (not the indices themselves). */ 831 if (!ctx->ListState.Current.UseLoopback) { 832 save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used; 833 int indices_offset = save->current_bo_bytes_used / 4; 834 for (int i = 0; i < merged_prim_count; i++) { 835 merged_prims[i].start += indices_offset; 836 } 837 } 838 839 /* Then upload the indices. */ 840 if (node->cold->ib.obj) { 841 ctx->Driver.BufferSubData(ctx, 842 save->current_bo_bytes_used, 843 idx * sizeof(uint32_t), 844 indices, 845 node->cold->ib.obj); 846 save->current_bo_bytes_used += idx * sizeof(uint32_t); 847 } else { 848 node->cold->vertex_count = 0; 849 node->cold->prim_count = 0; 850 } 851 852 /* Prepare for DrawGallium */ 853 memset(&node->merged.info, 0, sizeof(struct pipe_draw_info)); 854 /* The other info fields will be updated in vbo_save_playback_vertex_list */ 855 node->merged.info.index_size = 4; 856 node->merged.info.instance_count = 1; 857 node->merged.info.index.gl_bo = node->cold->ib.obj; 858 if (merged_prim_count == 1) { 859 node->merged.info.mode = merged_prims[0].mode; 860 node->merged.start_count.start = merged_prims[0].start; 861 node->merged.start_count.count = merged_prims[0].count; 862 node->merged.start_count.index_bias = 0; 863 node->merged.mode = NULL; 864 } else { 865 node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char)); 866 node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias)); 867 for (unsigned i = 0; i < merged_prim_count; i++) { 868 node->merged.start_counts[i].start = merged_prims[i].start; 869 node->merged.start_counts[i].count = merged_prims[i].count; 870 node->merged.start_counts[i].index_bias = 0; 871 node->merged.mode[i] = merged_prims[i].mode; 872 } 873 } 874 node->merged.num_draws = merged_prim_count; 875 if (node->merged.num_draws > 1) { 876 bool same_mode = true; 877 for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) { 878 same_mode = node->merged.mode[i] == node->merged.mode[0]; 879 } 880 if (same_mode) { 881 /* All primitives use the same mode, so we can simplify a bit */ 882 node->merged.info.mode = node->merged.mode[0]; 883 free(node->merged.mode); 884 node->merged.mode = NULL; 885 } 886 } 887 888 free(indices); 889 free(merged_prims); 890 891end: 892 893 if (!save->current_bo) { 894 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1); 895 bool success = ctx->Driver.BufferData(ctx, 896 GL_ELEMENT_ARRAY_BUFFER_ARB, 897 VBO_SAVE_BUFFER_SIZE, 898 NULL, 899 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT, 900 save->current_bo); 901 if (!success) 902 handle_out_of_memory(ctx); 903 } 904 905 GLuint offsets[VBO_ATTRIB_MAX]; 906 for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) { 907 offsets[i] = offset; 908 offset += save->attrsz[i] * sizeof(GLfloat); 909 } 910 /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs 911 * Note that this may reuse the previous one of possible. 912 */ 913 for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) { 914 /* create or reuse the vao */ 915 update_vao(ctx, vpm, &save->VAO[vpm], 916 save->current_bo, buffer_offset, stride, 917 save->enabled, save->attrsz, save->attrtype, offsets); 918 /* Reference the vao in the dlist */ 919 node->VAO[vpm] = NULL; 920 _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]); 921 } 922 923 /* Prepare for DrawGalliumVertexState */ 924 if (node->merged.num_draws && ctx->Driver.DrawGalliumVertexState) { 925 for (unsigned i = 0; i < VP_MODE_MAX; i++) { 926 uint32_t enabled_attribs = _vbo_get_vao_filter(i) & 927 node->VAO[i]->_EnabledWithMapMode; 928 929 node->merged.gallium.state[i] = 930 ctx->Driver.CreateGalliumVertexState(ctx, node->VAO[i], 931 node->cold->ib.obj, 932 enabled_attribs); 933 node->merged.gallium.private_refcount[i] = 0; 934 node->merged.gallium.enabled_attribs[i] = enabled_attribs; 935 } 936 937 node->merged.gallium.ctx = ctx; 938 node->merged.gallium.info.mode = node->merged.info.mode; 939 node->merged.gallium.info.take_vertex_state_ownership = false; 940 assert(node->merged.info.index_size == 4); 941 } 942 943 /* Deal with GL_COMPILE_AND_EXECUTE: 944 */ 945 if (ctx->ExecuteFlag) { 946 struct _glapi_table *dispatch = GET_DISPATCH(); 947 948 _glapi_set_dispatch(ctx->Exec); 949 950 /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to 951 * use buffer_in_ram (which contains all vertices) instead of current_bo 952 * (which contains deduplicated vertices *when* UseLoopback is false). 953 * 954 * The problem is that the VAO offset is based on current_bo's layout, 955 * so we have to use a temp value. 956 */ 957 struct gl_vertex_array_object *vao = node->VAO[VP_MODE_SHADER]; 958 GLintptr original = vao->BufferBinding[0].Offset; 959 /* 'start_offset' has been added to all primitives 'start', so undo it here. */ 960 vao->BufferBinding[0].Offset = -(GLintptr)(start_offset * stride); 961 _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram); 962 vao->BufferBinding[0].Offset = original; 963 964 _glapi_set_dispatch(dispatch); 965 } 966 967 /* Reset our structures for the next run of vertices: 968 */ 969 reset_counters(ctx); 970} 971 972 973/** 974 * This is called when we fill a vertex buffer before we hit a glEnd(). 975 * We 976 * TODO -- If no new vertices have been stored, don't bother saving it. 977 */ 978static void 979wrap_buffers(struct gl_context *ctx) 980{ 981 struct vbo_save_context *save = &vbo_context(ctx)->save; 982 GLint i = save->prim_store->used - 1; 983 GLenum mode; 984 985 assert(i < (GLint) save->prim_store->size); 986 assert(i >= 0); 987 988 /* Close off in-progress primitive. 989 */ 990 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start); 991 mode = save->prim_store->prims[i].mode; 992 993 /* store the copied vertices, and allocate a new list. 994 */ 995 compile_vertex_list(ctx); 996 997 /* Restart interrupted primitive 998 */ 999 save->prim_store->prims[0].mode = mode; 1000 save->prim_store->prims[0].begin = 0; 1001 save->prim_store->prims[0].end = 0; 1002 save->prim_store->prims[0].start = 0; 1003 save->prim_store->prims[0].count = 0; 1004 save->prim_store->used = 1; 1005} 1006 1007 1008/** 1009 * Called only when buffers are wrapped as the result of filling the 1010 * vertex_store struct. 1011 */ 1012static void 1013wrap_filled_vertex(struct gl_context *ctx) 1014{ 1015 struct vbo_save_context *save = &vbo_context(ctx)->save; 1016 unsigned numComponents; 1017 1018 /* Emit a glEnd to close off the last vertex list. 1019 */ 1020 wrap_buffers(ctx); 1021 1022 assert(save->vertex_store->used == 0 && save->vertex_store->used == 0); 1023 1024 /* Copy stored stored vertices to start of new list. 1025 */ 1026 numComponents = save->copied.nr * save->vertex_size; 1027 1028 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram; 1029 if (numComponents) { 1030 assert(save->copied.buffer); 1031 memcpy(buffer_ptr, 1032 save->copied.buffer, 1033 numComponents * sizeof(fi_type)); 1034 free(save->copied.buffer); 1035 save->copied.buffer = NULL; 1036 } 1037 save->vertex_store->used = numComponents; 1038} 1039 1040 1041static void 1042copy_to_current(struct gl_context *ctx) 1043{ 1044 struct vbo_save_context *save = &vbo_context(ctx)->save; 1045 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); 1046 1047 while (enabled) { 1048 const int i = u_bit_scan64(&enabled); 1049 assert(save->attrsz[i]); 1050 1051 if (save->attrtype[i] == GL_DOUBLE || 1052 save->attrtype[i] == GL_UNSIGNED_INT64_ARB) 1053 memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat)); 1054 else 1055 COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i], 1056 save->attrptr[i], save->attrtype[i]); 1057 } 1058} 1059 1060 1061static void 1062copy_from_current(struct gl_context *ctx) 1063{ 1064 struct vbo_save_context *save = &vbo_context(ctx)->save; 1065 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); 1066 1067 while (enabled) { 1068 const int i = u_bit_scan64(&enabled); 1069 1070 switch (save->attrsz[i]) { 1071 case 4: 1072 save->attrptr[i][3] = save->current[i][3]; 1073 FALLTHROUGH; 1074 case 3: 1075 save->attrptr[i][2] = save->current[i][2]; 1076 FALLTHROUGH; 1077 case 2: 1078 save->attrptr[i][1] = save->current[i][1]; 1079 FALLTHROUGH; 1080 case 1: 1081 save->attrptr[i][0] = save->current[i][0]; 1082 break; 1083 case 0: 1084 unreachable("Unexpected vertex attribute size"); 1085 } 1086 } 1087} 1088 1089 1090/** 1091 * Called when we increase the size of a vertex attribute. For example, 1092 * if we've seen one or more glTexCoord2f() calls and now we get a 1093 * glTexCoord3f() call. 1094 * Flush existing data, set new attrib size, replay copied vertices. 1095 */ 1096static void 1097upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) 1098{ 1099 struct vbo_save_context *save = &vbo_context(ctx)->save; 1100 GLuint oldsz; 1101 GLuint i; 1102 fi_type *tmp; 1103 1104 /* Store the current run of vertices, and emit a GL_END. Emit a 1105 * BEGIN in the new buffer. 1106 */ 1107 if (save->vertex_store->used) 1108 wrap_buffers(ctx); 1109 else 1110 assert(save->copied.nr == 0); 1111 1112 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case 1113 * when the attribute already exists in the vertex and is having 1114 * its size increased. 1115 */ 1116 copy_to_current(ctx); 1117 1118 /* Fix up sizes: 1119 */ 1120 oldsz = save->attrsz[attr]; 1121 save->attrsz[attr] = newsz; 1122 save->enabled |= BITFIELD64_BIT(attr); 1123 1124 save->vertex_size += newsz - oldsz; 1125 1126 /* Recalculate all the attrptr[] values: 1127 */ 1128 tmp = save->vertex; 1129 for (i = 0; i < VBO_ATTRIB_MAX; i++) { 1130 if (save->attrsz[i]) { 1131 save->attrptr[i] = tmp; 1132 tmp += save->attrsz[i]; 1133 } 1134 else { 1135 save->attrptr[i] = NULL; /* will not be dereferenced. */ 1136 } 1137 } 1138 1139 /* Copy from current to repopulate the vertex with correct values. 1140 */ 1141 copy_from_current(ctx); 1142 1143 /* Replay stored vertices to translate them to new format here. 1144 * 1145 * If there are copied vertices and the new (upgraded) attribute 1146 * has not been defined before, this list is somewhat degenerate, 1147 * and will need fixup at runtime. 1148 */ 1149 if (save->copied.nr) { 1150 assert(save->copied.buffer); 1151 const fi_type *data = save->copied.buffer; 1152 grow_vertex_storage(ctx, save->copied.nr); 1153 fi_type *dest = save->vertex_store->buffer_in_ram; 1154 1155 /* Need to note this and fix up at runtime (or loopback): 1156 */ 1157 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { 1158 assert(oldsz == 0); 1159 save->dangling_attr_ref = GL_TRUE; 1160 } 1161 1162 for (i = 0; i < save->copied.nr; i++) { 1163 GLbitfield64 enabled = save->enabled; 1164 while (enabled) { 1165 const int j = u_bit_scan64(&enabled); 1166 assert(save->attrsz[j]); 1167 if (j == attr) { 1168 int k; 1169 const fi_type *src = oldsz ? data : save->current[attr]; 1170 int copy = oldsz ? oldsz : newsz; 1171 for (k = 0; k < copy; k++) 1172 dest[k] = src[k]; 1173 for (; k < newsz; k++) { 1174 switch (save->attrtype[j]) { 1175 case GL_FLOAT: 1176 dest[k] = FLOAT_AS_UNION(k == 3); 1177 break; 1178 case GL_INT: 1179 dest[k] = INT_AS_UNION(k == 3); 1180 break; 1181 case GL_UNSIGNED_INT: 1182 dest[k] = UINT_AS_UNION(k == 3); 1183 break; 1184 default: 1185 dest[k] = FLOAT_AS_UNION(k == 3); 1186 assert(!"Unexpected type in upgrade_vertex"); 1187 break; 1188 } 1189 } 1190 dest += newsz; 1191 data += oldsz; 1192 } else { 1193 GLint sz = save->attrsz[j]; 1194 for (int k = 0; k < sz; k++) 1195 dest[k] = data[k]; 1196 data += sz; 1197 dest += sz; 1198 } 1199 } 1200 } 1201 1202 save->vertex_store->used += save->vertex_size * save->copied.nr; 1203 free(save->copied.buffer); 1204 save->copied.buffer = NULL; 1205 } 1206} 1207 1208 1209/** 1210 * This is called when the size of a vertex attribute changes. 1211 * For example, after seeing one or more glTexCoord2f() calls we 1212 * get a glTexCoord4f() or glTexCoord1f() call. 1213 */ 1214static void 1215fixup_vertex(struct gl_context *ctx, GLuint attr, 1216 GLuint sz, GLenum newType) 1217{ 1218 struct vbo_save_context *save = &vbo_context(ctx)->save; 1219 1220 if (sz > save->attrsz[attr] || 1221 newType != save->attrtype[attr]) { 1222 /* New size is larger. Need to flush existing vertices and get 1223 * an enlarged vertex format. 1224 */ 1225 upgrade_vertex(ctx, attr, sz); 1226 } 1227 else if (sz < save->active_sz[attr]) { 1228 GLuint i; 1229 const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]); 1230 1231 /* New size is equal or smaller - just need to fill in some 1232 * zeros. 1233 */ 1234 for (i = sz; i <= save->attrsz[attr]; i++) 1235 save->attrptr[attr][i - 1] = id[i - 1]; 1236 } 1237 1238 save->active_sz[attr] = sz; 1239 1240 grow_vertex_storage(ctx, 1); 1241} 1242 1243 1244/** 1245 * Reset the current size of all vertex attributes to the default 1246 * value of 0. This signals that we haven't yet seen any per-vertex 1247 * commands such as glNormal3f() or glTexCoord2f(). 1248 */ 1249static void 1250reset_vertex(struct gl_context *ctx) 1251{ 1252 struct vbo_save_context *save = &vbo_context(ctx)->save; 1253 1254 while (save->enabled) { 1255 const int i = u_bit_scan64(&save->enabled); 1256 assert(save->attrsz[i]); 1257 save->attrsz[i] = 0; 1258 save->active_sz[i] = 0; 1259 } 1260 1261 save->vertex_size = 0; 1262} 1263 1264 1265/** 1266 * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex? 1267 * It depends on a few things, including whether we're inside or outside 1268 * of glBegin/glEnd. 1269 */ 1270static inline bool 1271is_vertex_position(const struct gl_context *ctx, GLuint index) 1272{ 1273 return (index == 0 && 1274 _mesa_attr_zero_aliases_vertex(ctx) && 1275 _mesa_inside_dlist_begin_end(ctx)); 1276} 1277 1278 1279 1280#define ERROR(err) _mesa_compile_error(ctx, err, __func__); 1281 1282 1283/* Only one size for each attribute may be active at once. Eg. if 1284 * Color3f is installed/active, then Color4f may not be, even if the 1285 * vertex actually contains 4 color coordinates. This is because the 1286 * 3f version won't otherwise set color[3] to 1.0 -- this is the job 1287 * of the chooser function when switching between Color4f and Color3f. 1288 */ 1289#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ 1290do { \ 1291 struct vbo_save_context *save = &vbo_context(ctx)->save; \ 1292 int sz = (sizeof(C) / sizeof(GLfloat)); \ 1293 \ 1294 if (save->active_sz[A] != N) \ 1295 fixup_vertex(ctx, A, N * sz, T); \ 1296 \ 1297 { \ 1298 C *dest = (C *)save->attrptr[A]; \ 1299 if (N>0) dest[0] = V0; \ 1300 if (N>1) dest[1] = V1; \ 1301 if (N>2) dest[2] = V2; \ 1302 if (N>3) dest[3] = V3; \ 1303 save->attrtype[A] = T; \ 1304 } \ 1305 \ 1306 if ((A) == VBO_ATTRIB_POS) { \ 1307 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + \ 1308 save->vertex_store->used; \ 1309 \ 1310 for (int i = 0; i < save->vertex_size; i++) \ 1311 buffer_ptr[i] = save->vertex[i]; \ 1312 \ 1313 save->vertex_store->used += save->vertex_size; \ 1314 unsigned used_next = (save->vertex_store->used + \ 1315 save->vertex_size) * sizeof(float); \ 1316 if (used_next > save->vertex_store->buffer_in_ram_size) { \ 1317 grow_vertex_storage(ctx, get_vertex_count(save)); \ 1318 assert(used_next <= \ 1319 save->vertex_store->buffer_in_ram_size); \ 1320 } \ 1321 } \ 1322} while (0) 1323 1324#define TAG(x) _save_##x 1325 1326#include "vbo_attrib_tmp.h" 1327 1328 1329#define MAT( ATTR, N, face, params ) \ 1330do { \ 1331 if (face != GL_BACK) \ 1332 MAT_ATTR( ATTR, N, params ); /* front */ \ 1333 if (face != GL_FRONT) \ 1334 MAT_ATTR( ATTR + 1, N, params ); /* back */ \ 1335} while (0) 1336 1337 1338/** 1339 * Save a glMaterial call found between glBegin/End. 1340 * glMaterial calls outside Begin/End are handled in dlist.c. 1341 */ 1342static void GLAPIENTRY 1343_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 1344{ 1345 GET_CURRENT_CONTEXT(ctx); 1346 1347 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 1348 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)"); 1349 return; 1350 } 1351 1352 switch (pname) { 1353 case GL_EMISSION: 1354 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params); 1355 break; 1356 case GL_AMBIENT: 1357 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); 1358 break; 1359 case GL_DIFFUSE: 1360 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); 1361 break; 1362 case GL_SPECULAR: 1363 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params); 1364 break; 1365 case GL_SHININESS: 1366 if (*params < 0 || *params > ctx->Const.MaxShininess) { 1367 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)"); 1368 } 1369 else { 1370 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params); 1371 } 1372 break; 1373 case GL_COLOR_INDEXES: 1374 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params); 1375 break; 1376 case GL_AMBIENT_AND_DIFFUSE: 1377 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); 1378 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); 1379 break; 1380 default: 1381 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)"); 1382 return; 1383 } 1384} 1385 1386 1387/* Cope with EvalCoord/CallList called within a begin/end object: 1388 * -- Flush current buffer 1389 * -- Fallback to opcodes for the rest of the begin/end object. 1390 */ 1391static void 1392dlist_fallback(struct gl_context *ctx) 1393{ 1394 struct vbo_save_context *save = &vbo_context(ctx)->save; 1395 1396 if (save->vertex_store->used || save->prim_store->used) { 1397 if (save->prim_store->used > 0 && save->vertex_store->used > 0) { 1398 assert(save->vertex_size); 1399 /* Close off in-progress primitive. */ 1400 GLint i = save->prim_store->used - 1; 1401 save->prim_store->prims[i].count = 1402 get_vertex_count(save) - 1403 save->prim_store->prims[i].start; 1404 } 1405 1406 /* Need to replay this display list with loopback, 1407 * unfortunately, otherwise this primitive won't be handled 1408 * properly: 1409 */ 1410 save->dangling_attr_ref = GL_TRUE; 1411 1412 compile_vertex_list(ctx); 1413 } 1414 1415 copy_to_current(ctx); 1416 reset_vertex(ctx); 1417 if (save->out_of_memory) { 1418 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); 1419 } 1420 else { 1421 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 1422 } 1423 ctx->Driver.SaveNeedFlush = GL_FALSE; 1424} 1425 1426 1427static void GLAPIENTRY 1428_save_EvalCoord1f(GLfloat u) 1429{ 1430 GET_CURRENT_CONTEXT(ctx); 1431 dlist_fallback(ctx); 1432 CALL_EvalCoord1f(ctx->Save, (u)); 1433} 1434 1435static void GLAPIENTRY 1436_save_EvalCoord1fv(const GLfloat * v) 1437{ 1438 GET_CURRENT_CONTEXT(ctx); 1439 dlist_fallback(ctx); 1440 CALL_EvalCoord1fv(ctx->Save, (v)); 1441} 1442 1443static void GLAPIENTRY 1444_save_EvalCoord2f(GLfloat u, GLfloat v) 1445{ 1446 GET_CURRENT_CONTEXT(ctx); 1447 dlist_fallback(ctx); 1448 CALL_EvalCoord2f(ctx->Save, (u, v)); 1449} 1450 1451static void GLAPIENTRY 1452_save_EvalCoord2fv(const GLfloat * v) 1453{ 1454 GET_CURRENT_CONTEXT(ctx); 1455 dlist_fallback(ctx); 1456 CALL_EvalCoord2fv(ctx->Save, (v)); 1457} 1458 1459static void GLAPIENTRY 1460_save_EvalPoint1(GLint i) 1461{ 1462 GET_CURRENT_CONTEXT(ctx); 1463 dlist_fallback(ctx); 1464 CALL_EvalPoint1(ctx->Save, (i)); 1465} 1466 1467static void GLAPIENTRY 1468_save_EvalPoint2(GLint i, GLint j) 1469{ 1470 GET_CURRENT_CONTEXT(ctx); 1471 dlist_fallback(ctx); 1472 CALL_EvalPoint2(ctx->Save, (i, j)); 1473} 1474 1475static void GLAPIENTRY 1476_save_CallList(GLuint l) 1477{ 1478 GET_CURRENT_CONTEXT(ctx); 1479 dlist_fallback(ctx); 1480 CALL_CallList(ctx->Save, (l)); 1481} 1482 1483static void GLAPIENTRY 1484_save_CallLists(GLsizei n, GLenum type, const GLvoid * v) 1485{ 1486 GET_CURRENT_CONTEXT(ctx); 1487 dlist_fallback(ctx); 1488 CALL_CallLists(ctx->Save, (n, type, v)); 1489} 1490 1491 1492 1493/** 1494 * Called when a glBegin is getting compiled into a display list. 1495 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of. 1496 */ 1497void 1498vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode, 1499 bool no_current_update) 1500{ 1501 struct vbo_save_context *save = &vbo_context(ctx)->save; 1502 const GLuint i = save->prim_store->used++; 1503 1504 ctx->Driver.CurrentSavePrimitive = mode; 1505 1506 if (!save->prim_store || i >= save->prim_store->size) { 1507 save->prim_store = realloc_prim_store(save->prim_store, i * 2); 1508 } 1509 save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; 1510 save->prim_store->prims[i].begin = 1; 1511 save->prim_store->prims[i].end = 0; 1512 save->prim_store->prims[i].start = get_vertex_count(save); 1513 save->prim_store->prims[i].count = 0; 1514 1515 save->no_current_update = no_current_update; 1516 1517 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); 1518 1519 /* We need to call vbo_save_SaveFlushVertices() if there's state change */ 1520 ctx->Driver.SaveNeedFlush = GL_TRUE; 1521} 1522 1523 1524static void GLAPIENTRY 1525_save_End(void) 1526{ 1527 GET_CURRENT_CONTEXT(ctx); 1528 struct vbo_save_context *save = &vbo_context(ctx)->save; 1529 const GLint i = save->prim_store->used - 1; 1530 1531 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 1532 save->prim_store->prims[i].end = 1; 1533 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start); 1534 1535 /* Swap out this vertex format while outside begin/end. Any color, 1536 * etc. received between here and the next begin will be compiled 1537 * as opcodes. 1538 */ 1539 if (save->out_of_memory) { 1540 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); 1541 } 1542 else { 1543 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 1544 } 1545} 1546 1547 1548static void GLAPIENTRY 1549_save_Begin(GLenum mode) 1550{ 1551 GET_CURRENT_CONTEXT(ctx); 1552 (void) mode; 1553 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin"); 1554} 1555 1556 1557static void GLAPIENTRY 1558_save_PrimitiveRestartNV(void) 1559{ 1560 GET_CURRENT_CONTEXT(ctx); 1561 struct vbo_save_context *save = &vbo_context(ctx)->save; 1562 1563 if (save->prim_store->used == 0) { 1564 /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV 1565 * is an error. 1566 */ 1567 _mesa_compile_error(ctx, GL_INVALID_OPERATION, 1568 "glPrimitiveRestartNV called outside glBegin/End"); 1569 } else { 1570 /* get current primitive mode */ 1571 GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode; 1572 bool no_current_update = save->no_current_update; 1573 1574 /* restart primitive */ 1575 CALL_End(ctx->CurrentServerDispatch, ()); 1576 vbo_save_NotifyBegin(ctx, curPrim, no_current_update); 1577 } 1578} 1579 1580 1581/* Unlike the functions above, these are to be hooked into the vtxfmt 1582 * maintained in ctx->ListState, active when the list is known or 1583 * suspected to be outside any begin/end primitive. 1584 * Note: OBE = Outside Begin/End 1585 */ 1586static void GLAPIENTRY 1587_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) 1588{ 1589 GET_CURRENT_CONTEXT(ctx); 1590 struct _glapi_table *dispatch = ctx->CurrentServerDispatch; 1591 1592 vbo_save_NotifyBegin(ctx, GL_QUADS, false); 1593 CALL_Vertex2f(dispatch, (x1, y1)); 1594 CALL_Vertex2f(dispatch, (x2, y1)); 1595 CALL_Vertex2f(dispatch, (x2, y2)); 1596 CALL_Vertex2f(dispatch, (x1, y2)); 1597 CALL_End(dispatch, ()); 1598} 1599 1600 1601static void GLAPIENTRY 1602_save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) 1603{ 1604 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2); 1605} 1606 1607static void GLAPIENTRY 1608_save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2) 1609{ 1610 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]); 1611} 1612 1613static void GLAPIENTRY 1614_save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2) 1615{ 1616 _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]); 1617} 1618 1619static void GLAPIENTRY 1620_save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2) 1621{ 1622 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2); 1623} 1624 1625static void GLAPIENTRY 1626_save_OBE_Rectiv(const GLint *v1, const GLint *v2) 1627{ 1628 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]); 1629} 1630 1631static void GLAPIENTRY 1632_save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) 1633{ 1634 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2); 1635} 1636 1637static void GLAPIENTRY 1638_save_OBE_Rectsv(const GLshort *v1, const GLshort *v2) 1639{ 1640 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]); 1641} 1642 1643static void GLAPIENTRY 1644_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) 1645{ 1646 GET_CURRENT_CONTEXT(ctx); 1647 struct gl_vertex_array_object *vao = ctx->Array.VAO; 1648 struct vbo_save_context *save = &vbo_context(ctx)->save; 1649 GLint i; 1650 1651 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1652 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)"); 1653 return; 1654 } 1655 if (count < 0) { 1656 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)"); 1657 return; 1658 } 1659 1660 if (save->out_of_memory) 1661 return; 1662 1663 grow_vertex_storage(ctx, count); 1664 1665 /* Make sure to process any VBO binding changes */ 1666 _mesa_update_state(ctx); 1667 1668 _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT); 1669 1670 vbo_save_NotifyBegin(ctx, mode, true); 1671 1672 for (i = 0; i < count; i++) 1673 _mesa_array_element(ctx, start + i); 1674 CALL_End(ctx->CurrentServerDispatch, ()); 1675 1676 _mesa_vao_unmap_arrays(ctx, vao); 1677} 1678 1679 1680static void GLAPIENTRY 1681_save_OBE_MultiDrawArrays(GLenum mode, const GLint *first, 1682 const GLsizei *count, GLsizei primcount) 1683{ 1684 GET_CURRENT_CONTEXT(ctx); 1685 GLint i; 1686 1687 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1688 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)"); 1689 return; 1690 } 1691 1692 if (primcount < 0) { 1693 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1694 "glMultiDrawArrays(primcount<0)"); 1695 return; 1696 } 1697 1698 unsigned vertcount = 0; 1699 for (i = 0; i < primcount; i++) { 1700 if (count[i] < 0) { 1701 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1702 "glMultiDrawArrays(count[i]<0)"); 1703 return; 1704 } 1705 vertcount += count[i]; 1706 } 1707 1708 grow_vertex_storage(ctx, vertcount); 1709 1710 for (i = 0; i < primcount; i++) { 1711 if (count[i] > 0) { 1712 _save_OBE_DrawArrays(mode, first[i], count[i]); 1713 } 1714 } 1715} 1716 1717 1718static void 1719array_element(struct gl_context *ctx, 1720 GLint basevertex, GLuint elt, unsigned index_size_shift) 1721{ 1722 /* Section 10.3.5 Primitive Restart: 1723 * [...] 1724 * When one of the *BaseVertex drawing commands specified in section 10.5 1725 * is used, the primitive restart comparison occurs before the basevertex 1726 * offset is added to the array index. 1727 */ 1728 /* If PrimitiveRestart is enabled and the index is the RestartIndex 1729 * then we call PrimitiveRestartNV and return. 1730 */ 1731 if (ctx->Array._PrimitiveRestart[index_size_shift] && 1732 elt == ctx->Array._RestartIndex[index_size_shift]) { 1733 CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ()); 1734 return; 1735 } 1736 1737 _mesa_array_element(ctx, basevertex + elt); 1738} 1739 1740 1741/* Could do better by copying the arrays and element list intact and 1742 * then emitting an indexed prim at runtime. 1743 */ 1744static void GLAPIENTRY 1745_save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 1746 const GLvoid * indices, GLint basevertex) 1747{ 1748 GET_CURRENT_CONTEXT(ctx); 1749 struct vbo_save_context *save = &vbo_context(ctx)->save; 1750 struct gl_vertex_array_object *vao = ctx->Array.VAO; 1751 struct gl_buffer_object *indexbuf = vao->IndexBufferObj; 1752 GLint i; 1753 1754 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1755 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)"); 1756 return; 1757 } 1758 if (count < 0) { 1759 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); 1760 return; 1761 } 1762 if (type != GL_UNSIGNED_BYTE && 1763 type != GL_UNSIGNED_SHORT && 1764 type != GL_UNSIGNED_INT) { 1765 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)"); 1766 return; 1767 } 1768 1769 if (save->out_of_memory) 1770 return; 1771 1772 grow_vertex_storage(ctx, count); 1773 1774 /* Make sure to process any VBO binding changes */ 1775 _mesa_update_state(ctx); 1776 1777 _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT); 1778 1779 if (indexbuf) 1780 indices = 1781 ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices); 1782 1783 vbo_save_NotifyBegin(ctx, mode, true); 1784 1785 switch (type) { 1786 case GL_UNSIGNED_BYTE: 1787 for (i = 0; i < count; i++) 1788 array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0); 1789 break; 1790 case GL_UNSIGNED_SHORT: 1791 for (i = 0; i < count; i++) 1792 array_element(ctx, basevertex, ((GLushort *) indices)[i], 1); 1793 break; 1794 case GL_UNSIGNED_INT: 1795 for (i = 0; i < count; i++) 1796 array_element(ctx, basevertex, ((GLuint *) indices)[i], 2); 1797 break; 1798 default: 1799 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); 1800 break; 1801 } 1802 1803 CALL_End(ctx->CurrentServerDispatch, ()); 1804 1805 _mesa_vao_unmap(ctx, vao); 1806} 1807 1808static void GLAPIENTRY 1809_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, 1810 const GLvoid * indices) 1811{ 1812 _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0); 1813} 1814 1815 1816static void GLAPIENTRY 1817_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 1818 GLsizei count, GLenum type, 1819 const GLvoid * indices) 1820{ 1821 GET_CURRENT_CONTEXT(ctx); 1822 struct vbo_save_context *save = &vbo_context(ctx)->save; 1823 1824 if (!_mesa_is_valid_prim_mode(ctx, mode)) { 1825 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)"); 1826 return; 1827 } 1828 if (count < 0) { 1829 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1830 "glDrawRangeElements(count<0)"); 1831 return; 1832 } 1833 if (type != GL_UNSIGNED_BYTE && 1834 type != GL_UNSIGNED_SHORT && 1835 type != GL_UNSIGNED_INT) { 1836 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)"); 1837 return; 1838 } 1839 if (end < start) { 1840 _mesa_compile_error(ctx, GL_INVALID_VALUE, 1841 "glDrawRangeElements(end < start)"); 1842 return; 1843 } 1844 1845 if (save->out_of_memory) 1846 return; 1847 1848 _save_OBE_DrawElements(mode, count, type, indices); 1849} 1850 1851 1852static void GLAPIENTRY 1853_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, 1854 const GLvoid * const *indices, GLsizei primcount) 1855{ 1856 GET_CURRENT_CONTEXT(ctx); 1857 struct _glapi_table *dispatch = ctx->CurrentServerDispatch; 1858 GLsizei i; 1859 1860 int vertcount = 0; 1861 for (i = 0; i < primcount; i++) { 1862 vertcount += count[i]; 1863 } 1864 grow_vertex_storage(ctx, vertcount); 1865 1866 for (i = 0; i < primcount; i++) { 1867 if (count[i] > 0) { 1868 CALL_DrawElements(dispatch, (mode, count[i], type, indices[i])); 1869 } 1870 } 1871} 1872 1873 1874static void GLAPIENTRY 1875_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, 1876 GLenum type, 1877 const GLvoid * const *indices, 1878 GLsizei primcount, 1879 const GLint *basevertex) 1880{ 1881 GET_CURRENT_CONTEXT(ctx); 1882 struct _glapi_table *dispatch = ctx->CurrentServerDispatch; 1883 GLsizei i; 1884 1885 int vertcount = 0; 1886 for (i = 0; i < primcount; i++) { 1887 vertcount += count[i]; 1888 } 1889 grow_vertex_storage(ctx, vertcount); 1890 1891 for (i = 0; i < primcount; i++) { 1892 if (count[i] > 0) { 1893 CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type, 1894 indices[i], 1895 basevertex[i])); 1896 } 1897 } 1898} 1899 1900 1901static void 1902vtxfmt_init(struct gl_context *ctx) 1903{ 1904 struct vbo_save_context *save = &vbo_context(ctx)->save; 1905 GLvertexformat *vfmt = &save->vtxfmt; 1906 1907#define NAME_AE(x) _ae_##x 1908#define NAME_CALLLIST(x) _save_##x 1909#define NAME(x) _save_##x 1910#define NAME_ES(x) _save_##x##ARB 1911 1912#include "vbo_init_tmp.h" 1913} 1914 1915 1916/** 1917 * Initialize the dispatch table with the VBO functions for display 1918 * list compilation. 1919 */ 1920void 1921vbo_initialize_save_dispatch(const struct gl_context *ctx, 1922 struct _glapi_table *exec) 1923{ 1924 SET_DrawArrays(exec, _save_OBE_DrawArrays); 1925 SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays); 1926 SET_DrawElements(exec, _save_OBE_DrawElements); 1927 SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex); 1928 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements); 1929 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements); 1930 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex); 1931 SET_Rectf(exec, _save_OBE_Rectf); 1932 SET_Rectd(exec, _save_OBE_Rectd); 1933 SET_Rectdv(exec, _save_OBE_Rectdv); 1934 SET_Rectfv(exec, _save_OBE_Rectfv); 1935 SET_Recti(exec, _save_OBE_Recti); 1936 SET_Rectiv(exec, _save_OBE_Rectiv); 1937 SET_Rects(exec, _save_OBE_Rects); 1938 SET_Rectsv(exec, _save_OBE_Rectsv); 1939 1940 /* Note: other glDraw functins aren't compiled into display lists */ 1941} 1942 1943 1944 1945void 1946vbo_save_SaveFlushVertices(struct gl_context *ctx) 1947{ 1948 struct vbo_save_context *save = &vbo_context(ctx)->save; 1949 1950 /* Noop when we are actually active: 1951 */ 1952 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX) 1953 return; 1954 1955 if (save->vertex_store->used || save->prim_store->used) 1956 compile_vertex_list(ctx); 1957 1958 copy_to_current(ctx); 1959 reset_vertex(ctx); 1960 ctx->Driver.SaveNeedFlush = GL_FALSE; 1961} 1962 1963 1964/** 1965 * Called from glNewList when we're starting to compile a display list. 1966 */ 1967void 1968vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) 1969{ 1970 struct vbo_save_context *save = &vbo_context(ctx)->save; 1971 1972 (void) list; 1973 (void) mode; 1974 1975 if (!save->prim_store) 1976 save->prim_store = realloc_prim_store(NULL, 8); 1977 1978 if (!save->vertex_store) 1979 save->vertex_store = CALLOC_STRUCT(vbo_save_vertex_store); 1980 1981 reset_vertex(ctx); 1982 ctx->Driver.SaveNeedFlush = GL_FALSE; 1983} 1984 1985 1986/** 1987 * Called from glEndList when we're finished compiling a display list. 1988 */ 1989void 1990vbo_save_EndList(struct gl_context *ctx) 1991{ 1992 struct vbo_save_context *save = &vbo_context(ctx)->save; 1993 1994 /* EndList called inside a (saved) Begin/End pair? 1995 */ 1996 if (_mesa_inside_dlist_begin_end(ctx)) { 1997 if (save->prim_store->used > 0) { 1998 GLint i = save->prim_store->used - 1; 1999 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 2000 save->prim_store->prims[i].end = 0; 2001 save->prim_store->prims[i].count = get_vertex_count(save) - save->prim_store->prims[i].start; 2002 } 2003 2004 /* Make sure this vertex list gets replayed by the "loopback" 2005 * mechanism: 2006 */ 2007 save->dangling_attr_ref = GL_TRUE; 2008 vbo_save_SaveFlushVertices(ctx); 2009 2010 /* Swap out this vertex format while outside begin/end. Any color, 2011 * etc. received between here and the next begin will be compiled 2012 * as opcodes. 2013 */ 2014 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); 2015 } 2016 2017 assert(save->vertex_size == 0); 2018} 2019 2020/** 2021 * Called during context creation/init. 2022 */ 2023static void 2024current_init(struct gl_context *ctx) 2025{ 2026 struct vbo_save_context *save = &vbo_context(ctx)->save; 2027 GLint i; 2028 2029 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) { 2030 const GLuint j = i - VBO_ATTRIB_POS; 2031 assert(j < VERT_ATTRIB_MAX); 2032 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; 2033 save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j]; 2034 } 2035 2036 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { 2037 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; 2038 assert(j < MAT_ATTRIB_MAX); 2039 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; 2040 save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j]; 2041 } 2042} 2043 2044 2045/** 2046 * Initialize the display list compiler. Called during context creation. 2047 */ 2048void 2049vbo_save_api_init(struct vbo_save_context *save) 2050{ 2051 struct gl_context *ctx = gl_context_from_vbo_save(save); 2052 2053 vtxfmt_init(ctx); 2054 current_init(ctx); 2055} 2056