1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Keith Whitwell <keithw@vmware.com>
26 */
27
28
29#include "main/glheader.h"
30#include "main/arrayobj.h"
31#include "main/api_arrayelt.h"
32#include "main/vtxfmt.h"
33#include "vbo_private.h"
34
35const GLubyte
36_vbo_attribute_alias_map[VP_MODE_MAX][VERT_ATTRIB_MAX] = {
37   /* VP_MODE_FF: */
38   {
39      VBO_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
40      VBO_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
41      VBO_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
42      VBO_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
43      VBO_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
44      VBO_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
45      VBO_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
46      VBO_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
47      VBO_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
48      VBO_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
49      VBO_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
50      VBO_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
51      VBO_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
52      VBO_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
53      VBO_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
54      VBO_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
55      VBO_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
56      VBO_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
57      VBO_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
58      VBO_ATTRIB_MAT_FRONT_AMBIENT,   /* VERT_ATTRIB_GENERIC4 */
59      VBO_ATTRIB_MAT_BACK_AMBIENT,    /* VERT_ATTRIB_GENERIC5 */
60      VBO_ATTRIB_MAT_FRONT_DIFFUSE,   /* VERT_ATTRIB_GENERIC6 */
61      VBO_ATTRIB_MAT_BACK_DIFFUSE,    /* VERT_ATTRIB_GENERIC7 */
62      VBO_ATTRIB_MAT_FRONT_SPECULAR,  /* VERT_ATTRIB_GENERIC8 */
63      VBO_ATTRIB_MAT_BACK_SPECULAR,   /* VERT_ATTRIB_GENERIC9 */
64      VBO_ATTRIB_MAT_FRONT_EMISSION,  /* VERT_ATTRIB_GENERIC10 */
65      VBO_ATTRIB_MAT_BACK_EMISSION,   /* VERT_ATTRIB_GENERIC11 */
66      VBO_ATTRIB_MAT_FRONT_SHININESS, /* VERT_ATTRIB_GENERIC12 */
67      VBO_ATTRIB_MAT_BACK_SHININESS,  /* VERT_ATTRIB_GENERIC13 */
68      VBO_ATTRIB_MAT_FRONT_INDEXES,   /* VERT_ATTRIB_GENERIC14 */
69      VBO_ATTRIB_MAT_BACK_INDEXES,    /* VERT_ATTRIB_GENERIC15 */
70      VBO_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
71   },
72
73   /* VP_MODE_SHADER: */
74   {
75      VBO_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
76      VBO_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
77      VBO_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
78      VBO_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
79      VBO_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
80      VBO_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
81      VBO_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
82      VBO_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
83      VBO_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
84      VBO_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
85      VBO_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
86      VBO_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
87      VBO_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
88      VBO_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
89      VBO_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
90      VBO_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
91      VBO_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
92      VBO_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
93      VBO_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
94      VBO_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
95      VBO_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
96      VBO_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
97      VBO_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
98      VBO_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
99      VBO_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
100      VBO_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
101      VBO_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
102      VBO_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
103      VBO_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
104      VBO_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
105      VBO_ATTRIB_GENERIC15,           /* VERT_ATTRIB_GENERIC15 */
106      VBO_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
107   }
108};
109
110
111void
112vbo_exec_init(struct gl_context *ctx, bool use_buffer_objects)
113{
114   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
115
116   vbo_exec_vtx_init(exec, use_buffer_objects);
117
118   ctx->Driver.NeedFlush = 0;
119   ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
120
121   exec->eval.recalculate_maps = GL_TRUE;
122}
123
124
125void vbo_exec_destroy( struct gl_context *ctx )
126{
127   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
128
129   vbo_exec_vtx_destroy( exec );
130}
131
132
133/**
134 * In some degenarate cases we can improve our ability to merge
135 * consecutive primitives.  For example:
136 * glBegin(GL_LINE_STRIP);
137 * glVertex(1);
138 * glVertex(1);
139 * glEnd();
140 * glBegin(GL_LINE_STRIP);
141 * glVertex(1);
142 * glVertex(1);
143 * glEnd();
144 * Can be merged as a GL_LINES prim with four vertices.
145 *
146 * This function converts 2-vertex line strips/loops into GL_LINES, etc.
147 */
148void
149vbo_try_prim_conversion(GLubyte *mode, unsigned *count)
150{
151   if (*mode == GL_LINE_STRIP && *count == 2) {
152      /* convert 2-vertex line strip to a separate line */
153      *mode = GL_LINES;
154   } else if ((*mode == GL_TRIANGLE_STRIP || *mode == GL_TRIANGLE_FAN) &&
155              *count == 3) {
156      /* convert 3-vertex tri strip or fan to a separate triangle */
157      *mode = GL_TRIANGLES;
158   }
159
160   /* Note: we can't convert a 4-vertex quad strip to a separate quad
161    * because the vertex ordering is different.  We'd have to muck
162    * around in the vertex data to make it work.
163    */
164}
165
166
167/**
168 * Function for merging two subsequent glBegin/glEnd draws.
169 * Return true if p1 was concatenated onto p0 (to discard p1 in the caller).
170 */
171bool
172vbo_merge_draws(struct gl_context *ctx, bool in_dlist,
173                GLubyte mode0, GLubyte mode1,
174                unsigned start0, unsigned start1,
175                unsigned *count0, unsigned count1,
176                unsigned basevertex0, unsigned basevertex1,
177                bool *end0, bool begin1, bool end1)
178{
179   /* The prim mode must match (ex: both GL_TRIANGLES) */
180   if (mode0 != mode1)
181      return false;
182
183   /* p1's vertices must come right after p0 */
184   if (start0 + *count0 != start1)
185      return false;
186
187   /* This checks whether mode is equal to any line primitive type, taking
188    * advantage of the fact that primitives types go from 0 to 14.
189    *
190    * Lines and lines with adjacency reset the line stipple pattern for every
191    * primitive, so draws can be merged even if line stippling is enabled.
192    */
193   if ((1 << mode0) &
194       ((1 << GL_LINE_LOOP) |
195        (1 << GL_LINE_STRIP) |
196        (1 << GL_LINE_STRIP_ADJACENCY))) {
197      /* "begin" resets the line stipple pattern during line stipple emulation
198       * in tnl.
199       *
200       * StippleFlag can be unknown when compiling a display list.
201       *
202       * Other uses of "begin" are internal to the vbo module, and in those
203       * cases, "begin" is not used after merging draws.
204       */
205      if (begin1 == 1 && (in_dlist || ctx->Line.StippleFlag))
206         return false;
207
208      /* _mesa_prim::end is irrelevant at this point and is only used
209       * before this function is called.
210       */
211   }
212
213   assert(basevertex0 == basevertex1);
214
215   switch (mode0) {
216   case GL_POINTS:
217      /* can always merge subsequent GL_POINTS primitives */
218      break;
219   /* check independent primitives with no extra vertices */
220   case GL_LINES:
221      if (*count0 % 2)
222         return false;
223      break;
224   case GL_TRIANGLES:
225      if (*count0 % 3)
226         return false;
227      break;
228   case GL_QUADS:
229   case GL_LINES_ADJACENCY:
230      if (*count0 % 4)
231         return false;
232      break;
233   case GL_TRIANGLES_ADJACENCY:
234      if (*count0 % 6)
235         return false;
236      break;
237   case GL_PATCHES:
238      /* "patch_vertices" can be unknown when compiling a display list. */
239      if (in_dlist ||
240          *count0 % ctx->TessCtrlProgram.patch_vertices)
241         return false;
242      break;
243   default:
244      return false;
245   }
246
247   /* Merge draws. */
248   *count0 += count1;
249   *end0 = end1;
250   return true;
251}
252
253/**
254 * Copy zero, one or two vertices from the current vertex buffer into
255 * the temporary "copy" buffer.
256 * This is used when a single primitive overflows a vertex buffer and
257 * we need to continue the primitive in a new vertex buffer.
258 * The temporary "copy" buffer holds the vertices which need to get
259 * copied from the old buffer to the new one.
260 */
261unsigned
262vbo_copy_vertices(struct gl_context *ctx,
263                  GLenum mode,
264                  unsigned start, unsigned *pcount, bool begin,
265                  unsigned vertex_size,
266                  bool in_dlist,
267                  fi_type *dst,
268                  const fi_type *src)
269{
270   const unsigned count = *pcount;
271   unsigned copy = 0;
272
273   switch (mode) {
274   case GL_POINTS:
275      return 0;
276   case GL_LINES:
277      copy = count % 2;
278      break;
279   case GL_TRIANGLES:
280      copy = count % 3;
281      break;
282   case GL_QUADS:
283   case GL_LINES_ADJACENCY:
284      copy = count % 4;
285      break;
286   case GL_TRIANGLES_ADJACENCY:
287      copy = count % 6;
288      break;
289   case GL_LINE_STRIP:
290      copy = MIN2(1, count);
291      break;
292   case GL_LINE_STRIP_ADJACENCY:
293      /* We need to copy 3 vertices, because:
294       *    Last strip:  ---o---o---x     (last line)
295       *    Next strip:     x---o---o---  (next line)
296       */
297      copy = MIN2(3, count);
298      break;
299   case GL_PATCHES:
300      if (in_dlist) {
301         /* We don't know the value of GL_PATCH_VERTICES when compiling
302          * a display list.
303          *
304          * Fail an assertion in debug builds and use the value of 3
305          * in release builds, which is more likely than any other value.
306          */
307         assert(!"patch_vertices is unknown");
308         copy = count % 3;
309      } else {
310         copy = count % ctx->TessCtrlProgram.patch_vertices;
311      }
312      break;
313   case GL_LINE_LOOP:
314      if (!in_dlist && begin == 0) {
315         /* We're dealing with the second or later section of a split/wrapped
316          * GL_LINE_LOOP.  Since we're converting line loops to line strips,
317          * we've already incremented the last_prim->start counter by one to
318          * skip the 0th vertex in the loop.  We need to undo that (effectively
319          * subtract one from last_prim->start) so that we copy the 0th vertex
320          * to the next vertex buffer.
321          */
322         assert(start > 0);
323         src -= vertex_size;
324      }
325      FALLTHROUGH;
326   case GL_TRIANGLE_FAN:
327   case GL_POLYGON:
328      if (count == 0) {
329         return 0;
330      } else if (count == 1) {
331         memcpy(dst, src + 0, vertex_size * sizeof(GLfloat));
332         return 1;
333      } else {
334         memcpy(dst, src + 0, vertex_size * sizeof(GLfloat));
335         memcpy(dst + vertex_size, src + (count - 1) * vertex_size,
336                vertex_size * sizeof(GLfloat));
337         return 2;
338      }
339   case GL_TRIANGLE_STRIP:
340      /* Draw an even number of triangles to keep front/back facing the same. */
341      *pcount -= count % 2;
342      FALLTHROUGH;
343   case GL_QUAD_STRIP:
344      if (count <= 1)
345         copy = count;
346      else
347         copy = 2 + (count % 2);
348      break;
349   case PRIM_OUTSIDE_BEGIN_END:
350      return 0;
351   case GL_TRIANGLE_STRIP_ADJACENCY:
352      /* TODO: Splitting tri strips with adjacency is too complicated. */
353   default:
354      unreachable("Unexpected primitive type");
355      return 0;
356   }
357
358   memcpy(dst, src + (count - copy) * vertex_size,
359          copy * vertex_size * sizeof(GLfloat));
360   return copy;
361}
362