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