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