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