vbo_exec_array.c revision 762c9766c93697af8d7fbaa729aed118789dbe8e
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009 VMware, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29#include "main/glheader.h" 30#include "main/context.h" 31#include "main/state.h" 32#include "main/api_validate.h" 33#include "main/varray.h" 34#include "main/bufferobj.h" 35#include "main/enums.h" 36#include "main/macros.h" 37 38#include "vbo_context.h" 39 40 41/** 42 * All vertex buffers should be in an unmapped state when we're about 43 * to draw. This debug function checks that. 44 */ 45static void 46check_buffers_are_unmapped(const struct gl_client_array **inputs) 47{ 48#ifdef DEBUG 49 GLuint i; 50 51 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 52 if (inputs[i]) { 53 struct gl_buffer_object *obj = inputs[i]->BufferObj; 54 assert(!_mesa_bufferobj_mapped(obj)); 55 (void) obj; 56 } 57 } 58#endif 59} 60 61 62/** 63 * A debug function that may be called from other parts of Mesa as 64 * needed during debugging. 65 */ 66void 67vbo_check_buffers_are_unmapped(struct gl_context *ctx) 68{ 69 struct vbo_context *vbo = vbo_context(ctx); 70 struct vbo_exec_context *exec = &vbo->exec; 71 /* check the current vertex arrays */ 72 check_buffers_are_unmapped(exec->array.inputs); 73 /* check the current glBegin/glVertex/glEnd-style VBO */ 74 assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj)); 75} 76 77 78 79/** 80 * Compute min and max elements by scanning the index buffer for 81 * glDraw[Range]Elements() calls. 82 * If primitive restart is enabled, we need to ignore restart 83 * indexes when computing min/max. 84 */ 85void 86vbo_get_minmax_index(struct gl_context *ctx, 87 const struct _mesa_prim *prim, 88 const struct _mesa_index_buffer *ib, 89 GLuint *min_index, GLuint *max_index) 90{ 91 const GLboolean restart = ctx->Array.PrimitiveRestart; 92 const GLuint restartIndex = ctx->Array.RestartIndex; 93 const GLuint count = prim->count; 94 const void *indices; 95 GLuint i; 96 97 if (_mesa_is_bufferobj(ib->obj)) { 98 unsigned map_size; 99 100 switch (ib->type) { 101 case GL_UNSIGNED_INT: 102 map_size = count * sizeof(GLuint); 103 break; 104 case GL_UNSIGNED_SHORT: 105 map_size = count * sizeof(GLushort); 106 break; 107 case GL_UNSIGNED_BYTE: 108 map_size = count * sizeof(GLubyte); 109 break; 110 default: 111 assert(0); 112 map_size = 0; 113 } 114 115 indices = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr, map_size, 116 GL_MAP_READ_BIT, ib->obj); 117 } else { 118 indices = ib->ptr; 119 } 120 121 switch (ib->type) { 122 case GL_UNSIGNED_INT: { 123 const GLuint *ui_indices = (const GLuint *)indices; 124 GLuint max_ui = 0; 125 GLuint min_ui = ~0U; 126 if (restart) { 127 for (i = 0; i < count; i++) { 128 if (ui_indices[i] != restartIndex) { 129 if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; 130 if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; 131 } 132 } 133 } 134 else { 135 for (i = 0; i < count; i++) { 136 if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; 137 if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; 138 } 139 } 140 *min_index = min_ui; 141 *max_index = max_ui; 142 break; 143 } 144 case GL_UNSIGNED_SHORT: { 145 const GLushort *us_indices = (const GLushort *)indices; 146 GLuint max_us = 0; 147 GLuint min_us = ~0U; 148 if (restart) { 149 for (i = 0; i < count; i++) { 150 if (us_indices[i] != restartIndex) { 151 if (us_indices[i] > max_us) max_us = us_indices[i]; 152 if (us_indices[i] < min_us) min_us = us_indices[i]; 153 } 154 } 155 } 156 else { 157 for (i = 0; i < count; i++) { 158 if (us_indices[i] > max_us) max_us = us_indices[i]; 159 if (us_indices[i] < min_us) min_us = us_indices[i]; 160 } 161 } 162 *min_index = min_us; 163 *max_index = max_us; 164 break; 165 } 166 case GL_UNSIGNED_BYTE: { 167 const GLubyte *ub_indices = (const GLubyte *)indices; 168 GLuint max_ub = 0; 169 GLuint min_ub = ~0U; 170 if (restart) { 171 for (i = 0; i < count; i++) { 172 if (ub_indices[i] != restartIndex) { 173 if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; 174 if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; 175 } 176 } 177 } 178 else { 179 for (i = 0; i < count; i++) { 180 if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; 181 if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; 182 } 183 } 184 *min_index = min_ub; 185 *max_index = max_ub; 186 break; 187 } 188 default: 189 assert(0); 190 break; 191 } 192 193 if (_mesa_is_bufferobj(ib->obj)) { 194 ctx->Driver.UnmapBuffer(ctx, ib->obj); 195 } 196} 197 198 199/** 200 * Check that element 'j' of the array has reasonable data. 201 * Map VBO if needed. 202 * For debugging purposes; not normally used. 203 */ 204static void 205check_array_data(struct gl_context *ctx, struct gl_client_array *array, 206 GLuint attrib, GLuint j) 207{ 208 if (array->Enabled) { 209 const void *data = array->Ptr; 210 if (_mesa_is_bufferobj(array->BufferObj)) { 211 if (!array->BufferObj->Pointer) { 212 /* need to map now */ 213 array->BufferObj->Pointer = 214 ctx->Driver.MapBufferRange(ctx, 0, array->BufferObj->Size, 215 GL_MAP_READ_BIT, array->BufferObj); 216 } 217 data = ADD_POINTERS(data, array->BufferObj->Pointer); 218 } 219 switch (array->Type) { 220 case GL_FLOAT: 221 { 222 GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j); 223 GLint k; 224 for (k = 0; k < array->Size; k++) { 225 if (IS_INF_OR_NAN(f[k]) || 226 f[k] >= 1.0e20 || f[k] <= -1.0e10) { 227 printf("Bad array data:\n"); 228 printf(" Element[%u].%u = %f\n", j, k, f[k]); 229 printf(" Array %u at %p\n", attrib, (void* ) array); 230 printf(" Type 0x%x, Size %d, Stride %d\n", 231 array->Type, array->Size, array->Stride); 232 printf(" Address/offset %p in Buffer Object %u\n", 233 array->Ptr, array->BufferObj->Name); 234 f[k] = 1.0; /* XXX replace the bad value! */ 235 } 236 /*assert(!IS_INF_OR_NAN(f[k]));*/ 237 } 238 } 239 break; 240 default: 241 ; 242 } 243 } 244} 245 246 247/** 248 * Unmap the buffer object referenced by given array, if mapped. 249 */ 250static void 251unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array) 252{ 253 if (array->Enabled && 254 _mesa_is_bufferobj(array->BufferObj) && 255 _mesa_bufferobj_mapped(array->BufferObj)) { 256 ctx->Driver.UnmapBuffer(ctx, array->BufferObj); 257 } 258} 259 260 261/** 262 * Examine the array's data for NaNs, etc. 263 * For debug purposes; not normally used. 264 */ 265static void 266check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, 267 const void *elements, GLint basevertex) 268{ 269 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 270 const void *elemMap; 271 GLint i, k; 272 273 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { 274 elemMap = ctx->Driver.MapBufferRange(ctx, 0, 275 ctx->Array.ArrayObj->ElementArrayBufferObj->Size, 276 GL_MAP_READ_BIT, 277 ctx->Array.ArrayObj->ElementArrayBufferObj); 278 elements = ADD_POINTERS(elements, elemMap); 279 } 280 281 for (i = 0; i < count; i++) { 282 GLuint j; 283 284 /* j = element[i] */ 285 switch (elemType) { 286 case GL_UNSIGNED_BYTE: 287 j = ((const GLubyte *) elements)[i]; 288 break; 289 case GL_UNSIGNED_SHORT: 290 j = ((const GLushort *) elements)[i]; 291 break; 292 case GL_UNSIGNED_INT: 293 j = ((const GLuint *) elements)[i]; 294 break; 295 default: 296 assert(0); 297 } 298 299 /* check element j of each enabled array */ 300 for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { 301 check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j); 302 } 303 } 304 305 if (_mesa_is_bufferobj(arrayObj->ElementArrayBufferObj)) { 306 ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj); 307 } 308 309 for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { 310 unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); 311 } 312} 313 314 315/** 316 * Check array data, looking for NaNs, etc. 317 */ 318static void 319check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count) 320{ 321 /* TO DO */ 322} 323 324 325/** 326 * Print info/data for glDrawArrays(), for debugging. 327 */ 328static void 329print_draw_arrays(struct gl_context *ctx, 330 GLenum mode, GLint start, GLsizei count) 331{ 332 struct vbo_context *vbo = vbo_context(ctx); 333 struct vbo_exec_context *exec = &vbo->exec; 334 int i; 335 336 printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n", 337 mode, start, count); 338 339 for (i = 0; i < 32; i++) { 340 struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj; 341 GLuint bufName = bufObj->Name; 342 GLint stride = exec->array.inputs[i]->Stride; 343 printf("attr %2d: size %d stride %d enabled %d " 344 "ptr %p Bufobj %u\n", 345 i, 346 exec->array.inputs[i]->Size, 347 stride, 348 /*exec->array.inputs[i]->Enabled,*/ 349 exec->array.legacy_array[i]->Enabled, 350 exec->array.inputs[i]->Ptr, 351 bufName); 352 353 if (bufName) { 354 GLubyte *p = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, 355 GL_MAP_READ_BIT, bufObj); 356 int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr; 357 float *f = (float *) (p + offset); 358 int *k = (int *) f; 359 int i; 360 int n = (count * stride) / 4; 361 if (n > 32) 362 n = 32; 363 printf(" Data at offset %d:\n", offset); 364 for (i = 0; i < n; i++) { 365 printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]); 366 } 367 ctx->Driver.UnmapBuffer(ctx, bufObj); 368 } 369 } 370} 371 372 373/** 374 * Bind the VBO executor to the current vertex array object prior 375 * to drawing. 376 * 377 * Just translate the arrayobj into a sane layout. 378 */ 379static void 380bind_array_obj(struct gl_context *ctx) 381{ 382 struct vbo_context *vbo = vbo_context(ctx); 383 struct vbo_exec_context *exec = &vbo->exec; 384 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 385 GLuint i; 386 387 for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) 388 exec->array.legacy_array[i] = &arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)]; 389 390 for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) { 391 assert(i < Elements(exec->array.generic_array)); 392 exec->array.generic_array[i] = &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(i)]; 393 } 394} 395 396 397/** 398 * Set the vbo->exec->inputs[] pointers to point to the enabled 399 * vertex arrays. This depends on the current vertex program/shader 400 * being executed because of whether or not generic vertex arrays 401 * alias the conventional vertex arrays. 402 * For arrays that aren't enabled, we set the input[attrib] pointer 403 * to point at a zero-stride current value "array". 404 */ 405static void 406recalculate_input_bindings(struct gl_context *ctx) 407{ 408 struct vbo_context *vbo = vbo_context(ctx); 409 struct vbo_exec_context *exec = &vbo->exec; 410 const struct gl_client_array **inputs = &exec->array.inputs[0]; 411 GLbitfield64 const_inputs = 0x0; 412 GLuint i; 413 414 switch (get_program_mode(ctx)) { 415 case VP_NONE: 416 /* When no vertex program is active (or the vertex program is generated 417 * from fixed-function state). We put the material values into the 418 * generic slots. This is the only situation where material values 419 * are available as per-vertex attributes. 420 */ 421 for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) { 422 if (exec->array.legacy_array[i]->Enabled) 423 inputs[i] = exec->array.legacy_array[i]; 424 else { 425 inputs[i] = &vbo->legacy_currval[i]; 426 const_inputs |= VERT_BIT(i); 427 } 428 } 429 430 for (i = 0; i < MAT_ATTRIB_MAX; i++) { 431 inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->mat_currval[i]; 432 const_inputs |= VERT_BIT_GENERIC(i); 433 } 434 435 /* Could use just about anything, just to fill in the empty 436 * slots: 437 */ 438 for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_GENERIC_MAX; i++) { 439 inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; 440 const_inputs |= VERT_BIT_GENERIC(i); 441 } 442 443 /* There is no need to make _NEW_ARRAY dirty here for the TnL program, 444 * because it already takes care of invalidating the state necessary 445 * to revalidate vertex arrays. Not marking the state as dirty also 446 * improves performance (quite significantly in some apps). 447 */ 448 if (!ctx->VertexProgram._MaintainTnlProgram) 449 ctx->NewState |= _NEW_ARRAY; 450 break; 451 452 case VP_NV: 453 /* NV_vertex_program - attribute arrays alias and override 454 * conventional, legacy arrays. No materials, and the generic 455 * slots are vacant. 456 */ 457 for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) { 458 if (i < VERT_ATTRIB_GENERIC_MAX 459 && exec->array.generic_array[i]->Enabled) 460 inputs[i] = exec->array.generic_array[i]; 461 else if (exec->array.legacy_array[i]->Enabled) 462 inputs[i] = exec->array.legacy_array[i]; 463 else { 464 inputs[i] = &vbo->legacy_currval[i]; 465 const_inputs |= VERT_BIT_FF(i); 466 } 467 } 468 469 /* Could use just about anything, just to fill in the empty 470 * slots: 471 */ 472 for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) { 473 inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; 474 const_inputs |= VERT_BIT_GENERIC(i); 475 } 476 477 ctx->NewState |= _NEW_ARRAY; 478 break; 479 480 case VP_ARB: 481 /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0] 482 * attribute array aliases and overrides the legacy position array. 483 * 484 * Otherwise, legacy attributes available in the legacy slots, 485 * generic attributes in the generic slots and materials are not 486 * available as per-vertex attributes. 487 */ 488 if (exec->array.generic_array[0]->Enabled) 489 inputs[0] = exec->array.generic_array[0]; 490 else if (exec->array.legacy_array[0]->Enabled) 491 inputs[0] = exec->array.legacy_array[0]; 492 else { 493 inputs[0] = &vbo->legacy_currval[0]; 494 const_inputs |= VERT_BIT_POS; 495 } 496 497 for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) { 498 if (exec->array.legacy_array[i]->Enabled) 499 inputs[i] = exec->array.legacy_array[i]; 500 else { 501 inputs[i] = &vbo->legacy_currval[i]; 502 const_inputs |= VERT_BIT_FF(i); 503 } 504 } 505 506 for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) { 507 if (exec->array.generic_array[i]->Enabled) 508 inputs[VERT_ATTRIB_GENERIC(i)] = exec->array.generic_array[i]; 509 else { 510 inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i]; 511 const_inputs |= VERT_BIT_GENERIC(i); 512 } 513 } 514 515 inputs[VERT_ATTRIB_GENERIC0] = inputs[0]; 516 ctx->NewState |= _NEW_ARRAY; 517 break; 518 } 519 520 _mesa_set_varying_vp_inputs( ctx, VERT_BIT_ALL & (~const_inputs) ); 521} 522 523 524/** 525 * Examine the enabled vertex arrays to set the exec->array.inputs[] values. 526 * These will point to the arrays to actually use for drawing. Some will 527 * be user-provided arrays, other will be zero-stride const-valued arrays. 528 * Note that this might set the _NEW_ARRAY dirty flag so state validation 529 * must be done after this call. 530 */ 531void 532vbo_bind_arrays(struct gl_context *ctx) 533{ 534 if (!ctx->Array.RebindArrays) { 535 return; 536 } 537 538 bind_array_obj(ctx); 539 recalculate_input_bindings(ctx); 540 ctx->Array.RebindArrays = GL_FALSE; 541} 542 543 544/** 545 * Helper function called by the other DrawArrays() functions below. 546 * This is where we handle primitive restart for drawing non-indexed 547 * arrays. If primitive restart is enabled, it typically means 548 * splitting one DrawArrays() into two. 549 */ 550static void 551vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, 552 GLsizei count, GLuint numInstances) 553{ 554 struct vbo_context *vbo = vbo_context(ctx); 555 struct vbo_exec_context *exec = &vbo->exec; 556 struct _mesa_prim prim[2]; 557 558 vbo_bind_arrays(ctx); 559 560 /* Again... because we may have changed the bitmask of per-vertex varying 561 * attributes. If we regenerate the fixed-function vertex program now 562 * we may be able to prune down the number of vertex attributes which we 563 * need in the shader. 564 */ 565 if (ctx->NewState) 566 _mesa_update_state(ctx); 567 568 /* init most fields to zero */ 569 memset(prim, 0, sizeof(prim)); 570 prim[0].begin = 1; 571 prim[0].end = 1; 572 prim[0].mode = mode; 573 prim[0].num_instances = numInstances; 574 575 /* Implement the primitive restart index */ 576 if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { 577 GLuint primCount = 0; 578 579 if (ctx->Array.RestartIndex == start) { 580 /* special case: RestartIndex at beginning */ 581 if (count > 1) { 582 prim[0].start = start + 1; 583 prim[0].count = count - 1; 584 primCount = 1; 585 } 586 } 587 else if (ctx->Array.RestartIndex == start + count - 1) { 588 /* special case: RestartIndex at end */ 589 if (count > 1) { 590 prim[0].start = start; 591 prim[0].count = count - 1; 592 primCount = 1; 593 } 594 } 595 else { 596 /* general case: RestartIndex in middle, split into two prims */ 597 prim[0].start = start; 598 prim[0].count = ctx->Array.RestartIndex - start; 599 600 prim[1] = prim[0]; 601 prim[1].start = ctx->Array.RestartIndex + 1; 602 prim[1].count = count - prim[1].start; 603 604 primCount = 2; 605 } 606 607 if (primCount > 0) { 608 /* draw one or two prims */ 609 check_buffers_are_unmapped(exec->array.inputs); 610 vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL, 611 GL_TRUE, start, start + count - 1); 612 } 613 } 614 else { 615 /* no prim restart */ 616 prim[0].start = start; 617 prim[0].count = count; 618 619 check_buffers_are_unmapped(exec->array.inputs); 620 vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL, 621 GL_TRUE, start, start + count - 1); 622 } 623} 624 625 626 627/** 628 * Called from glDrawArrays when in immediate mode (not display list mode). 629 */ 630static void GLAPIENTRY 631vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) 632{ 633 GET_CURRENT_CONTEXT(ctx); 634 635 if (MESA_VERBOSE & VERBOSE_DRAW) 636 _mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n", 637 _mesa_lookup_enum_by_nr(mode), start, count); 638 639 if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) 640 return; 641 642 FLUSH_CURRENT( ctx, 0 ); 643 644 if (!_mesa_valid_to_render(ctx, "glDrawArrays")) { 645 return; 646 } 647 648 if (0) 649 check_draw_arrays_data(ctx, start, count); 650 651 vbo_draw_arrays(ctx, mode, start, count, 1); 652 653 if (0) 654 print_draw_arrays(ctx, mode, start, count); 655} 656 657 658/** 659 * Called from glDrawArraysInstanced when in immediate mode (not 660 * display list mode). 661 */ 662static void GLAPIENTRY 663vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count, 664 GLsizei numInstances) 665{ 666 GET_CURRENT_CONTEXT(ctx); 667 668 if (MESA_VERBOSE & VERBOSE_DRAW) 669 _mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n", 670 _mesa_lookup_enum_by_nr(mode), start, count, numInstances); 671 672 if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, numInstances)) 673 return; 674 675 FLUSH_CURRENT( ctx, 0 ); 676 677 if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) { 678 return; 679 } 680 681 if (0) 682 check_draw_arrays_data(ctx, start, count); 683 684 vbo_draw_arrays(ctx, mode, start, count, numInstances); 685 686 if (0) 687 print_draw_arrays(ctx, mode, start, count); 688} 689 690 691/** 692 * Map GL_ELEMENT_ARRAY_BUFFER and print contents. 693 * For debugging. 694 */ 695static void 696dump_element_buffer(struct gl_context *ctx, GLenum type) 697{ 698 const GLvoid *map = 699 ctx->Driver.MapBufferRange(ctx, 0, 700 ctx->Array.ArrayObj->ElementArrayBufferObj->Size, 701 GL_MAP_READ_BIT, 702 ctx->Array.ArrayObj->ElementArrayBufferObj); 703 switch (type) { 704 case GL_UNSIGNED_BYTE: 705 { 706 const GLubyte *us = (const GLubyte *) map; 707 GLint i; 708 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size; i++) { 709 printf("%02x ", us[i]); 710 if (i % 32 == 31) 711 printf("\n"); 712 } 713 printf("\n"); 714 } 715 break; 716 case GL_UNSIGNED_SHORT: 717 { 718 const GLushort *us = (const GLushort *) map; 719 GLint i; 720 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 2; i++) { 721 printf("%04x ", us[i]); 722 if (i % 16 == 15) 723 printf("\n"); 724 } 725 printf("\n"); 726 } 727 break; 728 case GL_UNSIGNED_INT: 729 { 730 const GLuint *us = (const GLuint *) map; 731 GLint i; 732 for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 4; i++) { 733 printf("%08x ", us[i]); 734 if (i % 8 == 7) 735 printf("\n"); 736 } 737 printf("\n"); 738 } 739 break; 740 default: 741 ; 742 } 743 744 ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj); 745} 746 747 748/** 749 * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements. 750 * Do the rendering for a glDrawElements or glDrawRangeElements call after 751 * we've validated buffer bounds, etc. 752 */ 753static void 754vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, 755 GLboolean index_bounds_valid, 756 GLuint start, GLuint end, 757 GLsizei count, GLenum type, 758 const GLvoid *indices, 759 GLint basevertex, GLint numInstances) 760{ 761 struct vbo_context *vbo = vbo_context(ctx); 762 struct vbo_exec_context *exec = &vbo->exec; 763 struct _mesa_index_buffer ib; 764 struct _mesa_prim prim[1]; 765 766 FLUSH_CURRENT( ctx, 0 ); 767 768 if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) { 769 return; 770 } 771 772 vbo_bind_arrays( ctx ); 773 774 /* check for dirty state again */ 775 if (ctx->NewState) 776 _mesa_update_state( ctx ); 777 778 ib.count = count; 779 ib.type = type; 780 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; 781 ib.ptr = indices; 782 783 prim[0].begin = 1; 784 prim[0].end = 1; 785 prim[0].weak = 0; 786 prim[0].pad = 0; 787 prim[0].mode = mode; 788 prim[0].start = 0; 789 prim[0].count = count; 790 prim[0].indexed = 1; 791 prim[0].basevertex = basevertex; 792 prim[0].num_instances = numInstances; 793 794 /* Need to give special consideration to rendering a range of 795 * indices starting somewhere above zero. Typically the 796 * application is issuing multiple DrawRangeElements() to draw 797 * successive primitives layed out linearly in the vertex arrays. 798 * Unless the vertex arrays are all in a VBO (or locked as with 799 * CVA), the OpenGL semantics imply that we need to re-read or 800 * re-upload the vertex data on each draw call. 801 * 802 * In the case of hardware tnl, we want to avoid starting the 803 * upload at zero, as it will mean every draw call uploads an 804 * increasing amount of not-used vertex data. Worse - in the 805 * software tnl module, all those vertices might be transformed and 806 * lit but never rendered. 807 * 808 * If we just upload or transform the vertices in start..end, 809 * however, the indices will be incorrect. 810 * 811 * At this level, we don't know exactly what the requirements of 812 * the backend are going to be, though it will likely boil down to 813 * either: 814 * 815 * 1) Do nothing, everything is in a VBO and is processed once 816 * only. 817 * 818 * 2) Adjust the indices and vertex arrays so that start becomes 819 * zero. 820 * 821 * Rather than doing anything here, I'll provide a helper function 822 * for the latter case elsewhere. 823 */ 824 825 check_buffers_are_unmapped(exec->array.inputs); 826 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, 827 index_bounds_valid, start, end ); 828} 829 830 831/** 832 * Called by glDrawRangeElementsBaseVertex() in immediate mode. 833 */ 834static void GLAPIENTRY 835vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, 836 GLuint start, GLuint end, 837 GLsizei count, GLenum type, 838 const GLvoid *indices, 839 GLint basevertex) 840{ 841 static GLuint warnCount = 0; 842 GET_CURRENT_CONTEXT(ctx); 843 844 if (MESA_VERBOSE & VERBOSE_DRAW) 845 _mesa_debug(ctx, 846 "glDrawRangeElementsBaseVertex(%s, %u, %u, %d, %s, %p, %d)\n", 847 _mesa_lookup_enum_by_nr(mode), start, end, count, 848 _mesa_lookup_enum_by_nr(type), indices, basevertex); 849 850 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, 851 type, indices, basevertex )) 852 return; 853 854 /* NOTE: It's important that 'end' is a reasonable value. 855 * in _tnl_draw_prims(), we use end to determine how many vertices 856 * to transform. If it's too large, we can unnecessarily split prims 857 * or we can read/write out of memory in several different places! 858 */ 859 860 /* Catch/fix some potential user errors */ 861 if (type == GL_UNSIGNED_BYTE) { 862 start = MIN2(start, 0xff); 863 end = MIN2(end, 0xff); 864 } 865 else if (type == GL_UNSIGNED_SHORT) { 866 start = MIN2(start, 0xffff); 867 end = MIN2(end, 0xffff); 868 } 869 870 if (end >= ctx->Array.ArrayObj->_MaxElement) { 871 /* the max element is out of bounds of one or more enabled arrays */ 872 warnCount++; 873 874 if (warnCount < 10) { 875 _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " 876 "type 0x%x, indices=%p)\n" 877 "\tend is out of bounds (max=%u) " 878 "Element Buffer %u (size %d)\n" 879 "\tThis should probably be fixed in the application.", 880 start, end, count, type, indices, 881 ctx->Array.ArrayObj->_MaxElement - 1, 882 ctx->Array.ArrayObj->ElementArrayBufferObj->Name, 883 (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size); 884 } 885 886 if (0) 887 dump_element_buffer(ctx, type); 888 889 if (0) 890 _mesa_print_arrays(ctx); 891 892 /* 'end' was out of bounds, but now let's check the actual array 893 * indexes to see if any of them are out of bounds. 894 */ 895 if (0) { 896 GLuint max = _mesa_max_buffer_index(ctx, count, type, indices, 897 ctx->Array.ArrayObj->ElementArrayBufferObj); 898 if (max >= ctx->Array.ArrayObj->_MaxElement) { 899 if (warnCount < 10) { 900 _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, " 901 "count %d, type 0x%x, indices=%p)\n" 902 "\tindex=%u is out of bounds (max=%u) " 903 "Element Buffer %u (size %d)\n" 904 "\tSkipping the glDrawRangeElements() call", 905 start, end, count, type, indices, max, 906 ctx->Array.ArrayObj->_MaxElement - 1, 907 ctx->Array.ArrayObj->ElementArrayBufferObj->Name, 908 (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size); 909 } 910 } 911 /* XXX we could also find the min index and compare to 'start' 912 * to see if start is correct. But it's more likely to get the 913 * upper bound wrong. 914 */ 915 } 916 917 /* Set 'end' to the max possible legal value */ 918 assert(ctx->Array.ArrayObj->_MaxElement >= 1); 919 end = ctx->Array.ArrayObj->_MaxElement - 1; 920 921 if (end < start) { 922 return; 923 } 924 } 925 926 if (0) { 927 printf("glDraw[Range]Elements{,BaseVertex}" 928 "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " 929 "base %d\n", 930 start, end, type, count, 931 ctx->Array.ArrayObj->ElementArrayBufferObj->Name, 932 basevertex); 933 } 934 935#if 0 936 check_draw_elements_data(ctx, count, type, indices); 937#else 938 (void) check_draw_elements_data; 939#endif 940 941 vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, 942 count, type, indices, basevertex, 1); 943} 944 945 946/** 947 * Called by glDrawRangeElements() in immediate mode. 948 */ 949static void GLAPIENTRY 950vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end, 951 GLsizei count, GLenum type, const GLvoid *indices) 952{ 953 if (MESA_VERBOSE & VERBOSE_DRAW) { 954 GET_CURRENT_CONTEXT(ctx); 955 _mesa_debug(ctx, 956 "glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n", 957 _mesa_lookup_enum_by_nr(mode), start, end, count, 958 _mesa_lookup_enum_by_nr(type), indices); 959 } 960 961 vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, 962 indices, 0); 963} 964 965 966/** 967 * Called by glDrawElements() in immediate mode. 968 */ 969static void GLAPIENTRY 970vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, 971 const GLvoid *indices) 972{ 973 GET_CURRENT_CONTEXT(ctx); 974 975 if (MESA_VERBOSE & VERBOSE_DRAW) 976 _mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n", 977 _mesa_lookup_enum_by_nr(mode), count, 978 _mesa_lookup_enum_by_nr(type), indices); 979 980 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) 981 return; 982 983 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 984 count, type, indices, 0, 1); 985} 986 987 988/** 989 * Called by glDrawElementsBaseVertex() in immediate mode. 990 */ 991static void GLAPIENTRY 992vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 993 const GLvoid *indices, GLint basevertex) 994{ 995 GET_CURRENT_CONTEXT(ctx); 996 997 if (MESA_VERBOSE & VERBOSE_DRAW) 998 _mesa_debug(ctx, "glDrawElementsBaseVertex(%s, %d, %s, %p, %d)\n", 999 _mesa_lookup_enum_by_nr(mode), count, 1000 _mesa_lookup_enum_by_nr(type), indices, basevertex); 1001 1002 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 1003 basevertex )) 1004 return; 1005 1006 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 1007 count, type, indices, basevertex, 1); 1008} 1009 1010 1011/** 1012 * Called by glDrawElementsInstanced() in immediate mode. 1013 */ 1014static void GLAPIENTRY 1015vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, 1016 const GLvoid *indices, GLsizei numInstances) 1017{ 1018 GET_CURRENT_CONTEXT(ctx); 1019 1020 if (MESA_VERBOSE & VERBOSE_DRAW) 1021 _mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n", 1022 _mesa_lookup_enum_by_nr(mode), count, 1023 _mesa_lookup_enum_by_nr(type), indices, numInstances); 1024 1025 if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, 1026 numInstances, 0)) 1027 return; 1028 1029 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 1030 count, type, indices, 0, numInstances); 1031} 1032 1033/** 1034 * Called by glDrawElementsInstancedBaseVertex() in immediate mode. 1035 */ 1036static void GLAPIENTRY 1037vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, 1038 const GLvoid *indices, GLsizei numInstances, 1039 GLint basevertex) 1040{ 1041 GET_CURRENT_CONTEXT(ctx); 1042 1043 if (MESA_VERBOSE & VERBOSE_DRAW) 1044 _mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n", 1045 _mesa_lookup_enum_by_nr(mode), count, 1046 _mesa_lookup_enum_by_nr(type), indices, 1047 numInstances, basevertex); 1048 1049 if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, 1050 numInstances, basevertex)) 1051 return; 1052 1053 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 1054 count, type, indices, basevertex, numInstances); 1055} 1056 1057 1058/** 1059 * Inner support for both _mesa_MultiDrawElements() and 1060 * _mesa_MultiDrawRangeElements(). 1061 * This does the actual rendering after we've checked array indexes, etc. 1062 */ 1063static void 1064vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, 1065 const GLsizei *count, GLenum type, 1066 const GLvoid **indices, GLsizei primcount, 1067 const GLint *basevertex) 1068{ 1069 struct vbo_context *vbo = vbo_context(ctx); 1070 struct vbo_exec_context *exec = &vbo->exec; 1071 struct _mesa_index_buffer ib; 1072 struct _mesa_prim *prim; 1073 unsigned int index_type_size = 0; 1074 uintptr_t min_index_ptr, max_index_ptr; 1075 GLboolean fallback = GL_FALSE; 1076 int i; 1077 1078 if (primcount == 0) 1079 return; 1080 1081 FLUSH_CURRENT( ctx, 0 ); 1082 1083 if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { 1084 return; 1085 } 1086 1087 prim = calloc(1, primcount * sizeof(*prim)); 1088 if (prim == NULL) { 1089 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); 1090 return; 1091 } 1092 1093 /* Decide if we can do this all as one set of primitives sharing the 1094 * same index buffer, or if we have to reset the index pointer per 1095 * primitive. 1096 */ 1097 vbo_bind_arrays( ctx ); 1098 1099 /* check for dirty state again */ 1100 if (ctx->NewState) 1101 _mesa_update_state( ctx ); 1102 1103 switch (type) { 1104 case GL_UNSIGNED_INT: 1105 index_type_size = 4; 1106 break; 1107 case GL_UNSIGNED_SHORT: 1108 index_type_size = 2; 1109 break; 1110 case GL_UNSIGNED_BYTE: 1111 index_type_size = 1; 1112 break; 1113 default: 1114 assert(0); 1115 } 1116 1117 min_index_ptr = (uintptr_t)indices[0]; 1118 max_index_ptr = 0; 1119 for (i = 0; i < primcount; i++) { 1120 min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); 1121 max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + 1122 index_type_size * count[i]); 1123 } 1124 1125 /* Check if we can handle this thing as a bunch of index offsets from the 1126 * same index pointer. If we can't, then we have to fall back to doing 1127 * a draw_prims per primitive. 1128 * Check that the difference between each prim's indexes is a multiple of 1129 * the index/element size. 1130 */ 1131 if (index_type_size != 1) { 1132 for (i = 0; i < primcount; i++) { 1133 if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { 1134 fallback = GL_TRUE; 1135 break; 1136 } 1137 } 1138 } 1139 1140 /* If the index buffer isn't in a VBO, then treating the application's 1141 * subranges of the index buffer as one large index buffer may lead to 1142 * us reading unmapped memory. 1143 */ 1144 if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) 1145 fallback = GL_TRUE; 1146 1147 if (!fallback) { 1148 ib.count = (max_index_ptr - min_index_ptr) / index_type_size; 1149 ib.type = type; 1150 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; 1151 ib.ptr = (void *)min_index_ptr; 1152 1153 for (i = 0; i < primcount; i++) { 1154 prim[i].begin = (i == 0); 1155 prim[i].end = (i == primcount - 1); 1156 prim[i].weak = 0; 1157 prim[i].pad = 0; 1158 prim[i].mode = mode; 1159 prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; 1160 prim[i].count = count[i]; 1161 prim[i].indexed = 1; 1162 prim[i].num_instances = 1; 1163 if (basevertex != NULL) 1164 prim[i].basevertex = basevertex[i]; 1165 else 1166 prim[i].basevertex = 0; 1167 } 1168 1169 check_buffers_are_unmapped(exec->array.inputs); 1170 vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, 1171 GL_FALSE, ~0, ~0); 1172 } else { 1173 /* render one prim at a time */ 1174 for (i = 0; i < primcount; i++) { 1175 ib.count = count[i]; 1176 ib.type = type; 1177 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; 1178 ib.ptr = indices[i]; 1179 1180 prim[0].begin = 1; 1181 prim[0].end = 1; 1182 prim[0].weak = 0; 1183 prim[0].pad = 0; 1184 prim[0].mode = mode; 1185 prim[0].start = 0; 1186 prim[0].count = count[i]; 1187 prim[0].indexed = 1; 1188 prim[0].num_instances = 1; 1189 if (basevertex != NULL) 1190 prim[0].basevertex = basevertex[i]; 1191 else 1192 prim[0].basevertex = 0; 1193 1194 check_buffers_are_unmapped(exec->array.inputs); 1195 vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, 1196 GL_FALSE, ~0, ~0); 1197 } 1198 } 1199 1200 free(prim); 1201} 1202 1203 1204static void GLAPIENTRY 1205vbo_exec_MultiDrawElements(GLenum mode, 1206 const GLsizei *count, GLenum type, 1207 const GLvoid **indices, 1208 GLsizei primcount) 1209{ 1210 GET_CURRENT_CONTEXT(ctx); 1211 GLint i; 1212 1213 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 1214 1215 for (i = 0; i < primcount; i++) { 1216 if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], 1217 0)) 1218 return; 1219 } 1220 1221 vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, 1222 NULL); 1223} 1224 1225 1226static void GLAPIENTRY 1227vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, 1228 const GLsizei *count, GLenum type, 1229 const GLvoid **indices, 1230 GLsizei primcount, 1231 const GLsizei *basevertex) 1232{ 1233 GET_CURRENT_CONTEXT(ctx); 1234 GLint i; 1235 1236 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 1237 1238 for (i = 0; i < primcount; i++) { 1239 if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], 1240 basevertex[i])) 1241 return; 1242 } 1243 1244 vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, 1245 basevertex); 1246} 1247 1248 1249/** 1250 * Plug in the immediate-mode vertex array drawing commands into the 1251 * givven vbo_exec_context object. 1252 */ 1253void 1254vbo_exec_array_init( struct vbo_exec_context *exec ) 1255{ 1256 exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; 1257 exec->vtxfmt.DrawElements = vbo_exec_DrawElements; 1258 exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; 1259 exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; 1260 exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; 1261 exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; 1262 exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; 1263 exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced; 1264 exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced; 1265 exec->vtxfmt.DrawElementsInstancedBaseVertex = vbo_exec_DrawElementsInstancedBaseVertex; 1266} 1267 1268 1269void 1270vbo_exec_array_destroy( struct vbo_exec_context *exec ) 1271{ 1272 /* nothing to do */ 1273} 1274 1275 1276 1277/** 1278 * The following functions are only used for OpenGL ES 1/2 support. 1279 * And some aren't even supported (yet) in ES 1/2. 1280 */ 1281 1282 1283void GLAPIENTRY 1284_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count) 1285{ 1286 vbo_exec_DrawArrays(mode, first, count); 1287} 1288 1289 1290void GLAPIENTRY 1291_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, 1292 const GLvoid *indices) 1293{ 1294 vbo_exec_DrawElements(mode, count, type, indices); 1295} 1296 1297 1298void GLAPIENTRY 1299_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 1300 const GLvoid *indices, GLint basevertex) 1301{ 1302 vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); 1303} 1304 1305 1306void GLAPIENTRY 1307_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, 1308 GLenum type, const GLvoid *indices) 1309{ 1310 vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); 1311} 1312 1313 1314void GLAPIENTRY 1315_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, 1316 GLsizei count, GLenum type, 1317 const GLvoid *indices, GLint basevertex) 1318{ 1319 vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, 1320 indices, basevertex); 1321} 1322 1323 1324void GLAPIENTRY 1325_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, 1326 const GLvoid **indices, GLsizei primcount) 1327{ 1328 vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); 1329} 1330 1331 1332void GLAPIENTRY 1333_mesa_MultiDrawElementsBaseVertex(GLenum mode, 1334 const GLsizei *count, GLenum type, 1335 const GLvoid **indices, GLsizei primcount, 1336 const GLint *basevertex) 1337{ 1338 vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, 1339 primcount, basevertex); 1340} 1341