1/************************************************************************** 2 3Copyright 2002-2008 VMware, Inc. 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 21VMWARE 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 <keithw@vmware.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/dlist.h" 38#include "main/eval.h" 39#include "main/state.h" 40#include "main/light.h" 41#include "main/api_arrayelt.h" 42#include "main/draw_validate.h" 43#include "main/dispatch.h" 44#include "util/bitscan.h" 45#include "util/u_memory.h" 46#include "api_exec_decl.h" 47 48#include "vbo_private.h" 49 50/** ID/name for immediate-mode VBO */ 51#define IMM_BUFFER_NAME 0xaabbccdd 52 53 54static void 55vbo_reset_all_attr(struct vbo_exec_context *exec); 56 57 58/** 59 * Close off the last primitive, execute the buffer, restart the 60 * primitive. This is called when we fill a vertex buffer before 61 * hitting glEnd. 62 */ 63static void 64vbo_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 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 73 unsigned last = exec->vtx.prim_count - 1; 74 struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last]; 75 const bool last_begin = exec->vtx.markers[last].begin; 76 GLuint last_count = 0; 77 78 if (_mesa_inside_begin_end(ctx)) { 79 last_draw->count = exec->vtx.vert_count - last_draw->start; 80 last_count = last_draw->count; 81 exec->vtx.markers[last].end = 0; 82 } 83 84 /* Special handling for wrapping GL_LINE_LOOP */ 85 if (exec->vtx.mode[last] == GL_LINE_LOOP && 86 last_count > 0 && 87 !exec->vtx.markers[last].end) { 88 /* draw this section of the incomplete line loop as a line strip */ 89 exec->vtx.mode[last] = GL_LINE_STRIP; 90 if (!last_begin) { 91 /* This is not the first section of the line loop, so don't 92 * draw the 0th vertex. We're saving it until we draw the 93 * very last section of the loop. 94 */ 95 last_draw->start++; 96 last_draw->count--; 97 } 98 } 99 100 /* Execute the buffer and save copied vertices. 101 */ 102 if (exec->vtx.vert_count) 103 vbo_exec_vtx_flush(exec); 104 else { 105 exec->vtx.prim_count = 0; 106 exec->vtx.copied.nr = 0; 107 } 108 109 /* Emit a glBegin to start the new list. 110 */ 111 assert(exec->vtx.prim_count == 0); 112 113 if (_mesa_inside_begin_end(ctx)) { 114 exec->vtx.mode[0] = ctx->Driver.CurrentExecPrimitive; 115 exec->vtx.draw[0].start = 0; 116 exec->vtx.markers[0].begin = 0; 117 exec->vtx.prim_count++; 118 119 if (exec->vtx.copied.nr == last_count) 120 exec->vtx.markers[0].begin = last_begin; 121 } 122 } 123} 124 125 126/** 127 * Deal with buffer wrapping where provoked by the vertex buffer 128 * filling up, as opposed to upgrade_vertex(). 129 */ 130static void 131vbo_exec_vtx_wrap(struct vbo_exec_context *exec) 132{ 133 unsigned numComponents; 134 135 /* Run pipeline on current vertices, copy wrapped vertices 136 * to exec->vtx.copied. 137 */ 138 vbo_exec_wrap_buffers(exec); 139 140 if (!exec->vtx.buffer_ptr) { 141 /* probably ran out of memory earlier when allocating the VBO */ 142 return; 143 } 144 145 /* Copy stored stored vertices to start of new list. 146 */ 147 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); 148 149 numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size; 150 memcpy(exec->vtx.buffer_ptr, 151 exec->vtx.copied.buffer, 152 numComponents * sizeof(fi_type)); 153 exec->vtx.buffer_ptr += numComponents; 154 exec->vtx.vert_count += exec->vtx.copied.nr; 155 156 exec->vtx.copied.nr = 0; 157} 158 159 160/** 161 * Copy the active vertex's values to the ctx->Current fields. 162 */ 163static void 164vbo_exec_copy_to_current(struct vbo_exec_context *exec) 165{ 166 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 167 struct vbo_context *vbo = vbo_context(ctx); 168 GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); 169 bool color0_changed = false; 170 171 while (enabled) { 172 const int i = u_bit_scan64(&enabled); 173 174 /* Note: the exec->vtx.current[i] pointers point into the 175 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. 176 */ 177 GLfloat *current = (GLfloat *)vbo->current[i].Ptr; 178 fi_type tmp[8]; /* space for doubles */ 179 int dmul_shift = 0; 180 181 assert(exec->vtx.attr[i].size); 182 183 /* VBO_ATTRIB_SELECT_RESULT_INDEX has no current */ 184 if (!current) 185 continue; 186 187 if (exec->vtx.attr[i].type == GL_DOUBLE || 188 exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB) { 189 memset(tmp, 0, sizeof(tmp)); 190 memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attr[i].size * sizeof(GLfloat)); 191 dmul_shift = 1; 192 } else { 193 COPY_CLEAN_4V_TYPE_AS_UNION(tmp, 194 exec->vtx.attr[i].size, 195 exec->vtx.attrptr[i], 196 exec->vtx.attr[i].type); 197 } 198 199 if (memcmp(current, tmp, 4 * sizeof(GLfloat) << dmul_shift) != 0) { 200 memcpy(current, tmp, 4 * sizeof(GLfloat) << dmul_shift); 201 202 if (i == VBO_ATTRIB_COLOR0) 203 color0_changed = true; 204 205 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT) { 206 ctx->NewState |= _NEW_MATERIAL; 207 ctx->PopAttribState |= GL_LIGHTING_BIT; 208 209 /* The fixed-func vertex program uses this. */ 210 if (i == VBO_ATTRIB_MAT_FRONT_SHININESS || 211 i == VBO_ATTRIB_MAT_BACK_SHININESS) 212 ctx->NewState |= _NEW_FF_VERT_PROGRAM; 213 } else { 214 ctx->NewState |= _NEW_CURRENT_ATTRIB; 215 ctx->PopAttribState |= GL_CURRENT_BIT; 216 } 217 } 218 219 /* Given that we explicitly state size here, there is no need 220 * for the COPY_CLEAN above, could just copy 16 bytes and be 221 * done. The only problem is when Mesa accesses ctx->Current 222 * directly. 223 */ 224 /* Size here is in components - not bytes */ 225 if (exec->vtx.attr[i].type != vbo->current[i].Format.Type || 226 (exec->vtx.attr[i].size >> dmul_shift) != vbo->current[i].Format.Size) { 227 vbo_set_vertex_format(&vbo->current[i].Format, 228 exec->vtx.attr[i].size >> dmul_shift, 229 exec->vtx.attr[i].type); 230 } 231 } 232 233 if (color0_changed && ctx->Light.ColorMaterialEnabled) { 234 _mesa_update_color_material(ctx, 235 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 236 } 237} 238 239 240/** 241 * Flush existing data, set new attrib size, replay copied vertices. 242 * This is called when we transition from a small vertex attribute size 243 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. 244 * We need to go back over the previous 2-component texcoords and insert 245 * zero and one values. 246 * \param attr VBO_ATTRIB_x vertex attribute value 247 */ 248static void 249vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, 250 GLuint attr, GLuint newSize, GLenum newType) 251{ 252 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 253 struct vbo_context *vbo = vbo_context(ctx); 254 const GLint lastcount = exec->vtx.vert_count; 255 fi_type *old_attrptr[VBO_ATTRIB_MAX]; 256 const GLuint old_vtx_size_no_pos = exec->vtx.vertex_size_no_pos; 257 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ 258 const GLuint oldSize = exec->vtx.attr[attr].size; 259 GLuint i; 260 261 assert(attr < VBO_ATTRIB_MAX); 262 263 if (unlikely(!exec->vtx.buffer_ptr)) { 264 /* We should only hit this when use_buffer_objects=true */ 265 assert(exec->vtx.bufferobj); 266 vbo_exec_vtx_map(exec); 267 assert(exec->vtx.buffer_ptr); 268 } 269 270 /* Run pipeline on current vertices, copy wrapped vertices 271 * to exec->vtx.copied. 272 */ 273 vbo_exec_wrap_buffers(exec); 274 275 if (unlikely(exec->vtx.copied.nr)) { 276 /* We're in the middle of a primitive, keep the old vertex 277 * format around to be able to translate the copied vertices to 278 * the new format. 279 */ 280 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); 281 } 282 283 /* Heuristic: Attempt to isolate attributes received outside 284 * begin/end so that they don't bloat the vertices. 285 */ 286 if (!_mesa_inside_begin_end(ctx) && 287 !oldSize && lastcount > 8 && exec->vtx.vertex_size) { 288 vbo_exec_copy_to_current(exec); 289 vbo_reset_all_attr(exec); 290 } 291 292 /* Fix up sizes: 293 */ 294 exec->vtx.attr[attr].size = newSize; 295 exec->vtx.attr[attr].active_size = newSize; 296 exec->vtx.attr[attr].type = newType; 297 exec->vtx.vertex_size += newSize - oldSize; 298 exec->vtx.vertex_size_no_pos = exec->vtx.vertex_size - exec->vtx.attr[0].size; 299 exec->vtx.max_vert = vbo_compute_max_verts(exec); 300 exec->vtx.vert_count = 0; 301 exec->vtx.buffer_ptr = exec->vtx.buffer_map; 302 exec->vtx.enabled |= BITFIELD64_BIT(attr); 303 304 if (attr != 0) { 305 if (unlikely(oldSize)) { 306 unsigned offset = exec->vtx.attrptr[attr] - exec->vtx.vertex; 307 308 /* If there are attribs after the resized attrib... */ 309 if (offset + oldSize < old_vtx_size_no_pos) { 310 int size_diff = newSize - oldSize; 311 fi_type *old_first = exec->vtx.attrptr[attr] + oldSize; 312 fi_type *new_first = exec->vtx.attrptr[attr] + newSize; 313 fi_type *old_last = exec->vtx.vertex + old_vtx_size_no_pos - 1; 314 fi_type *new_last = exec->vtx.vertex + exec->vtx.vertex_size_no_pos - 1; 315 316 if (size_diff < 0) { 317 /* Decreasing the size: Copy from first to last to move 318 * elements to the left. 319 */ 320 fi_type *old_end = old_last + 1; 321 fi_type *old = old_first; 322 fi_type *new = new_first; 323 324 do { 325 *new++ = *old++; 326 } while (old != old_end); 327 } else { 328 /* Increasing the size: Copy from last to first to move 329 * elements to the right. 330 */ 331 fi_type *old_end = old_first - 1; 332 fi_type *old = old_last; 333 fi_type *new = new_last; 334 335 do { 336 *new-- = *old--; 337 } while (old != old_end); 338 } 339 340 /* Update pointers to attribs, because we moved them. */ 341 GLbitfield64 enabled = exec->vtx.enabled & 342 ~BITFIELD64_BIT(VBO_ATTRIB_POS) & 343 ~BITFIELD64_BIT(attr); 344 while (enabled) { 345 unsigned i = u_bit_scan64(&enabled); 346 347 if (exec->vtx.attrptr[i] > exec->vtx.attrptr[attr]) 348 exec->vtx.attrptr[i] += size_diff; 349 } 350 } 351 } else { 352 /* Just have to append the new attribute at the end */ 353 exec->vtx.attrptr[attr] = exec->vtx.vertex + 354 exec->vtx.vertex_size_no_pos - newSize; 355 } 356 } 357 358 /* The position is always last. */ 359 exec->vtx.attrptr[0] = exec->vtx.vertex + exec->vtx.vertex_size_no_pos; 360 361 /* Replay stored vertices to translate them 362 * to new format here. 363 * 364 * -- No need to replay - just copy piecewise 365 */ 366 if (unlikely(exec->vtx.copied.nr)) { 367 fi_type *data = exec->vtx.copied.buffer; 368 fi_type *dest = exec->vtx.buffer_ptr; 369 370 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); 371 372 for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 373 GLbitfield64 enabled = exec->vtx.enabled; 374 while (enabled) { 375 const int j = u_bit_scan64(&enabled); 376 GLuint sz = exec->vtx.attr[j].size; 377 GLint old_offset = old_attrptr[j] - exec->vtx.vertex; 378 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; 379 380 assert(sz); 381 382 if (j == attr) { 383 if (oldSize) { 384 fi_type tmp[4]; 385 COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize, 386 data + old_offset, 387 exec->vtx.attr[j].type); 388 COPY_SZ_4V(dest + new_offset, newSize, tmp); 389 } else { 390 fi_type *current = (fi_type *)vbo->current[j].Ptr; 391 COPY_SZ_4V(dest + new_offset, sz, current); 392 } 393 } 394 else { 395 COPY_SZ_4V(dest + new_offset, sz, data + old_offset); 396 } 397 } 398 399 data += old_vtx_size; 400 dest += exec->vtx.vertex_size; 401 } 402 403 exec->vtx.buffer_ptr = dest; 404 exec->vtx.vert_count += exec->vtx.copied.nr; 405 exec->vtx.copied.nr = 0; 406 } 407} 408 409 410/** 411 * This is when a vertex attribute transitions to a different size. 412 * For example, we saw a bunch of glTexCoord2f() calls and now we got a 413 * glTexCoord4f() call. We promote the array from size=2 to size=4. 414 * \param newSize size of new vertex (number of 32-bit words). 415 * \param attr VBO_ATTRIB_x vertex attribute value 416 */ 417static void 418vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, 419 GLuint newSize, GLenum newType) 420{ 421 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 422 423 assert(attr < VBO_ATTRIB_MAX); 424 425 if (newSize > exec->vtx.attr[attr].size || 426 newType != exec->vtx.attr[attr].type) { 427 /* New size is larger. Need to flush existing vertices and get 428 * an enlarged vertex format. 429 */ 430 vbo_exec_wrap_upgrade_vertex(exec, attr, newSize, newType); 431 } 432 else if (newSize < exec->vtx.attr[attr].active_size) { 433 GLuint i; 434 const fi_type *id = 435 vbo_get_default_vals_as_union(exec->vtx.attr[attr].type); 436 437 /* New size is smaller - just need to fill in some 438 * zeros. Don't need to flush or wrap. 439 */ 440 for (i = newSize; i <= exec->vtx.attr[attr].size; i++) 441 exec->vtx.attrptr[attr][i-1] = id[i-1]; 442 443 exec->vtx.attr[attr].active_size = newSize; 444 } 445} 446 447 448/** 449 * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex? 450 * It depends on a few things, including whether we're inside or outside 451 * of glBegin/glEnd. 452 */ 453static inline bool 454is_vertex_position(const struct gl_context *ctx, GLuint index) 455{ 456 return (index == 0 && 457 _mesa_attr_zero_aliases_vertex(ctx) && 458 _mesa_inside_begin_end(ctx)); 459} 460 461/* Write a 64-bit value into a 32-bit pointer by preserving endianness. */ 462#if UTIL_ARCH_LITTLE_ENDIAN 463 #define SET_64BIT(dst32, u64) do { \ 464 *(dst32)++ = (u64); \ 465 *(dst32)++ = (uint64_t)(u64) >> 32; \ 466 } while (0) 467#else 468 #define SET_64BIT(dst32, u64) do { \ 469 *(dst32)++ = (uint64_t)(u64) >> 32; \ 470 *(dst32)++ = (u64); \ 471 } while (0) 472#endif 473 474 475/** 476 * This macro is used to implement all the glVertex, glColor, glTexCoord, 477 * glVertexAttrib, etc functions. 478 * \param A VBO_ATTRIB_x attribute index 479 * \param N attribute size (1..4) 480 * \param T type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT) 481 * \param C cast type (uint32_t or uint64_t) 482 * \param V0, V1, v2, V3 attribute value 483 */ 484#define ATTR_UNION_BASE(A, N, T, C, V0, V1, V2, V3) \ 485do { \ 486 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 487 int sz = (sizeof(C) / sizeof(GLfloat)); \ 488 \ 489 assert(sz == 1 || sz == 2); \ 490 /* store a copy of the attribute in exec except for glVertex */ \ 491 if ((A) != 0) { \ 492 /* Check if attribute size or type is changing. */ \ 493 if (unlikely(exec->vtx.attr[A].active_size != N * sz || \ 494 exec->vtx.attr[A].type != T)) { \ 495 vbo_exec_fixup_vertex(ctx, A, N * sz, T); \ 496 } \ 497 \ 498 C *dest = (C *)exec->vtx.attrptr[A]; \ 499 if (N>0) dest[0] = V0; \ 500 if (N>1) dest[1] = V1; \ 501 if (N>2) dest[2] = V2; \ 502 if (N>3) dest[3] = V3; \ 503 assert(exec->vtx.attr[A].type == T); \ 504 \ 505 /* we now have accumulated a per-vertex attribute */ \ 506 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ 507 } else { \ 508 /* This is a glVertex call */ \ 509 int size = exec->vtx.attr[0].size; \ 510 \ 511 /* Check if attribute size or type is changing. */ \ 512 if (unlikely(size < N * sz || \ 513 exec->vtx.attr[0].type != T)) { \ 514 vbo_exec_wrap_upgrade_vertex(exec, 0, N * sz, T); \ 515 } \ 516 \ 517 uint32_t *dst = (uint32_t *)exec->vtx.buffer_ptr; \ 518 uint32_t *src = (uint32_t *)exec->vtx.vertex; \ 519 unsigned vertex_size_no_pos = exec->vtx.vertex_size_no_pos; \ 520 \ 521 /* Copy over attributes from exec. */ \ 522 for (unsigned i = 0; i < vertex_size_no_pos; i++) \ 523 *dst++ = *src++; \ 524 \ 525 /* Store the position, which is always last and can have 32 or */ \ 526 /* 64 bits per channel. */ \ 527 if (sizeof(C) == 4) { \ 528 if (N > 0) *dst++ = V0; \ 529 if (N > 1) *dst++ = V1; \ 530 if (N > 2) *dst++ = V2; \ 531 if (N > 3) *dst++ = V3; \ 532 \ 533 if (unlikely(N < size)) { \ 534 if (N < 2 && size >= 2) *dst++ = V1; \ 535 if (N < 3 && size >= 3) *dst++ = V2; \ 536 if (N < 4 && size >= 4) *dst++ = V3; \ 537 } \ 538 } else { \ 539 /* 64 bits: dst can be unaligned, so copy each 4-byte word */ \ 540 /* separately */ \ 541 if (N > 0) SET_64BIT(dst, V0); \ 542 if (N > 1) SET_64BIT(dst, V1); \ 543 if (N > 2) SET_64BIT(dst, V2); \ 544 if (N > 3) SET_64BIT(dst, V3); \ 545 \ 546 if (unlikely(N * 2 < size)) { \ 547 if (N < 2 && size >= 4) SET_64BIT(dst, V1); \ 548 if (N < 3 && size >= 6) SET_64BIT(dst, V2); \ 549 if (N < 4 && size >= 8) SET_64BIT(dst, V3); \ 550 } \ 551 } \ 552 \ 553 /* dst now points at the beginning of the next vertex */ \ 554 exec->vtx.buffer_ptr = (fi_type*)dst; \ 555 \ 556 /* Don't set FLUSH_UPDATE_CURRENT because */ \ 557 /* Current.Attrib[VBO_ATTRIB_POS] is never used. */ \ 558 \ 559 if (unlikely(++exec->vtx.vert_count >= exec->vtx.max_vert)) \ 560 vbo_exec_vtx_wrap(exec); \ 561 } \ 562} while (0) 563 564#undef ERROR 565#define ERROR(err) _mesa_error(ctx, err, __func__) 566#define TAG(x) _mesa_##x 567#define SUPPRESS_STATIC 568 569#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ 570 ATTR_UNION_BASE(A, N, T, C, V0, V1, V2, V3) 571 572#include "vbo_attrib_tmp.h" 573 574 575/** 576 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled, 577 * this may be a (partial) no-op. 578 */ 579void GLAPIENTRY 580_mesa_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 581{ 582 GLbitfield updateMats; 583 GET_CURRENT_CONTEXT(ctx); 584 585 /* This function should be a no-op when it tries to update material 586 * attributes which are currently tracking glColor via glColorMaterial. 587 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits 588 * indicating which material attributes can actually be updated below. 589 */ 590 if (ctx->Light.ColorMaterialEnabled) { 591 updateMats = ~ctx->Light._ColorMaterialBitmask; 592 } 593 else { 594 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */ 595 updateMats = ALL_MATERIAL_BITS; 596 } 597 598 if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) { 599 updateMats &= FRONT_MATERIAL_BITS; 600 } 601 else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) { 602 updateMats &= BACK_MATERIAL_BITS; 603 } 604 else if (face != GL_FRONT_AND_BACK) { 605 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)"); 606 return; 607 } 608 609 switch (pname) { 610 case GL_EMISSION: 611 if (updateMats & MAT_BIT_FRONT_EMISSION) 612 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params); 613 if (updateMats & MAT_BIT_BACK_EMISSION) 614 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params); 615 break; 616 case GL_AMBIENT: 617 if (updateMats & MAT_BIT_FRONT_AMBIENT) 618 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 619 if (updateMats & MAT_BIT_BACK_AMBIENT) 620 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 621 break; 622 case GL_DIFFUSE: 623 if (updateMats & MAT_BIT_FRONT_DIFFUSE) 624 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 625 if (updateMats & MAT_BIT_BACK_DIFFUSE) 626 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 627 break; 628 case GL_SPECULAR: 629 if (updateMats & MAT_BIT_FRONT_SPECULAR) 630 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params); 631 if (updateMats & MAT_BIT_BACK_SPECULAR) 632 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params); 633 break; 634 case GL_SHININESS: 635 if (*params < 0 || *params > ctx->Const.MaxShininess) { 636 _mesa_error(ctx, GL_INVALID_VALUE, 637 "glMaterial(invalid shininess: %f out range [0, %f])", 638 *params, ctx->Const.MaxShininess); 639 return; 640 } 641 if (updateMats & MAT_BIT_FRONT_SHININESS) 642 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params); 643 if (updateMats & MAT_BIT_BACK_SHININESS) 644 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params); 645 break; 646 case GL_COLOR_INDEXES: 647 if (ctx->API != API_OPENGL_COMPAT) { 648 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 649 return; 650 } 651 if (updateMats & MAT_BIT_FRONT_INDEXES) 652 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params); 653 if (updateMats & MAT_BIT_BACK_INDEXES) 654 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params); 655 break; 656 case GL_AMBIENT_AND_DIFFUSE: 657 if (updateMats & MAT_BIT_FRONT_AMBIENT) 658 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 659 if (updateMats & MAT_BIT_FRONT_DIFFUSE) 660 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 661 if (updateMats & MAT_BIT_BACK_AMBIENT) 662 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 663 if (updateMats & MAT_BIT_BACK_DIFFUSE) 664 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 665 break; 666 default: 667 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 668 return; 669 } 670} 671 672 673/** 674 * Flush (draw) vertices. 675 * 676 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 677 */ 678static void 679vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, unsigned flags) 680{ 681 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 682 683 if (flags & FLUSH_STORED_VERTICES) { 684 if (exec->vtx.vert_count) { 685 vbo_exec_vtx_flush(exec); 686 } 687 688 if (exec->vtx.vertex_size) { 689 vbo_exec_copy_to_current(exec); 690 vbo_reset_all_attr(exec); 691 } 692 693 /* All done. */ 694 ctx->Driver.NeedFlush = 0; 695 } else { 696 assert(flags == FLUSH_UPDATE_CURRENT); 697 698 /* Note that the vertex size is unchanged. 699 * (vbo_reset_all_attr isn't called) 700 */ 701 vbo_exec_copy_to_current(exec); 702 703 /* Only FLUSH_UPDATE_CURRENT is done. */ 704 ctx->Driver.NeedFlush = ~FLUSH_UPDATE_CURRENT; 705 } 706} 707 708 709void GLAPIENTRY 710_mesa_EvalCoord1f(GLfloat u) 711{ 712 GET_CURRENT_CONTEXT(ctx); 713 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 714 715 { 716 GLint i; 717 if (exec->eval.recalculate_maps) 718 vbo_exec_eval_update(exec); 719 720 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 721 if (exec->eval.map1[i].map) 722 if (exec->vtx.attr[i].active_size != exec->eval.map1[i].sz) 723 vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT); 724 } 725 } 726 727 memcpy(exec->vtx.copied.buffer, exec->vtx.vertex, 728 exec->vtx.vertex_size * sizeof(GLfloat)); 729 730 vbo_exec_do_EvalCoord1f(exec, u); 731 732 memcpy(exec->vtx.vertex, exec->vtx.copied.buffer, 733 exec->vtx.vertex_size * sizeof(GLfloat)); 734} 735 736 737void GLAPIENTRY 738_mesa_EvalCoord2f(GLfloat u, GLfloat v) 739{ 740 GET_CURRENT_CONTEXT(ctx); 741 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 742 743 { 744 GLint i; 745 if (exec->eval.recalculate_maps) 746 vbo_exec_eval_update(exec); 747 748 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 749 if (exec->eval.map2[i].map) 750 if (exec->vtx.attr[i].active_size != exec->eval.map2[i].sz) 751 vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT); 752 } 753 754 if (ctx->Eval.AutoNormal) 755 if (exec->vtx.attr[VBO_ATTRIB_NORMAL].active_size != 3) 756 vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT); 757 } 758 759 memcpy(exec->vtx.copied.buffer, exec->vtx.vertex, 760 exec->vtx.vertex_size * sizeof(GLfloat)); 761 762 vbo_exec_do_EvalCoord2f(exec, u, v); 763 764 memcpy(exec->vtx.vertex, exec->vtx.copied.buffer, 765 exec->vtx.vertex_size * sizeof(GLfloat)); 766} 767 768 769void GLAPIENTRY 770_mesa_EvalCoord1fv(const GLfloat *u) 771{ 772 _mesa_EvalCoord1f(u[0]); 773} 774 775 776void GLAPIENTRY 777_mesa_EvalCoord2fv(const GLfloat *u) 778{ 779 _mesa_EvalCoord2f(u[0], u[1]); 780} 781 782 783void GLAPIENTRY 784_mesa_EvalPoint1(GLint i) 785{ 786 GET_CURRENT_CONTEXT(ctx); 787 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / 788 (GLfloat) ctx->Eval.MapGrid1un); 789 GLfloat u = i * du + ctx->Eval.MapGrid1u1; 790 791 _mesa_EvalCoord1f(u); 792} 793 794 795void GLAPIENTRY 796_mesa_EvalPoint2(GLint i, GLint j) 797{ 798 GET_CURRENT_CONTEXT(ctx); 799 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 800 (GLfloat) ctx->Eval.MapGrid2un); 801 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 802 (GLfloat) ctx->Eval.MapGrid2vn); 803 GLfloat u = i * du + ctx->Eval.MapGrid2u1; 804 GLfloat v = j * dv + ctx->Eval.MapGrid2v1; 805 806 _mesa_EvalCoord2f(u, v); 807} 808 809 810/** 811 * Called via glBegin. 812 */ 813void GLAPIENTRY 814_mesa_Begin(GLenum mode) 815{ 816 GET_CURRENT_CONTEXT(ctx); 817 struct vbo_context *vbo = vbo_context(ctx); 818 struct vbo_exec_context *exec = &vbo->exec; 819 int i; 820 821 if (_mesa_inside_begin_end(ctx)) { 822 _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin"); 823 return; 824 } 825 826 if (ctx->NewState) 827 _mesa_update_state(ctx); 828 829 GLenum error = _mesa_valid_prim_mode(ctx, mode); 830 if (error != GL_NO_ERROR) { 831 _mesa_error(ctx, error, "glBegin"); 832 return; 833 } 834 835 /* Heuristic: attempt to isolate attributes occurring outside 836 * begin/end pairs. 837 * 838 * Use FLUSH_STORED_VERTICES, because it updates current attribs and 839 * sets vertex_size to 0. (FLUSH_UPDATE_CURRENT doesn't change vertex_size) 840 */ 841 if (exec->vtx.vertex_size && !exec->vtx.attr[VBO_ATTRIB_POS].size) 842 vbo_exec_FlushVertices_internal(exec, FLUSH_STORED_VERTICES); 843 844 i = exec->vtx.prim_count++; 845 exec->vtx.mode[i] = mode; 846 exec->vtx.draw[i].start = exec->vtx.vert_count; 847 exec->vtx.markers[i].begin = 1; 848 849 ctx->Driver.CurrentExecPrimitive = mode; 850 851 ctx->Exec = _mesa_hw_select_enabled(ctx) ? 852 ctx->HWSelectModeBeginEnd : ctx->BeginEnd; 853 854 /* We may have been called from a display list, in which case we should 855 * leave dlist.c's dispatch table in place. 856 */ 857 if (ctx->GLThread.enabled) { 858 if (ctx->CurrentServerDispatch == ctx->OutsideBeginEnd) 859 ctx->CurrentServerDispatch = ctx->Exec; 860 } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) { 861 ctx->CurrentClientDispatch = ctx->CurrentServerDispatch = ctx->Exec; 862 _glapi_set_dispatch(ctx->CurrentClientDispatch); 863 } else { 864 assert(ctx->CurrentClientDispatch == ctx->Save); 865 } 866} 867 868 869/** 870 * Try to merge / concatenate the two most recent VBO primitives. 871 */ 872static void 873try_vbo_merge(struct vbo_exec_context *exec) 874{ 875 unsigned cur = exec->vtx.prim_count - 1; 876 877 assert(exec->vtx.prim_count >= 1); 878 879 vbo_try_prim_conversion(&exec->vtx.mode[cur], &exec->vtx.draw[cur].count); 880 881 if (exec->vtx.prim_count >= 2) { 882 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 883 unsigned prev = cur - 1; 884 885 if (vbo_merge_draws(ctx, false, 886 exec->vtx.mode[prev], 887 exec->vtx.mode[cur], 888 exec->vtx.draw[prev].start, 889 exec->vtx.draw[cur].start, 890 &exec->vtx.draw[prev].count, 891 exec->vtx.draw[cur].count, 892 0, 0, 893 &exec->vtx.markers[prev].end, 894 exec->vtx.markers[cur].begin, 895 exec->vtx.markers[cur].end)) 896 exec->vtx.prim_count--; /* drop the last primitive */ 897 } 898} 899 900 901/** 902 * Called via glEnd. 903 */ 904void GLAPIENTRY 905_mesa_End(void) 906{ 907 GET_CURRENT_CONTEXT(ctx); 908 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 909 910 if (!_mesa_inside_begin_end(ctx)) { 911 _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd"); 912 return; 913 } 914 915 ctx->Exec = ctx->OutsideBeginEnd; 916 917 if (ctx->GLThread.enabled) { 918 if (ctx->CurrentServerDispatch == ctx->BeginEnd || 919 ctx->CurrentServerDispatch == ctx->HWSelectModeBeginEnd) { 920 ctx->CurrentServerDispatch = ctx->Exec; 921 } 922 } else if (ctx->CurrentClientDispatch == ctx->BeginEnd || 923 ctx->CurrentClientDispatch == ctx->HWSelectModeBeginEnd) { 924 ctx->CurrentClientDispatch = ctx->CurrentServerDispatch = ctx->Exec; 925 _glapi_set_dispatch(ctx->CurrentClientDispatch); 926 } 927 928 if (exec->vtx.prim_count > 0) { 929 /* close off current primitive */ 930 unsigned last = exec->vtx.prim_count - 1; 931 struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last]; 932 unsigned count = exec->vtx.vert_count - last_draw->start; 933 934 last_draw->count = count; 935 exec->vtx.markers[last].end = 1; 936 937 if (count) { 938 /* mark result buffer used */ 939 if (_mesa_hw_select_enabled(ctx)) 940 ctx->Select.ResultUsed = GL_TRUE; 941 942 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; 943 } 944 945 /* Special handling for GL_LINE_LOOP */ 946 if (exec->vtx.mode[last] == GL_LINE_LOOP && 947 exec->vtx.markers[last].begin == 0) { 948 /* We're finishing drawing a line loop. Append 0th vertex onto 949 * end of vertex buffer so we can draw it as a line strip. 950 */ 951 const fi_type *src = exec->vtx.buffer_map + 952 last_draw->start * exec->vtx.vertex_size; 953 fi_type *dst = exec->vtx.buffer_map + 954 exec->vtx.vert_count * exec->vtx.vertex_size; 955 956 /* copy 0th vertex to end of buffer */ 957 memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type)); 958 959 last_draw->start++; /* skip vertex0 */ 960 /* note that the count stays unchanged */ 961 exec->vtx.mode[last] = GL_LINE_STRIP; 962 963 /* Increment the vertex count so the next primitive doesn't 964 * overwrite the last vertex which we just added. 965 */ 966 exec->vtx.vert_count++; 967 exec->vtx.buffer_ptr += exec->vtx.vertex_size; 968 } 969 970 try_vbo_merge(exec); 971 } 972 973 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 974 975 if (exec->vtx.prim_count == VBO_MAX_PRIM) 976 vbo_exec_vtx_flush(exec); 977 978 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 979 _mesa_flush(ctx); 980 } 981} 982 983 984/** 985 * Called via glPrimitiveRestartNV() 986 */ 987void GLAPIENTRY 988_mesa_PrimitiveRestartNV(void) 989{ 990 GLenum curPrim; 991 GET_CURRENT_CONTEXT(ctx); 992 993 curPrim = ctx->Driver.CurrentExecPrimitive; 994 995 if (curPrim == PRIM_OUTSIDE_BEGIN_END) { 996 _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV"); 997 } 998 else { 999 _mesa_End(); 1000 _mesa_Begin(curPrim); 1001 } 1002} 1003 1004 1005/** 1006 * A special version of glVertexAttrib4f that does not treat index 0 as 1007 * VBO_ATTRIB_POS. 1008 */ 1009static void 1010VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1011{ 1012 GET_CURRENT_CONTEXT(ctx); 1013 if (index < ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) 1014 ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w); 1015 else 1016 ERROR(GL_INVALID_VALUE); 1017} 1018 1019static void GLAPIENTRY 1020_es_VertexAttrib4fARB(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 1021{ 1022 VertexAttrib4f_nopos(index, x, y, z, w); 1023} 1024 1025 1026static void GLAPIENTRY 1027_es_VertexAttrib1fARB(GLuint indx, GLfloat x) 1028{ 1029 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f); 1030} 1031 1032 1033static void GLAPIENTRY 1034_es_VertexAttrib1fvARB(GLuint indx, const GLfloat* values) 1035{ 1036 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f); 1037} 1038 1039 1040static void GLAPIENTRY 1041_es_VertexAttrib2fARB(GLuint indx, GLfloat x, GLfloat y) 1042{ 1043 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f); 1044} 1045 1046 1047static void GLAPIENTRY 1048_es_VertexAttrib2fvARB(GLuint indx, const GLfloat* values) 1049{ 1050 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f); 1051} 1052 1053 1054static void GLAPIENTRY 1055_es_VertexAttrib3fARB(GLuint indx, GLfloat x, GLfloat y, GLfloat z) 1056{ 1057 VertexAttrib4f_nopos(indx, x, y, z, 1.0f); 1058} 1059 1060 1061static void GLAPIENTRY 1062_es_VertexAttrib3fvARB(GLuint indx, const GLfloat* values) 1063{ 1064 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f); 1065} 1066 1067 1068static void GLAPIENTRY 1069_es_VertexAttrib4fvARB(GLuint indx, const GLfloat* values) 1070{ 1071 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]); 1072} 1073 1074 1075void 1076vbo_install_exec_vtxfmt(struct gl_context *ctx) 1077{ 1078#define NAME_AE(x) _mesa_##x 1079#define NAME_CALLLIST(x) _mesa_##x 1080#define NAME(x) _mesa_##x 1081#define NAME_ES(x) _es_##x 1082 1083 struct _glapi_table *tab = ctx->Exec; 1084 #include "api_vtxfmt_init.h" 1085 1086 if (ctx->BeginEnd) { 1087 tab = ctx->BeginEnd; 1088 #include "api_vtxfmt_init.h" 1089 } 1090} 1091 1092 1093static void 1094vbo_reset_all_attr(struct vbo_exec_context *exec) 1095{ 1096 while (exec->vtx.enabled) { 1097 const int i = u_bit_scan64(&exec->vtx.enabled); 1098 1099 /* Reset the vertex attribute by setting its size to zero. */ 1100 exec->vtx.attr[i].size = 0; 1101 exec->vtx.attr[i].type = GL_FLOAT; 1102 exec->vtx.attr[i].active_size = 0; 1103 exec->vtx.attrptr[i] = NULL; 1104 } 1105 1106 exec->vtx.vertex_size = 0; 1107} 1108 1109 1110void 1111vbo_exec_vtx_init(struct vbo_exec_context *exec) 1112{ 1113 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 1114 1115 exec->vtx.bufferobj = _mesa_bufferobj_alloc(ctx, IMM_BUFFER_NAME); 1116 1117 exec->vtx.enabled = u_bit_consecutive64(0, VBO_ATTRIB_MAX); /* reset all */ 1118 vbo_reset_all_attr(exec); 1119 1120 exec->vtx.info.instance_count = 1; 1121 exec->vtx.info.max_index = ~0; 1122} 1123 1124 1125void 1126vbo_exec_vtx_destroy(struct vbo_exec_context *exec) 1127{ 1128 /* using a real VBO for vertex data */ 1129 struct gl_context *ctx = gl_context_from_vbo_exec(exec); 1130 1131 /* True VBOs should already be unmapped 1132 */ 1133 if (exec->vtx.buffer_map) { 1134 assert(!exec->vtx.bufferobj || 1135 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); 1136 if (!exec->vtx.bufferobj) { 1137 align_free(exec->vtx.buffer_map); 1138 exec->vtx.buffer_map = NULL; 1139 exec->vtx.buffer_ptr = NULL; 1140 } 1141 } 1142 1143 /* Free the vertex buffer. Unmap first if needed. 1144 */ 1145 if (exec->vtx.bufferobj && 1146 _mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) { 1147 _mesa_bufferobj_unmap(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 1148 } 1149 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 1150} 1151 1152 1153/** 1154 * If inside glBegin()/glEnd(), it should assert(0). Otherwise, if 1155 * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered 1156 * vertices, if FLUSH_UPDATE_CURRENT bit is set updates 1157 * __struct gl_contextRec::Current and gl_light_attrib::Material 1158 * 1159 * Note that the default T&L engine never clears the 1160 * FLUSH_UPDATE_CURRENT bit, even after performing the update. 1161 * 1162 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 1163 */ 1164void 1165vbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags) 1166{ 1167 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1168 1169#ifndef NDEBUG 1170 /* debug check: make sure we don't get called recursively */ 1171 exec->flush_call_depth++; 1172 assert(exec->flush_call_depth == 1); 1173#endif 1174 1175 if (_mesa_inside_begin_end(ctx)) { 1176 /* We've had glBegin but not glEnd! */ 1177#ifndef NDEBUG 1178 exec->flush_call_depth--; 1179 assert(exec->flush_call_depth == 0); 1180#endif 1181 return; 1182 } 1183 1184 /* Flush (draw). */ 1185 vbo_exec_FlushVertices_internal(exec, flags); 1186 1187#ifndef NDEBUG 1188 exec->flush_call_depth--; 1189 assert(exec->flush_call_depth == 0); 1190#endif 1191} 1192 1193 1194void GLAPIENTRY 1195_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 1196{ 1197 _mesa_Color4f(r, g, b, a); 1198} 1199 1200 1201void GLAPIENTRY 1202_es_Normal3f(GLfloat x, GLfloat y, GLfloat z) 1203{ 1204 _mesa_Normal3f(x, y, z); 1205} 1206 1207 1208void GLAPIENTRY 1209_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 1210{ 1211 _mesa_MultiTexCoord4fARB(target, s, t, r, q); 1212} 1213 1214 1215void GLAPIENTRY 1216_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 1217{ 1218 _mesa_Materialfv(face, pname, params); 1219} 1220 1221 1222void GLAPIENTRY 1223_es_Materialf(GLenum face, GLenum pname, GLfloat param) 1224{ 1225 GLfloat p[4]; 1226 p[0] = param; 1227 p[1] = p[2] = p[3] = 0.0F; 1228 _mesa_Materialfv(face, pname, p); 1229} 1230 1231#undef TAG 1232#undef SUPPRESS_STATIC 1233#define TAG(x) _hw_select_##x 1234/* filter out none vertex api */ 1235#define HW_SELECT_MODE 1236 1237#undef ATTR_UNION 1238#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ 1239 do { \ 1240 if ((A) == 0) { \ 1241 ATTR_UNION_BASE(VBO_ATTRIB_SELECT_RESULT_OFFSET, 1, GL_UNSIGNED_INT, uint32_t, \ 1242 ctx->Select.ResultOffset, 0, 0, 0); \ 1243 } \ 1244 ATTR_UNION_BASE(A, N, T, C, V0, V1, V2, V3); \ 1245 } while (0) 1246 1247#include "vbo_attrib_tmp.h" 1248 1249void 1250vbo_install_hw_select_begin_end(struct gl_context *ctx) 1251{ 1252 int numEntries = MAX2(_gloffset_COUNT, _glapi_get_dispatch_table_size()); 1253 memcpy(ctx->HWSelectModeBeginEnd, ctx->BeginEnd, numEntries * sizeof(_glapi_proc)); 1254 1255#undef NAME 1256#define NAME(x) _hw_select_##x 1257 struct _glapi_table *tab = ctx->HWSelectModeBeginEnd; 1258 #include "api_hw_select_init.h" 1259} 1260