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