17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 47117f1b4Smrg * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg * 247117f1b4Smrg * Authors: 25af69d88dSmrg * Keith Whitwell <keithw@vmware.com> 267117f1b4Smrg */ 277117f1b4Smrg 287117f1b4Smrg 29c1f859d4Smrg#include "main/glheader.h" 3001e04c3fSmrg#include "main/arrayobj.h" 3101e04c3fSmrg#include "main/api_arrayelt.h" 32c1f859d4Smrg#include "main/vtxfmt.h" 3301e04c3fSmrg#include "vbo_private.h" 3401e04c3fSmrg 3501e04c3fSmrgconst GLubyte 3601e04c3fSmrg_vbo_attribute_alias_map[VP_MODE_MAX][VERT_ATTRIB_MAX] = { 3701e04c3fSmrg /* VP_MODE_FF: */ 3801e04c3fSmrg { 3901e04c3fSmrg VBO_ATTRIB_POS, /* VERT_ATTRIB_POS */ 4001e04c3fSmrg VBO_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 4101e04c3fSmrg VBO_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 4201e04c3fSmrg VBO_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 4301e04c3fSmrg VBO_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 4401e04c3fSmrg VBO_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 4501e04c3fSmrg VBO_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 4601e04c3fSmrg VBO_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 4701e04c3fSmrg VBO_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 4801e04c3fSmrg VBO_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 4901e04c3fSmrg VBO_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 5001e04c3fSmrg VBO_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 5101e04c3fSmrg VBO_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 5201e04c3fSmrg VBO_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 5301e04c3fSmrg VBO_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 5401e04c3fSmrg VBO_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 5501e04c3fSmrg VBO_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 5601e04c3fSmrg VBO_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 5701e04c3fSmrg VBO_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 5801e04c3fSmrg VBO_ATTRIB_MAT_FRONT_AMBIENT, /* VERT_ATTRIB_GENERIC4 */ 5901e04c3fSmrg VBO_ATTRIB_MAT_BACK_AMBIENT, /* VERT_ATTRIB_GENERIC5 */ 6001e04c3fSmrg VBO_ATTRIB_MAT_FRONT_DIFFUSE, /* VERT_ATTRIB_GENERIC6 */ 6101e04c3fSmrg VBO_ATTRIB_MAT_BACK_DIFFUSE, /* VERT_ATTRIB_GENERIC7 */ 6201e04c3fSmrg VBO_ATTRIB_MAT_FRONT_SPECULAR, /* VERT_ATTRIB_GENERIC8 */ 6301e04c3fSmrg VBO_ATTRIB_MAT_BACK_SPECULAR, /* VERT_ATTRIB_GENERIC9 */ 6401e04c3fSmrg VBO_ATTRIB_MAT_FRONT_EMISSION, /* VERT_ATTRIB_GENERIC10 */ 6501e04c3fSmrg VBO_ATTRIB_MAT_BACK_EMISSION, /* VERT_ATTRIB_GENERIC11 */ 6601e04c3fSmrg VBO_ATTRIB_MAT_FRONT_SHININESS, /* VERT_ATTRIB_GENERIC12 */ 6701e04c3fSmrg VBO_ATTRIB_MAT_BACK_SHININESS, /* VERT_ATTRIB_GENERIC13 */ 6801e04c3fSmrg VBO_ATTRIB_MAT_FRONT_INDEXES, /* VERT_ATTRIB_GENERIC14 */ 697ec681f3Smrg VBO_ATTRIB_MAT_BACK_INDEXES, /* VERT_ATTRIB_GENERIC15 */ 707ec681f3Smrg VBO_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 7101e04c3fSmrg }, 7201e04c3fSmrg 7301e04c3fSmrg /* VP_MODE_SHADER: */ 7401e04c3fSmrg { 7501e04c3fSmrg VBO_ATTRIB_POS, /* VERT_ATTRIB_POS */ 7601e04c3fSmrg VBO_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 7701e04c3fSmrg VBO_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 7801e04c3fSmrg VBO_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 7901e04c3fSmrg VBO_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 8001e04c3fSmrg VBO_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 8101e04c3fSmrg VBO_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 8201e04c3fSmrg VBO_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 8301e04c3fSmrg VBO_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 8401e04c3fSmrg VBO_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 8501e04c3fSmrg VBO_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 8601e04c3fSmrg VBO_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 8701e04c3fSmrg VBO_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 8801e04c3fSmrg VBO_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 8901e04c3fSmrg VBO_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 9001e04c3fSmrg VBO_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 9101e04c3fSmrg VBO_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 9201e04c3fSmrg VBO_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 9301e04c3fSmrg VBO_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 9401e04c3fSmrg VBO_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 9501e04c3fSmrg VBO_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 9601e04c3fSmrg VBO_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 9701e04c3fSmrg VBO_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 9801e04c3fSmrg VBO_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 9901e04c3fSmrg VBO_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 10001e04c3fSmrg VBO_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 10101e04c3fSmrg VBO_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 10201e04c3fSmrg VBO_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 10301e04c3fSmrg VBO_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 10401e04c3fSmrg VBO_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 1057ec681f3Smrg VBO_ATTRIB_GENERIC15, /* VERT_ATTRIB_GENERIC15 */ 1067ec681f3Smrg VBO_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 10701e04c3fSmrg } 10801e04c3fSmrg}; 1093464ebd5Sriastradh 1103464ebd5Sriastradh 11101e04c3fSmrgvoid 1127ec681f3Smrgvbo_exec_init(struct gl_context *ctx, bool use_buffer_objects) 1137117f1b4Smrg{ 1147117f1b4Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1157117f1b4Smrg 1167ec681f3Smrg vbo_exec_vtx_init(exec, use_buffer_objects); 1177117f1b4Smrg 1187117f1b4Smrg ctx->Driver.NeedFlush = 0; 1197117f1b4Smrg ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 1207117f1b4Smrg 12101e04c3fSmrg exec->eval.recalculate_maps = GL_TRUE; 1227117f1b4Smrg} 1237117f1b4Smrg 1247117f1b4Smrg 1253464ebd5Sriastradhvoid vbo_exec_destroy( struct gl_context *ctx ) 1267117f1b4Smrg{ 1277117f1b4Smrg struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 1287117f1b4Smrg 1297117f1b4Smrg vbo_exec_vtx_destroy( exec ); 1307117f1b4Smrg} 1317117f1b4Smrg 1323464ebd5Sriastradh 133af69d88dSmrg/** 134af69d88dSmrg * In some degenarate cases we can improve our ability to merge 135af69d88dSmrg * consecutive primitives. For example: 136af69d88dSmrg * glBegin(GL_LINE_STRIP); 137af69d88dSmrg * glVertex(1); 138af69d88dSmrg * glVertex(1); 139af69d88dSmrg * glEnd(); 140af69d88dSmrg * glBegin(GL_LINE_STRIP); 141af69d88dSmrg * glVertex(1); 142af69d88dSmrg * glVertex(1); 143af69d88dSmrg * glEnd(); 144af69d88dSmrg * Can be merged as a GL_LINES prim with four vertices. 145af69d88dSmrg * 146af69d88dSmrg * This function converts 2-vertex line strips/loops into GL_LINES, etc. 147af69d88dSmrg */ 148af69d88dSmrgvoid 1497ec681f3Smrgvbo_try_prim_conversion(GLubyte *mode, unsigned *count) 150af69d88dSmrg{ 1517ec681f3Smrg if (*mode == GL_LINE_STRIP && *count == 2) { 152af69d88dSmrg /* convert 2-vertex line strip to a separate line */ 1537ec681f3Smrg *mode = GL_LINES; 1547ec681f3Smrg } else if ((*mode == GL_TRIANGLE_STRIP || *mode == GL_TRIANGLE_FAN) && 1557ec681f3Smrg *count == 3) { 156af69d88dSmrg /* convert 3-vertex tri strip or fan to a separate triangle */ 1577ec681f3Smrg *mode = GL_TRIANGLES; 158af69d88dSmrg } 159af69d88dSmrg 160af69d88dSmrg /* Note: we can't convert a 4-vertex quad strip to a separate quad 161af69d88dSmrg * because the vertex ordering is different. We'd have to muck 162af69d88dSmrg * around in the vertex data to make it work. 163af69d88dSmrg */ 164af69d88dSmrg} 165af69d88dSmrg 166af69d88dSmrg 167af69d88dSmrg/** 1687ec681f3Smrg * Function for merging two subsequent glBegin/glEnd draws. 1697ec681f3Smrg * Return true if p1 was concatenated onto p0 (to discard p1 in the caller). 170af69d88dSmrg */ 171af69d88dSmrgbool 1727ec681f3Smrgvbo_merge_draws(struct gl_context *ctx, bool in_dlist, 1737ec681f3Smrg GLubyte mode0, GLubyte mode1, 1747ec681f3Smrg unsigned start0, unsigned start1, 1757ec681f3Smrg unsigned *count0, unsigned count1, 1767ec681f3Smrg unsigned basevertex0, unsigned basevertex1, 1777ec681f3Smrg bool *end0, bool begin1, bool end1) 178af69d88dSmrg{ 179af69d88dSmrg /* The prim mode must match (ex: both GL_TRIANGLES) */ 1807ec681f3Smrg if (mode0 != mode1) 181af69d88dSmrg return false; 182af69d88dSmrg 183af69d88dSmrg /* p1's vertices must come right after p0 */ 1847ec681f3Smrg if (start0 + *count0 != start1) 185af69d88dSmrg return false; 186af69d88dSmrg 1877ec681f3Smrg /* This checks whether mode is equal to any line primitive type, taking 1887ec681f3Smrg * advantage of the fact that primitives types go from 0 to 14. 1897ec681f3Smrg * 1907ec681f3Smrg * Lines and lines with adjacency reset the line stipple pattern for every 1917ec681f3Smrg * primitive, so draws can be merged even if line stippling is enabled. 1927ec681f3Smrg */ 1937ec681f3Smrg if ((1 << mode0) & 1947ec681f3Smrg ((1 << GL_LINE_LOOP) | 1957ec681f3Smrg (1 << GL_LINE_STRIP) | 1967ec681f3Smrg (1 << GL_LINE_STRIP_ADJACENCY))) { 1977ec681f3Smrg /* "begin" resets the line stipple pattern during line stipple emulation 1987ec681f3Smrg * in tnl. 1997ec681f3Smrg * 2007ec681f3Smrg * StippleFlag can be unknown when compiling a display list. 2017ec681f3Smrg * 2027ec681f3Smrg * Other uses of "begin" are internal to the vbo module, and in those 2037ec681f3Smrg * cases, "begin" is not used after merging draws. 2047ec681f3Smrg */ 2057ec681f3Smrg if (begin1 == 1 && (in_dlist || ctx->Line.StippleFlag)) 2067ec681f3Smrg return false; 207af69d88dSmrg 2087ec681f3Smrg /* _mesa_prim::end is irrelevant at this point and is only used 2097ec681f3Smrg * before this function is called. 2107ec681f3Smrg */ 2117ec681f3Smrg } 212af69d88dSmrg 2137ec681f3Smrg assert(basevertex0 == basevertex1); 214af69d88dSmrg 2157ec681f3Smrg switch (mode0) { 2167ec681f3Smrg case GL_POINTS: 2177ec681f3Smrg /* can always merge subsequent GL_POINTS primitives */ 2187ec681f3Smrg break; 2197ec681f3Smrg /* check independent primitives with no extra vertices */ 2207ec681f3Smrg case GL_LINES: 2217ec681f3Smrg if (*count0 % 2) 2227ec681f3Smrg return false; 2237ec681f3Smrg break; 2247ec681f3Smrg case GL_TRIANGLES: 2257ec681f3Smrg if (*count0 % 3) 2267ec681f3Smrg return false; 2277ec681f3Smrg break; 2287ec681f3Smrg case GL_QUADS: 2297ec681f3Smrg case GL_LINES_ADJACENCY: 2307ec681f3Smrg if (*count0 % 4) 2317ec681f3Smrg return false; 2327ec681f3Smrg break; 2337ec681f3Smrg case GL_TRIANGLES_ADJACENCY: 2347ec681f3Smrg if (*count0 % 6) 2357ec681f3Smrg return false; 2367ec681f3Smrg break; 2377ec681f3Smrg case GL_PATCHES: 2387ec681f3Smrg /* "patch_vertices" can be unknown when compiling a display list. */ 2397ec681f3Smrg if (in_dlist || 2407ec681f3Smrg *count0 % ctx->TessCtrlProgram.patch_vertices) 2417ec681f3Smrg return false; 2427ec681f3Smrg break; 2437ec681f3Smrg default: 2447ec681f3Smrg return false; 2457ec681f3Smrg } 246af69d88dSmrg 2477ec681f3Smrg /* Merge draws. */ 2487ec681f3Smrg *count0 += count1; 2497ec681f3Smrg *end0 = end1; 2507ec681f3Smrg return true; 251af69d88dSmrg} 252af69d88dSmrg 253af69d88dSmrg/** 2547ec681f3Smrg * Copy zero, one or two vertices from the current vertex buffer into 2557ec681f3Smrg * the temporary "copy" buffer. 2567ec681f3Smrg * This is used when a single primitive overflows a vertex buffer and 2577ec681f3Smrg * we need to continue the primitive in a new vertex buffer. 2587ec681f3Smrg * The temporary "copy" buffer holds the vertices which need to get 2597ec681f3Smrg * copied from the old buffer to the new one. 260af69d88dSmrg */ 2617ec681f3Smrgunsigned 2627ec681f3Smrgvbo_copy_vertices(struct gl_context *ctx, 2637ec681f3Smrg GLenum mode, 2647ec681f3Smrg unsigned start, unsigned *pcount, bool begin, 2657ec681f3Smrg unsigned vertex_size, 2667ec681f3Smrg bool in_dlist, 2677ec681f3Smrg fi_type *dst, 2687ec681f3Smrg const fi_type *src) 269af69d88dSmrg{ 2707ec681f3Smrg const unsigned count = *pcount; 2717ec681f3Smrg unsigned copy = 0; 2727ec681f3Smrg 2737ec681f3Smrg switch (mode) { 2747ec681f3Smrg case GL_POINTS: 2757ec681f3Smrg return 0; 2767ec681f3Smrg case GL_LINES: 2777ec681f3Smrg copy = count % 2; 2787ec681f3Smrg break; 2797ec681f3Smrg case GL_TRIANGLES: 2807ec681f3Smrg copy = count % 3; 2817ec681f3Smrg break; 2827ec681f3Smrg case GL_QUADS: 2837ec681f3Smrg case GL_LINES_ADJACENCY: 2847ec681f3Smrg copy = count % 4; 2857ec681f3Smrg break; 2867ec681f3Smrg case GL_TRIANGLES_ADJACENCY: 2877ec681f3Smrg copy = count % 6; 2887ec681f3Smrg break; 2897ec681f3Smrg case GL_LINE_STRIP: 2907ec681f3Smrg copy = MIN2(1, count); 2917ec681f3Smrg break; 2927ec681f3Smrg case GL_LINE_STRIP_ADJACENCY: 2937ec681f3Smrg /* We need to copy 3 vertices, because: 2947ec681f3Smrg * Last strip: ---o---o---x (last line) 2957ec681f3Smrg * Next strip: x---o---o--- (next line) 2967ec681f3Smrg */ 2977ec681f3Smrg copy = MIN2(3, count); 2987ec681f3Smrg break; 2997ec681f3Smrg case GL_PATCHES: 3007ec681f3Smrg if (in_dlist) { 3017ec681f3Smrg /* We don't know the value of GL_PATCH_VERTICES when compiling 3027ec681f3Smrg * a display list. 3037ec681f3Smrg * 3047ec681f3Smrg * Fail an assertion in debug builds and use the value of 3 3057ec681f3Smrg * in release builds, which is more likely than any other value. 3067ec681f3Smrg */ 3077ec681f3Smrg assert(!"patch_vertices is unknown"); 3087ec681f3Smrg copy = count % 3; 3097ec681f3Smrg } else { 3107ec681f3Smrg copy = count % ctx->TessCtrlProgram.patch_vertices; 3117ec681f3Smrg } 3127ec681f3Smrg break; 3137ec681f3Smrg case GL_LINE_LOOP: 3147ec681f3Smrg if (!in_dlist && begin == 0) { 3157ec681f3Smrg /* We're dealing with the second or later section of a split/wrapped 3167ec681f3Smrg * GL_LINE_LOOP. Since we're converting line loops to line strips, 3177ec681f3Smrg * we've already incremented the last_prim->start counter by one to 3187ec681f3Smrg * skip the 0th vertex in the loop. We need to undo that (effectively 3197ec681f3Smrg * subtract one from last_prim->start) so that we copy the 0th vertex 3207ec681f3Smrg * to the next vertex buffer. 3217ec681f3Smrg */ 3227ec681f3Smrg assert(start > 0); 3237ec681f3Smrg src -= vertex_size; 3247ec681f3Smrg } 3257ec681f3Smrg FALLTHROUGH; 3267ec681f3Smrg case GL_TRIANGLE_FAN: 3277ec681f3Smrg case GL_POLYGON: 3287ec681f3Smrg if (count == 0) { 3297ec681f3Smrg return 0; 3307ec681f3Smrg } else if (count == 1) { 3317ec681f3Smrg memcpy(dst, src + 0, vertex_size * sizeof(GLfloat)); 3327ec681f3Smrg return 1; 3337ec681f3Smrg } else { 3347ec681f3Smrg memcpy(dst, src + 0, vertex_size * sizeof(GLfloat)); 3357ec681f3Smrg memcpy(dst + vertex_size, src + (count - 1) * vertex_size, 3367ec681f3Smrg vertex_size * sizeof(GLfloat)); 3377ec681f3Smrg return 2; 3387ec681f3Smrg } 3397ec681f3Smrg case GL_TRIANGLE_STRIP: 3407ec681f3Smrg /* Draw an even number of triangles to keep front/back facing the same. */ 3417ec681f3Smrg *pcount -= count % 2; 3427ec681f3Smrg FALLTHROUGH; 3437ec681f3Smrg case GL_QUAD_STRIP: 3447ec681f3Smrg if (count <= 1) 3457ec681f3Smrg copy = count; 3467ec681f3Smrg else 3477ec681f3Smrg copy = 2 + (count % 2); 3487ec681f3Smrg break; 3497ec681f3Smrg case PRIM_OUTSIDE_BEGIN_END: 3507ec681f3Smrg return 0; 3517ec681f3Smrg case GL_TRIANGLE_STRIP_ADJACENCY: 3527ec681f3Smrg /* TODO: Splitting tri strips with adjacency is too complicated. */ 3537ec681f3Smrg default: 3547ec681f3Smrg unreachable("Unexpected primitive type"); 3557ec681f3Smrg return 0; 3567ec681f3Smrg } 357af69d88dSmrg 3587ec681f3Smrg memcpy(dst, src + (count - copy) * vertex_size, 3597ec681f3Smrg copy * vertex_size * sizeof(GLfloat)); 3607ec681f3Smrg return copy; 361af69d88dSmrg} 362