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_validate.h" 45#include "main/dispatch.h" 46 47#include "vbo_context.h" 48#include "vbo_noop.h" 49 50 51#ifdef ERROR 52#undef ERROR 53#endif 54 55 56/** ID/name for immediate-mode VBO */ 57#define IMM_BUFFER_NAME 0xaabbccdd 58 59 60static void reset_attrfv( struct vbo_exec_context *exec ); 61 62 63/** 64 * Close off the last primitive, execute the buffer, restart the 65 * primitive. 66 */ 67static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec ) 68{ 69 if (exec->vtx.prim_count == 0) { 70 exec->vtx.copied.nr = 0; 71 exec->vtx.vert_count = 0; 72 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 73 } 74 else { 75 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin; 76 GLuint last_count; 77 78 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 79 GLint i = exec->vtx.prim_count - 1; 80 assert(i >= 0); 81 exec->vtx.prim[i].count = (exec->vtx.vert_count - 82 exec->vtx.prim[i].start); 83 } 84 85 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count; 86 87 /* Execute the buffer and save copied vertices. 88 */ 89 if (exec->vtx.vert_count) 90 vbo_exec_vtx_flush( exec, GL_FALSE ); 91 else { 92 exec->vtx.prim_count = 0; 93 exec->vtx.copied.nr = 0; 94 } 95 96 /* Emit a glBegin to start the new list. 97 */ 98 assert(exec->vtx.prim_count == 0); 99 100 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 101 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive; 102 exec->vtx.prim[0].start = 0; 103 exec->vtx.prim[0].count = 0; 104 exec->vtx.prim_count++; 105 106 if (exec->vtx.copied.nr == last_count) 107 exec->vtx.prim[0].begin = last_begin; 108 } 109 } 110} 111 112 113/** 114 * Deal with buffer wrapping where provoked by the vertex buffer 115 * filling up, as opposed to upgrade_vertex(). 116 */ 117void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ) 118{ 119 GLfloat *data = exec->vtx.copied.buffer; 120 GLuint i; 121 122 /* Run pipeline on current vertices, copy wrapped vertices 123 * to exec->vtx.copied. 124 */ 125 vbo_exec_wrap_buffers( exec ); 126 127 if (!exec->vtx.buffer_ptr) { 128 /* probably ran out of memory earlier when allocating the VBO */ 129 return; 130 } 131 132 /* Copy stored stored vertices to start of new list. 133 */ 134 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); 135 136 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 137 memcpy( exec->vtx.buffer_ptr, data, 138 exec->vtx.vertex_size * sizeof(GLfloat)); 139 exec->vtx.buffer_ptr += exec->vtx.vertex_size; 140 data += exec->vtx.vertex_size; 141 exec->vtx.vert_count++; 142 } 143 144 exec->vtx.copied.nr = 0; 145} 146 147 148/** 149 * Copy the active vertex's values to the ctx->Current fields. 150 */ 151static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) 152{ 153 struct gl_context *ctx = exec->ctx; 154 struct vbo_context *vbo = vbo_context(ctx); 155 GLuint i; 156 157 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 158 if (exec->vtx.attrsz[i]) { 159 /* Note: the exec->vtx.current[i] pointers point into the 160 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. 161 */ 162 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; 163 GLfloat tmp[4]; 164 165 COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, 166 exec->vtx.attrsz[i], 167 exec->vtx.attrptr[i], 168 exec->vtx.attrtype[i]); 169 170 if (exec->vtx.attrtype[i] != vbo->currval[i].Type || 171 memcmp(current, tmp, sizeof(tmp)) != 0) { 172 memcpy(current, tmp, sizeof(tmp)); 173 174 /* Given that we explicitly state size here, there is no need 175 * for the COPY_CLEAN above, could just copy 16 bytes and be 176 * done. The only problem is when Mesa accesses ctx->Current 177 * directly. 178 */ 179 vbo->currval[i].Size = exec->vtx.attrsz[i]; 180 vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); 181 vbo->currval[i].Type = exec->vtx.attrtype[i]; 182 vbo->currval[i].Integer = 183 vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]); 184 185 /* This triggers rather too much recalculation of Mesa state 186 * that doesn't get used (eg light positions). 187 */ 188 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && 189 i <= VBO_ATTRIB_MAT_BACK_INDEXES) 190 ctx->NewState |= _NEW_LIGHT; 191 192 ctx->NewState |= _NEW_CURRENT_ATTRIB; 193 } 194 } 195 } 196 197 /* Colormaterial -- this kindof sucks. 198 */ 199 if (ctx->Light.ColorMaterialEnabled && 200 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { 201 _mesa_update_color_material(ctx, 202 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 203 } 204} 205 206 207/** 208 * Copy current vertex attribute values into the current vertex. 209 */ 210static void 211vbo_exec_copy_from_current(struct vbo_exec_context *exec) 212{ 213 struct gl_context *ctx = exec->ctx; 214 struct vbo_context *vbo = vbo_context(ctx); 215 GLint i; 216 217 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { 218 const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr; 219 switch (exec->vtx.attrsz[i]) { 220 case 4: exec->vtx.attrptr[i][3] = current[3]; 221 case 3: exec->vtx.attrptr[i][2] = current[2]; 222 case 2: exec->vtx.attrptr[i][1] = current[1]; 223 case 1: exec->vtx.attrptr[i][0] = current[0]; 224 break; 225 } 226 } 227} 228 229 230/** 231 * Flush existing data, set new attrib size, replay copied vertices. 232 * This is called when we transition from a small vertex attribute size 233 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. 234 * We need to go back over the previous 2-component texcoords and insert 235 * zero and one values. 236 */ 237static void 238vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, 239 GLuint attr, GLuint newSize ) 240{ 241 struct gl_context *ctx = exec->ctx; 242 struct vbo_context *vbo = vbo_context(ctx); 243 const GLint lastcount = exec->vtx.vert_count; 244 GLfloat *old_attrptr[VBO_ATTRIB_MAX]; 245 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ 246 const GLuint oldSize = exec->vtx.attrsz[attr]; 247 GLuint i; 248 249 /* Run pipeline on current vertices, copy wrapped vertices 250 * to exec->vtx.copied. 251 */ 252 vbo_exec_wrap_buffers( exec ); 253 254 if (unlikely(exec->vtx.copied.nr)) { 255 /* We're in the middle of a primitive, keep the old vertex 256 * format around to be able to translate the copied vertices to 257 * the new format. 258 */ 259 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); 260 } 261 262 if (unlikely(oldSize)) { 263 /* Do a COPY_TO_CURRENT to ensure back-copying works for the 264 * case when the attribute already exists in the vertex and is 265 * having its size increased. 266 */ 267 vbo_exec_copy_to_current( exec ); 268 } 269 270 /* Heuristic: Attempt to isolate attributes received outside 271 * begin/end so that they don't bloat the vertices. 272 */ 273 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END && 274 !oldSize && lastcount > 8 && exec->vtx.vertex_size) { 275 vbo_exec_copy_to_current( exec ); 276 reset_attrfv( exec ); 277 } 278 279 /* Fix up sizes: 280 */ 281 exec->vtx.attrsz[attr] = newSize; 282 exec->vtx.vertex_size += newSize - oldSize; 283 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / 284 (exec->vtx.vertex_size * sizeof(GLfloat))); 285 exec->vtx.vert_count = 0; 286 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 287 288 if (unlikely(oldSize)) { 289 /* Size changed, recalculate all the attrptr[] values 290 */ 291 GLfloat *tmp = exec->vtx.vertex; 292 293 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 294 if (exec->vtx.attrsz[i]) { 295 exec->vtx.attrptr[i] = tmp; 296 tmp += exec->vtx.attrsz[i]; 297 } 298 else 299 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */ 300 } 301 302 /* Copy from current to repopulate the vertex with correct 303 * values. 304 */ 305 vbo_exec_copy_from_current( exec ); 306 } 307 else { 308 /* Just have to append the new attribute at the end */ 309 exec->vtx.attrptr[attr] = exec->vtx.vertex + 310 exec->vtx.vertex_size - newSize; 311 } 312 313 /* Replay stored vertices to translate them 314 * to new format here. 315 * 316 * -- No need to replay - just copy piecewise 317 */ 318 if (unlikely(exec->vtx.copied.nr)) { 319 GLfloat *data = exec->vtx.copied.buffer; 320 GLfloat *dest = exec->vtx.buffer_ptr; 321 GLuint j; 322 323 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); 324 325 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 326 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { 327 GLuint sz = exec->vtx.attrsz[j]; 328 329 if (sz) { 330 GLint old_offset = old_attrptr[j] - exec->vtx.vertex; 331 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; 332 333 if (j == attr) { 334 if (oldSize) { 335 GLfloat tmp[4]; 336 COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, oldSize, 337 data + old_offset, 338 exec->vtx.attrtype[j]); 339 COPY_SZ_4V(dest + new_offset, newSize, tmp); 340 } else { 341 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr; 342 COPY_SZ_4V(dest + new_offset, sz, current); 343 } 344 } 345 else { 346 COPY_SZ_4V(dest + new_offset, sz, data + old_offset); 347 } 348 } 349 } 350 351 data += old_vtx_size; 352 dest += exec->vtx.vertex_size; 353 } 354 355 exec->vtx.buffer_ptr = dest; 356 exec->vtx.vert_count += exec->vtx.copied.nr; 357 exec->vtx.copied.nr = 0; 358 } 359} 360 361 362/** 363 * This is when a vertex attribute transitions to a different size. 364 * For example, we saw a bunch of glTexCoord2f() calls and now we got a 365 * glTexCoord4f() call. We promote the array from size=2 to size=4. 366 */ 367static void 368vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize) 369{ 370 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 371 372 if (newSize > exec->vtx.attrsz[attr]) { 373 /* New size is larger. Need to flush existing vertices and get 374 * an enlarged vertex format. 375 */ 376 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize ); 377 } 378 else if (newSize < exec->vtx.active_sz[attr]) { 379 GLuint i; 380 const GLfloat *id = 381 vbo_get_default_vals_as_float(exec->vtx.attrtype[attr]); 382 383 /* New size is smaller - just need to fill in some 384 * zeros. Don't need to flush or wrap. 385 */ 386 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++) 387 exec->vtx.attrptr[attr][i-1] = id[i-1]; 388 } 389 390 exec->vtx.active_sz[attr] = newSize; 391 392 /* Does setting NeedFlush belong here? Necessitates resetting 393 * vtxfmt on each flush (otherwise flags won't get reset 394 * afterwards). 395 */ 396 if (attr == 0) 397 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; 398} 399 400 401/** 402 * This macro is used to implement all the glVertex, glColor, glTexCoord, 403 * glVertexAttrib, etc functions. 404 */ 405#define ATTR( A, N, T, V0, V1, V2, V3 ) \ 406do { \ 407 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 408 \ 409 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \ 410 ctx->Driver.BeginVertices( ctx ); \ 411 \ 412 if (unlikely(exec->vtx.active_sz[A] != N)) \ 413 vbo_exec_fixup_vertex(ctx, A, N); \ 414 \ 415 { \ 416 GLfloat *dest = exec->vtx.attrptr[A]; \ 417 if (N>0) dest[0] = V0; \ 418 if (N>1) dest[1] = V1; \ 419 if (N>2) dest[2] = V2; \ 420 if (N>3) dest[3] = V3; \ 421 exec->vtx.attrtype[A] = T; \ 422 } \ 423 \ 424 if ((A) == 0) { \ 425 /* This is a glVertex call */ \ 426 GLuint i; \ 427 \ 428 for (i = 0; i < exec->vtx.vertex_size; i++) \ 429 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \ 430 \ 431 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \ 432 \ 433 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \ 434 /* something to draw (not just updating a color or texcoord).*/ \ 435 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \ 436 \ 437 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \ 438 vbo_exec_vtx_wrap( exec ); \ 439 } \ 440} while (0) 441 442 443#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ ) 444#define TAG(x) vbo_##x 445 446#include "vbo_attrib_tmp.h" 447 448 449 450/** 451 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled, 452 * this may be a (partial) no-op. 453 */ 454static void GLAPIENTRY 455vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 456{ 457 GLbitfield updateMats; 458 GET_CURRENT_CONTEXT(ctx); 459 460 /* This function should be a no-op when it tries to update material 461 * attributes which are currently tracking glColor via glColorMaterial. 462 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits 463 * indicating which material attributes can actually be updated below. 464 */ 465 if (ctx->Light.ColorMaterialEnabled) { 466 updateMats = ~ctx->Light._ColorMaterialBitmask; 467 } 468 else { 469 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */ 470 updateMats = ALL_MATERIAL_BITS; 471 } 472 473 if (ctx->API == API_OPENGL && face == GL_FRONT) { 474 updateMats &= FRONT_MATERIAL_BITS; 475 } 476 else if (ctx->API == API_OPENGL && face == GL_BACK) { 477 updateMats &= BACK_MATERIAL_BITS; 478 } 479 else if (face != GL_FRONT_AND_BACK) { 480 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)"); 481 return; 482 } 483 484 switch (pname) { 485 case GL_EMISSION: 486 if (updateMats & MAT_BIT_FRONT_EMISSION) 487 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params); 488 if (updateMats & MAT_BIT_BACK_EMISSION) 489 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params); 490 break; 491 case GL_AMBIENT: 492 if (updateMats & MAT_BIT_FRONT_AMBIENT) 493 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 494 if (updateMats & MAT_BIT_BACK_AMBIENT) 495 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 496 break; 497 case GL_DIFFUSE: 498 if (updateMats & MAT_BIT_FRONT_DIFFUSE) 499 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 500 if (updateMats & MAT_BIT_BACK_DIFFUSE) 501 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 502 break; 503 case GL_SPECULAR: 504 if (updateMats & MAT_BIT_FRONT_SPECULAR) 505 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params); 506 if (updateMats & MAT_BIT_BACK_SPECULAR) 507 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params); 508 break; 509 case GL_SHININESS: 510 if (*params < 0 || *params > ctx->Const.MaxShininess) { 511 _mesa_error(ctx, GL_INVALID_VALUE, 512 "glMaterial(invalid shininess: %f out range [0, %f])", 513 *params, ctx->Const.MaxShininess); 514 return; 515 } 516 if (updateMats & MAT_BIT_FRONT_SHININESS) 517 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params); 518 if (updateMats & MAT_BIT_BACK_SHININESS) 519 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params); 520 break; 521 case GL_COLOR_INDEXES: 522 if (ctx->API != API_OPENGL) { 523 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 524 return; 525 } 526 if (updateMats & MAT_BIT_FRONT_INDEXES) 527 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params); 528 if (updateMats & MAT_BIT_BACK_INDEXES) 529 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params); 530 break; 531 case GL_AMBIENT_AND_DIFFUSE: 532 if (updateMats & MAT_BIT_FRONT_AMBIENT) 533 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 534 if (updateMats & MAT_BIT_FRONT_DIFFUSE) 535 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 536 if (updateMats & MAT_BIT_BACK_AMBIENT) 537 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 538 if (updateMats & MAT_BIT_BACK_DIFFUSE) 539 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 540 break; 541 default: 542 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 543 return; 544 } 545} 546 547 548/** 549 * Flush (draw) vertices. 550 * \param unmap - leave VBO unmapped after flushing? 551 */ 552static void 553vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap) 554{ 555 if (exec->vtx.vert_count || unmap) { 556 vbo_exec_vtx_flush( exec, unmap ); 557 } 558 559 if (exec->vtx.vertex_size) { 560 vbo_exec_copy_to_current( exec ); 561 reset_attrfv( exec ); 562 } 563} 564 565 566#if FEATURE_beginend 567 568 569#if FEATURE_evaluators 570 571static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u ) 572{ 573 GET_CURRENT_CONTEXT( ctx ); 574 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 575 576 { 577 GLint i; 578 if (exec->eval.recalculate_maps) 579 vbo_exec_eval_update( exec ); 580 581 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 582 if (exec->eval.map1[i].map) 583 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz) 584 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz ); 585 } 586 } 587 588 589 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 590 exec->vtx.vertex_size * sizeof(GLfloat)); 591 592 vbo_exec_do_EvalCoord1f( exec, u ); 593 594 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 595 exec->vtx.vertex_size * sizeof(GLfloat)); 596} 597 598static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v ) 599{ 600 GET_CURRENT_CONTEXT( ctx ); 601 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 602 603 { 604 GLint i; 605 if (exec->eval.recalculate_maps) 606 vbo_exec_eval_update( exec ); 607 608 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 609 if (exec->eval.map2[i].map) 610 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz) 611 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz ); 612 } 613 614 if (ctx->Eval.AutoNormal) 615 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3) 616 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 ); 617 } 618 619 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 620 exec->vtx.vertex_size * sizeof(GLfloat)); 621 622 vbo_exec_do_EvalCoord2f( exec, u, v ); 623 624 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 625 exec->vtx.vertex_size * sizeof(GLfloat)); 626} 627 628static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u ) 629{ 630 vbo_exec_EvalCoord1f( u[0] ); 631} 632 633static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u ) 634{ 635 vbo_exec_EvalCoord2f( u[0], u[1] ); 636} 637 638static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i ) 639{ 640 GET_CURRENT_CONTEXT( ctx ); 641 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / 642 (GLfloat) ctx->Eval.MapGrid1un); 643 GLfloat u = i * du + ctx->Eval.MapGrid1u1; 644 645 vbo_exec_EvalCoord1f( u ); 646} 647 648 649static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j ) 650{ 651 GET_CURRENT_CONTEXT( ctx ); 652 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 653 (GLfloat) ctx->Eval.MapGrid2un); 654 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 655 (GLfloat) ctx->Eval.MapGrid2vn); 656 GLfloat u = i * du + ctx->Eval.MapGrid2u1; 657 GLfloat v = j * dv + ctx->Eval.MapGrid2v1; 658 659 vbo_exec_EvalCoord2f( u, v ); 660} 661 662 663static void GLAPIENTRY 664vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2) 665{ 666 GET_CURRENT_CONTEXT(ctx); 667 GLint i; 668 GLfloat u, du; 669 GLenum prim; 670 671 ASSERT_OUTSIDE_BEGIN_END(ctx); 672 673 switch (mode) { 674 case GL_POINT: 675 prim = GL_POINTS; 676 break; 677 case GL_LINE: 678 prim = GL_LINE_STRIP; 679 break; 680 default: 681 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" ); 682 return; 683 } 684 685 /* No effect if vertex maps disabled. 686 */ 687 if (!ctx->Eval.Map1Vertex4 && 688 !ctx->Eval.Map1Vertex3 && 689 !(ctx->VertexProgram._Enabled && ctx->Eval.Map1Attrib[VERT_ATTRIB_POS])) 690 return; 691 692 du = ctx->Eval.MapGrid1du; 693 u = ctx->Eval.MapGrid1u1 + i1 * du; 694 695 CALL_Begin(GET_DISPATCH(), (prim)); 696 for (i=i1;i<=i2;i++,u+=du) { 697 CALL_EvalCoord1f(GET_DISPATCH(), (u)); 698 } 699 CALL_End(GET_DISPATCH(), ()); 700} 701 702 703static void GLAPIENTRY 704vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) 705{ 706 GET_CURRENT_CONTEXT(ctx); 707 GLfloat u, du, v, dv, v1, u1; 708 GLint i, j; 709 710 ASSERT_OUTSIDE_BEGIN_END(ctx); 711 712 switch (mode) { 713 case GL_POINT: 714 case GL_LINE: 715 case GL_FILL: 716 break; 717 default: 718 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" ); 719 return; 720 } 721 722 /* No effect if vertex maps disabled. 723 */ 724 if (!ctx->Eval.Map2Vertex4 && 725 !ctx->Eval.Map2Vertex3 && 726 !(ctx->VertexProgram._Enabled && ctx->Eval.Map2Attrib[VERT_ATTRIB_POS])) 727 return; 728 729 du = ctx->Eval.MapGrid2du; 730 dv = ctx->Eval.MapGrid2dv; 731 v1 = ctx->Eval.MapGrid2v1 + j1 * dv; 732 u1 = ctx->Eval.MapGrid2u1 + i1 * du; 733 734 switch (mode) { 735 case GL_POINT: 736 CALL_Begin(GET_DISPATCH(), (GL_POINTS)); 737 for (v=v1,j=j1;j<=j2;j++,v+=dv) { 738 for (u=u1,i=i1;i<=i2;i++,u+=du) { 739 CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); 740 } 741 } 742 CALL_End(GET_DISPATCH(), ()); 743 break; 744 case GL_LINE: 745 for (v=v1,j=j1;j<=j2;j++,v+=dv) { 746 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP)); 747 for (u=u1,i=i1;i<=i2;i++,u+=du) { 748 CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); 749 } 750 CALL_End(GET_DISPATCH(), ()); 751 } 752 for (u=u1,i=i1;i<=i2;i++,u+=du) { 753 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP)); 754 for (v=v1,j=j1;j<=j2;j++,v+=dv) { 755 CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); 756 } 757 CALL_End(GET_DISPATCH(), ()); 758 } 759 break; 760 case GL_FILL: 761 for (v=v1,j=j1;j<j2;j++,v+=dv) { 762 CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP)); 763 for (u=u1,i=i1;i<=i2;i++,u+=du) { 764 CALL_EvalCoord2f(GET_DISPATCH(), (u, v)); 765 CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv)); 766 } 767 CALL_End(GET_DISPATCH(), ()); 768 } 769 break; 770 } 771} 772 773#endif /* FEATURE_evaluators */ 774 775 776/** 777 * Execute a glRectf() function. This is not suitable for GL_COMPILE 778 * modes (as the test for outside begin/end is not compiled), 779 * but may be useful for drivers in circumstances which exclude 780 * display list interactions. 781 * 782 * (None of the functions in this file are suitable for GL_COMPILE 783 * modes). 784 */ 785static void GLAPIENTRY 786vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) 787{ 788 GET_CURRENT_CONTEXT(ctx); 789 ASSERT_OUTSIDE_BEGIN_END(ctx); 790 791 CALL_Begin(GET_DISPATCH(), (GL_QUADS)); 792 CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); 793 CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); 794 CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); 795 CALL_Vertex2f(GET_DISPATCH(), (x1, y2)); 796 CALL_End(GET_DISPATCH(), ()); 797} 798 799 800/** 801 * Called via glBegin. 802 */ 803static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) 804{ 805 GET_CURRENT_CONTEXT( ctx ); 806 807 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) { 808 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 809 int i; 810 811 if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) { 812 return; 813 } 814 815 vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END); 816 817 if (ctx->Driver.PrepareExecBegin) 818 ctx->Driver.PrepareExecBegin(ctx); 819 820 if (ctx->NewState) { 821 _mesa_update_state( ctx ); 822 823 CALL_Begin(ctx->Exec, (mode)); 824 return; 825 } 826 827 if (!_mesa_valid_to_render(ctx, "glBegin")) { 828 return; 829 } 830 831 /* Heuristic: attempt to isolate attributes occuring outside 832 * begin/end pairs. 833 */ 834 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 835 vbo_exec_FlushVertices_internal(exec, GL_FALSE); 836 837 i = exec->vtx.prim_count++; 838 exec->vtx.prim[i].mode = mode; 839 exec->vtx.prim[i].begin = 1; 840 exec->vtx.prim[i].end = 0; 841 exec->vtx.prim[i].indexed = 0; 842 exec->vtx.prim[i].weak = 0; 843 exec->vtx.prim[i].pad = 0; 844 exec->vtx.prim[i].start = exec->vtx.vert_count; 845 exec->vtx.prim[i].count = 0; 846 exec->vtx.prim[i].num_instances = 1; 847 exec->vtx.prim[i].base_instance = 0; 848 849 ctx->Driver.CurrentExecPrimitive = mode; 850 } 851 else 852 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); 853 854} 855 856 857/** 858 * Called via glEnd. 859 */ 860static void GLAPIENTRY vbo_exec_End( void ) 861{ 862 GET_CURRENT_CONTEXT( ctx ); 863 864 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 865 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 866 867 if (exec->vtx.prim_count > 0) { 868 /* close off current primitive */ 869 int idx = exec->vtx.vert_count; 870 int i = exec->vtx.prim_count - 1; 871 872 exec->vtx.prim[i].end = 1; 873 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start; 874 } 875 876 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 877 878 if (exec->vtx.prim_count == VBO_MAX_PRIM) 879 vbo_exec_vtx_flush( exec, GL_FALSE ); 880 } 881 else 882 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); 883 884 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 885 _mesa_flush(ctx); 886 } 887} 888 889 890/** 891 * Called via glPrimitiveRestartNV() 892 */ 893static void GLAPIENTRY 894vbo_exec_PrimitiveRestartNV(void) 895{ 896 GLenum curPrim; 897 GET_CURRENT_CONTEXT( ctx ); 898 899 curPrim = ctx->Driver.CurrentExecPrimitive; 900 901 if (curPrim == PRIM_OUTSIDE_BEGIN_END) { 902 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" ); 903 } 904 else { 905 vbo_exec_End(); 906 vbo_exec_Begin(curPrim); 907 } 908} 909 910 911 912static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 913{ 914 struct gl_context *ctx = exec->ctx; 915 GLvertexformat *vfmt = &exec->vtxfmt; 916 917 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); 918 919 vfmt->Begin = vbo_exec_Begin; 920 vfmt->End = vbo_exec_End; 921 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV; 922 923 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_); 924 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_); 925 926 vfmt->Rectf = vbo_exec_Rectf; 927 928 /* from attrib_tmp.h: 929 */ 930 vfmt->Color3f = vbo_Color3f; 931 vfmt->Color3fv = vbo_Color3fv; 932 vfmt->Color4f = vbo_Color4f; 933 vfmt->Color4fv = vbo_Color4fv; 934 vfmt->FogCoordfEXT = vbo_FogCoordfEXT; 935 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT; 936 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f; 937 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv; 938 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f; 939 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv; 940 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f; 941 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv; 942 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f; 943 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv; 944 vfmt->Normal3f = vbo_Normal3f; 945 vfmt->Normal3fv = vbo_Normal3fv; 946 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT; 947 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT; 948 vfmt->TexCoord1f = vbo_TexCoord1f; 949 vfmt->TexCoord1fv = vbo_TexCoord1fv; 950 vfmt->TexCoord2f = vbo_TexCoord2f; 951 vfmt->TexCoord2fv = vbo_TexCoord2fv; 952 vfmt->TexCoord3f = vbo_TexCoord3f; 953 vfmt->TexCoord3fv = vbo_TexCoord3fv; 954 vfmt->TexCoord4f = vbo_TexCoord4f; 955 vfmt->TexCoord4fv = vbo_TexCoord4fv; 956 vfmt->Vertex2f = vbo_Vertex2f; 957 vfmt->Vertex2fv = vbo_Vertex2fv; 958 vfmt->Vertex3f = vbo_Vertex3f; 959 vfmt->Vertex3fv = vbo_Vertex3fv; 960 vfmt->Vertex4f = vbo_Vertex4f; 961 vfmt->Vertex4fv = vbo_Vertex4fv; 962 963 if (ctx->API == API_OPENGLES2) { 964 vfmt->VertexAttrib1fARB = _es_VertexAttrib1f; 965 vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv; 966 vfmt->VertexAttrib2fARB = _es_VertexAttrib2f; 967 vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv; 968 vfmt->VertexAttrib3fARB = _es_VertexAttrib3f; 969 vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv; 970 vfmt->VertexAttrib4fARB = _es_VertexAttrib4f; 971 vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv; 972 } else { 973 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB; 974 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB; 975 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB; 976 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB; 977 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB; 978 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB; 979 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB; 980 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB; 981 } 982 983 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV; 984 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV; 985 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV; 986 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV; 987 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV; 988 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV; 989 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV; 990 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV; 991 992 /* integer-valued */ 993 vfmt->VertexAttribI1i = vbo_VertexAttribI1i; 994 vfmt->VertexAttribI2i = vbo_VertexAttribI2i; 995 vfmt->VertexAttribI3i = vbo_VertexAttribI3i; 996 vfmt->VertexAttribI4i = vbo_VertexAttribI4i; 997 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv; 998 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv; 999 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv; 1000 1001 /* unsigned integer-valued */ 1002 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui; 1003 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui; 1004 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui; 1005 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui; 1006 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv; 1007 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv; 1008 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv; 1009 1010 vfmt->Materialfv = vbo_Materialfv; 1011 1012 vfmt->EdgeFlag = vbo_EdgeFlag; 1013 vfmt->Indexf = vbo_Indexf; 1014 vfmt->Indexfv = vbo_Indexfv; 1015 1016 /* ARB_vertex_type_2_10_10_10_rev */ 1017 vfmt->VertexP2ui = vbo_VertexP2ui; 1018 vfmt->VertexP2uiv = vbo_VertexP2uiv; 1019 vfmt->VertexP3ui = vbo_VertexP3ui; 1020 vfmt->VertexP3uiv = vbo_VertexP3uiv; 1021 vfmt->VertexP4ui = vbo_VertexP4ui; 1022 vfmt->VertexP4uiv = vbo_VertexP4uiv; 1023 1024 vfmt->TexCoordP1ui = vbo_TexCoordP1ui; 1025 vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv; 1026 vfmt->TexCoordP2ui = vbo_TexCoordP2ui; 1027 vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv; 1028 vfmt->TexCoordP3ui = vbo_TexCoordP3ui; 1029 vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv; 1030 vfmt->TexCoordP4ui = vbo_TexCoordP4ui; 1031 vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv; 1032 1033 vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui; 1034 vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv; 1035 vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui; 1036 vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv; 1037 vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui; 1038 vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv; 1039 vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui; 1040 vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv; 1041 1042 vfmt->NormalP3ui = vbo_NormalP3ui; 1043 vfmt->NormalP3uiv = vbo_NormalP3uiv; 1044 1045 vfmt->ColorP3ui = vbo_ColorP3ui; 1046 vfmt->ColorP3uiv = vbo_ColorP3uiv; 1047 vfmt->ColorP4ui = vbo_ColorP4ui; 1048 vfmt->ColorP4uiv = vbo_ColorP4uiv; 1049 1050 vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui; 1051 vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv; 1052 1053 vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui; 1054 vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv; 1055 vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui; 1056 vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv; 1057 vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui; 1058 vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv; 1059 vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui; 1060 vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv; 1061} 1062 1063 1064#else /* FEATURE_beginend */ 1065 1066 1067static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) 1068{ 1069 /* silence warnings */ 1070 (void) vbo_Color3f; 1071 (void) vbo_Color3fv; 1072 (void) vbo_Color4f; 1073 (void) vbo_Color4fv; 1074 (void) vbo_FogCoordfEXT; 1075 (void) vbo_FogCoordfvEXT; 1076 (void) vbo_MultiTexCoord1f; 1077 (void) vbo_MultiTexCoord1fv; 1078 (void) vbo_MultiTexCoord2f; 1079 (void) vbo_MultiTexCoord2fv; 1080 (void) vbo_MultiTexCoord3f; 1081 (void) vbo_MultiTexCoord3fv; 1082 (void) vbo_MultiTexCoord4f; 1083 (void) vbo_MultiTexCoord4fv; 1084 (void) vbo_Normal3f; 1085 (void) vbo_Normal3fv; 1086 (void) vbo_SecondaryColor3fEXT; 1087 (void) vbo_SecondaryColor3fvEXT; 1088 (void) vbo_TexCoord1f; 1089 (void) vbo_TexCoord1fv; 1090 (void) vbo_TexCoord2f; 1091 (void) vbo_TexCoord2fv; 1092 (void) vbo_TexCoord3f; 1093 (void) vbo_TexCoord3fv; 1094 (void) vbo_TexCoord4f; 1095 (void) vbo_TexCoord4fv; 1096 (void) vbo_Vertex2f; 1097 (void) vbo_Vertex2fv; 1098 (void) vbo_Vertex3f; 1099 (void) vbo_Vertex3fv; 1100 (void) vbo_Vertex4f; 1101 (void) vbo_Vertex4fv; 1102 1103 (void) vbo_VertexAttrib1fARB; 1104 (void) vbo_VertexAttrib1fvARB; 1105 (void) vbo_VertexAttrib2fARB; 1106 (void) vbo_VertexAttrib2fvARB; 1107 (void) vbo_VertexAttrib3fARB; 1108 (void) vbo_VertexAttrib3fvARB; 1109 (void) vbo_VertexAttrib4fARB; 1110 (void) vbo_VertexAttrib4fvARB; 1111 1112 (void) vbo_VertexAttrib1fNV; 1113 (void) vbo_VertexAttrib1fvNV; 1114 (void) vbo_VertexAttrib2fNV; 1115 (void) vbo_VertexAttrib2fvNV; 1116 (void) vbo_VertexAttrib3fNV; 1117 (void) vbo_VertexAttrib3fvNV; 1118 (void) vbo_VertexAttrib4fNV; 1119 (void) vbo_VertexAttrib4fvNV; 1120 1121 (void) vbo_Materialfv; 1122 1123 (void) vbo_EdgeFlag; 1124 (void) vbo_Indexf; 1125 (void) vbo_Indexfv; 1126} 1127 1128 1129#endif /* FEATURE_beginend */ 1130 1131 1132/** 1133 * Tell the VBO module to use a real OpenGL vertex buffer object to 1134 * store accumulated immediate-mode vertex data. 1135 * This replaces the malloced buffer which was created in 1136 * vb_exec_vtx_init() below. 1137 */ 1138void vbo_use_buffer_objects(struct gl_context *ctx) 1139{ 1140 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1141 /* Any buffer name but 0 can be used here since this bufferobj won't 1142 * go into the bufferobj hashtable. 1143 */ 1144 GLuint bufName = IMM_BUFFER_NAME; 1145 GLenum target = GL_ARRAY_BUFFER_ARB; 1146 GLenum usage = GL_STREAM_DRAW_ARB; 1147 GLsizei size = VBO_VERT_BUFFER_SIZE; 1148 1149 /* Make sure this func is only used once */ 1150 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj); 1151 if (exec->vtx.buffer_map) { 1152 _mesa_align_free(exec->vtx.buffer_map); 1153 exec->vtx.buffer_map = NULL; 1154 exec->vtx.buffer_ptr = NULL; 1155 } 1156 1157 /* Allocate a real buffer object now */ 1158 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 1159 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target); 1160 if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj)) { 1161 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation"); 1162 } 1163} 1164 1165 1166/** 1167 * If this function is called, all VBO buffers will be unmapped when 1168 * we flush. 1169 * Otherwise, if a simple command like glColor3f() is called and we flush, 1170 * the current VBO may be left mapped. 1171 */ 1172void 1173vbo_always_unmap_buffers(struct gl_context *ctx) 1174{ 1175 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1176 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES; 1177} 1178 1179 1180void vbo_exec_vtx_init( struct vbo_exec_context *exec ) 1181{ 1182 struct gl_context *ctx = exec->ctx; 1183 struct vbo_context *vbo = vbo_context(ctx); 1184 GLuint i; 1185 1186 /* Allocate a buffer object. Will just reuse this object 1187 * continuously, unless vbo_use_buffer_objects() is called to enable 1188 * use of real VBOs. 1189 */ 1190 _mesa_reference_buffer_object(ctx, 1191 &exec->vtx.bufferobj, 1192 ctx->Shared->NullBufferObj); 1193 1194 ASSERT(!exec->vtx.buffer_map); 1195 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64); 1196 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 1197 1198 vbo_exec_vtxfmt_init( exec ); 1199 _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop); 1200 1201 /* Hook our functions into the dispatch table. 1202 */ 1203 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt ); 1204 1205 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 1206 ASSERT(i < Elements(exec->vtx.attrsz)); 1207 exec->vtx.attrsz[i] = 0; 1208 ASSERT(i < Elements(exec->vtx.attrtype)); 1209 exec->vtx.attrtype[i] = GL_FLOAT; 1210 ASSERT(i < Elements(exec->vtx.active_sz)); 1211 exec->vtx.active_sz[i] = 0; 1212 } 1213 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) { 1214 ASSERT(i < Elements(exec->vtx.inputs)); 1215 ASSERT(i < Elements(exec->vtx.arrays)); 1216 exec->vtx.inputs[i] = &exec->vtx.arrays[i]; 1217 } 1218 1219 { 1220 struct gl_client_array *arrays = exec->vtx.arrays; 1221 unsigned i; 1222 1223 memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS], 1224 VERT_ATTRIB_FF_MAX * sizeof(arrays[0])); 1225 for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) { 1226 struct gl_client_array *array; 1227 array = &arrays[VERT_ATTRIB_FF(i)]; 1228 array->BufferObj = NULL; 1229 _mesa_reference_buffer_object(ctx, &arrays->BufferObj, 1230 vbo->currval[VBO_ATTRIB_POS+i].BufferObj); 1231 } 1232 1233 memcpy(arrays + VERT_ATTRIB_GENERIC(0), 1234 &vbo->currval[VBO_ATTRIB_GENERIC0], 1235 VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0])); 1236 1237 for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) { 1238 struct gl_client_array *array; 1239 array = &arrays[VERT_ATTRIB_GENERIC(i)]; 1240 array->BufferObj = NULL; 1241 _mesa_reference_buffer_object(ctx, &array->BufferObj, 1242 vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj); 1243 } 1244 } 1245 1246 exec->vtx.vertex_size = 0; 1247 1248 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT; 1249} 1250 1251 1252void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ) 1253{ 1254 /* using a real VBO for vertex data */ 1255 struct gl_context *ctx = exec->ctx; 1256 unsigned i; 1257 1258 /* True VBOs should already be unmapped 1259 */ 1260 if (exec->vtx.buffer_map) { 1261 ASSERT(exec->vtx.bufferobj->Name == 0 || 1262 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); 1263 if (exec->vtx.bufferobj->Name == 0) { 1264 _mesa_align_free(exec->vtx.buffer_map); 1265 exec->vtx.buffer_map = NULL; 1266 exec->vtx.buffer_ptr = NULL; 1267 } 1268 } 1269 1270 /* Drop any outstanding reference to the vertex buffer 1271 */ 1272 for (i = 0; i < Elements(exec->vtx.arrays); i++) { 1273 _mesa_reference_buffer_object(ctx, 1274 &exec->vtx.arrays[i].BufferObj, 1275 NULL); 1276 } 1277 1278 /* Free the vertex buffer. Unmap first if needed. 1279 */ 1280 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) { 1281 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj); 1282 } 1283 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 1284} 1285 1286 1287/** 1288 * Called upon first glVertex, glColor, glTexCoord, etc. 1289 */ 1290void vbo_exec_BeginVertices( struct gl_context *ctx ) 1291{ 1292 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1293 1294 vbo_exec_vtx_map( exec ); 1295 1296 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0); 1297 assert(exec->begin_vertices_flags); 1298 1299 ctx->Driver.NeedFlush |= exec->begin_vertices_flags; 1300} 1301 1302 1303/** 1304 * Called via ctx->Driver.FlushVertices() 1305 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 1306 */ 1307void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags ) 1308{ 1309 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1310 1311#ifdef DEBUG 1312 /* debug check: make sure we don't get called recursively */ 1313 exec->flush_call_depth++; 1314 assert(exec->flush_call_depth == 1); 1315#endif 1316 1317 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { 1318 /* We've had glBegin but not glEnd! */ 1319#ifdef DEBUG 1320 exec->flush_call_depth--; 1321 assert(exec->flush_call_depth == 0); 1322#endif 1323 return; 1324 } 1325 1326 /* Flush (draw), and make sure VBO is left unmapped when done */ 1327 vbo_exec_FlushVertices_internal(exec, GL_TRUE); 1328 1329 /* Need to do this to ensure BeginVertices gets called again: 1330 */ 1331 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags); 1332 1333#ifdef DEBUG 1334 exec->flush_call_depth--; 1335 assert(exec->flush_call_depth == 0); 1336#endif 1337} 1338 1339 1340static void reset_attrfv( struct vbo_exec_context *exec ) 1341{ 1342 GLuint i; 1343 1344 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 1345 exec->vtx.attrsz[i] = 0; 1346 exec->vtx.attrtype[i] = GL_FLOAT; 1347 exec->vtx.active_sz[i] = 0; 1348 } 1349 1350 exec->vtx.vertex_size = 0; 1351} 1352 1353 1354void GLAPIENTRY 1355_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 1356{ 1357 vbo_Color4f(r, g, b, a); 1358} 1359 1360 1361void GLAPIENTRY 1362_es_Normal3f(GLfloat x, GLfloat y, GLfloat z) 1363{ 1364 vbo_Normal3f(x, y, z); 1365} 1366 1367 1368void GLAPIENTRY 1369_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 1370{ 1371 vbo_MultiTexCoord4f(target, s, t, r, q); 1372} 1373 1374 1375void GLAPIENTRY 1376_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 1377{ 1378 vbo_Materialfv(face, pname, params); 1379} 1380 1381 1382void GLAPIENTRY 1383_es_Materialf(GLenum face, GLenum pname, GLfloat param) 1384{ 1385 GLfloat p[4]; 1386 p[0] = param; 1387 p[1] = p[2] = p[3] = 0.0F; 1388 vbo_Materialfv(face, pname, p); 1389} 1390 1391 1392/** 1393 * A special version of glVertexAttrib4f that does not treat index 0 as 1394 * VBO_ATTRIB_POS. 1395 */ 1396static void 1397VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1398{ 1399 GET_CURRENT_CONTEXT(ctx); 1400 if (index < MAX_VERTEX_GENERIC_ATTRIBS) 1401 ATTR(VBO_ATTRIB_GENERIC0 + index, 4, GL_FLOAT, x, y, z, w); 1402 else 1403 ERROR(GL_INVALID_VALUE); 1404} 1405 1406void GLAPIENTRY 1407_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1408{ 1409 VertexAttrib4f_nopos(index, x, y, z, w); 1410} 1411 1412 1413void GLAPIENTRY 1414_es_VertexAttrib1f(GLuint indx, GLfloat x) 1415{ 1416 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f); 1417} 1418 1419 1420void GLAPIENTRY 1421_es_VertexAttrib1fv(GLuint indx, const GLfloat* values) 1422{ 1423 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f); 1424} 1425 1426 1427void GLAPIENTRY 1428_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) 1429{ 1430 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f); 1431} 1432 1433 1434void GLAPIENTRY 1435_es_VertexAttrib2fv(GLuint indx, const GLfloat* values) 1436{ 1437 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f); 1438} 1439 1440 1441void GLAPIENTRY 1442_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) 1443{ 1444 VertexAttrib4f_nopos(indx, x, y, z, 1.0f); 1445} 1446 1447 1448void GLAPIENTRY 1449_es_VertexAttrib3fv(GLuint indx, const GLfloat* values) 1450{ 1451 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f); 1452} 1453 1454 1455void GLAPIENTRY 1456_es_VertexAttrib4fv(GLuint indx, const GLfloat* values) 1457{ 1458 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]); 1459} 1460