17117f1b4Smrg/************************************************************************** 27117f1b4Smrg 3af69d88dSmrgCopyright 2002-2008 VMware, Inc. 47117f1b4Smrg 57117f1b4SmrgAll Rights Reserved. 67117f1b4Smrg 77117f1b4SmrgPermission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrgcopy of this software and associated documentation files (the "Software"), 97117f1b4Smrgto deal in the Software without restriction, including without limitation 107117f1b4Smrgon the rights to use, copy, modify, merge, publish, distribute, sub 117117f1b4Smrglicense, and/or sell copies of the Software, and to permit persons to whom 127117f1b4Smrgthe Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg 147117f1b4SmrgThe above copyright notice and this permission notice (including the next 157117f1b4Smrgparagraph) shall be included in all copies or substantial portions of the 167117f1b4SmrgSoftware. 177117f1b4Smrg 187117f1b4SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 197117f1b4SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207117f1b4SmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21af69d88dSmrgVMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 227117f1b4SmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 237117f1b4SmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 247117f1b4SmrgUSE OR OTHER DEALINGS IN THE SOFTWARE. 257117f1b4Smrg 267117f1b4Smrg**************************************************************************/ 277117f1b4Smrg 287117f1b4Smrg/* 297117f1b4Smrg * Authors: 30af69d88dSmrg * Keith Whitwell <keithw@vmware.com> 317117f1b4Smrg */ 327117f1b4Smrg 33c1f859d4Smrg#include "main/glheader.h" 34c1f859d4Smrg#include "main/bufferobj.h" 35c1f859d4Smrg#include "main/context.h" 36c1f859d4Smrg#include "main/macros.h" 37c1f859d4Smrg#include "main/vtxfmt.h" 38c1f859d4Smrg#include "main/dlist.h" 394a49301eSmrg#include "main/eval.h" 40c1f859d4Smrg#include "main/state.h" 41c1f859d4Smrg#include "main/light.h" 42c1f859d4Smrg#include "main/api_arrayelt.h" 4301e04c3fSmrg#include "main/draw_validate.h" 44cdc920a0Smrg#include "main/dispatch.h" 4501e04c3fSmrg#include "util/bitscan.h" 467ec681f3Smrg#include "util/u_memory.h" 477117f1b4Smrg 48af69d88dSmrg#include "vbo_noop.h" 4901e04c3fSmrg#include "vbo_private.h" 507117f1b4Smrg 517117f1b4Smrg 524a49301eSmrg/** ID/name for immediate-mode VBO */ 534a49301eSmrg#define IMM_BUFFER_NAME 0xaabbccdd 544a49301eSmrg 554a49301eSmrg 567ec681f3Smrgstatic void GLAPIENTRY 577ec681f3Smrgvbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params); 587ec681f3Smrg 597ec681f3Smrgstatic void GLAPIENTRY 607ec681f3Smrgvbo_exec_EvalCoord1f(GLfloat u); 617ec681f3Smrg 627ec681f3Smrgstatic void GLAPIENTRY 637ec681f3Smrgvbo_exec_EvalCoord2f(GLfloat u, GLfloat v); 647ec681f3Smrg 657ec681f3Smrg 6601e04c3fSmrgstatic void 6701e04c3fSmrgvbo_reset_all_attr(struct vbo_exec_context *exec); 687117f1b4Smrg 697117f1b4Smrg 704a49301eSmrg/** 714a49301eSmrg * Close off the last primitive, execute the buffer, restart the 7201e04c3fSmrg * primitive. This is called when we fill a vertex buffer before 7301e04c3fSmrg * hitting glEnd. 747117f1b4Smrg */ 7501e04c3fSmrgstatic void 7601e04c3fSmrgvbo_exec_wrap_buffers(struct vbo_exec_context *exec) 777117f1b4Smrg{ 787117f1b4Smrg if (exec->vtx.prim_count == 0) { 797117f1b4Smrg exec->vtx.copied.nr = 0; 807117f1b4Smrg exec->vtx.vert_count = 0; 814a49301eSmrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 827117f1b4Smrg } 837117f1b4Smrg else { 847ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 857ec681f3Smrg unsigned last = exec->vtx.prim_count - 1; 867ec681f3Smrg struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last]; 877ec681f3Smrg const bool last_begin = exec->vtx.markers[last].begin; 887ec681f3Smrg GLuint last_count = 0; 897ec681f3Smrg 907ec681f3Smrg if (_mesa_inside_begin_end(ctx)) { 917ec681f3Smrg last_draw->count = exec->vtx.vert_count - last_draw->start; 927ec681f3Smrg last_count = last_draw->count; 937ec681f3Smrg exec->vtx.markers[last].end = 0; 947117f1b4Smrg } 957117f1b4Smrg 9601e04c3fSmrg /* Special handling for wrapping GL_LINE_LOOP */ 977ec681f3Smrg if (exec->vtx.mode[last] == GL_LINE_LOOP && 9801e04c3fSmrg last_count > 0 && 997ec681f3Smrg !exec->vtx.markers[last].end) { 10001e04c3fSmrg /* draw this section of the incomplete line loop as a line strip */ 1017ec681f3Smrg exec->vtx.mode[last] = GL_LINE_STRIP; 1027ec681f3Smrg if (!last_begin) { 10301e04c3fSmrg /* This is not the first section of the line loop, so don't 10401e04c3fSmrg * draw the 0th vertex. We're saving it until we draw the 10501e04c3fSmrg * very last section of the loop. 10601e04c3fSmrg */ 1077ec681f3Smrg last_draw->start++; 1087ec681f3Smrg last_draw->count--; 10901e04c3fSmrg } 11001e04c3fSmrg } 1117117f1b4Smrg 1127117f1b4Smrg /* Execute the buffer and save copied vertices. 1137117f1b4Smrg */ 1147117f1b4Smrg if (exec->vtx.vert_count) 1157ec681f3Smrg vbo_exec_vtx_flush(exec); 1167117f1b4Smrg else { 11701e04c3fSmrg exec->vtx.prim_count = 0; 11801e04c3fSmrg exec->vtx.copied.nr = 0; 1197117f1b4Smrg } 1207117f1b4Smrg 1217117f1b4Smrg /* Emit a glBegin to start the new list. 1227117f1b4Smrg */ 1237117f1b4Smrg assert(exec->vtx.prim_count == 0); 1247117f1b4Smrg 1257ec681f3Smrg if (_mesa_inside_begin_end(ctx)) { 1267ec681f3Smrg exec->vtx.mode[0] = ctx->Driver.CurrentExecPrimitive; 1277ec681f3Smrg exec->vtx.draw[0].start = 0; 1287ec681f3Smrg exec->vtx.markers[0].begin = 0; 12901e04c3fSmrg exec->vtx.prim_count++; 13001e04c3fSmrg 13101e04c3fSmrg if (exec->vtx.copied.nr == last_count) 1327ec681f3Smrg exec->vtx.markers[0].begin = last_begin; 1337117f1b4Smrg } 1347117f1b4Smrg } 1357117f1b4Smrg} 1367117f1b4Smrg 1377117f1b4Smrg 1384a49301eSmrg/** 1394a49301eSmrg * Deal with buffer wrapping where provoked by the vertex buffer 1407117f1b4Smrg * filling up, as opposed to upgrade_vertex(). 1417117f1b4Smrg */ 14201e04c3fSmrgstatic void 14301e04c3fSmrgvbo_exec_vtx_wrap(struct vbo_exec_context *exec) 1447117f1b4Smrg{ 14501e04c3fSmrg unsigned numComponents; 1467117f1b4Smrg 1477117f1b4Smrg /* Run pipeline on current vertices, copy wrapped vertices 1487117f1b4Smrg * to exec->vtx.copied. 1497117f1b4Smrg */ 15001e04c3fSmrg vbo_exec_wrap_buffers(exec); 15101e04c3fSmrg 152af69d88dSmrg if (!exec->vtx.buffer_ptr) { 153af69d88dSmrg /* probably ran out of memory earlier when allocating the VBO */ 154af69d88dSmrg return; 155af69d88dSmrg } 156af69d88dSmrg 15701e04c3fSmrg /* Copy stored stored vertices to start of new list. 1587117f1b4Smrg */ 1597117f1b4Smrg assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); 1607117f1b4Smrg 16101e04c3fSmrg numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size; 16201e04c3fSmrg memcpy(exec->vtx.buffer_ptr, 16301e04c3fSmrg exec->vtx.copied.buffer, 16401e04c3fSmrg numComponents * sizeof(fi_type)); 16501e04c3fSmrg exec->vtx.buffer_ptr += numComponents; 16601e04c3fSmrg exec->vtx.vert_count += exec->vtx.copied.nr; 1677117f1b4Smrg 1687117f1b4Smrg exec->vtx.copied.nr = 0; 1697117f1b4Smrg} 1707117f1b4Smrg 1717117f1b4Smrg 1724a49301eSmrg/** 1737117f1b4Smrg * Copy the active vertex's values to the ctx->Current fields. 1747117f1b4Smrg */ 17501e04c3fSmrgstatic void 17601e04c3fSmrgvbo_exec_copy_to_current(struct vbo_exec_context *exec) 1777117f1b4Smrg{ 1787ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 1797117f1b4Smrg struct vbo_context *vbo = vbo_context(ctx); 18001e04c3fSmrg GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); 1817ec681f3Smrg bool color0_changed = false; 1827117f1b4Smrg 18301e04c3fSmrg while (enabled) { 18401e04c3fSmrg const int i = u_bit_scan64(&enabled); 1854a49301eSmrg 18601e04c3fSmrg /* Note: the exec->vtx.current[i] pointers point into the 18701e04c3fSmrg * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. 18801e04c3fSmrg */ 18901e04c3fSmrg GLfloat *current = (GLfloat *)vbo->current[i].Ptr; 19001e04c3fSmrg fi_type tmp[8]; /* space for doubles */ 1917ec681f3Smrg int dmul_shift = 0; 19201e04c3fSmrg 1937ec681f3Smrg assert(exec->vtx.attr[i].size); 19401e04c3fSmrg 1957ec681f3Smrg if (exec->vtx.attr[i].type == GL_DOUBLE || 1967ec681f3Smrg exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB) { 19701e04c3fSmrg memset(tmp, 0, sizeof(tmp)); 1987ec681f3Smrg memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attr[i].size * sizeof(GLfloat)); 1997ec681f3Smrg dmul_shift = 1; 20001e04c3fSmrg } else { 20101e04c3fSmrg COPY_CLEAN_4V_TYPE_AS_UNION(tmp, 2027ec681f3Smrg exec->vtx.attr[i].size, 203af69d88dSmrg exec->vtx.attrptr[i], 2047ec681f3Smrg exec->vtx.attr[i].type); 20501e04c3fSmrg } 20601e04c3fSmrg 2077ec681f3Smrg if (memcmp(current, tmp, 4 * sizeof(GLfloat) << dmul_shift) != 0) { 2087ec681f3Smrg memcpy(current, tmp, 4 * sizeof(GLfloat) << dmul_shift); 20901e04c3fSmrg 2107ec681f3Smrg if (i == VBO_ATTRIB_COLOR0) 2117ec681f3Smrg color0_changed = true; 21201e04c3fSmrg 2137ec681f3Smrg if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT) { 2147ec681f3Smrg ctx->NewState |= _NEW_MATERIAL; 2157ec681f3Smrg ctx->PopAttribState |= GL_LIGHTING_BIT; 2167ec681f3Smrg 2177ec681f3Smrg /* The fixed-func vertex program uses this. */ 2187ec681f3Smrg if (i == VBO_ATTRIB_MAT_FRONT_SHININESS || 2197ec681f3Smrg i == VBO_ATTRIB_MAT_BACK_SHININESS) 2207ec681f3Smrg ctx->NewState |= _NEW_FF_VERT_PROGRAM; 2217ec681f3Smrg } else { 2227ec681f3Smrg ctx->NewState |= _NEW_CURRENT_ATTRIB; 2237ec681f3Smrg ctx->PopAttribState |= GL_CURRENT_BIT; 2247ec681f3Smrg } 2257ec681f3Smrg } 22601e04c3fSmrg 2277ec681f3Smrg /* Given that we explicitly state size here, there is no need 2287ec681f3Smrg * for the COPY_CLEAN above, could just copy 16 bytes and be 2297ec681f3Smrg * done. The only problem is when Mesa accesses ctx->Current 2307ec681f3Smrg * directly. 2317ec681f3Smrg */ 2327ec681f3Smrg /* Size here is in components - not bytes */ 2337ec681f3Smrg if (exec->vtx.attr[i].type != vbo->current[i].Format.Type || 2347ec681f3Smrg (exec->vtx.attr[i].size >> dmul_shift) != vbo->current[i].Format.Size) { 2357ec681f3Smrg vbo_set_vertex_format(&vbo->current[i].Format, 2367ec681f3Smrg exec->vtx.attr[i].size >> dmul_shift, 2377ec681f3Smrg exec->vtx.attr[i].type); 2387117f1b4Smrg } 2397117f1b4Smrg } 2407117f1b4Smrg 2417ec681f3Smrg if (color0_changed && ctx->Light.ColorMaterialEnabled) { 24201e04c3fSmrg _mesa_update_color_material(ctx, 24301e04c3fSmrg ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 2447117f1b4Smrg } 2457117f1b4Smrg} 2467117f1b4Smrg 2477117f1b4Smrg 2484a49301eSmrg/** 2494a49301eSmrg * Flush existing data, set new attrib size, replay copied vertices. 2503464ebd5Sriastradh * This is called when we transition from a small vertex attribute size 2513464ebd5Sriastradh * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. 2523464ebd5Sriastradh * We need to go back over the previous 2-component texcoords and insert 2533464ebd5Sriastradh * zero and one values. 25401e04c3fSmrg * \param attr VBO_ATTRIB_x vertex attribute value 25501e04c3fSmrg */ 2563464ebd5Sriastradhstatic void 2573464ebd5Sriastradhvbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, 2587ec681f3Smrg GLuint attr, GLuint newSize, GLenum newType) 2597117f1b4Smrg{ 2607ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 2617117f1b4Smrg struct vbo_context *vbo = vbo_context(ctx); 2623464ebd5Sriastradh const GLint lastcount = exec->vtx.vert_count; 26301e04c3fSmrg fi_type *old_attrptr[VBO_ATTRIB_MAX]; 2647ec681f3Smrg const GLuint old_vtx_size_no_pos = exec->vtx.vertex_size_no_pos; 2653464ebd5Sriastradh const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ 2667ec681f3Smrg const GLuint oldSize = exec->vtx.attr[attr].size; 2677117f1b4Smrg GLuint i; 2687117f1b4Smrg 26901e04c3fSmrg assert(attr < VBO_ATTRIB_MAX); 27001e04c3fSmrg 2717ec681f3Smrg if (unlikely(!exec->vtx.buffer_ptr)) { 2727ec681f3Smrg /* We should only hit this when use_buffer_objects=true */ 2737ec681f3Smrg assert(exec->vtx.bufferobj); 2747ec681f3Smrg vbo_exec_vtx_map(exec); 2757ec681f3Smrg assert(exec->vtx.buffer_ptr); 2767ec681f3Smrg } 2777ec681f3Smrg 2787117f1b4Smrg /* Run pipeline on current vertices, copy wrapped vertices 2797117f1b4Smrg * to exec->vtx.copied. 2807117f1b4Smrg */ 28101e04c3fSmrg vbo_exec_wrap_buffers(exec); 2827117f1b4Smrg 2833464ebd5Sriastradh if (unlikely(exec->vtx.copied.nr)) { 2843464ebd5Sriastradh /* We're in the middle of a primitive, keep the old vertex 2853464ebd5Sriastradh * format around to be able to translate the copied vertices to 2863464ebd5Sriastradh * the new format. 2873464ebd5Sriastradh */ 2883464ebd5Sriastradh memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); 2893464ebd5Sriastradh } 2907117f1b4Smrg 2917117f1b4Smrg /* Heuristic: Attempt to isolate attributes received outside 2927117f1b4Smrg * begin/end so that they don't bloat the vertices. 2937117f1b4Smrg */ 294af69d88dSmrg if (!_mesa_inside_begin_end(ctx) && 2953464ebd5Sriastradh !oldSize && lastcount > 8 && exec->vtx.vertex_size) { 29601e04c3fSmrg vbo_exec_copy_to_current(exec); 29701e04c3fSmrg vbo_reset_all_attr(exec); 2987117f1b4Smrg } 2997117f1b4Smrg 3007117f1b4Smrg /* Fix up sizes: 3017117f1b4Smrg */ 3027ec681f3Smrg exec->vtx.attr[attr].size = newSize; 3037ec681f3Smrg exec->vtx.attr[attr].active_size = newSize; 3047ec681f3Smrg exec->vtx.attr[attr].type = newType; 3053464ebd5Sriastradh exec->vtx.vertex_size += newSize - oldSize; 3067ec681f3Smrg exec->vtx.vertex_size_no_pos = exec->vtx.vertex_size - exec->vtx.attr[0].size; 30701e04c3fSmrg exec->vtx.max_vert = vbo_compute_max_verts(exec); 3087117f1b4Smrg exec->vtx.vert_count = 0; 3094a49301eSmrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 31001e04c3fSmrg exec->vtx.enabled |= BITFIELD64_BIT(attr); 3117117f1b4Smrg 3127ec681f3Smrg if (attr != 0) { 3137ec681f3Smrg if (unlikely(oldSize)) { 3147ec681f3Smrg unsigned offset = exec->vtx.attrptr[attr] - exec->vtx.vertex; 3157ec681f3Smrg 3167ec681f3Smrg /* If there are attribs after the resized attrib... */ 3177ec681f3Smrg if (offset + oldSize < old_vtx_size_no_pos) { 3187ec681f3Smrg int size_diff = newSize - oldSize; 3197ec681f3Smrg fi_type *old_first = exec->vtx.attrptr[attr] + oldSize; 3207ec681f3Smrg fi_type *new_first = exec->vtx.attrptr[attr] + newSize; 3217ec681f3Smrg fi_type *old_last = exec->vtx.vertex + old_vtx_size_no_pos - 1; 3227ec681f3Smrg fi_type *new_last = exec->vtx.vertex + exec->vtx.vertex_size_no_pos - 1; 3237ec681f3Smrg 3247ec681f3Smrg if (size_diff < 0) { 3257ec681f3Smrg /* Decreasing the size: Copy from first to last to move 3267ec681f3Smrg * elements to the left. 3277ec681f3Smrg */ 3287ec681f3Smrg fi_type *old_end = old_last + 1; 3297ec681f3Smrg fi_type *old = old_first; 3307ec681f3Smrg fi_type *new = new_first; 3317ec681f3Smrg 3327ec681f3Smrg do { 3337ec681f3Smrg *new++ = *old++; 3347ec681f3Smrg } while (old != old_end); 3357ec681f3Smrg } else { 3367ec681f3Smrg /* Increasing the size: Copy from last to first to move 3377ec681f3Smrg * elements to the right. 3387ec681f3Smrg */ 3397ec681f3Smrg fi_type *old_end = old_first - 1; 3407ec681f3Smrg fi_type *old = old_last; 3417ec681f3Smrg fi_type *new = new_last; 3427ec681f3Smrg 3437ec681f3Smrg do { 3447ec681f3Smrg *new-- = *old--; 3457ec681f3Smrg } while (old != old_end); 3467ec681f3Smrg } 3477ec681f3Smrg 3487ec681f3Smrg /* Update pointers to attribs, because we moved them. */ 3497ec681f3Smrg GLbitfield64 enabled = exec->vtx.enabled & 3507ec681f3Smrg ~BITFIELD64_BIT(VBO_ATTRIB_POS) & 3517ec681f3Smrg ~BITFIELD64_BIT(attr); 3527ec681f3Smrg while (enabled) { 3537ec681f3Smrg unsigned i = u_bit_scan64(&enabled); 3543464ebd5Sriastradh 3557ec681f3Smrg if (exec->vtx.attrptr[i] > exec->vtx.attrptr[attr]) 3567ec681f3Smrg exec->vtx.attrptr[i] += size_diff; 3577ec681f3Smrg } 35801e04c3fSmrg } 3597ec681f3Smrg } else { 3607ec681f3Smrg /* Just have to append the new attribute at the end */ 3617ec681f3Smrg exec->vtx.attrptr[attr] = exec->vtx.vertex + 3627ec681f3Smrg exec->vtx.vertex_size_no_pos - newSize; 3637117f1b4Smrg } 3643464ebd5Sriastradh } 3657117f1b4Smrg 3667ec681f3Smrg /* The position is always last. */ 3677ec681f3Smrg exec->vtx.attrptr[0] = exec->vtx.vertex + exec->vtx.vertex_size_no_pos; 3687ec681f3Smrg 3697117f1b4Smrg /* Replay stored vertices to translate them 3707117f1b4Smrg * to new format here. 3717117f1b4Smrg * 3727117f1b4Smrg * -- No need to replay - just copy piecewise 3737117f1b4Smrg */ 3743464ebd5Sriastradh if (unlikely(exec->vtx.copied.nr)) { 37501e04c3fSmrg fi_type *data = exec->vtx.copied.buffer; 37601e04c3fSmrg fi_type *dest = exec->vtx.buffer_ptr; 3777117f1b4Smrg 3784a49301eSmrg assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); 3793464ebd5Sriastradh 3807117f1b4Smrg for (i = 0 ; i < exec->vtx.copied.nr ; i++) { 38101e04c3fSmrg GLbitfield64 enabled = exec->vtx.enabled; 38201e04c3fSmrg while (enabled) { 38301e04c3fSmrg const int j = u_bit_scan64(&enabled); 3847ec681f3Smrg GLuint sz = exec->vtx.attr[j].size; 38501e04c3fSmrg GLint old_offset = old_attrptr[j] - exec->vtx.vertex; 38601e04c3fSmrg GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; 38701e04c3fSmrg 38801e04c3fSmrg assert(sz); 38901e04c3fSmrg 39001e04c3fSmrg if (j == attr) { 39101e04c3fSmrg if (oldSize) { 39201e04c3fSmrg fi_type tmp[4]; 39301e04c3fSmrg COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize, 39401e04c3fSmrg data + old_offset, 3957ec681f3Smrg exec->vtx.attr[j].type); 39601e04c3fSmrg COPY_SZ_4V(dest + new_offset, newSize, tmp); 39701e04c3fSmrg } else { 39801e04c3fSmrg fi_type *current = (fi_type *)vbo->current[j].Ptr; 39901e04c3fSmrg COPY_SZ_4V(dest + new_offset, sz, current); 40001e04c3fSmrg } 40101e04c3fSmrg } 40201e04c3fSmrg else { 40301e04c3fSmrg COPY_SZ_4V(dest + new_offset, sz, data + old_offset); 40401e04c3fSmrg } 40501e04c3fSmrg } 40601e04c3fSmrg 40701e04c3fSmrg data += old_vtx_size; 40801e04c3fSmrg dest += exec->vtx.vertex_size; 4097117f1b4Smrg } 4107117f1b4Smrg 4114a49301eSmrg exec->vtx.buffer_ptr = dest; 4127117f1b4Smrg exec->vtx.vert_count += exec->vtx.copied.nr; 4137117f1b4Smrg exec->vtx.copied.nr = 0; 4147117f1b4Smrg } 4157117f1b4Smrg} 4167117f1b4Smrg 4177117f1b4Smrg 4183464ebd5Sriastradh/** 4193464ebd5Sriastradh * This is when a vertex attribute transitions to a different size. 4203464ebd5Sriastradh * For example, we saw a bunch of glTexCoord2f() calls and now we got a 4213464ebd5Sriastradh * glTexCoord4f() call. We promote the array from size=2 to size=4. 42201e04c3fSmrg * \param newSize size of new vertex (number of 32-bit words). 42301e04c3fSmrg * \param attr VBO_ATTRIB_x vertex attribute value 4243464ebd5Sriastradh */ 4253464ebd5Sriastradhstatic void 42601e04c3fSmrgvbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, 42701e04c3fSmrg GLuint newSize, GLenum newType) 4287117f1b4Smrg{ 4297117f1b4Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 4307117f1b4Smrg 43101e04c3fSmrg assert(attr < VBO_ATTRIB_MAX); 43201e04c3fSmrg 4337ec681f3Smrg if (newSize > exec->vtx.attr[attr].size || 4347ec681f3Smrg newType != exec->vtx.attr[attr].type) { 4357117f1b4Smrg /* New size is larger. Need to flush existing vertices and get 4367117f1b4Smrg * an enlarged vertex format. 4377117f1b4Smrg */ 4387ec681f3Smrg vbo_exec_wrap_upgrade_vertex(exec, attr, newSize, newType); 4397117f1b4Smrg } 4407ec681f3Smrg else if (newSize < exec->vtx.attr[attr].active_size) { 4413464ebd5Sriastradh GLuint i; 44201e04c3fSmrg const fi_type *id = 4437ec681f3Smrg vbo_get_default_vals_as_union(exec->vtx.attr[attr].type); 4447117f1b4Smrg 4457117f1b4Smrg /* New size is smaller - just need to fill in some 4467117f1b4Smrg * zeros. Don't need to flush or wrap. 4477117f1b4Smrg */ 4487ec681f3Smrg for (i = newSize; i <= exec->vtx.attr[attr].size; i++) 44901e04c3fSmrg exec->vtx.attrptr[attr][i-1] = id[i-1]; 4507117f1b4Smrg 4517ec681f3Smrg exec->vtx.attr[attr].active_size = newSize; 4527ec681f3Smrg } 45301e04c3fSmrg} 45401e04c3fSmrg 45501e04c3fSmrg 4568a1362adSmaya/** 4578a1362adSmaya * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex? 4588a1362adSmaya * It depends on a few things, including whether we're inside or outside 4598a1362adSmaya * of glBegin/glEnd. 4608a1362adSmaya */ 4618a1362adSmayastatic inline bool 4628a1362adSmayais_vertex_position(const struct gl_context *ctx, GLuint index) 4638a1362adSmaya{ 4648a1362adSmaya return (index == 0 && 4658a1362adSmaya _mesa_attr_zero_aliases_vertex(ctx) && 4668a1362adSmaya _mesa_inside_begin_end(ctx)); 4678a1362adSmaya} 4688a1362adSmaya 4697ec681f3Smrg/* Write a 64-bit value into a 32-bit pointer by preserving endianness. */ 4707ec681f3Smrg#if UTIL_ARCH_LITTLE_ENDIAN 4717ec681f3Smrg #define SET_64BIT(dst32, u64) do { \ 4727ec681f3Smrg *(dst32)++ = (u64); \ 4737ec681f3Smrg *(dst32)++ = (uint64_t)(u64) >> 32; \ 4747ec681f3Smrg } while (0) 4757ec681f3Smrg#else 4767ec681f3Smrg #define SET_64BIT(dst32, u64) do { \ 4777ec681f3Smrg *(dst32)++ = (uint64_t)(u64) >> 32; \ 4787ec681f3Smrg *(dst32)++ = (u64); \ 4797ec681f3Smrg } while (0) 4807ec681f3Smrg#endif 4817ec681f3Smrg 4828a1362adSmaya 4833464ebd5Sriastradh/** 4843464ebd5Sriastradh * This macro is used to implement all the glVertex, glColor, glTexCoord, 4853464ebd5Sriastradh * glVertexAttrib, etc functions. 48601e04c3fSmrg * \param A VBO_ATTRIB_x attribute index 48701e04c3fSmrg * \param N attribute size (1..4) 48801e04c3fSmrg * \param T type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT) 4897ec681f3Smrg * \param C cast type (uint32_t or uint64_t) 49001e04c3fSmrg * \param V0, V1, v2, V3 attribute value 4917117f1b4Smrg */ 49201e04c3fSmrg#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ 49301e04c3fSmrgdo { \ 49401e04c3fSmrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ 49501e04c3fSmrg int sz = (sizeof(C) / sizeof(GLfloat)); \ 49601e04c3fSmrg \ 49701e04c3fSmrg assert(sz == 1 || sz == 2); \ 4987ec681f3Smrg /* store a copy of the attribute in exec except for glVertex */ \ 4997ec681f3Smrg if ((A) != 0) { \ 5007ec681f3Smrg /* Check if attribute size or type is changing. */ \ 5017ec681f3Smrg if (unlikely(exec->vtx.attr[A].active_size != N * sz || \ 5027ec681f3Smrg exec->vtx.attr[A].type != T)) { \ 5037ec681f3Smrg vbo_exec_fixup_vertex(ctx, A, N * sz, T); \ 5047ec681f3Smrg } \ 50501e04c3fSmrg \ 50601e04c3fSmrg C *dest = (C *)exec->vtx.attrptr[A]; \ 50701e04c3fSmrg if (N>0) dest[0] = V0; \ 50801e04c3fSmrg if (N>1) dest[1] = V1; \ 50901e04c3fSmrg if (N>2) dest[2] = V2; \ 51001e04c3fSmrg if (N>3) dest[3] = V3; \ 5117ec681f3Smrg assert(exec->vtx.attr[A].type == T); \ 51201e04c3fSmrg \ 5137ec681f3Smrg /* we now have accumulated a per-vertex attribute */ \ 5147ec681f3Smrg ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ 5157ec681f3Smrg } else { \ 51601e04c3fSmrg /* This is a glVertex call */ \ 5177ec681f3Smrg int size = exec->vtx.attr[0].size; \ 51801e04c3fSmrg \ 5197ec681f3Smrg /* Check if attribute size or type is changing. */ \ 5207ec681f3Smrg if (unlikely(size < N * sz || \ 5217ec681f3Smrg exec->vtx.attr[0].type != T)) { \ 5227ec681f3Smrg vbo_exec_wrap_upgrade_vertex(exec, 0, N * sz, T); \ 52301e04c3fSmrg } \ 52401e04c3fSmrg \ 5257ec681f3Smrg uint32_t *dst = (uint32_t *)exec->vtx.buffer_ptr; \ 5267ec681f3Smrg uint32_t *src = (uint32_t *)exec->vtx.vertex; \ 5277ec681f3Smrg unsigned vertex_size_no_pos = exec->vtx.vertex_size_no_pos; \ 52801e04c3fSmrg \ 5297ec681f3Smrg /* Copy over attributes from exec. */ \ 5307ec681f3Smrg for (unsigned i = 0; i < vertex_size_no_pos; i++) \ 5317ec681f3Smrg *dst++ = *src++; \ 53201e04c3fSmrg \ 5337ec681f3Smrg /* Store the position, which is always last and can have 32 or */ \ 5347ec681f3Smrg /* 64 bits per channel. */ \ 5357ec681f3Smrg if (sizeof(C) == 4) { \ 5367ec681f3Smrg if (N > 0) *dst++ = V0; \ 5377ec681f3Smrg if (N > 1) *dst++ = V1; \ 5387ec681f3Smrg if (N > 2) *dst++ = V2; \ 5397ec681f3Smrg if (N > 3) *dst++ = V3; \ 54001e04c3fSmrg \ 5417ec681f3Smrg if (unlikely(N < size)) { \ 5427ec681f3Smrg if (N < 2 && size >= 2) *dst++ = V1; \ 5437ec681f3Smrg if (N < 3 && size >= 3) *dst++ = V2; \ 5447ec681f3Smrg if (N < 4 && size >= 4) *dst++ = V3; \ 5457ec681f3Smrg } \ 5467ec681f3Smrg } else { \ 5477ec681f3Smrg /* 64 bits: dst can be unaligned, so copy each 4-byte word */ \ 5487ec681f3Smrg /* separately */ \ 5497ec681f3Smrg if (N > 0) SET_64BIT(dst, V0); \ 5507ec681f3Smrg if (N > 1) SET_64BIT(dst, V1); \ 5517ec681f3Smrg if (N > 2) SET_64BIT(dst, V2); \ 5527ec681f3Smrg if (N > 3) SET_64BIT(dst, V3); \ 5537ec681f3Smrg \ 5547ec681f3Smrg if (unlikely(N * 2 < size)) { \ 5557ec681f3Smrg if (N < 2 && size >= 4) SET_64BIT(dst, V1); \ 5567ec681f3Smrg if (N < 3 && size >= 6) SET_64BIT(dst, V2); \ 5577ec681f3Smrg if (N < 4 && size >= 8) SET_64BIT(dst, V3); \ 5587ec681f3Smrg } \ 5597ec681f3Smrg } \ 56001e04c3fSmrg \ 5617ec681f3Smrg /* dst now points at the beginning of the next vertex */ \ 5627ec681f3Smrg exec->vtx.buffer_ptr = (fi_type*)dst; \ 5637ec681f3Smrg \ 5647ec681f3Smrg /* Don't set FLUSH_UPDATE_CURRENT because */ \ 5657ec681f3Smrg /* Current.Attrib[VBO_ATTRIB_POS] is never used. */ \ 5667ec681f3Smrg \ 5677ec681f3Smrg if (unlikely(++exec->vtx.vert_count >= exec->vtx.max_vert)) \ 56801e04c3fSmrg vbo_exec_vtx_wrap(exec); \ 56901e04c3fSmrg } \ 5707117f1b4Smrg} while (0) 5717117f1b4Smrg 5727117f1b4Smrg 57301e04c3fSmrg#undef ERROR 57401e04c3fSmrg#define ERROR(err) _mesa_error(ctx, err, __func__) 5757ec681f3Smrg#define TAG(x) vbo_exec_##x 5767117f1b4Smrg 5777117f1b4Smrg#include "vbo_attrib_tmp.h" 5787117f1b4Smrg 5797117f1b4Smrg 5807117f1b4Smrg 581af69d88dSmrg/** 582af69d88dSmrg * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled, 583af69d88dSmrg * this may be a (partial) no-op. 584af69d88dSmrg */ 585af69d88dSmrgstatic void GLAPIENTRY 5867ec681f3Smrgvbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 587af69d88dSmrg{ 588af69d88dSmrg GLbitfield updateMats; 589af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 590af69d88dSmrg 591af69d88dSmrg /* This function should be a no-op when it tries to update material 592af69d88dSmrg * attributes which are currently tracking glColor via glColorMaterial. 593af69d88dSmrg * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits 594af69d88dSmrg * indicating which material attributes can actually be updated below. 595af69d88dSmrg */ 596af69d88dSmrg if (ctx->Light.ColorMaterialEnabled) { 597af69d88dSmrg updateMats = ~ctx->Light._ColorMaterialBitmask; 598af69d88dSmrg } 599af69d88dSmrg else { 600af69d88dSmrg /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */ 601af69d88dSmrg updateMats = ALL_MATERIAL_BITS; 602af69d88dSmrg } 603af69d88dSmrg 604af69d88dSmrg if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) { 605af69d88dSmrg updateMats &= FRONT_MATERIAL_BITS; 606af69d88dSmrg } 607af69d88dSmrg else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) { 608af69d88dSmrg updateMats &= BACK_MATERIAL_BITS; 609af69d88dSmrg } 610af69d88dSmrg else if (face != GL_FRONT_AND_BACK) { 611af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)"); 612af69d88dSmrg return; 613af69d88dSmrg } 614af69d88dSmrg 615af69d88dSmrg switch (pname) { 616af69d88dSmrg case GL_EMISSION: 617af69d88dSmrg if (updateMats & MAT_BIT_FRONT_EMISSION) 618af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params); 619af69d88dSmrg if (updateMats & MAT_BIT_BACK_EMISSION) 620af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params); 621af69d88dSmrg break; 622af69d88dSmrg case GL_AMBIENT: 623af69d88dSmrg if (updateMats & MAT_BIT_FRONT_AMBIENT) 624af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 625af69d88dSmrg if (updateMats & MAT_BIT_BACK_AMBIENT) 626af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 627af69d88dSmrg break; 628af69d88dSmrg case GL_DIFFUSE: 629af69d88dSmrg if (updateMats & MAT_BIT_FRONT_DIFFUSE) 630af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 631af69d88dSmrg if (updateMats & MAT_BIT_BACK_DIFFUSE) 632af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 633af69d88dSmrg break; 634af69d88dSmrg case GL_SPECULAR: 635af69d88dSmrg if (updateMats & MAT_BIT_FRONT_SPECULAR) 636af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params); 637af69d88dSmrg if (updateMats & MAT_BIT_BACK_SPECULAR) 638af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params); 639af69d88dSmrg break; 640af69d88dSmrg case GL_SHININESS: 641af69d88dSmrg if (*params < 0 || *params > ctx->Const.MaxShininess) { 642af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 643af69d88dSmrg "glMaterial(invalid shininess: %f out range [0, %f])", 64401e04c3fSmrg *params, ctx->Const.MaxShininess); 645af69d88dSmrg return; 646af69d88dSmrg } 647af69d88dSmrg if (updateMats & MAT_BIT_FRONT_SHININESS) 648af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params); 649af69d88dSmrg if (updateMats & MAT_BIT_BACK_SHININESS) 650af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params); 651af69d88dSmrg break; 652af69d88dSmrg case GL_COLOR_INDEXES: 653af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) { 654af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 655af69d88dSmrg return; 656af69d88dSmrg } 657af69d88dSmrg if (updateMats & MAT_BIT_FRONT_INDEXES) 658af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params); 659af69d88dSmrg if (updateMats & MAT_BIT_BACK_INDEXES) 660af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params); 661af69d88dSmrg break; 662af69d88dSmrg case GL_AMBIENT_AND_DIFFUSE: 663af69d88dSmrg if (updateMats & MAT_BIT_FRONT_AMBIENT) 664af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params); 665af69d88dSmrg if (updateMats & MAT_BIT_FRONT_DIFFUSE) 666af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params); 667af69d88dSmrg if (updateMats & MAT_BIT_BACK_AMBIENT) 668af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params); 669af69d88dSmrg if (updateMats & MAT_BIT_BACK_DIFFUSE) 670af69d88dSmrg MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params); 671af69d88dSmrg break; 672af69d88dSmrg default: 673af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)"); 674af69d88dSmrg return; 675af69d88dSmrg } 676af69d88dSmrg} 677af69d88dSmrg 678af69d88dSmrg 679af69d88dSmrg/** 680af69d88dSmrg * Flush (draw) vertices. 6817ec681f3Smrg * 6827ec681f3Smrg * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 683af69d88dSmrg */ 684af69d88dSmrgstatic void 6857ec681f3Smrgvbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, unsigned flags) 686af69d88dSmrg{ 6877ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 6887ec681f3Smrg 6897ec681f3Smrg if (flags & FLUSH_STORED_VERTICES) { 6907ec681f3Smrg if (exec->vtx.vert_count) { 6917ec681f3Smrg vbo_exec_vtx_flush(exec); 6927ec681f3Smrg } 693af69d88dSmrg 6947ec681f3Smrg if (exec->vtx.vertex_size) { 6957ec681f3Smrg vbo_exec_copy_to_current(exec); 6967ec681f3Smrg vbo_reset_all_attr(exec); 6977ec681f3Smrg } 6987ec681f3Smrg 6997ec681f3Smrg /* All done. */ 7007ec681f3Smrg ctx->Driver.NeedFlush = 0; 7017ec681f3Smrg } else { 7027ec681f3Smrg assert(flags == FLUSH_UPDATE_CURRENT); 7037ec681f3Smrg 7047ec681f3Smrg /* Note that the vertex size is unchanged. 7057ec681f3Smrg * (vbo_reset_all_attr isn't called) 7067ec681f3Smrg */ 70701e04c3fSmrg vbo_exec_copy_to_current(exec); 7087ec681f3Smrg 7097ec681f3Smrg /* Only FLUSH_UPDATE_CURRENT is done. */ 7107ec681f3Smrg ctx->Driver.NeedFlush = ~FLUSH_UPDATE_CURRENT; 711af69d88dSmrg } 712af69d88dSmrg} 7137117f1b4Smrg 7144a49301eSmrg 71501e04c3fSmrgstatic void GLAPIENTRY 71601e04c3fSmrgvbo_exec_EvalCoord1f(GLfloat u) 7177117f1b4Smrg{ 71801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 7197117f1b4Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 7207117f1b4Smrg 7217117f1b4Smrg { 7227117f1b4Smrg GLint i; 72301e04c3fSmrg if (exec->eval.recalculate_maps) 72401e04c3fSmrg vbo_exec_eval_update(exec); 7257117f1b4Smrg 7267117f1b4Smrg for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 72701e04c3fSmrg if (exec->eval.map1[i].map) 7287ec681f3Smrg if (exec->vtx.attr[i].active_size != exec->eval.map1[i].sz) 72901e04c3fSmrg vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT); 7307117f1b4Smrg } 7317117f1b4Smrg } 7327117f1b4Smrg 73301e04c3fSmrg memcpy(exec->vtx.copied.buffer, exec->vtx.vertex, 73401e04c3fSmrg exec->vtx.vertex_size * sizeof(GLfloat)); 7357117f1b4Smrg 73601e04c3fSmrg vbo_exec_do_EvalCoord1f(exec, u); 7377117f1b4Smrg 73801e04c3fSmrg memcpy(exec->vtx.vertex, exec->vtx.copied.buffer, 73901e04c3fSmrg exec->vtx.vertex_size * sizeof(GLfloat)); 7407117f1b4Smrg} 7417117f1b4Smrg 74201e04c3fSmrg 74301e04c3fSmrgstatic void GLAPIENTRY 74401e04c3fSmrgvbo_exec_EvalCoord2f(GLfloat u, GLfloat v) 7457117f1b4Smrg{ 74601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 7477117f1b4Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 7487117f1b4Smrg 7497117f1b4Smrg { 7507117f1b4Smrg GLint i; 75101e04c3fSmrg if (exec->eval.recalculate_maps) 75201e04c3fSmrg vbo_exec_eval_update(exec); 7537117f1b4Smrg 7547117f1b4Smrg for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { 75501e04c3fSmrg if (exec->eval.map2[i].map) 7567ec681f3Smrg if (exec->vtx.attr[i].active_size != exec->eval.map2[i].sz) 75701e04c3fSmrg vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT); 7587117f1b4Smrg } 7597117f1b4Smrg 76001e04c3fSmrg if (ctx->Eval.AutoNormal) 7617ec681f3Smrg if (exec->vtx.attr[VBO_ATTRIB_NORMAL].active_size != 3) 76201e04c3fSmrg vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT); 7637117f1b4Smrg } 7647117f1b4Smrg 76501e04c3fSmrg memcpy(exec->vtx.copied.buffer, exec->vtx.vertex, 76601e04c3fSmrg exec->vtx.vertex_size * sizeof(GLfloat)); 7677117f1b4Smrg 76801e04c3fSmrg vbo_exec_do_EvalCoord2f(exec, u, v); 7697117f1b4Smrg 77001e04c3fSmrg memcpy(exec->vtx.vertex, exec->vtx.copied.buffer, 77101e04c3fSmrg exec->vtx.vertex_size * sizeof(GLfloat)); 7727117f1b4Smrg} 7737117f1b4Smrg 77401e04c3fSmrg 77501e04c3fSmrgstatic void GLAPIENTRY 77601e04c3fSmrgvbo_exec_EvalCoord1fv(const GLfloat *u) 7777117f1b4Smrg{ 77801e04c3fSmrg vbo_exec_EvalCoord1f(u[0]); 7797117f1b4Smrg} 7807117f1b4Smrg 78101e04c3fSmrg 78201e04c3fSmrgstatic void GLAPIENTRY 78301e04c3fSmrgvbo_exec_EvalCoord2fv(const GLfloat *u) 7847117f1b4Smrg{ 78501e04c3fSmrg vbo_exec_EvalCoord2f(u[0], u[1]); 7867117f1b4Smrg} 7877117f1b4Smrg 78801e04c3fSmrg 78901e04c3fSmrgstatic void GLAPIENTRY 79001e04c3fSmrgvbo_exec_EvalPoint1(GLint i) 7917117f1b4Smrg{ 79201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 7937117f1b4Smrg GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / 79401e04c3fSmrg (GLfloat) ctx->Eval.MapGrid1un); 7957117f1b4Smrg GLfloat u = i * du + ctx->Eval.MapGrid1u1; 7967117f1b4Smrg 79701e04c3fSmrg vbo_exec_EvalCoord1f(u); 7987117f1b4Smrg} 7997117f1b4Smrg 8007117f1b4Smrg 80101e04c3fSmrgstatic void GLAPIENTRY 80201e04c3fSmrgvbo_exec_EvalPoint2(GLint i, GLint j) 8037117f1b4Smrg{ 80401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 80501e04c3fSmrg GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 80601e04c3fSmrg (GLfloat) ctx->Eval.MapGrid2un); 80701e04c3fSmrg GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 80801e04c3fSmrg (GLfloat) ctx->Eval.MapGrid2vn); 8097117f1b4Smrg GLfloat u = i * du + ctx->Eval.MapGrid2u1; 8107117f1b4Smrg GLfloat v = j * dv + ctx->Eval.MapGrid2v1; 8117117f1b4Smrg 81201e04c3fSmrg vbo_exec_EvalCoord2f(u, v); 8137117f1b4Smrg} 8147117f1b4Smrg 8157117f1b4Smrg 8163464ebd5Sriastradh/** 817af69d88dSmrg * Called via glBegin. 8183464ebd5Sriastradh */ 81901e04c3fSmrgstatic void GLAPIENTRY 82001e04c3fSmrgvbo_exec_Begin(GLenum mode) 8213464ebd5Sriastradh{ 82201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 82301e04c3fSmrg struct vbo_context *vbo = vbo_context(ctx); 82401e04c3fSmrg struct vbo_exec_context *exec = &vbo->exec; 825af69d88dSmrg int i; 826af69d88dSmrg 827af69d88dSmrg if (_mesa_inside_begin_end(ctx)) { 828af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin"); 829af69d88dSmrg return; 8303464ebd5Sriastradh } 8313464ebd5Sriastradh 8327ec681f3Smrg if (ctx->NewState) 83301e04c3fSmrg _mesa_update_state(ctx); 834af69d88dSmrg 8357ec681f3Smrg GLenum error = _mesa_valid_prim_mode(ctx, mode); 8367ec681f3Smrg if (error != GL_NO_ERROR) { 8377ec681f3Smrg _mesa_error(ctx, error, "glBegin"); 838af69d88dSmrg return; 839af69d88dSmrg } 840af69d88dSmrg 84101e04c3fSmrg /* Heuristic: attempt to isolate attributes occurring outside 842af69d88dSmrg * begin/end pairs. 8437ec681f3Smrg * 8447ec681f3Smrg * Use FLUSH_STORED_VERTICES, because it updates current attribs and 8457ec681f3Smrg * sets vertex_size to 0. (FLUSH_UPDATE_CURRENT doesn't change vertex_size) 846af69d88dSmrg */ 8477ec681f3Smrg if (exec->vtx.vertex_size && !exec->vtx.attr[VBO_ATTRIB_POS].size) 8487ec681f3Smrg vbo_exec_FlushVertices_internal(exec, FLUSH_STORED_VERTICES); 849af69d88dSmrg 850af69d88dSmrg i = exec->vtx.prim_count++; 8517ec681f3Smrg exec->vtx.mode[i] = mode; 8527ec681f3Smrg exec->vtx.draw[i].start = exec->vtx.vert_count; 8537ec681f3Smrg exec->vtx.markers[i].begin = 1; 854af69d88dSmrg 855af69d88dSmrg ctx->Driver.CurrentExecPrimitive = mode; 856af69d88dSmrg 857af69d88dSmrg ctx->Exec = ctx->BeginEnd; 8588a1362adSmaya 859af69d88dSmrg /* We may have been called from a display list, in which case we should 860af69d88dSmrg * leave dlist.c's dispatch table in place. 861af69d88dSmrg */ 8628a1362adSmaya if (ctx->CurrentClientDispatch == ctx->MarshalExec) { 8638a1362adSmaya ctx->CurrentServerDispatch = ctx->Exec; 8648a1362adSmaya } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) { 8658a1362adSmaya ctx->CurrentClientDispatch = ctx->Exec; 86601e04c3fSmrg _glapi_set_dispatch(ctx->CurrentClientDispatch); 867af69d88dSmrg } else { 86801e04c3fSmrg assert(ctx->CurrentClientDispatch == ctx->Save); 8693464ebd5Sriastradh } 8703464ebd5Sriastradh} 8713464ebd5Sriastradh 8723464ebd5Sriastradh 8734a49301eSmrg/** 874af69d88dSmrg * Try to merge / concatenate the two most recent VBO primitives. 8757117f1b4Smrg */ 876af69d88dSmrgstatic void 877af69d88dSmrgtry_vbo_merge(struct vbo_exec_context *exec) 8787117f1b4Smrg{ 8797ec681f3Smrg unsigned cur = exec->vtx.prim_count - 1; 8807117f1b4Smrg 881af69d88dSmrg assert(exec->vtx.prim_count >= 1); 8827117f1b4Smrg 8837ec681f3Smrg vbo_try_prim_conversion(&exec->vtx.mode[cur], &exec->vtx.draw[cur].count); 8847117f1b4Smrg 885af69d88dSmrg if (exec->vtx.prim_count >= 2) { 8867ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 8877ec681f3Smrg unsigned prev = cur - 1; 8887ec681f3Smrg 8897ec681f3Smrg if (vbo_merge_draws(ctx, false, 8907ec681f3Smrg exec->vtx.mode[prev], 8917ec681f3Smrg exec->vtx.mode[cur], 8927ec681f3Smrg exec->vtx.draw[prev].start, 8937ec681f3Smrg exec->vtx.draw[cur].start, 8947ec681f3Smrg &exec->vtx.draw[prev].count, 8957ec681f3Smrg exec->vtx.draw[cur].count, 8967ec681f3Smrg 0, 0, 8977ec681f3Smrg &exec->vtx.markers[prev].end, 8987ec681f3Smrg exec->vtx.markers[cur].begin, 8997ec681f3Smrg exec->vtx.markers[cur].end)) 900af69d88dSmrg exec->vtx.prim_count--; /* drop the last primitive */ 9017117f1b4Smrg } 9027117f1b4Smrg} 9037117f1b4Smrg 9044a49301eSmrg 9054a49301eSmrg/** 9064a49301eSmrg * Called via glEnd. 9074a49301eSmrg */ 90801e04c3fSmrgstatic void GLAPIENTRY 90901e04c3fSmrgvbo_exec_End(void) 9107117f1b4Smrg{ 91101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 912af69d88dSmrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 9137117f1b4Smrg 914af69d88dSmrg if (!_mesa_inside_begin_end(ctx)) { 915af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd"); 916af69d88dSmrg return; 917af69d88dSmrg } 9187117f1b4Smrg 919af69d88dSmrg ctx->Exec = ctx->OutsideBeginEnd; 9208a1362adSmaya 9218a1362adSmaya if (ctx->CurrentClientDispatch == ctx->MarshalExec) { 9228a1362adSmaya ctx->CurrentServerDispatch = ctx->Exec; 9238a1362adSmaya } else if (ctx->CurrentClientDispatch == ctx->BeginEnd) { 9248a1362adSmaya ctx->CurrentClientDispatch = ctx->Exec; 92501e04c3fSmrg _glapi_set_dispatch(ctx->CurrentClientDispatch); 926af69d88dSmrg } 9273464ebd5Sriastradh 928af69d88dSmrg if (exec->vtx.prim_count > 0) { 929af69d88dSmrg /* close off current primitive */ 9307ec681f3Smrg unsigned last = exec->vtx.prim_count - 1; 9317ec681f3Smrg struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last]; 9327ec681f3Smrg unsigned count = exec->vtx.vert_count - last_draw->start; 93301e04c3fSmrg 9347ec681f3Smrg last_draw->count = count; 9357ec681f3Smrg exec->vtx.markers[last].end = 1; 9367ec681f3Smrg 9377ec681f3Smrg if (count) 9387ec681f3Smrg ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; 93901e04c3fSmrg 94001e04c3fSmrg /* Special handling for GL_LINE_LOOP */ 9417ec681f3Smrg if (exec->vtx.mode[last] == GL_LINE_LOOP && 9427ec681f3Smrg exec->vtx.markers[last].begin == 0) { 94301e04c3fSmrg /* We're finishing drawing a line loop. Append 0th vertex onto 94401e04c3fSmrg * end of vertex buffer so we can draw it as a line strip. 94501e04c3fSmrg */ 94601e04c3fSmrg const fi_type *src = exec->vtx.buffer_map + 9477ec681f3Smrg last_draw->start * exec->vtx.vertex_size; 94801e04c3fSmrg fi_type *dst = exec->vtx.buffer_map + 94901e04c3fSmrg exec->vtx.vert_count * exec->vtx.vertex_size; 95001e04c3fSmrg 95101e04c3fSmrg /* copy 0th vertex to end of buffer */ 95201e04c3fSmrg memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type)); 9537117f1b4Smrg 9547ec681f3Smrg last_draw->start++; /* skip vertex0 */ 9557ec681f3Smrg /* note that the count stays unchanged */ 9567ec681f3Smrg exec->vtx.mode[last] = GL_LINE_STRIP; 95701e04c3fSmrg 95801e04c3fSmrg /* Increment the vertex count so the next primitive doesn't 95901e04c3fSmrg * overwrite the last vertex which we just added. 96001e04c3fSmrg */ 96101e04c3fSmrg exec->vtx.vert_count++; 96201e04c3fSmrg exec->vtx.buffer_ptr += exec->vtx.vertex_size; 96301e04c3fSmrg } 9647117f1b4Smrg 965af69d88dSmrg try_vbo_merge(exec); 966af69d88dSmrg } 967af69d88dSmrg 968af69d88dSmrg ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 969af69d88dSmrg 970af69d88dSmrg if (exec->vtx.prim_count == VBO_MAX_PRIM) 9717ec681f3Smrg vbo_exec_vtx_flush(exec); 972af69d88dSmrg 973af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 974af69d88dSmrg _mesa_flush(ctx); 9757117f1b4Smrg } 9767117f1b4Smrg} 9777117f1b4Smrg 9787117f1b4Smrg 9793464ebd5Sriastradh/** 9803464ebd5Sriastradh * Called via glPrimitiveRestartNV() 9813464ebd5Sriastradh */ 9823464ebd5Sriastradhstatic void GLAPIENTRY 9833464ebd5Sriastradhvbo_exec_PrimitiveRestartNV(void) 9843464ebd5Sriastradh{ 9853464ebd5Sriastradh GLenum curPrim; 98601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9873464ebd5Sriastradh 9883464ebd5Sriastradh curPrim = ctx->Driver.CurrentExecPrimitive; 9893464ebd5Sriastradh 9903464ebd5Sriastradh if (curPrim == PRIM_OUTSIDE_BEGIN_END) { 99101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV"); 9923464ebd5Sriastradh } 9933464ebd5Sriastradh else { 9943464ebd5Sriastradh vbo_exec_End(); 9953464ebd5Sriastradh vbo_exec_Begin(curPrim); 9963464ebd5Sriastradh } 9973464ebd5Sriastradh} 9983464ebd5Sriastradh 9993464ebd5Sriastradh 100001e04c3fSmrgstatic void 100101e04c3fSmrgvbo_exec_vtxfmt_init(struct vbo_exec_context *exec) 10027117f1b4Smrg{ 10037ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 10047117f1b4Smrg GLvertexformat *vfmt = &exec->vtxfmt; 10057117f1b4Smrg 10067ec681f3Smrg#define NAME_AE(x) _ae_##x 10077ec681f3Smrg#define NAME_CALLLIST(x) _mesa_##x 10087ec681f3Smrg#define NAME(x) vbo_exec_##x 10097ec681f3Smrg#define NAME_ES(x) _es_##x 10107117f1b4Smrg 10117ec681f3Smrg#include "vbo_init_tmp.h" 10127117f1b4Smrg} 10137117f1b4Smrg 10147117f1b4Smrg 10157ec681f3Smrgstatic void 10167ec681f3Smrgvbo_reset_all_attr(struct vbo_exec_context *exec) 1017c1f859d4Smrg{ 10187ec681f3Smrg while (exec->vtx.enabled) { 10197ec681f3Smrg const int i = u_bit_scan64(&exec->vtx.enabled); 1020c1f859d4Smrg 10217ec681f3Smrg /* Reset the vertex attribute by setting its size to zero. */ 10227ec681f3Smrg exec->vtx.attr[i].size = 0; 10237ec681f3Smrg exec->vtx.attr[i].type = GL_FLOAT; 10247ec681f3Smrg exec->vtx.attr[i].active_size = 0; 10257ec681f3Smrg exec->vtx.attrptr[i] = NULL; 1026af69d88dSmrg } 1027c1f859d4Smrg 10287ec681f3Smrg exec->vtx.vertex_size = 0; 10293464ebd5Sriastradh} 10303464ebd5Sriastradh 1031c1f859d4Smrg 103201e04c3fSmrgvoid 10337ec681f3Smrgvbo_exec_vtx_init(struct vbo_exec_context *exec, bool use_buffer_objects) 10347117f1b4Smrg{ 10357ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 10367117f1b4Smrg 10377ec681f3Smrg if (use_buffer_objects) { 10387ec681f3Smrg /* Use buffer objects for immediate mode. */ 10397ec681f3Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 10407ec681f3Smrg exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, IMM_BUFFER_NAME); 10417ec681f3Smrg } else { 10427ec681f3Smrg /* Use allocated memory for immediate mode. */ 10437ec681f3Smrg exec->vtx.bufferobj = NULL; 10447ec681f3Smrg exec->vtx.buffer_map = 10457ec681f3Smrg align_malloc(ctx->Const.glBeginEndBufferSize, 64); 10467ec681f3Smrg exec->vtx.buffer_ptr = exec->vtx.buffer_map; 10477ec681f3Smrg } 10484a49301eSmrg 104901e04c3fSmrg vbo_exec_vtxfmt_init(exec); 10507ec681f3Smrg _mesa_noop_vtxfmt_init(ctx, &exec->vtxfmt_noop); 10517117f1b4Smrg 10527ec681f3Smrg exec->vtx.enabled = u_bit_consecutive64(0, VBO_ATTRIB_MAX); /* reset all */ 10537ec681f3Smrg vbo_reset_all_attr(exec); 10543464ebd5Sriastradh 10557ec681f3Smrg exec->vtx.info.instance_count = 1; 10567ec681f3Smrg exec->vtx.info.max_index = ~0; 10577117f1b4Smrg} 10587117f1b4Smrg 10597117f1b4Smrg 106001e04c3fSmrgvoid 106101e04c3fSmrgvbo_exec_vtx_destroy(struct vbo_exec_context *exec) 10627117f1b4Smrg{ 10634a49301eSmrg /* using a real VBO for vertex data */ 10647ec681f3Smrg struct gl_context *ctx = gl_context_from_vbo_exec(exec); 10654a49301eSmrg 10664a49301eSmrg /* True VBOs should already be unmapped 10674a49301eSmrg */ 10684a49301eSmrg if (exec->vtx.buffer_map) { 10697ec681f3Smrg assert(!exec->vtx.bufferobj || 10704a49301eSmrg exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); 10717ec681f3Smrg if (!exec->vtx.bufferobj) { 10727ec681f3Smrg align_free(exec->vtx.buffer_map); 1073c1f859d4Smrg exec->vtx.buffer_map = NULL; 10744a49301eSmrg exec->vtx.buffer_ptr = NULL; 1075c1f859d4Smrg } 10767117f1b4Smrg } 10777117f1b4Smrg 10783464ebd5Sriastradh /* Free the vertex buffer. Unmap first if needed. 10794a49301eSmrg */ 10807ec681f3Smrg if (exec->vtx.bufferobj && 10817ec681f3Smrg _mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) { 1082af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); 10833464ebd5Sriastradh } 10844a49301eSmrg _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); 10854a49301eSmrg} 10867117f1b4Smrg 10877117f1b4Smrg 10883464ebd5Sriastradh/** 108901e04c3fSmrg * If inside glBegin()/glEnd(), it should assert(0). Otherwise, if 109001e04c3fSmrg * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered 109101e04c3fSmrg * vertices, if FLUSH_UPDATE_CURRENT bit is set updates 109201e04c3fSmrg * __struct gl_contextRec::Current and gl_light_attrib::Material 109301e04c3fSmrg * 109401e04c3fSmrg * Note that the default T&L engine never clears the 109501e04c3fSmrg * FLUSH_UPDATE_CURRENT bit, even after performing the update. 109601e04c3fSmrg * 10974a49301eSmrg * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT 10984a49301eSmrg */ 109901e04c3fSmrgvoid 110001e04c3fSmrgvbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags) 11014a49301eSmrg{ 11024a49301eSmrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 11034a49301eSmrg 11047ec681f3Smrg#ifndef NDEBUG 11054a49301eSmrg /* debug check: make sure we don't get called recursively */ 11064a49301eSmrg exec->flush_call_depth++; 11074a49301eSmrg assert(exec->flush_call_depth == 1); 11084a49301eSmrg#endif 11094a49301eSmrg 1110af69d88dSmrg if (_mesa_inside_begin_end(ctx)) { 11113464ebd5Sriastradh /* We've had glBegin but not glEnd! */ 11127ec681f3Smrg#ifndef NDEBUG 11134a49301eSmrg exec->flush_call_depth--; 11144a49301eSmrg assert(exec->flush_call_depth == 0); 11154a49301eSmrg#endif 11164a49301eSmrg return; 11174a49301eSmrg } 11187117f1b4Smrg 11197ec681f3Smrg /* Flush (draw). */ 11207ec681f3Smrg vbo_exec_FlushVertices_internal(exec, flags); 11214a49301eSmrg 11227ec681f3Smrg#ifndef NDEBUG 11234a49301eSmrg exec->flush_call_depth--; 11244a49301eSmrg assert(exec->flush_call_depth == 0); 11254a49301eSmrg#endif 11267117f1b4Smrg} 11277117f1b4Smrg 11287117f1b4Smrg 11294a49301eSmrgvoid GLAPIENTRY 11303464ebd5Sriastradh_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 11314a49301eSmrg{ 11327ec681f3Smrg vbo_exec_Color4f(r, g, b, a); 11334a49301eSmrg} 11344a49301eSmrg 11354a49301eSmrg 11364a49301eSmrgvoid GLAPIENTRY 11373464ebd5Sriastradh_es_Normal3f(GLfloat x, GLfloat y, GLfloat z) 11384a49301eSmrg{ 11397ec681f3Smrg vbo_exec_Normal3f(x, y, z); 11404a49301eSmrg} 11414a49301eSmrg 11424a49301eSmrg 11434a49301eSmrgvoid GLAPIENTRY 11443464ebd5Sriastradh_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) 11454a49301eSmrg{ 11467ec681f3Smrg vbo_exec_MultiTexCoord4f(target, s, t, r, q); 11474a49301eSmrg} 11484a49301eSmrg 11493464ebd5Sriastradh 11504a49301eSmrgvoid GLAPIENTRY 11513464ebd5Sriastradh_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params) 11524a49301eSmrg{ 11537ec681f3Smrg vbo_exec_Materialfv(face, pname, params); 11544a49301eSmrg} 11554a49301eSmrg 11564a49301eSmrg 11574a49301eSmrgvoid GLAPIENTRY 11583464ebd5Sriastradh_es_Materialf(GLenum face, GLenum pname, GLfloat param) 11593464ebd5Sriastradh{ 11603464ebd5Sriastradh GLfloat p[4]; 11613464ebd5Sriastradh p[0] = param; 11623464ebd5Sriastradh p[1] = p[2] = p[3] = 0.0F; 11637ec681f3Smrg vbo_exec_Materialfv(face, pname, p); 11643464ebd5Sriastradh} 11653464ebd5Sriastradh 11663464ebd5Sriastradh 11673464ebd5Sriastradh/** 11683464ebd5Sriastradh * A special version of glVertexAttrib4f that does not treat index 0 as 11693464ebd5Sriastradh * VBO_ATTRIB_POS. 11703464ebd5Sriastradh */ 11713464ebd5Sriastradhstatic void 11723464ebd5SriastradhVertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 11733464ebd5Sriastradh{ 11743464ebd5Sriastradh GET_CURRENT_CONTEXT(ctx); 11753464ebd5Sriastradh if (index < MAX_VERTEX_GENERIC_ATTRIBS) 117601e04c3fSmrg ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w); 11773464ebd5Sriastradh else 11783464ebd5Sriastradh ERROR(GL_INVALID_VALUE); 11793464ebd5Sriastradh} 11803464ebd5Sriastradh 11813464ebd5Sriastradhvoid GLAPIENTRY 11823464ebd5Sriastradh_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 11833464ebd5Sriastradh{ 11843464ebd5Sriastradh VertexAttrib4f_nopos(index, x, y, z, w); 11853464ebd5Sriastradh} 11863464ebd5Sriastradh 11873464ebd5Sriastradh 11883464ebd5Sriastradhvoid GLAPIENTRY 11893464ebd5Sriastradh_es_VertexAttrib1f(GLuint indx, GLfloat x) 11903464ebd5Sriastradh{ 11913464ebd5Sriastradh VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f); 11923464ebd5Sriastradh} 11933464ebd5Sriastradh 11943464ebd5Sriastradh 11953464ebd5Sriastradhvoid GLAPIENTRY 11963464ebd5Sriastradh_es_VertexAttrib1fv(GLuint indx, const GLfloat* values) 11973464ebd5Sriastradh{ 11983464ebd5Sriastradh VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f); 11993464ebd5Sriastradh} 12003464ebd5Sriastradh 12013464ebd5Sriastradh 12023464ebd5Sriastradhvoid GLAPIENTRY 12033464ebd5Sriastradh_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) 12043464ebd5Sriastradh{ 12053464ebd5Sriastradh VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f); 12063464ebd5Sriastradh} 12073464ebd5Sriastradh 12083464ebd5Sriastradh 12093464ebd5Sriastradhvoid GLAPIENTRY 12103464ebd5Sriastradh_es_VertexAttrib2fv(GLuint indx, const GLfloat* values) 12113464ebd5Sriastradh{ 12123464ebd5Sriastradh VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f); 12133464ebd5Sriastradh} 12143464ebd5Sriastradh 12153464ebd5Sriastradh 12163464ebd5Sriastradhvoid GLAPIENTRY 12173464ebd5Sriastradh_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) 12183464ebd5Sriastradh{ 12193464ebd5Sriastradh VertexAttrib4f_nopos(indx, x, y, z, 1.0f); 12203464ebd5Sriastradh} 12213464ebd5Sriastradh 12223464ebd5Sriastradh 12233464ebd5Sriastradhvoid GLAPIENTRY 12243464ebd5Sriastradh_es_VertexAttrib3fv(GLuint indx, const GLfloat* values) 12253464ebd5Sriastradh{ 12263464ebd5Sriastradh VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f); 12273464ebd5Sriastradh} 12283464ebd5Sriastradh 12293464ebd5Sriastradh 12303464ebd5Sriastradhvoid GLAPIENTRY 12313464ebd5Sriastradh_es_VertexAttrib4fv(GLuint indx, const GLfloat* values) 12324a49301eSmrg{ 12333464ebd5Sriastradh VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]); 12344a49301eSmrg} 1235