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