vbo_exec_api.c revision 3464ebd5
1/************************************************************************** 2 3Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas. 4 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the "Software"), 9to deal in the Software without restriction, including without limitation 10on the rights to use, copy, modify, merge, publish, distribute, sub 11license, and/or sell copies of the Software, and to permit persons to whom 12the Software is furnished to do so, subject to the following conditions: 13 14The above copyright notice and this permission notice (including the next 15paragraph) shall be included in all copies or substantial portions of the 16Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26**************************************************************************/ 27 28/* 29 * Authors: 30 * Keith Whitwell <keith@tungstengraphics.com> 31 */ 32 33#include "main/glheader.h" 34#include "main/bufferobj.h" 35#include "main/context.h" 36#include "main/macros.h" 37#include "main/mfeatures.h" 38#include "main/vtxfmt.h" 39#include "main/dlist.h" 40#include "main/eval.h" 41#include "main/state.h" 42#include "main/light.h" 43#include "main/api_arrayelt.h" 44#include "main/api_noop.h" 45#include "main/dispatch.h" 46 47#include "vbo_context.h" 48 49#ifdef ERROR 50#undef ERROR 51#endif 52 53 54/** ID/name for immediate-mode VBO */ 55#define IMM_BUFFER_NAME 0xaabbccdd 56 57 58static void reset_attrfv( struct vbo_exec_context *exec ); 59 60 61/** 62 * Close off the last primitive, execute the buffer, restart the 63 * primitive. 64 */ 65static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec ) 66{ 67 if (exec->vtx.prim_count == 0) { 68 exec->vtx.copied.nr = 0; 69 exec->vtx.vert_count = 0; 70 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 71 } 72 else { 73 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin; 74 GLuint last_count; 75 76 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 77 GLint i = exec->vtx.prim_count - 1; 78 assert(i >= 0); 79 exec->vtx.prim[i].count = (exec->vtx.vert_count - 80 exec->vtx.prim[i].start); 81 } 82 83 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count; 84 85 /* Execute the buffer and save copied vertices. 86 */ 87 if (exec->vtx.vert_count) 88 vbo_exec_vtx_flush( exec, GL_FALSE ); 89 else { 90 exec->vtx.prim_count = 0; 91 exec->vtx.copied.nr = 0; 92 } 93 94 /* Emit a glBegin to start the new list. 95 */ 96 assert(exec->vtx.prim_count == 0); 97 98 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 99 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive; 100 exec->vtx.prim[0].start = 0; 101 exec->vtx.prim[0].count = 0; 102 exec->vtx.prim_count++; 103 104 if (exec->vtx.copied.nr == last_count) 105 exec->vtx.prim[0].begin = last_begin; 106 } 107 } 108} 109 110 111/** 112 * Deal with buffer wrapping where provoked by the vertex buffer 113 * filling up, as opposed to upgrade_vertex(). 114 */ 115void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ) 116{ 117 GLfloat *data = exec->vtx.copied.buffer; 118 GLuint i; 119 120 /* Run pipeline on current vertices, copy wrapped vertices 121 * to exec->vtx.copied. 122 */ 123 vbo_exec_wrap_buffers( exec ); 124 125 /* Copy stored stored vertices to start of new list. 126 */ 127 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); 128 129 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 130 memcpy( exec->vtx.buffer_ptr, data, 131 exec->vtx.vertex_size * sizeof(GLfloat)); 132 exec->vtx.buffer_ptr += exec->vtx.vertex_size; 133 data += exec->vtx.vertex_size; 134 exec->vtx.vert_count++; 135 } 136 137 exec->vtx.copied.nr = 0; 138} 139 140 141/** 142 * Copy the active vertex's values to the ctx->Current fields. 143 */ 144static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) 145{ 146 struct gl_context *ctx = exec->ctx; 147 struct vbo_context *vbo = vbo_context(ctx); 148 GLuint i; 149 150 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 151 if (exec->vtx.attrsz[i]) { 152 /* Note: the exec->vtx.current[i] pointers point into the 153 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. 154 */ 155 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; 156 GLfloat tmp[4]; 157 158 COPY_CLEAN_4V(tmp, 159 exec->vtx.attrsz[i], 160 exec->vtx.attrptr[i]); 161 162 if (memcmp(current, tmp, sizeof(tmp)) != 0) { 163 memcpy(current, tmp, sizeof(tmp)); 164 165 /* Given that we explicitly state size here, there is no need 166 * for the COPY_CLEAN above, could just copy 16 bytes and be 167 * done. The only problem is when Mesa accesses ctx->Current 168 * directly. 169 */ 170 vbo->currval[i].Size = exec->vtx.attrsz[i]; 171 assert(vbo->currval[i].Type == GL_FLOAT); 172 vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); 173 174 /* This triggers rather too much recalculation of Mesa state 175 * that doesn't get used (eg light positions). 176 */ 177 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && 178 i <= VBO_ATTRIB_MAT_BACK_INDEXES) 179 ctx->NewState |= _NEW_LIGHT; 180 181 ctx->NewState |= _NEW_CURRENT_ATTRIB; 182 } 183 } 184 } 185 186 /* Colormaterial -- this kindof sucks. 187 */ 188 if (ctx->Light.ColorMaterialEnabled && 189 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { 190 _mesa_update_color_material(ctx, 191 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 192 } 193} 194 195 196/** 197 * Copy current vertex attribute values into the current vertex. 198 */ 199static void 200vbo_exec_copy_from_current(struct vbo_exec_context *exec) 201{ 202 struct gl_context *ctx = exec->ctx; 203 struct vbo_context *vbo = vbo_context(ctx); 204 GLint i; 205 206 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { 207 const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr; 208 switch (exec->vtx.attrsz[i]) { 209 case 4: exec->vtx.attrptr[i][3] = current[3]; 210 case 3: exec->vtx.attrptr[i][2] = current[2]; 211 case 2: exec->vtx.attrptr[i][1] = current[1]; 212 case 1: exec->vtx.attrptr[i][0] = current[0]; 213 break; 214 } 215 } 216} 217 218 219/** 220 * Flush existing data, set new attrib size, replay copied vertices. 221 * This is called when we transition from a small vertex attribute size 222 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. 223 * We need to go back over the previous 2-component texcoords and insert 224 * zero and one values. 225 */ 226static void 227vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, 228 GLuint attr, GLuint newSize ) 229{ 230 struct gl_context *ctx = exec->ctx; 231 struct vbo_context *vbo = vbo_context(ctx); 232 const GLint lastcount = exec->vtx.vert_count; 233 GLfloat *old_attrptr[VBO_ATTRIB_MAX]; 234 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ 235 const GLuint oldSize = exec->vtx.attrsz[attr]; 236 GLuint i; 237 238 /* Run pipeline on current vertices, copy wrapped vertices 239 * to exec->vtx.copied. 240 */ 241 vbo_exec_wrap_buffers( exec ); 242 243 if (unlikely(exec->vtx.copied.nr)) { 244 /* We're in the middle of a primitive, keep the old vertex 245 * format around to be able to translate the copied vertices to 246 * the new format. 247 */ 248 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); 249 } 250 251 if (unlikely(oldSize)) { 252 /* Do a COPY_TO_CURRENT to ensure back-copying works for the 253 * case when the attribute already exists in the vertex and is 254 * having its size increased. 255 */ 256 vbo_exec_copy_to_current( exec ); 257 } 258 259 /* Heuristic: Attempt to isolate attributes received outside 260 * begin/end so that they don't bloat the vertices. 261 */ 262 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END && 263 !oldSize && lastcount > 8 && exec->vtx.vertex_size) { 264 vbo_exec_copy_to_current( exec ); 265 reset_attrfv( exec ); 266 } 267 268 /* Fix up sizes: 269 */ 270 exec->vtx.attrsz[attr] = newSize; 271 exec->vtx.vertex_size += newSize - oldSize; 272 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / 273 (exec->vtx.vertex_size * sizeof(GLfloat))); 274 exec->vtx.vert_count = 0; 275 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 276 277 if (unlikely(oldSize)) { 278 /* Size changed, recalculate all the attrptr[] values 279 */ 280 GLfloat *tmp = exec->vtx.vertex; 281 282 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 283 if (exec->vtx.attrsz[i]) { 284 exec->vtx.attrptr[i] = tmp; 285 tmp += exec->vtx.attrsz[i]; 286 } 287 else 288 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */ 289 } 290 291 /* Copy from current to repopulate the vertex with correct 292 * values. 293 */ 294 vbo_exec_copy_from_current( exec ); 295 } 296 else { 297 /* Just have to append the new attribute at the end */ 298 exec->vtx.attrptr[attr] = exec->vtx.vertex + 299 exec->vtx.vertex_size - newSize; 300 } 301 302 /* Replay stored vertices to translate them 303 * to new format here. 304 * 305 * -- No need to replay - just copy piecewise 306 */ 307 if (unlikely(exec->vtx.copied.nr)) { 308 GLfloat *data = exec->vtx.copied.buffer; 309 GLfloat *dest = exec->vtx.buffer_ptr; 310 GLuint j; 311 312 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); 313 314 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 315 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { 316 GLuint sz = exec->vtx.attrsz[j]; 317 318 if (sz) { 319 GLint old_offset = old_attrptr[j] - exec->vtx.vertex; 320 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; 321 322 if (j == attr) { 323 if (oldSize) { 324 GLfloat tmp[4]; 325 COPY_CLEAN_4V(tmp, oldSize, data + old_offset); 326 COPY_SZ_4V(dest + new_offset, newSize, tmp); 327 } else { 328 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr; 329 COPY_SZ_4V(dest + new_offset, sz, current); 330 } 331 } 332 else { 333 COPY_SZ_4V(dest + new_offset, sz, data + old_offset); 334 } 335 } 336 } 337 338 data += old_vtx_size; 339 dest += exec->vtx.vertex_size; 340 } 341 342 exec->vtx.buffer_ptr = dest; 343 exec->vtx.vert_count += exec->vtx.copied.nr; 344 exec->vtx.copied.nr = 0; 345 } 346} 347 348 349/** 350 * This is when a vertex attribute transitions to a different size. 351 * For example, we saw a bunch of glTexCoord2f() calls and now we got a 352 * glTexCoord4f() call. We promote the array from size=2 to size=4. 353 */ 354static void 355vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize) 356{ 357 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 358 359 if (newSize > exec->vtx.attrsz[attr]) { 360 /* New size is larger. Need to flush existing vertices and get 361 * an enlarged vertex format. 362 */ 363 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize ); 364 } 365 else if (newSize < exec->vtx.active_sz[attr]) { 366 static const GLfloat id[4] = { 0, 0, 0, 1 }; 367 GLuint i; 368 369 /* New size is smaller - just need to fill in some 370 * zeros. Don't need to flush or wrap. 371 */ 372 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++) 373 exec->vtx.attrptr[attr][i-1] = id[i-1]; 374 } 375 376 exec->vtx.active_sz[attr] = newSize; 377 378 /* Does setting NeedFlush belong here? Necessitates resetting 379 * vtxfmt on each flush (otherwise flags won't get reset 380 * afterwards). 381 */ 382 if (attr == 0) 383 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; 384} 385 386 387/** 388 * This macro is used to implement all the glVertex, glColor, glTexCoord, 389 * glVertexAttrib, etc functions. 390 */ 391#define ATTR( A, N, V0, V1, V2, V3 ) \ 392do { \ 393 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 394 \ 395 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \ 396 ctx->Driver.BeginVertices( ctx ); \ 397 \ 398 if (unlikely(exec->vtx.active_sz[A] != N)) \ 399 vbo_exec_fixup_vertex(ctx, A, N); \ 400 \ 401 { \ 402 GLfloat *dest = exec->vtx.attrptr[A]; \ 403 if (N>0) dest[0] = V0; \ 404 if (N>1) dest[1] = V1; \ 405 if (N>2) dest[2] = V2; \ 406 if (N>3) dest[3] = V3; \ 407 } \ 408 \ 409 if ((A) == 0) { \ 410 /* This is a glVertex call */ \ 411 GLuint i; \ 412 \ 413 for (i = 0; i < exec->vtx.vertex_size; i++) \ 414 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \ 415 \ 416 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \ 417 \ 418 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \ 419 /* something to draw (not just updating a color or texcoord).*/ \ 420 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \ 421 \ 422 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \ 423 vbo_exec_vtx_wrap( exec ); \ 424 } \ 425} while (0) 426 427 428#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ ) 429#define TAG(x) vbo_##x 430 431#include "vbo_attrib_tmp.h" 432 433 434#if FEATURE_beginend 435 436 437#if FEATURE_evaluators 438 439static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u ) 440{ 441 GET_CURRENT_CONTEXT( ctx ); 442 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 443 444 { 445 GLint i; 446 if (exec->eval.recalculate_maps) 447 vbo_exec_eval_update( exec ); 448 449 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 450 if (exec->eval.map1[i].map) 451 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz) 452 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz ); 453 } 454 } 455 456 457 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 458 exec->vtx.vertex_size * sizeof(GLfloat)); 459 460 vbo_exec_do_EvalCoord1f( exec, u ); 461 462 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 463 exec->vtx.vertex_size * sizeof(GLfloat)); 464} 465 466static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v ) 467{ 468 GET_CURRENT_CONTEXT( ctx ); 469 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 470 471 { 472 GLint i; 473 if (exec->eval.recalculate_maps) 474 vbo_exec_eval_update( exec ); 475 476 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 477 if (exec->eval.map2[i].map) 478 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz) 479 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz ); 480 } 481 482 if (ctx->Eval.AutoNormal) 483 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3) 484 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 ); 485 } 486 487 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 488 exec->vtx.vertex_size * sizeof(GLfloat)); 489 490 vbo_exec_do_EvalCoord2f( exec, u, v ); 491 492 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 493 exec->vtx.vertex_size * sizeof(GLfloat)); 494} 495 496static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u ) 497{ 498 vbo_exec_EvalCoord1f( u[0] ); 499} 500 501static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u ) 502{ 503 vbo_exec_EvalCoord2f( u[0], u[1] ); 504} 505 506static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i ) 507{ 508 GET_CURRENT_CONTEXT( ctx ); 509 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / 510 (GLfloat) ctx->Eval.MapGrid1un); 511 GLfloat u = i * du + ctx->Eval.MapGrid1u1; 512 513 vbo_exec_EvalCoord1f( u ); 514} 515 516 517static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j ) 518{ 519 GET_CURRENT_CONTEXT( ctx ); 520 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 521 (GLfloat) ctx->Eval.MapGrid2un); 522 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 523 (GLfloat) ctx->Eval.MapGrid2vn); 524 GLfloat u = i * du + ctx->Eval.MapGrid2u1; 525 GLfloat v = j * dv + ctx->Eval.MapGrid2v1; 526 527 vbo_exec_EvalCoord2f( u, v ); 528} 529 530/* use noop eval mesh */ 531#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1 532#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2 533 534#endif /* FEATURE_evaluators */ 535 536 537/** 538 * Flush (draw) vertices. 539 * \param unmap - leave VBO unmapped after flushing? 540 */ 541static void 542vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap) 543{ 544 if (exec->vtx.vert_count || unmap) { 545 vbo_exec_vtx_flush( exec, unmap ); 546 } 547 548 if (exec->vtx.vertex_size) { 549 vbo_exec_copy_to_current( exec ); 550 reset_attrfv( exec ); 551 } 552} 553 554 555/** 556 * Called via glBegin. 557 */ 558static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) 559{ 560 GET_CURRENT_CONTEXT( ctx ); 561 562 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) { 563 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 564 int i; 565 566 if (ctx->NewState) { 567 _mesa_update_state( ctx ); 568 569 CALL_Begin(ctx->Exec, (mode)); 570 return; 571 } 572 573 if (!_mesa_valid_to_render(ctx, "glBegin")) { 574 return; 575 } 576 577 /* Heuristic: attempt to isolate attributes occuring outside 578 * begin/end pairs. 579 */ 580 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 581 vbo_exec_FlushVertices_internal(exec, GL_FALSE); 582 583 i = exec->vtx.prim_count++; 584 exec->vtx.prim[i].mode = mode; 585 exec->vtx.prim[i].begin = 1; 586 exec->vtx.prim[i].end = 0; 587 exec->vtx.prim[i].indexed = 0; 588 exec->vtx.prim[i].weak = 0; 589 exec->vtx.prim[i].pad = 0; 590 exec->vtx.prim[i].start = exec->vtx.vert_count; 591 exec->vtx.prim[i].count = 0; 592 exec->vtx.prim[i].num_instances = 1; 593 594 ctx->Driver.CurrentExecPrimitive = mode; 595 } 596 else 597 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); 598 599} 600 601 602/** 603 * Called via glEnd. 604 */ 605static void GLAPIENTRY vbo_exec_End( void ) 606{ 607 GET_CURRENT_CONTEXT( ctx ); 608 609 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 610 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 611 612 if (exec->vtx.prim_count > 0) { 613 /* close off current primitive */ 614 int idx = exec->vtx.vert_count; 615 int i = exec->vtx.prim_count - 1; 616 617 exec->vtx.prim[i].end = 1; 618 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start; 619 } 620 621 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 622 623 if (exec->vtx.prim_count == VBO_MAX_PRIM) 624 vbo_exec_vtx_flush( exec, GL_FALSE ); 625 } 626 else 627 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); 628} 629 630 631/** 632 * Called via glPrimitiveRestartNV() 633 */ 634static void GLAPIENTRY 635vbo_exec_PrimitiveRestartNV(void) 636{ 637 GLenum curPrim; 638 GET_CURRENT_CONTEXT( ctx ); 639 640 curPrim = ctx->Driver.CurrentExecPrimitive; 641 642 if (curPrim == PRIM_OUTSIDE_BEGIN_END) { 643 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" ); 644 } 645 else { 646 vbo_exec_End(); 647 vbo_exec_Begin(curPrim); 648 } 649} 650 651 652 653static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 654{ 655 GLvertexformat *vfmt = &exec->vtxfmt; 656 657 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); 658 659 vfmt->Begin = vbo_exec_Begin; 660 vfmt->End = vbo_exec_End; 661 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV; 662 663 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_); 664 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_); 665 666 vfmt->Rectf = _mesa_noop_Rectf; 667 668 /* from attrib_tmp.h: 669 */ 670 vfmt->Color3f = vbo_Color3f; 671 vfmt->Color3fv = vbo_Color3fv; 672 vfmt->Color4f = vbo_Color4f; 673 vfmt->Color4fv = vbo_Color4fv; 674 vfmt->FogCoordfEXT = vbo_FogCoordfEXT; 675 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT; 676 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f; 677 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv; 678 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f; 679 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv; 680 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f; 681 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv; 682 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f; 683 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv; 684 vfmt->Normal3f = vbo_Normal3f; 685 vfmt->Normal3fv = vbo_Normal3fv; 686 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT; 687 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT; 688 vfmt->TexCoord1f = vbo_TexCoord1f; 689 vfmt->TexCoord1fv = vbo_TexCoord1fv; 690 vfmt->TexCoord2f = vbo_TexCoord2f; 691 vfmt->TexCoord2fv = vbo_TexCoord2fv; 692 vfmt->TexCoord3f = vbo_TexCoord3f; 693 vfmt->TexCoord3fv = vbo_TexCoord3fv; 694 vfmt->TexCoord4f = vbo_TexCoord4f; 695 vfmt->TexCoord4fv = vbo_TexCoord4fv; 696 vfmt->Vertex2f = vbo_Vertex2f; 697 vfmt->Vertex2fv = vbo_Vertex2fv; 698 vfmt->Vertex3f = vbo_Vertex3f; 699 vfmt->Vertex3fv = vbo_Vertex3fv; 700 vfmt->Vertex4f = vbo_Vertex4f; 701 vfmt->Vertex4fv = vbo_Vertex4fv; 702 703 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB; 704 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB; 705 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB; 706 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB; 707 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB; 708 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB; 709 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB; 710 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB; 711 712 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV; 713 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV; 714 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV; 715 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV; 716 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV; 717 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV; 718 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV; 719 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV; 720 721 /* integer-valued */ 722 vfmt->VertexAttribI1i = vbo_VertexAttribI1i; 723 vfmt->VertexAttribI2i = vbo_VertexAttribI2i; 724 vfmt->VertexAttribI3i = vbo_VertexAttribI3i; 725 vfmt->VertexAttribI4i = vbo_VertexAttribI4i; 726 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv; 727 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv; 728 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv; 729 730 /* unsigned integer-valued */ 731 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui; 732 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui; 733 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui; 734 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui; 735 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv; 736 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv; 737 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv; 738 739 vfmt->Materialfv = vbo_Materialfv; 740 741 vfmt->EdgeFlag = vbo_EdgeFlag; 742 vfmt->Indexf = vbo_Indexf; 743 vfmt->Indexfv = vbo_Indexfv; 744 745} 746 747 748#else /* FEATURE_beginend */ 749 750 751static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 752{ 753 /* silence warnings */ 754 (void) vbo_Color3f; 755 (void) vbo_Color3fv; 756 (void) vbo_Color4f; 757 (void) vbo_Color4fv; 758 (void) vbo_FogCoordfEXT; 759 (void) vbo_FogCoordfvEXT; 760 (void) vbo_MultiTexCoord1f; 761 (void) vbo_MultiTexCoord1fv; 762 (void) vbo_MultiTexCoord2f; 763 (void) vbo_MultiTexCoord2fv; 764 (void) vbo_MultiTexCoord3f; 765 (void) vbo_MultiTexCoord3fv; 766 (void) vbo_MultiTexCoord4f; 767 (void) vbo_MultiTexCoord4fv; 768 (void) vbo_Normal3f; 769 (void) vbo_Normal3fv; 770 (void) vbo_SecondaryColor3fEXT; 771 (void) vbo_SecondaryColor3fvEXT; 772 (void) vbo_TexCoord1f; 773 (void) vbo_TexCoord1fv; 774 (void) vbo_TexCoord2f; 775 (void) vbo_TexCoord2fv; 776 (void) vbo_TexCoord3f; 777 (void) vbo_TexCoord3fv; 778 (void) vbo_TexCoord4f; 779 (void) vbo_TexCoord4fv; 780 (void) vbo_Vertex2f; 781 (void) vbo_Vertex2fv; 782 (void) vbo_Vertex3f; 783 (void) vbo_Vertex3fv; 784 (void) vbo_Vertex4f; 785 (void) vbo_Vertex4fv; 786 787 (void) vbo_VertexAttrib1fARB; 788 (void) vbo_VertexAttrib1fvARB; 789 (void) vbo_VertexAttrib2fARB; 790 (void) vbo_VertexAttrib2fvARB; 791 (void) vbo_VertexAttrib3fARB; 792 (void) vbo_VertexAttrib3fvARB; 793 (void) vbo_VertexAttrib4fARB; 794 (void) vbo_VertexAttrib4fvARB; 795 796 (void) vbo_VertexAttrib1fNV; 797 (void) vbo_VertexAttrib1fvNV; 798 (void) vbo_VertexAttrib2fNV; 799 (void) vbo_VertexAttrib2fvNV; 800 (void) vbo_VertexAttrib3fNV; 801 (void) vbo_VertexAttrib3fvNV; 802 (void) vbo_VertexAttrib4fNV; 803 (void) vbo_VertexAttrib4fvNV; 804 805 (void) vbo_Materialfv; 806 807 (void) vbo_EdgeFlag; 808 (void) vbo_Indexf; 809 (void) vbo_Indexfv; 810} 811 812 813#endif /* FEATURE_beginend */ 814 815 816/** 817 * Tell the VBO module to use a real OpenGL vertex buffer object to 818 * store accumulated immediate-mode vertex data. 819 * This replaces the malloced buffer which was created in 820 * vb_exec_vtx_init() below. 821 */ 822void vbo_use_buffer_objects(struct gl_context *ctx) 823{ 824 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 825 /* Any buffer name but 0 can be used here since this bufferobj won't 826 * go into the bufferobj hashtable. 827 */ 828 GLuint bufName = IMM_BUFFER_NAME; 829 GLenum target = GL_ARRAY_BUFFER_ARB; 830 GLenum usage = GL_STREAM_DRAW_ARB; 831 GLsizei size = VBO_VERT_BUFFER_SIZE; 832 833 /* Make sure this func is only used once */ 834 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj); 835 if (exec->vtx.buffer_map) { 836 _mesa_align_free(exec->vtx.buffer_map); 837 exec->vtx.buffer_map = NULL; 838 exec->vtx.buffer_ptr = NULL; 839 } 840 841 /* Allocate a real buffer object now */ 842 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 843 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target); 844 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj); 845} 846 847 848/** 849 * If this function is called, all VBO buffers will be unmapped when 850 * we flush. 851 * Otherwise, if a simple command like glColor3f() is called and we flush, 852 * the current VBO may be left mapped. 853 */ 854void 855vbo_always_unmap_buffers(struct gl_context *ctx) 856{ 857 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 858 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES; 859} 860 861 862void vbo_exec_vtx_init( struct vbo_exec_context *exec ) 863{ 864 struct gl_context *ctx = exec->ctx; 865 struct vbo_context *vbo = vbo_context(ctx); 866 GLuint i; 867 868 /* Allocate a buffer object. Will just reuse this object 869 * continuously, unless vbo_use_buffer_objects() is called to enable 870 * use of real VBOs. 871 */ 872 _mesa_reference_buffer_object(ctx, 873 &exec->vtx.bufferobj, 874 ctx->Shared->NullBufferObj); 875 876 ASSERT(!exec->vtx.buffer_map); 877 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64); 878 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 879 880 vbo_exec_vtxfmt_init( exec ); 881 882 /* Hook our functions into the dispatch table. 883 */ 884 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt ); 885 886 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 887 ASSERT(i < Elements(exec->vtx.attrsz)); 888 exec->vtx.attrsz[i] = 0; 889 ASSERT(i < Elements(exec->vtx.active_sz)); 890 exec->vtx.active_sz[i] = 0; 891 } 892 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) { 893 ASSERT(i < Elements(exec->vtx.inputs)); 894 ASSERT(i < Elements(exec->vtx.arrays)); 895 exec->vtx.inputs[i] = &exec->vtx.arrays[i]; 896 } 897 898 { 899 struct gl_client_array *arrays = exec->vtx.arrays; 900 unsigned i; 901 902 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0])); 903 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0])); 904 905 for (i = 0; i < 16; ++i) { 906 arrays[i ].BufferObj = NULL; 907 arrays[i + 16].BufferObj = NULL; 908 _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj, 909 vbo->legacy_currval[i].BufferObj); 910 _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj, 911 vbo->generic_currval[i].BufferObj); 912 } 913 } 914 915 exec->vtx.vertex_size = 0; 916 917 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT; 918} 919 920 921void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ) 922{ 923 /* using a real VBO for vertex data */ 924 struct gl_context *ctx = exec->ctx; 925 unsigned i; 926 927 /* True VBOs should already be unmapped 928 */ 929 if (exec->vtx.buffer_map) { 930 ASSERT(exec->vtx.bufferobj->Name == 0 || 931 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); 932 if (exec->vtx.bufferobj->Name == 0) { 933 _mesa_align_free(exec->vtx.buffer_map); 934 exec->vtx.buffer_map = NULL; 935 exec->vtx.buffer_ptr = NULL; 936 } 937 } 938 939 /* Drop any outstanding reference to the vertex buffer 940 */ 941 for (i = 0; i < Elements(exec->vtx.arrays); i++) { 942 _mesa_reference_buffer_object(ctx, 943 &exec->vtx.arrays[i].BufferObj, 944 NULL); 945 } 946 947 /* Free the vertex buffer. Unmap first if needed. 948 */ 949 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) { 950 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj); 951 } 952 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 953} 954 955 956/** 957 * Called upon first glVertex, glColor, glTexCoord, etc. 958 */ 959void vbo_exec_BeginVertices( struct gl_context *ctx ) 960{ 961 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 962 963 vbo_exec_vtx_map( exec ); 964 965 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0); 966 assert(exec->begin_vertices_flags); 967 968 ctx->Driver.NeedFlush |= exec->begin_vertices_flags; 969} 970 971 972/** 973 * Called via ctx->Driver.FlushVertices() 974 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 975 */ 976void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags ) 977{ 978 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 979 980#ifdef DEBUG 981 /* debug check: make sure we don't get called recursively */ 982 exec->flush_call_depth++; 983 assert(exec->flush_call_depth == 1); 984#endif 985 986 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 987 /* We've had glBegin but not glEnd! */ 988#ifdef DEBUG 989 exec->flush_call_depth--; 990 assert(exec->flush_call_depth == 0); 991#endif 992 return; 993 } 994 995 /* Flush (draw), and make sure VBO is left unmapped when done */ 996 vbo_exec_FlushVertices_internal(exec, GL_TRUE); 997 998 /* Need to do this to ensure BeginVertices gets called again: 999 */ 1000 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags); 1001 1002#ifdef DEBUG 1003 exec->flush_call_depth--; 1004 assert(exec->flush_call_depth == 0); 1005#endif 1006} 1007 1008 1009static void reset_attrfv( struct vbo_exec_context *exec ) 1010{ 1011 GLuint i; 1012 1013 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 1014 exec->vtx.attrsz[i] = 0; 1015 exec->vtx.active_sz[i] = 0; 1016 } 1017 1018 exec->vtx.vertex_size = 0; 1019} 1020 1021 1022void GLAPIENTRY 1023_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 1024{ 1025 vbo_Color4f(r, g, b, a); 1026} 1027 1028 1029void GLAPIENTRY 1030_es_Normal3f(GLfloat x, GLfloat y, GLfloat z) 1031{ 1032 vbo_Normal3f(x, y, z); 1033} 1034 1035 1036void GLAPIENTRY 1037_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 1038{ 1039 vbo_MultiTexCoord4f(target, s, t, r, q); 1040} 1041 1042 1043void GLAPIENTRY 1044_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 1045{ 1046 vbo_Materialfv(face, pname, params); 1047} 1048 1049 1050void GLAPIENTRY 1051_es_Materialf(GLenum face, GLenum pname, GLfloat param) 1052{ 1053 GLfloat p[4]; 1054 p[0] = param; 1055 p[1] = p[2] = p[3] = 0.0F; 1056 vbo_Materialfv(face, pname, p); 1057} 1058 1059 1060/** 1061 * A special version of glVertexAttrib4f that does not treat index 0 as 1062 * VBO_ATTRIB_POS. 1063 */ 1064static void 1065VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1066{ 1067 GET_CURRENT_CONTEXT(ctx); 1068 if (index < MAX_VERTEX_GENERIC_ATTRIBS) 1069 ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w); 1070 else 1071 ERROR(GL_INVALID_VALUE); 1072} 1073 1074void GLAPIENTRY 1075_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1076{ 1077 VertexAttrib4f_nopos(index, x, y, z, w); 1078} 1079 1080 1081void GLAPIENTRY 1082_es_VertexAttrib1f(GLuint indx, GLfloat x) 1083{ 1084 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f); 1085} 1086 1087 1088void GLAPIENTRY 1089_es_VertexAttrib1fv(GLuint indx, const GLfloat* values) 1090{ 1091 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f); 1092} 1093 1094 1095void GLAPIENTRY 1096_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) 1097{ 1098 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f); 1099} 1100 1101 1102void GLAPIENTRY 1103_es_VertexAttrib2fv(GLuint indx, const GLfloat* values) 1104{ 1105 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f); 1106} 1107 1108 1109void GLAPIENTRY 1110_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) 1111{ 1112 VertexAttrib4f_nopos(indx, x, y, z, 1.0f); 1113} 1114 1115 1116void GLAPIENTRY 1117_es_VertexAttrib3fv(GLuint indx, const GLfloat* values) 1118{ 1119 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f); 1120} 1121 1122 1123void GLAPIENTRY 1124_es_VertexAttrib4fv(GLuint indx, const GLfloat* values) 1125{ 1126 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]); 1127} 1128