vbo_exec_array.c revision 29d27229a95837d085db785a2b4abb654457dafa
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/api_noop.h" 34#include "main/varray.h" 35#include "main/bufferobj.h" 36#include "main/macros.h" 37#include "glapi/dispatch.h" 38 39#include "vbo_context.h" 40 41 42/** 43 * Compute min and max elements for glDraw[Range]Elements() calls. 44 */ 45void 46vbo_get_minmax_index(GLcontext *ctx, 47 const struct _mesa_prim *prim, 48 const struct _mesa_index_buffer *ib, 49 GLuint *min_index, GLuint *max_index) 50{ 51 GLuint i; 52 GLsizei count = prim->count; 53 const void *indices; 54 55 if (_mesa_is_bufferobj(ib->obj)) { 56 const GLvoid *map = ctx->Driver.MapBuffer(ctx, 57 GL_ELEMENT_ARRAY_BUFFER_ARB, 58 GL_READ_ONLY, 59 ib->obj); 60 indices = ADD_POINTERS(map, ib->ptr); 61 } else { 62 indices = ib->ptr; 63 } 64 65 switch (ib->type) { 66 case GL_UNSIGNED_INT: { 67 const GLuint *ui_indices = (const GLuint *)indices; 68 GLuint max_ui = ui_indices[count-1]; 69 GLuint min_ui = ui_indices[0]; 70 for (i = 0; i < count; i++) { 71 if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; 72 if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; 73 } 74 *min_index = min_ui; 75 *max_index = max_ui; 76 break; 77 } 78 case GL_UNSIGNED_SHORT: { 79 const GLushort *us_indices = (const GLushort *)indices; 80 GLuint max_us = us_indices[count-1]; 81 GLuint min_us = us_indices[0]; 82 for (i = 0; i < count; i++) { 83 if (us_indices[i] > max_us) max_us = us_indices[i]; 84 if (us_indices[i] < min_us) min_us = us_indices[i]; 85 } 86 *min_index = min_us; 87 *max_index = max_us; 88 break; 89 } 90 case GL_UNSIGNED_BYTE: { 91 const GLubyte *ub_indices = (const GLubyte *)indices; 92 GLuint max_ub = ub_indices[count-1]; 93 GLuint min_ub = ub_indices[0]; 94 for (i = 0; i < count; i++) { 95 if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; 96 if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; 97 } 98 *min_index = min_ub; 99 *max_index = max_ub; 100 break; 101 } 102 default: 103 assert(0); 104 break; 105 } 106 107 if (_mesa_is_bufferobj(ib->obj)) { 108 ctx->Driver.UnmapBuffer(ctx, 109 GL_ELEMENT_ARRAY_BUFFER_ARB, 110 ib->obj); 111 } 112} 113 114 115/** 116 * Check that element 'j' of the array has reasonable data. 117 * Map VBO if needed. 118 */ 119static void 120check_array_data(GLcontext *ctx, struct gl_client_array *array, 121 GLuint attrib, GLuint j) 122{ 123 if (array->Enabled) { 124 const void *data = array->Ptr; 125 if (_mesa_is_bufferobj(array->BufferObj)) { 126 if (!array->BufferObj->Pointer) { 127 /* need to map now */ 128 array->BufferObj->Pointer = ctx->Driver.MapBuffer(ctx, 129 GL_ARRAY_BUFFER_ARB, 130 GL_READ_ONLY, 131 array->BufferObj); 132 } 133 data = ADD_POINTERS(data, array->BufferObj->Pointer); 134 } 135 switch (array->Type) { 136 case GL_FLOAT: 137 { 138 GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j); 139 GLuint k; 140 for (k = 0; k < array->Size; k++) { 141 if (IS_INF_OR_NAN(f[k]) || 142 f[k] >= 1.0e20 || f[k] <= -1.0e10) { 143 _mesa_printf("Bad array data:\n"); 144 _mesa_printf(" Element[%u].%u = %f\n", j, k, f[k]); 145 _mesa_printf(" Array %u at %p\n", attrib, (void* ) array); 146 _mesa_printf(" Type 0x%x, Size %d, Stride %d\n", 147 array->Type, array->Size, array->Stride); 148 _mesa_printf(" Address/offset %p in Buffer Object %u\n", 149 array->Ptr, array->BufferObj->Name); 150 f[k] = 1.0; /* XXX replace the bad value! */ 151 } 152 //assert(!IS_INF_OR_NAN(f[k])); 153 } 154 } 155 break; 156 default: 157 ; 158 } 159 } 160} 161 162 163/** 164 * Unmap the buffer object referenced by given array, if mapped. 165 */ 166static void 167unmap_array_buffer(GLcontext *ctx, struct gl_client_array *array) 168{ 169 if (array->Enabled && 170 _mesa_is_bufferobj(array->BufferObj) && 171 _mesa_bufferobj_mapped(array->BufferObj)) { 172 ctx->Driver.UnmapBuffer(ctx, 173 GL_ARRAY_BUFFER_ARB, 174 array->BufferObj); 175 } 176} 177 178 179/** 180 * Examine the array's data for NaNs, etc. 181 */ 182static void 183check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType, 184 const void *elements, GLint basevertex) 185{ 186 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 187 const void *elemMap; 188 GLint i, k; 189 190 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 191 elemMap = ctx->Driver.MapBuffer(ctx, 192 GL_ELEMENT_ARRAY_BUFFER_ARB, 193 GL_READ_ONLY, 194 ctx->Array.ElementArrayBufferObj); 195 elements = ADD_POINTERS(elements, elemMap); 196 } 197 198 for (i = 0; i < count; i++) { 199 GLuint j; 200 201 /* j = element[i] */ 202 switch (elemType) { 203 case GL_UNSIGNED_BYTE: 204 j = ((const GLubyte *) elements)[i]; 205 break; 206 case GL_UNSIGNED_SHORT: 207 j = ((const GLushort *) elements)[i]; 208 break; 209 case GL_UNSIGNED_INT: 210 j = ((const GLuint *) elements)[i]; 211 break; 212 default: 213 assert(0); 214 } 215 216 /* check element j of each enabled array */ 217 check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j); 218 check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j); 219 check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j); 220 check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j); 221 for (k = 0; k < Elements(arrayObj->TexCoord); k++) { 222 check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j); 223 } 224 for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { 225 check_array_data(ctx, &arrayObj->VertexAttrib[k], VERT_ATTRIB_GENERIC0 + k, j); 226 } 227 } 228 229 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 230 ctx->Driver.UnmapBuffer(ctx, 231 GL_ELEMENT_ARRAY_BUFFER_ARB, 232 ctx->Array.ElementArrayBufferObj); 233 } 234 235 unmap_array_buffer(ctx, &arrayObj->Vertex); 236 unmap_array_buffer(ctx, &arrayObj->Normal); 237 unmap_array_buffer(ctx, &arrayObj->Color); 238 for (k = 0; k < Elements(arrayObj->TexCoord); k++) { 239 unmap_array_buffer(ctx, &arrayObj->TexCoord[k]); 240 } 241 for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { 242 unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); 243 } 244} 245 246 247/** 248 * Check array data, looking for NaNs, etc. 249 */ 250static void 251check_draw_arrays_data(GLcontext *ctx, GLint start, GLsizei count) 252{ 253 /* TO DO */ 254} 255 256 257/** 258 * Print info/data for glDrawArrays(). 259 */ 260static void 261print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec, 262 GLenum mode, GLint start, GLsizei count) 263{ 264 int i; 265 266 _mesa_printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n", 267 mode, start, count); 268 269 for (i = 0; i < 32; i++) { 270 GLuint bufName = exec->array.inputs[i]->BufferObj->Name; 271 GLint stride = exec->array.inputs[i]->Stride; 272 _mesa_printf("attr %2d: size %d stride %d enabled %d " 273 "ptr %p Bufobj %u\n", 274 i, 275 exec->array.inputs[i]->Size, 276 stride, 277 /*exec->array.inputs[i]->Enabled,*/ 278 exec->array.legacy_array[i]->Enabled, 279 exec->array.inputs[i]->Ptr, 280 bufName); 281 282 if (bufName) { 283 struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName); 284 GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, 285 GL_READ_ONLY_ARB, buf); 286 int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr; 287 float *f = (float *) (p + offset); 288 int *k = (int *) f; 289 int i; 290 int n = (count * stride) / 4; 291 if (n > 32) 292 n = 32; 293 _mesa_printf(" Data at offset %d:\n", offset); 294 for (i = 0; i < n; i++) { 295 _mesa_printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]); 296 } 297 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, buf); 298 } 299 } 300} 301 302 303/** 304 * Just translate the arrayobj into a sane layout. 305 */ 306static void 307bind_array_obj(GLcontext *ctx) 308{ 309 struct vbo_context *vbo = vbo_context(ctx); 310 struct vbo_exec_context *exec = &vbo->exec; 311 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 312 GLuint i; 313 314 /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array 315 * rather than as individual named arrays. Then this function can 316 * go away. 317 */ 318 exec->array.legacy_array[VERT_ATTRIB_POS] = &arrayObj->Vertex; 319 exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &arrayObj->Weight; 320 exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &arrayObj->Normal; 321 exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &arrayObj->Color; 322 exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &arrayObj->SecondaryColor; 323 exec->array.legacy_array[VERT_ATTRIB_FOG] = &arrayObj->FogCoord; 324 exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &arrayObj->Index; 325 if (arrayObj->PointSize.Enabled) { 326 /* this aliases COLOR_INDEX */ 327 exec->array.legacy_array[VERT_ATTRIB_POINT_SIZE] = &arrayObj->PointSize; 328 } 329 exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &arrayObj->EdgeFlag; 330 331 for (i = 0; i < Elements(arrayObj->TexCoord); i++) 332 exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i]; 333 334 for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) { 335 assert(i < Elements(exec->array.generic_array)); 336 exec->array.generic_array[i] = &arrayObj->VertexAttrib[i]; 337 } 338 339 exec->array.array_obj = arrayObj->Name; 340} 341 342 343static void 344recalculate_input_bindings(GLcontext *ctx) 345{ 346 struct vbo_context *vbo = vbo_context(ctx); 347 struct vbo_exec_context *exec = &vbo->exec; 348 const struct gl_client_array **inputs = &exec->array.inputs[0]; 349 GLbitfield const_inputs = 0x0; 350 GLuint i; 351 352 exec->array.program_mode = get_program_mode(ctx); 353 exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled; 354 355 switch (exec->array.program_mode) { 356 case VP_NONE: 357 /* When no vertex program is active (or the vertex program is generated 358 * from fixed-function state). We put the material values into the 359 * generic slots. This is the only situation where material values 360 * are available as per-vertex attributes. 361 */ 362 for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { 363 if (exec->array.legacy_array[i]->Enabled) 364 inputs[i] = exec->array.legacy_array[i]; 365 else { 366 inputs[i] = &vbo->legacy_currval[i]; 367 const_inputs |= 1 << i; 368 } 369 } 370 371 for (i = 0; i < MAT_ATTRIB_MAX; i++) { 372 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->mat_currval[i]; 373 const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); 374 } 375 376 /* Could use just about anything, just to fill in the empty 377 * slots: 378 */ 379 for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) { 380 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; 381 const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); 382 } 383 break; 384 385 case VP_NV: 386 /* NV_vertex_program - attribute arrays alias and override 387 * conventional, legacy arrays. No materials, and the generic 388 * slots are vacant. 389 */ 390 for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { 391 if (exec->array.generic_array[i]->Enabled) 392 inputs[i] = exec->array.generic_array[i]; 393 else if (exec->array.legacy_array[i]->Enabled) 394 inputs[i] = exec->array.legacy_array[i]; 395 else { 396 inputs[i] = &vbo->legacy_currval[i]; 397 const_inputs |= 1 << i; 398 } 399 } 400 401 /* Could use just about anything, just to fill in the empty 402 * slots: 403 */ 404 for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) { 405 inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; 406 const_inputs |= 1 << i; 407 } 408 break; 409 410 case VP_ARB: 411 /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0] 412 * attribute array aliases and overrides the legacy position array. 413 * 414 * Otherwise, legacy attributes available in the legacy slots, 415 * generic attributes in the generic slots and materials are not 416 * available as per-vertex attributes. 417 */ 418 if (exec->array.generic_array[0]->Enabled) 419 inputs[0] = exec->array.generic_array[0]; 420 else if (exec->array.legacy_array[0]->Enabled) 421 inputs[0] = exec->array.legacy_array[0]; 422 else { 423 inputs[0] = &vbo->legacy_currval[0]; 424 const_inputs |= 1 << 0; 425 } 426 427 for (i = 1; i <= VERT_ATTRIB_TEX7; i++) { 428 if (exec->array.legacy_array[i]->Enabled) 429 inputs[i] = exec->array.legacy_array[i]; 430 else { 431 inputs[i] = &vbo->legacy_currval[i]; 432 const_inputs |= 1 << i; 433 } 434 } 435 436 for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { 437 if (exec->array.generic_array[i]->Enabled) 438 inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i]; 439 else { 440 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; 441 const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); 442 } 443 444 } 445 break; 446 } 447 448 _mesa_set_varying_vp_inputs( ctx, ~const_inputs ); 449} 450 451 452static void 453bind_arrays(GLcontext *ctx) 454{ 455#if 0 456 if (ctx->Array.ArrayObj.Name != exec->array.array_obj) { 457 bind_array_obj(ctx); 458 recalculate_input_bindings(ctx); 459 } 460 else if (exec->array.program_mode != get_program_mode(ctx) || 461 exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) { 462 463 recalculate_input_bindings(ctx); 464 } 465#else 466 bind_array_obj(ctx); 467 recalculate_input_bindings(ctx); 468#endif 469} 470 471 472 473/*********************************************************************** 474 * API functions. 475 */ 476 477static void GLAPIENTRY 478vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) 479{ 480 GET_CURRENT_CONTEXT(ctx); 481 struct vbo_context *vbo = vbo_context(ctx); 482 struct vbo_exec_context *exec = &vbo->exec; 483 struct _mesa_prim prim[1]; 484 485 if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) 486 return; 487 488 FLUSH_CURRENT( ctx, 0 ); 489 490 if (ctx->NewState) 491 _mesa_update_state( ctx ); 492 493 if (!_mesa_valid_to_render(ctx, "glDrawArrays")) { 494 return; 495 } 496 497#if 0 498 check_draw_arrays_data(ctx, start, count); 499#else 500 (void) check_draw_arrays_data; 501#endif 502 503 bind_arrays( ctx ); 504 505 /* Again... because we may have changed the bitmask of per-vertex varying 506 * attributes. If we regenerate the fixed-function vertex program now 507 * we may be able to prune down the number of vertex attributes which we 508 * need in the shader. 509 */ 510 if (ctx->NewState) 511 _mesa_update_state( ctx ); 512 513 prim[0].begin = 1; 514 prim[0].end = 1; 515 prim[0].weak = 0; 516 prim[0].pad = 0; 517 prim[0].mode = mode; 518 prim[0].start = start; 519 prim[0].count = count; 520 prim[0].indexed = 0; 521 prim[0].basevertex = 0; 522 523 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, 524 GL_TRUE, start, start + count - 1 ); 525 526#if 0 527 print_draw_arrays(ctx, exec, mode, start, count); 528#else 529 (void) print_draw_arrays; 530#endif 531} 532 533 534/** 535 * Map GL_ELEMENT_ARRAY_BUFFER and print contents. 536 */ 537static void 538dump_element_buffer(GLcontext *ctx, GLenum type) 539{ 540 const GLvoid *map = ctx->Driver.MapBuffer(ctx, 541 GL_ELEMENT_ARRAY_BUFFER_ARB, 542 GL_READ_ONLY, 543 ctx->Array.ElementArrayBufferObj); 544 switch (type) { 545 case GL_UNSIGNED_BYTE: 546 { 547 const GLubyte *us = (const GLubyte *) map; 548 GLuint i; 549 for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) { 550 _mesa_printf("%02x ", us[i]); 551 if (i % 32 == 31) 552 _mesa_printf("\n"); 553 } 554 _mesa_printf("\n"); 555 } 556 break; 557 case GL_UNSIGNED_SHORT: 558 { 559 const GLushort *us = (const GLushort *) map; 560 GLuint i; 561 for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) { 562 _mesa_printf("%04x ", us[i]); 563 if (i % 16 == 15) 564 _mesa_printf("\n"); 565 } 566 _mesa_printf("\n"); 567 } 568 break; 569 case GL_UNSIGNED_INT: 570 { 571 const GLuint *us = (const GLuint *) map; 572 GLuint i; 573 for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) { 574 _mesa_printf("%08x ", us[i]); 575 if (i % 8 == 7) 576 _mesa_printf("\n"); 577 } 578 _mesa_printf("\n"); 579 } 580 break; 581 default: 582 ; 583 } 584 585 ctx->Driver.UnmapBuffer(ctx, 586 GL_ELEMENT_ARRAY_BUFFER_ARB, 587 ctx->Array.ElementArrayBufferObj); 588} 589 590/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */ 591static void 592vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, 593 GLboolean index_bounds_valid, 594 GLuint start, GLuint end, 595 GLsizei count, GLenum type, 596 const GLvoid *indices, 597 GLint basevertex) 598{ 599 struct vbo_context *vbo = vbo_context(ctx); 600 struct vbo_exec_context *exec = &vbo->exec; 601 struct _mesa_index_buffer ib; 602 struct _mesa_prim prim[1]; 603 604 FLUSH_CURRENT( ctx, 0 ); 605 606 if (ctx->NewState) 607 _mesa_update_state( ctx ); 608 609 if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) { 610 return; 611 } 612 613 if (ctx->NewState) 614 _mesa_update_state( ctx ); 615 616 bind_arrays( ctx ); 617 618 ib.count = count; 619 ib.type = type; 620 ib.obj = ctx->Array.ElementArrayBufferObj; 621 ib.ptr = indices; 622 623 prim[0].begin = 1; 624 prim[0].end = 1; 625 prim[0].weak = 0; 626 prim[0].pad = 0; 627 prim[0].mode = mode; 628 prim[0].start = 0; 629 prim[0].count = count; 630 prim[0].indexed = 1; 631 prim[0].basevertex = basevertex; 632 633 /* Need to give special consideration to rendering a range of 634 * indices starting somewhere above zero. Typically the 635 * application is issuing multiple DrawRangeElements() to draw 636 * successive primitives layed out linearly in the vertex arrays. 637 * Unless the vertex arrays are all in a VBO (or locked as with 638 * CVA), the OpenGL semantics imply that we need to re-read or 639 * re-upload the vertex data on each draw call. 640 * 641 * In the case of hardware tnl, we want to avoid starting the 642 * upload at zero, as it will mean every draw call uploads an 643 * increasing amount of not-used vertex data. Worse - in the 644 * software tnl module, all those vertices might be transformed and 645 * lit but never rendered. 646 * 647 * If we just upload or transform the vertices in start..end, 648 * however, the indices will be incorrect. 649 * 650 * At this level, we don't know exactly what the requirements of 651 * the backend are going to be, though it will likely boil down to 652 * either: 653 * 654 * 1) Do nothing, everything is in a VBO and is processed once 655 * only. 656 * 657 * 2) Adjust the indices and vertex arrays so that start becomes 658 * zero. 659 * 660 * Rather than doing anything here, I'll provide a helper function 661 * for the latter case elsewhere. 662 */ 663 664 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, 665 index_bounds_valid, start, end ); 666} 667 668static void GLAPIENTRY 669vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, 670 GLuint start, GLuint end, 671 GLsizei count, GLenum type, 672 const GLvoid *indices, 673 GLint basevertex) 674{ 675 static GLuint warnCount = 0; 676 GET_CURRENT_CONTEXT(ctx); 677 678 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, 679 type, indices, basevertex )) 680 return; 681 682 /* NOTE: It's important that 'end' is a reasonable value. 683 * in _tnl_draw_prims(), we use end to determine how many vertices 684 * to transform. If it's too large, we can unnecessarily split prims 685 * or we can read/write out of memory in several different places! 686 */ 687 688 if (end >= ctx->Array.ArrayObj->_MaxElement) { 689 /* the max element is out of bounds of one or more enabled arrays */ 690 warnCount++; 691 692 if (warnCount < 10) { 693 _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " 694 "type 0x%x, indices=%p)\n" 695 "\tend is out of bounds (max=%u) " 696 "Element Buffer %u (size %d)\n" 697 "\tThis should probably be fixed in the application.", 698 start, end, count, type, indices, 699 ctx->Array.ArrayObj->_MaxElement - 1, 700 ctx->Array.ElementArrayBufferObj->Name, 701 ctx->Array.ElementArrayBufferObj->Size); 702 } 703 704 if (0) 705 dump_element_buffer(ctx, type); 706 707 if (0) 708 _mesa_print_arrays(ctx); 709 710#ifdef DEBUG 711 /* 'end' was out of bounds, but now let's check the actual array 712 * indexes to see if any of them are out of bounds. If so, warn 713 * and skip the draw to avoid potential segfault, etc. 714 */ 715 { 716 GLuint max = _mesa_max_buffer_index(ctx, count, type, indices, 717 ctx->Array.ElementArrayBufferObj); 718 if (max >= ctx->Array.ArrayObj->_MaxElement) { 719 if (warnCount < 10) { 720 _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, " 721 "count %d, type 0x%x, indices=%p)\n" 722 "\tindex=%u is out of bounds (max=%u) " 723 "Element Buffer %u (size %d)\n" 724 "\tSkipping the glDrawRangeElements() call", 725 start, end, count, type, indices, max, 726 ctx->Array.ArrayObj->_MaxElement - 1, 727 ctx->Array.ElementArrayBufferObj->Name, 728 ctx->Array.ElementArrayBufferObj->Size); 729 } 730 return; 731 } 732 /* XXX we could also find the min index and compare to 'start' 733 * to see if start is correct. But it's more likely to get the 734 * upper bound wrong. 735 */ 736 } 737#endif 738 } 739 else if (0) { 740 _mesa_printf("glDraw[Range]Elements{,BaseVertex}" 741 "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " 742 "base %d\n", 743 start, end, type, count, 744 ctx->Array.ElementArrayBufferObj->Name, 745 basevertex); 746 } 747 748#if 0 749 check_draw_elements_data(ctx, count, type, indices); 750#else 751 (void) check_draw_elements_data; 752#endif 753 754 vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, 755 count, type, indices, basevertex); 756} 757 758static void GLAPIENTRY 759vbo_exec_DrawRangeElements(GLenum mode, 760 GLuint start, GLuint end, 761 GLsizei count, GLenum type, 762 const GLvoid *indices) 763{ 764 vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, 765 indices, 0); 766} 767 768 769static void GLAPIENTRY 770vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, 771 const GLvoid *indices) 772{ 773 GET_CURRENT_CONTEXT(ctx); 774 775 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) 776 return; 777 778 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 779 count, type, indices, 0); 780} 781 782static void GLAPIENTRY 783vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 784 const GLvoid *indices, GLint basevertex) 785{ 786 GET_CURRENT_CONTEXT(ctx); 787 788 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 789 basevertex )) 790 return; 791 792 vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, 793 count, type, indices, basevertex); 794} 795 796/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */ 797static void 798vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, 799 const GLsizei *count, GLenum type, 800 const GLvoid **indices, GLsizei primcount, 801 const GLint *basevertex) 802{ 803 struct vbo_context *vbo = vbo_context(ctx); 804 struct vbo_exec_context *exec = &vbo->exec; 805 struct _mesa_index_buffer ib; 806 struct _mesa_prim *prim; 807 unsigned int index_type_size = 0; 808 uintptr_t min_index_ptr, max_index_ptr; 809 GLboolean fallback = GL_FALSE; 810 int i; 811 812 if (primcount == 0) 813 return; 814 815 FLUSH_CURRENT( ctx, 0 ); 816 817 if (ctx->NewState) 818 _mesa_update_state( ctx ); 819 820 if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { 821 return; 822 } 823 824 if (ctx->NewState) 825 _mesa_update_state( ctx ); 826 827 prim = _mesa_calloc(primcount * sizeof(*prim)); 828 if (prim == NULL) { 829 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); 830 return; 831 } 832 833 /* Decide if we can do this all as one set of primitives sharing the 834 * same index buffer, or if we have to reset the index pointer per primitive. 835 */ 836 bind_arrays( ctx ); 837 838 switch (type) { 839 case GL_UNSIGNED_INT: 840 index_type_size = 4; 841 break; 842 case GL_UNSIGNED_SHORT: 843 index_type_size = 2; 844 break; 845 case GL_UNSIGNED_BYTE: 846 index_type_size = 1; 847 break; 848 default: 849 assert(0); 850 } 851 852 min_index_ptr = (uintptr_t)indices[0]; 853 max_index_ptr = 0; 854 for (i = 0; i < primcount; i++) { 855 min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); 856 max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + 857 index_type_size * count[i]); 858 } 859 860 /* Check if we can handle this thing as a bunch of index offsets from the 861 * same index pointer. If we can't, then we have to fall back to doing 862 * a draw_prims per primitive. 863 */ 864 if (index_type_size != 1) { 865 for (i = 0; i < primcount; i++) { 866 if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { 867 fallback = GL_TRUE; 868 break; 869 } 870 } 871 } 872 873 /* If the index buffer isn't in a VBO, then treating the application's 874 * subranges of the index buffer as one large index buffer may lead to 875 * us reading unmapped memory. 876 */ 877 if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) 878 fallback = GL_TRUE; 879 880 if (!fallback) { 881 ib.count = (max_index_ptr - min_index_ptr) / index_type_size; 882 ib.type = type; 883 ib.obj = ctx->Array.ElementArrayBufferObj; 884 ib.ptr = (void *)min_index_ptr; 885 886 for (i = 0; i < primcount; i++) { 887 prim[i].begin = (i == 0); 888 prim[i].end = (i == primcount - 1); 889 prim[i].weak = 0; 890 prim[i].pad = 0; 891 prim[i].mode = mode; 892 prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; 893 prim[i].count = count[i]; 894 prim[i].indexed = 1; 895 if (basevertex != NULL) 896 prim[i].basevertex = basevertex[i]; 897 else 898 prim[i].basevertex = 0; 899 } 900 901 vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, 902 GL_FALSE, ~0, ~0); 903 } else { 904 for (i = 0; i < primcount; i++) { 905 ib.count = count[i]; 906 ib.type = type; 907 ib.obj = ctx->Array.ElementArrayBufferObj; 908 ib.ptr = indices[i]; 909 910 911 prim[0].begin = 1; 912 prim[0].end = 1; 913 prim[0].weak = 0; 914 prim[0].pad = 0; 915 prim[0].mode = mode; 916 prim[0].start = 0; 917 prim[0].count = count[i]; 918 prim[0].indexed = 1; 919 if (basevertex != NULL) 920 prim[0].basevertex = basevertex[i]; 921 else 922 prim[0].basevertex = 0; 923 } 924 925 vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, 926 GL_FALSE, ~0, ~0); 927 } 928 _mesa_free(prim); 929} 930 931static void GLAPIENTRY 932vbo_exec_MultiDrawElements(GLenum mode, 933 const GLsizei *count, GLenum type, 934 const GLvoid **indices, 935 GLsizei primcount) 936{ 937 GET_CURRENT_CONTEXT(ctx); 938 GLint i; 939 940 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 941 942 for (i = 0; i < primcount; i++) { 943 if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], 944 0)) 945 return; 946 } 947 948 vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, 949 NULL); 950} 951 952static void GLAPIENTRY 953vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, 954 const GLsizei *count, GLenum type, 955 const GLvoid **indices, 956 GLsizei primcount, 957 const GLsizei *basevertex) 958{ 959 GET_CURRENT_CONTEXT(ctx); 960 GLint i; 961 962 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 963 964 for (i = 0; i < primcount; i++) { 965 if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], 966 basevertex[i])) 967 return; 968 } 969 970 vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, 971 basevertex); 972} 973 974 975/*********************************************************************** 976 * Initialization 977 */ 978 979void 980vbo_exec_array_init( struct vbo_exec_context *exec ) 981{ 982#if 1 983 exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; 984 exec->vtxfmt.DrawElements = vbo_exec_DrawElements; 985 exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; 986 exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; 987 exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; 988 exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; 989 exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; 990#else 991 exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays; 992 exec->vtxfmt.DrawElements = _mesa_noop_DrawElements; 993 exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements; 994 exec->vtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; 995 exec->vtxfmt.DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex; 996 exec->vtxfmt.DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex; 997 exec->vtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; 998#endif 999} 1000 1001 1002void 1003vbo_exec_array_destroy( struct vbo_exec_context *exec ) 1004{ 1005 /* nothing to do */ 1006} 1007 1008 1009/* This API entrypoint is not ordinarily used */ 1010void GLAPIENTRY 1011_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count) 1012{ 1013 vbo_exec_DrawArrays(mode, first, count); 1014} 1015 1016 1017/* This API entrypoint is not ordinarily used */ 1018void GLAPIENTRY 1019_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, 1020 const GLvoid *indices) 1021{ 1022 vbo_exec_DrawElements(mode, count, type, indices); 1023} 1024 1025void GLAPIENTRY 1026_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, 1027 const GLvoid *indices, GLint basevertex) 1028{ 1029 vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); 1030} 1031 1032 1033/* This API entrypoint is not ordinarily used */ 1034void GLAPIENTRY 1035_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, 1036 GLenum type, const GLvoid *indices) 1037{ 1038 vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); 1039} 1040 1041void GLAPIENTRY 1042_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, 1043 GLsizei count, GLenum type, 1044 const GLvoid *indices, GLint basevertex) 1045{ 1046 vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, 1047 indices, basevertex); 1048} 1049 1050/* GL_EXT_multi_draw_arrays */ 1051void GLAPIENTRY 1052_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, 1053 const GLvoid **indices, GLsizei primcount) 1054{ 1055 vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); 1056} 1057 1058void GLAPIENTRY 1059_mesa_MultiDrawElementsBaseVertex(GLenum mode, 1060 const GLsizei *count, GLenum type, 1061 const GLvoid **indices, GLsizei primcount, 1062 const GLint *basevertex) 1063{ 1064 vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, 1065 primcount, basevertex); 1066} 1067