vbo_exec_api.c revision 99ae9e8d7d57ae37629754edd5b1e3716611827f
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/vtxfmt.h" 38#include "main/dlist.h" 39#include "main/eval.h" 40#include "main/state.h" 41#include "main/light.h" 42#include "main/api_arrayelt.h" 43#include "main/api_noop.h" 44#include "glapi/dispatch.h" 45 46#include "vbo_context.h" 47 48#ifdef ERROR 49#undef ERROR 50#endif 51 52 53/** ID/name for immediate-mode VBO */ 54#define IMM_BUFFER_NAME 0xaabbccdd 55 56 57static void reset_attrfv( struct vbo_exec_context *exec ); 58 59 60/** 61 * Close off the last primitive, execute the buffer, restart the 62 * primitive. 63 */ 64static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec ) 65{ 66 if (exec->vtx.prim_count == 0) { 67 exec->vtx.copied.nr = 0; 68 exec->vtx.vert_count = 0; 69 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 70 } 71 else { 72 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin; 73 GLuint last_count; 74 75 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 76 GLint i = exec->vtx.prim_count - 1; 77 assert(i >= 0); 78 exec->vtx.prim[i].count = (exec->vtx.vert_count - 79 exec->vtx.prim[i].start); 80 } 81 82 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count; 83 84 /* Execute the buffer and save copied vertices. 85 */ 86 if (exec->vtx.vert_count) 87 vbo_exec_vtx_flush( exec, GL_FALSE ); 88 else { 89 exec->vtx.prim_count = 0; 90 exec->vtx.copied.nr = 0; 91 } 92 93 /* Emit a glBegin to start the new list. 94 */ 95 assert(exec->vtx.prim_count == 0); 96 97 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 98 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive; 99 exec->vtx.prim[0].start = 0; 100 exec->vtx.prim[0].count = 0; 101 exec->vtx.prim_count++; 102 103 if (exec->vtx.copied.nr == last_count) 104 exec->vtx.prim[0].begin = last_begin; 105 } 106 } 107} 108 109 110/** 111 * Deal with buffer wrapping where provoked by the vertex buffer 112 * filling up, as opposed to upgrade_vertex(). 113 */ 114void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ) 115{ 116 GLfloat *data = exec->vtx.copied.buffer; 117 GLuint i; 118 119 /* Run pipeline on current vertices, copy wrapped vertices 120 * to exec->vtx.copied. 121 */ 122 vbo_exec_wrap_buffers( exec ); 123 124 /* Copy stored stored vertices to start of new list. 125 */ 126 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); 127 128 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 129 memcpy( exec->vtx.buffer_ptr, data, 130 exec->vtx.vertex_size * sizeof(GLfloat)); 131 exec->vtx.buffer_ptr += exec->vtx.vertex_size; 132 data += exec->vtx.vertex_size; 133 exec->vtx.vert_count++; 134 } 135 136 exec->vtx.copied.nr = 0; 137} 138 139 140/** 141 * Copy the active vertex's values to the ctx->Current fields. 142 */ 143static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) 144{ 145 GLcontext *ctx = exec->ctx; 146 struct vbo_context *vbo = vbo_context(ctx); 147 GLuint i; 148 149 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 150 if (exec->vtx.attrsz[i]) { 151 /* Note: the exec->vtx.current[i] pointers point into the 152 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. 153 */ 154 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; 155 GLfloat tmp[4]; 156 157 COPY_CLEAN_4V(tmp, 158 exec->vtx.attrsz[i], 159 exec->vtx.attrptr[i]); 160 161 if (memcmp(current, tmp, sizeof(tmp)) != 0) 162 { 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 172 /* This triggers rather too much recalculation of Mesa state 173 * that doesn't get used (eg light positions). 174 */ 175 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && 176 i <= VBO_ATTRIB_MAT_BACK_INDEXES) 177 ctx->NewState |= _NEW_LIGHT; 178 179 ctx->NewState |= _NEW_CURRENT_ATTRIB; 180 } 181 } 182 } 183 184 /* Colormaterial -- this kindof sucks. 185 */ 186 if (ctx->Light.ColorMaterialEnabled && 187 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { 188 _mesa_update_color_material(ctx, 189 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 190 } 191} 192 193 194static void vbo_exec_copy_from_current( struct vbo_exec_context *exec ) 195{ 196 GLcontext *ctx = exec->ctx; 197 struct vbo_context *vbo = vbo_context(ctx); 198 GLint i; 199 200 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 201 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; 202 switch (exec->vtx.attrsz[i]) { 203 case 4: exec->vtx.attrptr[i][3] = current[3]; 204 case 3: exec->vtx.attrptr[i][2] = current[2]; 205 case 2: exec->vtx.attrptr[i][1] = current[1]; 206 case 1: exec->vtx.attrptr[i][0] = current[0]; 207 break; 208 } 209 } 210} 211 212 213/** 214 * Flush existing data, set new attrib size, replay copied vertices. 215 */ 216static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec, 217 GLuint attr, 218 GLuint newsz ) 219{ 220 GLcontext *ctx = exec->ctx; 221 struct vbo_context *vbo = vbo_context(ctx); 222 GLint lastcount = exec->vtx.vert_count; 223 GLfloat *tmp; 224 GLuint oldsz; 225 GLuint i; 226 227 /* Run pipeline on current vertices, copy wrapped vertices 228 * to exec->vtx.copied. 229 */ 230 vbo_exec_wrap_buffers( exec ); 231 232 233 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case 234 * when the attribute already exists in the vertex and is having 235 * its size increased. 236 */ 237 vbo_exec_copy_to_current( exec ); 238 239 240 /* Heuristic: Attempt to isolate attributes received outside 241 * begin/end so that they don't bloat the vertices. 242 */ 243 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END && 244 exec->vtx.attrsz[attr] == 0 && 245 lastcount > 8 && 246 exec->vtx.vertex_size) { 247 reset_attrfv( exec ); 248 } 249 250 /* Fix up sizes: 251 */ 252 oldsz = exec->vtx.attrsz[attr]; 253 exec->vtx.attrsz[attr] = newsz; 254 255 exec->vtx.vertex_size += newsz - oldsz; 256 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / 257 (exec->vtx.vertex_size * sizeof(GLfloat))); 258 exec->vtx.vert_count = 0; 259 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 260 261 262 /* Recalculate all the attrptr[] values 263 */ 264 for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) { 265 if (exec->vtx.attrsz[i]) { 266 exec->vtx.attrptr[i] = tmp; 267 tmp += exec->vtx.attrsz[i]; 268 } 269 else 270 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */ 271 } 272 273 /* Copy from current to repopulate the vertex with correct values. 274 */ 275 vbo_exec_copy_from_current( exec ); 276 277 /* Replay stored vertices to translate them 278 * to new format here. 279 * 280 * -- No need to replay - just copy piecewise 281 */ 282 if (exec->vtx.copied.nr) 283 { 284 GLfloat *data = exec->vtx.copied.buffer; 285 GLfloat *dest = exec->vtx.buffer_ptr; 286 GLuint j; 287 288 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); 289 290 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 291 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { 292 if (exec->vtx.attrsz[j]) { 293 if (j == attr) { 294 if (oldsz) { 295 COPY_CLEAN_4V( dest, oldsz, data ); 296 data += oldsz; 297 dest += newsz; 298 } else { 299 const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr; 300 COPY_SZ_4V( dest, newsz, current ); 301 dest += newsz; 302 } 303 } 304 else { 305 GLuint sz = exec->vtx.attrsz[j]; 306 COPY_SZ_4V( dest, sz, data ); 307 dest += sz; 308 data += sz; 309 } 310 } 311 } 312 } 313 314 exec->vtx.buffer_ptr = dest; 315 exec->vtx.vert_count += exec->vtx.copied.nr; 316 exec->vtx.copied.nr = 0; 317 } 318} 319 320 321static void vbo_exec_fixup_vertex( GLcontext *ctx, 322 GLuint attr, GLuint sz ) 323{ 324 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 325 int i; 326 327 if (sz > exec->vtx.attrsz[attr]) { 328 /* New size is larger. Need to flush existing vertices and get 329 * an enlarged vertex format. 330 */ 331 vbo_exec_wrap_upgrade_vertex( exec, attr, sz ); 332 } 333 else if (sz < exec->vtx.active_sz[attr]) { 334 static const GLfloat id[4] = { 0, 0, 0, 1 }; 335 336 /* New size is smaller - just need to fill in some 337 * zeros. Don't need to flush or wrap. 338 */ 339 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++) 340 exec->vtx.attrptr[attr][i-1] = id[i-1]; 341 } 342 343 exec->vtx.active_sz[attr] = sz; 344 345 /* Does setting NeedFlush belong here? Necessitates resetting 346 * vtxfmt on each flush (otherwise flags won't get reset 347 * afterwards). 348 */ 349 if (attr == 0) 350 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; 351} 352 353 354#if FEATURE_beginend 355 356/* 357 */ 358#define ATTR( A, N, V0, V1, V2, V3 ) \ 359do { \ 360 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 361 \ 362 if (exec->vtx.active_sz[A] != N) \ 363 vbo_exec_fixup_vertex(ctx, A, N); \ 364 \ 365 { \ 366 GLfloat *dest = exec->vtx.attrptr[A]; \ 367 if (N>0) dest[0] = V0; \ 368 if (N>1) dest[1] = V1; \ 369 if (N>2) dest[2] = V2; \ 370 if (N>3) dest[3] = V3; \ 371 } \ 372 \ 373 if ((A) == 0) { \ 374 GLuint i; \ 375 \ 376 for (i = 0; i < exec->vtx.vertex_size; i++) \ 377 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \ 378 \ 379 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \ 380 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \ 381 \ 382 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \ 383 vbo_exec_vtx_wrap( exec ); \ 384 } \ 385} while (0) 386 387 388#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ ) 389#define TAG(x) vbo_##x 390 391#include "vbo_attrib_tmp.h" 392 393 394 395 396 397#if FEATURE_evaluators 398 399static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u ) 400{ 401 GET_CURRENT_CONTEXT( ctx ); 402 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 403 404 { 405 GLint i; 406 if (exec->eval.recalculate_maps) 407 vbo_exec_eval_update( exec ); 408 409 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 410 if (exec->eval.map1[i].map) 411 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz) 412 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz ); 413 } 414 } 415 416 417 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 418 exec->vtx.vertex_size * sizeof(GLfloat)); 419 420 vbo_exec_do_EvalCoord1f( exec, u ); 421 422 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 423 exec->vtx.vertex_size * sizeof(GLfloat)); 424} 425 426static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v ) 427{ 428 GET_CURRENT_CONTEXT( ctx ); 429 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 430 431 { 432 GLint i; 433 if (exec->eval.recalculate_maps) 434 vbo_exec_eval_update( exec ); 435 436 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 437 if (exec->eval.map2[i].map) 438 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz) 439 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz ); 440 } 441 442 if (ctx->Eval.AutoNormal) 443 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3) 444 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 ); 445 } 446 447 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 448 exec->vtx.vertex_size * sizeof(GLfloat)); 449 450 vbo_exec_do_EvalCoord2f( exec, u, v ); 451 452 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 453 exec->vtx.vertex_size * sizeof(GLfloat)); 454} 455 456static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u ) 457{ 458 vbo_exec_EvalCoord1f( u[0] ); 459} 460 461static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u ) 462{ 463 vbo_exec_EvalCoord2f( u[0], u[1] ); 464} 465 466static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i ) 467{ 468 GET_CURRENT_CONTEXT( ctx ); 469 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / 470 (GLfloat) ctx->Eval.MapGrid1un); 471 GLfloat u = i * du + ctx->Eval.MapGrid1u1; 472 473 vbo_exec_EvalCoord1f( u ); 474} 475 476 477static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j ) 478{ 479 GET_CURRENT_CONTEXT( ctx ); 480 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 481 (GLfloat) ctx->Eval.MapGrid2un); 482 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 483 (GLfloat) ctx->Eval.MapGrid2vn); 484 GLfloat u = i * du + ctx->Eval.MapGrid2u1; 485 GLfloat v = j * dv + ctx->Eval.MapGrid2v1; 486 487 vbo_exec_EvalCoord2f( u, v ); 488} 489 490/* use noop eval mesh */ 491#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1 492#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2 493 494#endif /* FEATURE_evaluators */ 495 496 497/** 498 * Called via glBegin. 499 */ 500static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) 501{ 502 GET_CURRENT_CONTEXT( ctx ); 503 504 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) { 505 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 506 int i; 507 508 if (ctx->NewState) { 509 _mesa_update_state( ctx ); 510 511 CALL_Begin(ctx->Exec, (mode)); 512 return; 513 } 514 515 if (!_mesa_valid_to_render(ctx, "glBegin")) { 516 return; 517 } 518 519 /* Heuristic: attempt to isolate attributes occuring outside 520 * begin/end pairs. 521 */ 522 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 523 vbo_exec_FlushVertices_internal( ctx, GL_FALSE ); 524 525 i = exec->vtx.prim_count++; 526 exec->vtx.prim[i].mode = mode; 527 exec->vtx.prim[i].begin = 1; 528 exec->vtx.prim[i].end = 0; 529 exec->vtx.prim[i].indexed = 0; 530 exec->vtx.prim[i].weak = 0; 531 exec->vtx.prim[i].pad = 0; 532 exec->vtx.prim[i].start = exec->vtx.vert_count; 533 exec->vtx.prim[i].count = 0; 534 535 ctx->Driver.CurrentExecPrimitive = mode; 536 } 537 else 538 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); 539 540} 541 542 543/** 544 * Called via glEnd. 545 */ 546static void GLAPIENTRY vbo_exec_End( void ) 547{ 548 GET_CURRENT_CONTEXT( ctx ); 549 550 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 551 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 552 int idx = exec->vtx.vert_count; 553 int i = exec->vtx.prim_count - 1; 554 555 exec->vtx.prim[i].end = 1; 556 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start; 557 558 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 559 560 if (exec->vtx.prim_count == VBO_MAX_PRIM) 561 vbo_exec_vtx_flush( exec, GL_FALSE ); 562 } 563 else 564 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); 565} 566 567 568static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 569{ 570 GLvertexformat *vfmt = &exec->vtxfmt; 571 572 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); 573 574 vfmt->Begin = vbo_exec_Begin; 575 vfmt->End = vbo_exec_End; 576 577 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_); 578 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_); 579 580 vfmt->Rectf = _mesa_noop_Rectf; 581 582 /* from attrib_tmp.h: 583 */ 584 vfmt->Color3f = vbo_Color3f; 585 vfmt->Color3fv = vbo_Color3fv; 586 vfmt->Color4f = vbo_Color4f; 587 vfmt->Color4fv = vbo_Color4fv; 588 vfmt->FogCoordfEXT = vbo_FogCoordfEXT; 589 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT; 590 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f; 591 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv; 592 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f; 593 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv; 594 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f; 595 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv; 596 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f; 597 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv; 598 vfmt->Normal3f = vbo_Normal3f; 599 vfmt->Normal3fv = vbo_Normal3fv; 600 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT; 601 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT; 602 vfmt->TexCoord1f = vbo_TexCoord1f; 603 vfmt->TexCoord1fv = vbo_TexCoord1fv; 604 vfmt->TexCoord2f = vbo_TexCoord2f; 605 vfmt->TexCoord2fv = vbo_TexCoord2fv; 606 vfmt->TexCoord3f = vbo_TexCoord3f; 607 vfmt->TexCoord3fv = vbo_TexCoord3fv; 608 vfmt->TexCoord4f = vbo_TexCoord4f; 609 vfmt->TexCoord4fv = vbo_TexCoord4fv; 610 vfmt->Vertex2f = vbo_Vertex2f; 611 vfmt->Vertex2fv = vbo_Vertex2fv; 612 vfmt->Vertex3f = vbo_Vertex3f; 613 vfmt->Vertex3fv = vbo_Vertex3fv; 614 vfmt->Vertex4f = vbo_Vertex4f; 615 vfmt->Vertex4fv = vbo_Vertex4fv; 616 617 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB; 618 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB; 619 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB; 620 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB; 621 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB; 622 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB; 623 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB; 624 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB; 625 626 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV; 627 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV; 628 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV; 629 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV; 630 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV; 631 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV; 632 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV; 633 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV; 634 635 vfmt->Materialfv = vbo_Materialfv; 636 637 vfmt->EdgeFlag = vbo_EdgeFlag; 638 vfmt->Indexf = vbo_Indexf; 639 vfmt->Indexfv = vbo_Indexfv; 640 641} 642 643 644#else /* FEATURE_beginend */ 645 646 647#define ATTR( A, N, V0, V1, V2, V3 ) \ 648do { \ 649 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 650 \ 651 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \ 652 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ 653 \ 654 if (exec->vtx.active_sz[A] != N) \ 655 vbo_exec_fixup_vertex(ctx, A, N); \ 656 \ 657 { \ 658 GLfloat *dest = exec->vtx.attrptr[A]; \ 659 if (N>0) dest[0] = V0; \ 660 if (N>1) dest[1] = V1; \ 661 if (N>2) dest[2] = V2; \ 662 if (N>3) dest[3] = V3; \ 663 } \ 664} while (0) 665 666#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ ) 667#define TAG(x) vbo_##x 668 669#include "vbo_attrib_tmp.h" 670 671static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 672{ 673 /* silence warnings */ 674 (void) vbo_Color3f; 675 (void) vbo_Color3fv; 676 (void) vbo_Color4f; 677 (void) vbo_Color4fv; 678 (void) vbo_FogCoordfEXT; 679 (void) vbo_FogCoordfvEXT; 680 (void) vbo_MultiTexCoord1f; 681 (void) vbo_MultiTexCoord1fv; 682 (void) vbo_MultiTexCoord2f; 683 (void) vbo_MultiTexCoord2fv; 684 (void) vbo_MultiTexCoord3f; 685 (void) vbo_MultiTexCoord3fv; 686 (void) vbo_MultiTexCoord4f; 687 (void) vbo_MultiTexCoord4fv; 688 (void) vbo_Normal3f; 689 (void) vbo_Normal3fv; 690 (void) vbo_SecondaryColor3fEXT; 691 (void) vbo_SecondaryColor3fvEXT; 692 (void) vbo_TexCoord1f; 693 (void) vbo_TexCoord1fv; 694 (void) vbo_TexCoord2f; 695 (void) vbo_TexCoord2fv; 696 (void) vbo_TexCoord3f; 697 (void) vbo_TexCoord3fv; 698 (void) vbo_TexCoord4f; 699 (void) vbo_TexCoord4fv; 700 (void) vbo_Vertex2f; 701 (void) vbo_Vertex2fv; 702 (void) vbo_Vertex3f; 703 (void) vbo_Vertex3fv; 704 (void) vbo_Vertex4f; 705 (void) vbo_Vertex4fv; 706 707 (void) vbo_VertexAttrib1fARB; 708 (void) vbo_VertexAttrib1fvARB; 709 (void) vbo_VertexAttrib2fARB; 710 (void) vbo_VertexAttrib2fvARB; 711 (void) vbo_VertexAttrib3fARB; 712 (void) vbo_VertexAttrib3fvARB; 713 (void) vbo_VertexAttrib4fARB; 714 (void) vbo_VertexAttrib4fvARB; 715 716 (void) vbo_VertexAttrib1fNV; 717 (void) vbo_VertexAttrib1fvNV; 718 (void) vbo_VertexAttrib2fNV; 719 (void) vbo_VertexAttrib2fvNV; 720 (void) vbo_VertexAttrib3fNV; 721 (void) vbo_VertexAttrib3fvNV; 722 (void) vbo_VertexAttrib4fNV; 723 (void) vbo_VertexAttrib4fvNV; 724 725 (void) vbo_Materialfv; 726 727 (void) vbo_EdgeFlag; 728 (void) vbo_Indexf; 729 (void) vbo_Indexfv; 730} 731 732 733#endif /* FEATURE_beginend */ 734 735 736/** 737 * Tell the VBO module to use a real OpenGL vertex buffer object to 738 * store accumulated immediate-mode vertex data. 739 * This replaces the malloced buffer which was created in 740 * vb_exec_vtx_init() below. 741 */ 742void vbo_use_buffer_objects(GLcontext *ctx) 743{ 744 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 745 /* Any buffer name but 0 can be used here since this bufferobj won't 746 * go into the bufferobj hashtable. 747 */ 748 GLuint bufName = IMM_BUFFER_NAME; 749 GLenum target = GL_ARRAY_BUFFER_ARB; 750 GLenum usage = GL_STREAM_DRAW_ARB; 751 GLsizei size = VBO_VERT_BUFFER_SIZE; 752 753 /* Make sure this func is only used once */ 754 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj); 755 if (exec->vtx.buffer_map) { 756 _mesa_align_free(exec->vtx.buffer_map); 757 exec->vtx.buffer_map = NULL; 758 exec->vtx.buffer_ptr = NULL; 759 } 760 761 /* Allocate a real buffer object now */ 762 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 763 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target); 764 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj); 765} 766 767 768 769void vbo_exec_vtx_init( struct vbo_exec_context *exec ) 770{ 771 GLcontext *ctx = exec->ctx; 772 struct vbo_context *vbo = vbo_context(ctx); 773 GLuint i; 774 775 /* Allocate a buffer object. Will just reuse this object 776 * continuously, unless vbo_use_buffer_objects() is called to enable 777 * use of real VBOs. 778 */ 779 _mesa_reference_buffer_object(ctx, 780 &exec->vtx.bufferobj, 781 ctx->Shared->NullBufferObj); 782 783 ASSERT(!exec->vtx.buffer_map); 784 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64); 785 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 786 787 vbo_exec_vtxfmt_init( exec ); 788 789 /* Hook our functions into the dispatch table. 790 */ 791 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt ); 792 793 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 794 ASSERT(i < Elements(exec->vtx.attrsz)); 795 exec->vtx.attrsz[i] = 0; 796 ASSERT(i < Elements(exec->vtx.active_sz)); 797 exec->vtx.active_sz[i] = 0; 798 } 799 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) { 800 ASSERT(i < Elements(exec->vtx.inputs)); 801 ASSERT(i < Elements(exec->vtx.arrays)); 802 exec->vtx.inputs[i] = &exec->vtx.arrays[i]; 803 } 804 805 { 806 struct gl_client_array *arrays = exec->vtx.arrays; 807 unsigned i; 808 809 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0])); 810 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0])); 811 812 for (i = 0; i < 16; ++i) { 813 arrays[i ].BufferObj = NULL; 814 arrays[i + 16].BufferObj = NULL; 815 _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj, 816 vbo->legacy_currval[i].BufferObj); 817 _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj, 818 vbo->generic_currval[i].BufferObj); 819 } 820 } 821 822 exec->vtx.vertex_size = 0; 823} 824 825 826void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ) 827{ 828 /* using a real VBO for vertex data */ 829 GLcontext *ctx = exec->ctx; 830 unsigned i; 831 832 /* True VBOs should already be unmapped 833 */ 834 if (exec->vtx.buffer_map) { 835 ASSERT(exec->vtx.bufferobj->Name == 0 || 836 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); 837 if (exec->vtx.bufferobj->Name == 0) { 838 _mesa_align_free(exec->vtx.buffer_map); 839 exec->vtx.buffer_map = NULL; 840 exec->vtx.buffer_ptr = NULL; 841 } 842 } 843 844 /* Drop any outstanding reference to the vertex buffer 845 */ 846 for (i = 0; i < Elements(exec->vtx.arrays); i++) { 847 _mesa_reference_buffer_object(ctx, 848 &exec->vtx.arrays[i].BufferObj, 849 NULL); 850 } 851 852 /* Free the vertex buffer: 853 */ 854 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 855} 856 857void vbo_exec_BeginVertices( GLcontext *ctx ) 858{ 859 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 860 if (0) printf("%s\n", __FUNCTION__); 861 vbo_exec_vtx_map( exec ); 862 863 assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0); 864 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; 865} 866 867void vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap ) 868{ 869 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 870 871 if (exec->vtx.vert_count || unmap) { 872 vbo_exec_vtx_flush( exec, unmap ); 873 } 874 875 if (exec->vtx.vertex_size) { 876 vbo_exec_copy_to_current( exec ); 877 reset_attrfv( exec ); 878 } 879} 880 881 882/** 883 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 884 */ 885void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags ) 886{ 887 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 888 889#ifdef DEBUG 890 /* debug check: make sure we don't get called recursively */ 891 exec->flush_call_depth++; 892 assert(exec->flush_call_depth == 1); 893#endif 894 895 if (0) printf("%s\n", __FUNCTION__); 896 897 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 898 if (0) printf("%s - inside begin/end\n", __FUNCTION__); 899#ifdef DEBUG 900 exec->flush_call_depth--; 901 assert(exec->flush_call_depth == 0); 902#endif 903 return; 904 } 905 906 vbo_exec_FlushVertices_internal( ctx, GL_TRUE ); 907 908 /* Need to do this to ensure BeginVertices gets called again: 909 */ 910 if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) { 911 _mesa_restore_exec_vtxfmt( ctx ); 912 exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT; 913 } 914 915 exec->ctx->Driver.NeedFlush &= ~flags; 916 917#ifdef DEBUG 918 exec->flush_call_depth--; 919 assert(exec->flush_call_depth == 0); 920#endif 921} 922 923 924static void reset_attrfv( struct vbo_exec_context *exec ) 925{ 926 GLuint i; 927 928 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 929 exec->vtx.attrsz[i] = 0; 930 exec->vtx.active_sz[i] = 0; 931 } 932 933 exec->vtx.vertex_size = 0; 934} 935 936 937void GLAPIENTRY 938_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 939{ 940 vbo_Color4f(r, g, b, a); 941} 942 943 944void GLAPIENTRY 945_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z) 946{ 947 vbo_Normal3f(x, y, z); 948} 949 950 951void GLAPIENTRY 952_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 953{ 954 vbo_MultiTexCoord4f(target, s, t, r, q); 955} 956 957void GLAPIENTRY 958_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 959{ 960 vbo_Materialfv(face, pname, params); 961} 962 963 964void GLAPIENTRY 965_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 966{ 967 vbo_VertexAttrib4fARB(index, x, y, z, w); 968} 969