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