1848b8605Smrg/**************************************************************************
2848b8605Smrg
3848b8605SmrgCopyright 2002-2008 VMware, Inc.
4848b8605Smrg
5848b8605SmrgAll Rights Reserved.
6848b8605Smrg
7848b8605SmrgPermission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrgcopy of this software and associated documentation files (the "Software"),
9848b8605Smrgto deal in the Software without restriction, including without limitation
10848b8605Smrgon the rights to use, copy, modify, merge, publish, distribute, sub
11848b8605Smrglicense, and/or sell copies of the Software, and to permit persons to whom
12848b8605Smrgthe Software is furnished to do so, subject to the following conditions:
13848b8605Smrg
14848b8605SmrgThe above copyright notice and this permission notice (including the next
15848b8605Smrgparagraph) shall be included in all copies or substantial portions of the
16848b8605SmrgSoftware.
17848b8605Smrg
18848b8605SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19848b8605SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20848b8605SmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21848b8605SmrgVMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22848b8605SmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23848b8605SmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24848b8605SmrgUSE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg
26848b8605Smrg**************************************************************************/
27848b8605Smrg
28848b8605Smrg/*
29848b8605Smrg * Authors:
30848b8605Smrg *   Keith Whitwell <keithw@vmware.com>
31848b8605Smrg */
32848b8605Smrg
33848b8605Smrg#include "main/glheader.h"
34848b8605Smrg#include "main/bufferobj.h"
35848b8605Smrg#include "main/context.h"
36848b8605Smrg#include "main/macros.h"
37848b8605Smrg#include "main/vtxfmt.h"
38848b8605Smrg#include "main/dlist.h"
39848b8605Smrg#include "main/eval.h"
40848b8605Smrg#include "main/state.h"
41848b8605Smrg#include "main/light.h"
42848b8605Smrg#include "main/api_arrayelt.h"
43b8e80941Smrg#include "main/draw_validate.h"
44848b8605Smrg#include "main/dispatch.h"
45b8e80941Smrg#include "util/bitscan.h"
46848b8605Smrg
47848b8605Smrg#include "vbo_noop.h"
48b8e80941Smrg#include "vbo_private.h"
49848b8605Smrg
50848b8605Smrg
51848b8605Smrg/** ID/name for immediate-mode VBO */
52848b8605Smrg#define IMM_BUFFER_NAME 0xaabbccdd
53848b8605Smrg
54848b8605Smrg
55b8e80941Smrgstatic void
56b8e80941Smrgvbo_reset_all_attr(struct vbo_exec_context *exec);
57848b8605Smrg
58848b8605Smrg
59848b8605Smrg/**
60848b8605Smrg * Close off the last primitive, execute the buffer, restart the
61b8e80941Smrg * primitive.  This is called when we fill a vertex buffer before
62b8e80941Smrg * hitting glEnd.
63848b8605Smrg */
64b8e80941Smrgstatic void
65b8e80941Smrgvbo_exec_wrap_buffers(struct vbo_exec_context *exec)
66848b8605Smrg{
67848b8605Smrg   if (exec->vtx.prim_count == 0) {
68848b8605Smrg      exec->vtx.copied.nr = 0;
69848b8605Smrg      exec->vtx.vert_count = 0;
70848b8605Smrg      exec->vtx.buffer_ptr = exec->vtx.buffer_map;
71848b8605Smrg   }
72848b8605Smrg   else {
73b8e80941Smrg      struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
74b8e80941Smrg      const GLuint last_begin = last_prim->begin;
75848b8605Smrg      GLuint last_count;
76848b8605Smrg
77848b8605Smrg      if (_mesa_inside_begin_end(exec->ctx)) {
78b8e80941Smrg         last_prim->count = exec->vtx.vert_count - last_prim->start;
79848b8605Smrg      }
80848b8605Smrg
81b8e80941Smrg      last_count = last_prim->count;
82b8e80941Smrg
83b8e80941Smrg      /* Special handling for wrapping GL_LINE_LOOP */
84b8e80941Smrg      if (last_prim->mode == GL_LINE_LOOP &&
85b8e80941Smrg          last_count > 0 &&
86b8e80941Smrg          !last_prim->end) {
87b8e80941Smrg         /* draw this section of the incomplete line loop as a line strip */
88b8e80941Smrg         last_prim->mode = GL_LINE_STRIP;
89b8e80941Smrg         if (!last_prim->begin) {
90b8e80941Smrg            /* This is not the first section of the line loop, so don't
91b8e80941Smrg             * draw the 0th vertex.  We're saving it until we draw the
92b8e80941Smrg             * very last section of the loop.
93b8e80941Smrg             */
94b8e80941Smrg            last_prim->start++;
95b8e80941Smrg            last_prim->count--;
96b8e80941Smrg         }
97b8e80941Smrg      }
98848b8605Smrg
99848b8605Smrg      /* Execute the buffer and save copied vertices.
100848b8605Smrg       */
101848b8605Smrg      if (exec->vtx.vert_count)
102b8e80941Smrg         vbo_exec_vtx_flush(exec, GL_FALSE);
103848b8605Smrg      else {
104b8e80941Smrg         exec->vtx.prim_count = 0;
105b8e80941Smrg         exec->vtx.copied.nr = 0;
106848b8605Smrg      }
107848b8605Smrg
108848b8605Smrg      /* Emit a glBegin to start the new list.
109848b8605Smrg       */
110848b8605Smrg      assert(exec->vtx.prim_count == 0);
111848b8605Smrg
112848b8605Smrg      if (_mesa_inside_begin_end(exec->ctx)) {
113b8e80941Smrg         exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
114b8e80941Smrg         exec->vtx.prim[0].begin = 0;
115b8e80941Smrg         exec->vtx.prim[0].end = 0;
116b8e80941Smrg         exec->vtx.prim[0].start = 0;
117b8e80941Smrg         exec->vtx.prim[0].count = 0;
118b8e80941Smrg         exec->vtx.prim_count++;
119b8e80941Smrg
120b8e80941Smrg         if (exec->vtx.copied.nr == last_count)
121b8e80941Smrg            exec->vtx.prim[0].begin = last_begin;
122848b8605Smrg      }
123848b8605Smrg   }
124848b8605Smrg}
125848b8605Smrg
126848b8605Smrg
127848b8605Smrg/**
128848b8605Smrg * Deal with buffer wrapping where provoked by the vertex buffer
129848b8605Smrg * filling up, as opposed to upgrade_vertex().
130848b8605Smrg */
131b8e80941Smrgstatic void
132b8e80941Smrgvbo_exec_vtx_wrap(struct vbo_exec_context *exec)
133848b8605Smrg{
134b8e80941Smrg   unsigned numComponents;
135848b8605Smrg
136848b8605Smrg   /* Run pipeline on current vertices, copy wrapped vertices
137848b8605Smrg    * to exec->vtx.copied.
138848b8605Smrg    */
139b8e80941Smrg   vbo_exec_wrap_buffers(exec);
140b8e80941Smrg
141848b8605Smrg   if (!exec->vtx.buffer_ptr) {
142848b8605Smrg      /* probably ran out of memory earlier when allocating the VBO */
143848b8605Smrg      return;
144848b8605Smrg   }
145848b8605Smrg
146b8e80941Smrg   /* Copy stored stored vertices to start of new list.
147848b8605Smrg    */
148848b8605Smrg   assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
149848b8605Smrg
150b8e80941Smrg   numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
151b8e80941Smrg   memcpy(exec->vtx.buffer_ptr,
152b8e80941Smrg          exec->vtx.copied.buffer,
153b8e80941Smrg          numComponents * sizeof(fi_type));
154b8e80941Smrg   exec->vtx.buffer_ptr += numComponents;
155b8e80941Smrg   exec->vtx.vert_count += exec->vtx.copied.nr;
156848b8605Smrg
157848b8605Smrg   exec->vtx.copied.nr = 0;
158848b8605Smrg}
159848b8605Smrg
160848b8605Smrg
161848b8605Smrg/**
162848b8605Smrg * Copy the active vertex's values to the ctx->Current fields.
163848b8605Smrg */
164b8e80941Smrgstatic void
165b8e80941Smrgvbo_exec_copy_to_current(struct vbo_exec_context *exec)
166848b8605Smrg{
167848b8605Smrg   struct gl_context *ctx = exec->ctx;
168848b8605Smrg   struct vbo_context *vbo = vbo_context(ctx);
169b8e80941Smrg   GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
170848b8605Smrg
171b8e80941Smrg   while (enabled) {
172b8e80941Smrg      const int i = u_bit_scan64(&enabled);
173848b8605Smrg
174b8e80941Smrg      /* Note: the exec->vtx.current[i] pointers point into the
175b8e80941Smrg       * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
176b8e80941Smrg       */
177b8e80941Smrg      GLfloat *current = (GLfloat *)vbo->current[i].Ptr;
178b8e80941Smrg      fi_type tmp[8]; /* space for doubles */
179b8e80941Smrg      int dmul = 1;
180b8e80941Smrg
181b8e80941Smrg      if (exec->vtx.attrtype[i] == GL_DOUBLE ||
182b8e80941Smrg          exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB)
183b8e80941Smrg         dmul = 2;
184b8e80941Smrg
185b8e80941Smrg      assert(exec->vtx.attrsz[i]);
186b8e80941Smrg
187b8e80941Smrg      if (exec->vtx.attrtype[i] == GL_DOUBLE ||
188b8e80941Smrg          exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB) {
189b8e80941Smrg         memset(tmp, 0, sizeof(tmp));
190b8e80941Smrg         memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat));
191b8e80941Smrg      } else {
192b8e80941Smrg         COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
193848b8605Smrg                                     exec->vtx.attrsz[i],
194848b8605Smrg                                     exec->vtx.attrptr[i],
195848b8605Smrg                                     exec->vtx.attrtype[i]);
196b8e80941Smrg      }
197b8e80941Smrg
198b8e80941Smrg      if (exec->vtx.attrtype[i] != vbo->current[i].Format.Type ||
199b8e80941Smrg          memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
200b8e80941Smrg         memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
201b8e80941Smrg
202b8e80941Smrg         /* Given that we explicitly state size here, there is no need
203b8e80941Smrg          * for the COPY_CLEAN above, could just copy 16 bytes and be
204b8e80941Smrg          * done.  The only problem is when Mesa accesses ctx->Current
205b8e80941Smrg          * directly.
206b8e80941Smrg          */
207b8e80941Smrg         /* Size here is in components - not bytes */
208b8e80941Smrg         vbo_set_vertex_format(&vbo->current[i].Format,
209b8e80941Smrg                               exec->vtx.attrsz[i] / dmul,
210b8e80941Smrg                               exec->vtx.attrtype[i]);
211b8e80941Smrg
212b8e80941Smrg         /* This triggers rather too much recalculation of Mesa state
213b8e80941Smrg          * that doesn't get used (eg light positions).
214b8e80941Smrg          */
215b8e80941Smrg         if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
216b8e80941Smrg             i <= VBO_ATTRIB_MAT_BACK_INDEXES)
217b8e80941Smrg            ctx->NewState |= _NEW_LIGHT;
218b8e80941Smrg
219b8e80941Smrg         ctx->NewState |= _NEW_CURRENT_ATTRIB;
220848b8605Smrg      }
221848b8605Smrg   }
222848b8605Smrg
223848b8605Smrg   /* Colormaterial -- this kindof sucks.
224848b8605Smrg    */
225848b8605Smrg   if (ctx->Light.ColorMaterialEnabled &&
226848b8605Smrg       exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
227b8e80941Smrg      _mesa_update_color_material(ctx,
228b8e80941Smrg                                  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
229848b8605Smrg   }
230848b8605Smrg}
231848b8605Smrg
232848b8605Smrg
233848b8605Smrg/**
234848b8605Smrg * Copy current vertex attribute values into the current vertex.
235848b8605Smrg */
236848b8605Smrgstatic void
237848b8605Smrgvbo_exec_copy_from_current(struct vbo_exec_context *exec)
238848b8605Smrg{
239848b8605Smrg   struct gl_context *ctx = exec->ctx;
240848b8605Smrg   struct vbo_context *vbo = vbo_context(ctx);
241848b8605Smrg   GLint i;
242848b8605Smrg
243848b8605Smrg   for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
244b8e80941Smrg      if (exec->vtx.attrtype[i] == GL_DOUBLE ||
245b8e80941Smrg          exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB) {
246b8e80941Smrg         memcpy(exec->vtx.attrptr[i], vbo->current[i].Ptr,
247b8e80941Smrg                exec->vtx.attrsz[i] * sizeof(GLfloat));
248b8e80941Smrg      } else {
249b8e80941Smrg         const fi_type *current = (fi_type *) vbo->current[i].Ptr;
250b8e80941Smrg         switch (exec->vtx.attrsz[i]) {
251b8e80941Smrg         case 4: exec->vtx.attrptr[i][3] = current[3];
252b8e80941Smrg         case 3: exec->vtx.attrptr[i][2] = current[2];
253b8e80941Smrg         case 2: exec->vtx.attrptr[i][1] = current[1];
254b8e80941Smrg         case 1: exec->vtx.attrptr[i][0] = current[0];
255b8e80941Smrg            break;
256b8e80941Smrg         }
257848b8605Smrg      }
258848b8605Smrg   }
259848b8605Smrg}
260848b8605Smrg
261848b8605Smrg
262848b8605Smrg/**
263848b8605Smrg * Flush existing data, set new attrib size, replay copied vertices.
264848b8605Smrg * This is called when we transition from a small vertex attribute size
265848b8605Smrg * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
266848b8605Smrg * We need to go back over the previous 2-component texcoords and insert
267848b8605Smrg * zero and one values.
268b8e80941Smrg * \param attr  VBO_ATTRIB_x vertex attribute value
269b8e80941Smrg */
270848b8605Smrgstatic void
271848b8605Smrgvbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
272b8e80941Smrg                             GLuint attr, GLuint newSize)
273848b8605Smrg{
274848b8605Smrg   struct gl_context *ctx = exec->ctx;
275848b8605Smrg   struct vbo_context *vbo = vbo_context(ctx);
276848b8605Smrg   const GLint lastcount = exec->vtx.vert_count;
277b8e80941Smrg   fi_type *old_attrptr[VBO_ATTRIB_MAX];
278848b8605Smrg   const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
279848b8605Smrg   const GLuint oldSize = exec->vtx.attrsz[attr];
280848b8605Smrg   GLuint i;
281848b8605Smrg
282b8e80941Smrg   assert(attr < VBO_ATTRIB_MAX);
283b8e80941Smrg
284848b8605Smrg   /* Run pipeline on current vertices, copy wrapped vertices
285848b8605Smrg    * to exec->vtx.copied.
286848b8605Smrg    */
287b8e80941Smrg   vbo_exec_wrap_buffers(exec);
288848b8605Smrg
289848b8605Smrg   if (unlikely(exec->vtx.copied.nr)) {
290848b8605Smrg      /* We're in the middle of a primitive, keep the old vertex
291848b8605Smrg       * format around to be able to translate the copied vertices to
292848b8605Smrg       * the new format.
293848b8605Smrg       */
294848b8605Smrg      memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
295848b8605Smrg   }
296848b8605Smrg
297848b8605Smrg   if (unlikely(oldSize)) {
298848b8605Smrg      /* Do a COPY_TO_CURRENT to ensure back-copying works for the
299848b8605Smrg       * case when the attribute already exists in the vertex and is
300848b8605Smrg       * having its size increased.
301848b8605Smrg       */
302b8e80941Smrg      vbo_exec_copy_to_current(exec);
303848b8605Smrg   }
304848b8605Smrg
305848b8605Smrg   /* Heuristic: Attempt to isolate attributes received outside
306848b8605Smrg    * begin/end so that they don't bloat the vertices.
307848b8605Smrg    */
308848b8605Smrg   if (!_mesa_inside_begin_end(ctx) &&
309848b8605Smrg       !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
310b8e80941Smrg      vbo_exec_copy_to_current(exec);
311b8e80941Smrg      vbo_reset_all_attr(exec);
312848b8605Smrg   }
313848b8605Smrg
314848b8605Smrg   /* Fix up sizes:
315848b8605Smrg    */
316848b8605Smrg   exec->vtx.attrsz[attr] = newSize;
317848b8605Smrg   exec->vtx.vertex_size += newSize - oldSize;
318b8e80941Smrg   exec->vtx.max_vert = vbo_compute_max_verts(exec);
319848b8605Smrg   exec->vtx.vert_count = 0;
320848b8605Smrg   exec->vtx.buffer_ptr = exec->vtx.buffer_map;
321b8e80941Smrg   exec->vtx.enabled |= BITFIELD64_BIT(attr);
322848b8605Smrg
323848b8605Smrg   if (unlikely(oldSize)) {
324848b8605Smrg      /* Size changed, recalculate all the attrptr[] values
325848b8605Smrg       */
326b8e80941Smrg      fi_type *tmp = exec->vtx.vertex;
327848b8605Smrg
328848b8605Smrg      for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
329b8e80941Smrg         if (exec->vtx.attrsz[i]) {
330b8e80941Smrg            exec->vtx.attrptr[i] = tmp;
331b8e80941Smrg            tmp += exec->vtx.attrsz[i];
332b8e80941Smrg         }
333b8e80941Smrg         else
334b8e80941Smrg            exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
335848b8605Smrg      }
336848b8605Smrg
337848b8605Smrg      /* Copy from current to repopulate the vertex with correct
338848b8605Smrg       * values.
339848b8605Smrg       */
340b8e80941Smrg      vbo_exec_copy_from_current(exec);
341848b8605Smrg   }
342848b8605Smrg   else {
343848b8605Smrg      /* Just have to append the new attribute at the end */
344848b8605Smrg      exec->vtx.attrptr[attr] = exec->vtx.vertex +
345b8e80941Smrg        exec->vtx.vertex_size - newSize;
346848b8605Smrg   }
347848b8605Smrg
348848b8605Smrg   /* Replay stored vertices to translate them
349848b8605Smrg    * to new format here.
350848b8605Smrg    *
351848b8605Smrg    * -- No need to replay - just copy piecewise
352848b8605Smrg    */
353848b8605Smrg   if (unlikely(exec->vtx.copied.nr)) {
354b8e80941Smrg      fi_type *data = exec->vtx.copied.buffer;
355b8e80941Smrg      fi_type *dest = exec->vtx.buffer_ptr;
356848b8605Smrg
357848b8605Smrg      assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
358848b8605Smrg
359848b8605Smrg      for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
360b8e80941Smrg         GLbitfield64 enabled = exec->vtx.enabled;
361b8e80941Smrg         while (enabled) {
362b8e80941Smrg            const int j = u_bit_scan64(&enabled);
363b8e80941Smrg            GLuint sz = exec->vtx.attrsz[j];
364b8e80941Smrg            GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
365b8e80941Smrg            GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
366b8e80941Smrg
367b8e80941Smrg            assert(sz);
368b8e80941Smrg
369b8e80941Smrg            if (j == attr) {
370b8e80941Smrg               if (oldSize) {
371b8e80941Smrg                  fi_type tmp[4];
372b8e80941Smrg                  COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
373b8e80941Smrg                                              data + old_offset,
374b8e80941Smrg                                              exec->vtx.attrtype[j]);
375b8e80941Smrg                  COPY_SZ_4V(dest + new_offset, newSize, tmp);
376b8e80941Smrg               } else {
377b8e80941Smrg                  fi_type *current = (fi_type *)vbo->current[j].Ptr;
378b8e80941Smrg                  COPY_SZ_4V(dest + new_offset, sz, current);
379b8e80941Smrg               }
380b8e80941Smrg            }
381b8e80941Smrg            else {
382b8e80941Smrg               COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
383b8e80941Smrg            }
384b8e80941Smrg         }
385b8e80941Smrg
386b8e80941Smrg         data += old_vtx_size;
387b8e80941Smrg         dest += exec->vtx.vertex_size;
388848b8605Smrg      }
389848b8605Smrg
390848b8605Smrg      exec->vtx.buffer_ptr = dest;
391848b8605Smrg      exec->vtx.vert_count += exec->vtx.copied.nr;
392848b8605Smrg      exec->vtx.copied.nr = 0;
393848b8605Smrg   }
394848b8605Smrg}
395848b8605Smrg
396848b8605Smrg
397848b8605Smrg/**
398848b8605Smrg * This is when a vertex attribute transitions to a different size.
399848b8605Smrg * For example, we saw a bunch of glTexCoord2f() calls and now we got a
400848b8605Smrg * glTexCoord4f() call.  We promote the array from size=2 to size=4.
401b8e80941Smrg * \param newSize  size of new vertex (number of 32-bit words).
402b8e80941Smrg * \param attr  VBO_ATTRIB_x vertex attribute value
403848b8605Smrg */
404848b8605Smrgstatic void
405b8e80941Smrgvbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
406b8e80941Smrg                      GLuint newSize, GLenum newType)
407848b8605Smrg{
408848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
409848b8605Smrg
410b8e80941Smrg   assert(attr < VBO_ATTRIB_MAX);
411b8e80941Smrg
412b8e80941Smrg   if (newSize > exec->vtx.attrsz[attr] ||
413b8e80941Smrg       newType != exec->vtx.attrtype[attr]) {
414848b8605Smrg      /* New size is larger.  Need to flush existing vertices and get
415848b8605Smrg       * an enlarged vertex format.
416848b8605Smrg       */
417b8e80941Smrg      vbo_exec_wrap_upgrade_vertex(exec, attr, newSize);
418848b8605Smrg   }
419848b8605Smrg   else if (newSize < exec->vtx.active_sz[attr]) {
420848b8605Smrg      GLuint i;
421b8e80941Smrg      const fi_type *id =
422b8e80941Smrg            vbo_get_default_vals_as_union(exec->vtx.attrtype[attr]);
423848b8605Smrg
424848b8605Smrg      /* New size is smaller - just need to fill in some
425848b8605Smrg       * zeros.  Don't need to flush or wrap.
426848b8605Smrg       */
427848b8605Smrg      for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
428b8e80941Smrg         exec->vtx.attrptr[attr][i-1] = id[i-1];
429848b8605Smrg   }
430848b8605Smrg
431848b8605Smrg   exec->vtx.active_sz[attr] = newSize;
432b8e80941Smrg   exec->vtx.attrtype[attr] = newType;
433848b8605Smrg
434848b8605Smrg   /* Does setting NeedFlush belong here?  Necessitates resetting
435848b8605Smrg    * vtxfmt on each flush (otherwise flags won't get reset
436848b8605Smrg    * afterwards).
437848b8605Smrg    */
438b8e80941Smrg   if (attr == 0)
439848b8605Smrg      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
440848b8605Smrg}
441848b8605Smrg
442848b8605Smrg
443b8e80941Smrg/**
444b8e80941Smrg * Called upon first glVertex, glColor, glTexCoord, etc.
445b8e80941Smrg */
446b8e80941Smrgstatic void
447b8e80941Smrgvbo_exec_begin_vertices(struct gl_context *ctx)
448b8e80941Smrg{
449b8e80941Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
450b8e80941Smrg
451b8e80941Smrg   vbo_exec_vtx_map(exec);
452b8e80941Smrg
453b8e80941Smrg   assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
454b8e80941Smrg   assert(exec->begin_vertices_flags);
455b8e80941Smrg
456b8e80941Smrg   ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
457b8e80941Smrg}
458b8e80941Smrg
459b8e80941Smrg
460b8e80941Smrg/**
461b8e80941Smrg * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
462b8e80941Smrg * It depends on a few things, including whether we're inside or outside
463b8e80941Smrg * of glBegin/glEnd.
464b8e80941Smrg */
465b8e80941Smrgstatic inline bool
466b8e80941Smrgis_vertex_position(const struct gl_context *ctx, GLuint index)
467b8e80941Smrg{
468b8e80941Smrg   return (index == 0 &&
469b8e80941Smrg           _mesa_attr_zero_aliases_vertex(ctx) &&
470b8e80941Smrg           _mesa_inside_begin_end(ctx));
471b8e80941Smrg}
472b8e80941Smrg
473b8e80941Smrg
474848b8605Smrg/**
475848b8605Smrg * This macro is used to implement all the glVertex, glColor, glTexCoord,
476848b8605Smrg * glVertexAttrib, etc functions.
477b8e80941Smrg * \param A  VBO_ATTRIB_x attribute index
478b8e80941Smrg * \param N  attribute size (1..4)
479b8e80941Smrg * \param T  type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
480b8e80941Smrg * \param C  cast type (fi_type or double)
481b8e80941Smrg * \param V0, V1, v2, V3  attribute value
482848b8605Smrg */
483b8e80941Smrg#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                          \
484b8e80941Smrgdo {                                                                    \
485b8e80941Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;             \
486b8e80941Smrg   int sz = (sizeof(C) / sizeof(GLfloat));                              \
487b8e80941Smrg                                                                        \
488b8e80941Smrg   assert(sz == 1 || sz == 2);                                          \
489b8e80941Smrg                                                                        \
490b8e80941Smrg   /* check if attribute size or type is changing */                    \
491b8e80941Smrg   if (unlikely(exec->vtx.active_sz[A] != N * sz) ||                    \
492b8e80941Smrg       unlikely(exec->vtx.attrtype[A] != T)) {                          \
493b8e80941Smrg      vbo_exec_fixup_vertex(ctx, A, N * sz, T);                         \
494b8e80941Smrg   }                                                                    \
495b8e80941Smrg                                                                        \
496b8e80941Smrg   /* store vertex attribute in vertex buffer */                        \
497b8e80941Smrg   {                                                                    \
498b8e80941Smrg      C *dest = (C *)exec->vtx.attrptr[A];                              \
499b8e80941Smrg      if (N>0) dest[0] = V0;                                            \
500b8e80941Smrg      if (N>1) dest[1] = V1;                                            \
501b8e80941Smrg      if (N>2) dest[2] = V2;                                            \
502b8e80941Smrg      if (N>3) dest[3] = V3;                                            \
503b8e80941Smrg      assert(exec->vtx.attrtype[A] == T);                               \
504b8e80941Smrg   }                                                                    \
505b8e80941Smrg                                                                        \
506b8e80941Smrg   if ((A) == 0) {                                                      \
507b8e80941Smrg      /* This is a glVertex call */                                     \
508b8e80941Smrg      GLuint i;                                                         \
509b8e80941Smrg                                                                        \
510b8e80941Smrg      if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
511b8e80941Smrg         vbo_exec_begin_vertices(ctx);                                  \
512b8e80941Smrg      }                                                                 \
513b8e80941Smrg                                                                        \
514b8e80941Smrg      if (unlikely(!exec->vtx.buffer_ptr)) {                            \
515b8e80941Smrg         vbo_exec_vtx_map(exec);                                        \
516b8e80941Smrg      }                                                                 \
517b8e80941Smrg      assert(exec->vtx.buffer_ptr);                                     \
518b8e80941Smrg                                                                        \
519b8e80941Smrg      /* copy 32-bit words */                                           \
520b8e80941Smrg      for (i = 0; i < exec->vtx.vertex_size; i++)                       \
521b8e80941Smrg         exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];                 \
522b8e80941Smrg                                                                        \
523b8e80941Smrg      exec->vtx.buffer_ptr += exec->vtx.vertex_size;                    \
524b8e80941Smrg                                                                        \
525b8e80941Smrg      /* Set FLUSH_STORED_VERTICES to indicate that there's now */      \
526b8e80941Smrg      /* something to draw (not just updating a color or texcoord).*/   \
527b8e80941Smrg      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;                   \
528b8e80941Smrg                                                                        \
529b8e80941Smrg      if (++exec->vtx.vert_count >= exec->vtx.max_vert)                 \
530b8e80941Smrg         vbo_exec_vtx_wrap(exec);                                       \
531b8e80941Smrg   } else {                                                             \
532b8e80941Smrg      /* we now have accumulated per-vertex attributes */               \
533b8e80941Smrg      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;                    \
534b8e80941Smrg   }                                                                    \
535848b8605Smrg} while (0)
536848b8605Smrg
537848b8605Smrg
538b8e80941Smrg#undef ERROR
539b8e80941Smrg#define ERROR(err) _mesa_error(ctx, err, __func__)
540848b8605Smrg#define TAG(x) vbo_##x
541848b8605Smrg
542848b8605Smrg#include "vbo_attrib_tmp.h"
543848b8605Smrg
544848b8605Smrg
545848b8605Smrg
546848b8605Smrg/**
547848b8605Smrg * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
548848b8605Smrg * this may be a (partial) no-op.
549848b8605Smrg */
550848b8605Smrgstatic void GLAPIENTRY
551848b8605Smrgvbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
552848b8605Smrg{
553848b8605Smrg   GLbitfield updateMats;
554848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
555848b8605Smrg
556848b8605Smrg   /* This function should be a no-op when it tries to update material
557848b8605Smrg    * attributes which are currently tracking glColor via glColorMaterial.
558848b8605Smrg    * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
559848b8605Smrg    * indicating which material attributes can actually be updated below.
560848b8605Smrg    */
561848b8605Smrg   if (ctx->Light.ColorMaterialEnabled) {
562848b8605Smrg      updateMats = ~ctx->Light._ColorMaterialBitmask;
563848b8605Smrg   }
564848b8605Smrg   else {
565848b8605Smrg      /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
566848b8605Smrg      updateMats = ALL_MATERIAL_BITS;
567848b8605Smrg   }
568848b8605Smrg
569848b8605Smrg   if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
570848b8605Smrg      updateMats &= FRONT_MATERIAL_BITS;
571848b8605Smrg   }
572848b8605Smrg   else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
573848b8605Smrg      updateMats &= BACK_MATERIAL_BITS;
574848b8605Smrg   }
575848b8605Smrg   else if (face != GL_FRONT_AND_BACK) {
576848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
577848b8605Smrg      return;
578848b8605Smrg   }
579848b8605Smrg
580848b8605Smrg   switch (pname) {
581848b8605Smrg   case GL_EMISSION:
582848b8605Smrg      if (updateMats & MAT_BIT_FRONT_EMISSION)
583848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
584848b8605Smrg      if (updateMats & MAT_BIT_BACK_EMISSION)
585848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
586848b8605Smrg      break;
587848b8605Smrg   case GL_AMBIENT:
588848b8605Smrg      if (updateMats & MAT_BIT_FRONT_AMBIENT)
589848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
590848b8605Smrg      if (updateMats & MAT_BIT_BACK_AMBIENT)
591848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
592848b8605Smrg      break;
593848b8605Smrg   case GL_DIFFUSE:
594848b8605Smrg      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
595848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
596848b8605Smrg      if (updateMats & MAT_BIT_BACK_DIFFUSE)
597848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
598848b8605Smrg      break;
599848b8605Smrg   case GL_SPECULAR:
600848b8605Smrg      if (updateMats & MAT_BIT_FRONT_SPECULAR)
601848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
602848b8605Smrg      if (updateMats & MAT_BIT_BACK_SPECULAR)
603848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
604848b8605Smrg      break;
605848b8605Smrg   case GL_SHININESS:
606848b8605Smrg      if (*params < 0 || *params > ctx->Const.MaxShininess) {
607848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
608848b8605Smrg                     "glMaterial(invalid shininess: %f out range [0, %f])",
609b8e80941Smrg                     *params, ctx->Const.MaxShininess);
610848b8605Smrg         return;
611848b8605Smrg      }
612848b8605Smrg      if (updateMats & MAT_BIT_FRONT_SHININESS)
613848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
614848b8605Smrg      if (updateMats & MAT_BIT_BACK_SHININESS)
615848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
616848b8605Smrg      break;
617848b8605Smrg   case GL_COLOR_INDEXES:
618848b8605Smrg      if (ctx->API != API_OPENGL_COMPAT) {
619848b8605Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
620848b8605Smrg         return;
621848b8605Smrg      }
622848b8605Smrg      if (updateMats & MAT_BIT_FRONT_INDEXES)
623848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
624848b8605Smrg      if (updateMats & MAT_BIT_BACK_INDEXES)
625848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
626848b8605Smrg      break;
627848b8605Smrg   case GL_AMBIENT_AND_DIFFUSE:
628848b8605Smrg      if (updateMats & MAT_BIT_FRONT_AMBIENT)
629848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
630848b8605Smrg      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
631848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
632848b8605Smrg      if (updateMats & MAT_BIT_BACK_AMBIENT)
633848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
634848b8605Smrg      if (updateMats & MAT_BIT_BACK_DIFFUSE)
635848b8605Smrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
636848b8605Smrg      break;
637848b8605Smrg   default:
638848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
639848b8605Smrg      return;
640848b8605Smrg   }
641848b8605Smrg}
642848b8605Smrg
643848b8605Smrg
644848b8605Smrg/**
645848b8605Smrg * Flush (draw) vertices.
646848b8605Smrg * \param  unmap - leave VBO unmapped after flushing?
647848b8605Smrg */
648848b8605Smrgstatic void
649848b8605Smrgvbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
650848b8605Smrg{
651848b8605Smrg   if (exec->vtx.vert_count || unmap) {
652b8e80941Smrg      vbo_exec_vtx_flush(exec, unmap);
653848b8605Smrg   }
654848b8605Smrg
655848b8605Smrg   if (exec->vtx.vertex_size) {
656b8e80941Smrg      vbo_exec_copy_to_current(exec);
657b8e80941Smrg      vbo_reset_all_attr(exec);
658848b8605Smrg   }
659848b8605Smrg}
660848b8605Smrg
661848b8605Smrg
662b8e80941Smrgstatic void GLAPIENTRY
663b8e80941Smrgvbo_exec_EvalCoord1f(GLfloat u)
664848b8605Smrg{
665b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
666848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
667848b8605Smrg
668848b8605Smrg   {
669848b8605Smrg      GLint i;
670b8e80941Smrg      if (exec->eval.recalculate_maps)
671b8e80941Smrg         vbo_exec_eval_update(exec);
672848b8605Smrg
673848b8605Smrg      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
674b8e80941Smrg         if (exec->eval.map1[i].map)
675b8e80941Smrg            if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
676b8e80941Smrg               vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT);
677848b8605Smrg      }
678848b8605Smrg   }
679848b8605Smrg
680b8e80941Smrg   memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
681b8e80941Smrg          exec->vtx.vertex_size * sizeof(GLfloat));
682848b8605Smrg
683b8e80941Smrg   vbo_exec_do_EvalCoord1f(exec, u);
684848b8605Smrg
685b8e80941Smrg   memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
686b8e80941Smrg          exec->vtx.vertex_size * sizeof(GLfloat));
687848b8605Smrg}
688848b8605Smrg
689b8e80941Smrg
690b8e80941Smrgstatic void GLAPIENTRY
691b8e80941Smrgvbo_exec_EvalCoord2f(GLfloat u, GLfloat v)
692848b8605Smrg{
693b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
694848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
695848b8605Smrg
696848b8605Smrg   {
697848b8605Smrg      GLint i;
698b8e80941Smrg      if (exec->eval.recalculate_maps)
699b8e80941Smrg         vbo_exec_eval_update(exec);
700848b8605Smrg
701848b8605Smrg      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
702b8e80941Smrg         if (exec->eval.map2[i].map)
703b8e80941Smrg            if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
704b8e80941Smrg               vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT);
705848b8605Smrg      }
706848b8605Smrg
707b8e80941Smrg      if (ctx->Eval.AutoNormal)
708b8e80941Smrg         if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
709b8e80941Smrg            vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT);
710848b8605Smrg   }
711848b8605Smrg
712b8e80941Smrg   memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
713b8e80941Smrg          exec->vtx.vertex_size * sizeof(GLfloat));
714848b8605Smrg
715b8e80941Smrg   vbo_exec_do_EvalCoord2f(exec, u, v);
716848b8605Smrg
717b8e80941Smrg   memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
718b8e80941Smrg          exec->vtx.vertex_size * sizeof(GLfloat));
719848b8605Smrg}
720848b8605Smrg
721b8e80941Smrg
722b8e80941Smrgstatic void GLAPIENTRY
723b8e80941Smrgvbo_exec_EvalCoord1fv(const GLfloat *u)
724848b8605Smrg{
725b8e80941Smrg   vbo_exec_EvalCoord1f(u[0]);
726848b8605Smrg}
727848b8605Smrg
728b8e80941Smrg
729b8e80941Smrgstatic void GLAPIENTRY
730b8e80941Smrgvbo_exec_EvalCoord2fv(const GLfloat *u)
731848b8605Smrg{
732b8e80941Smrg   vbo_exec_EvalCoord2f(u[0], u[1]);
733848b8605Smrg}
734848b8605Smrg
735b8e80941Smrg
736b8e80941Smrgstatic void GLAPIENTRY
737b8e80941Smrgvbo_exec_EvalPoint1(GLint i)
738848b8605Smrg{
739b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
740848b8605Smrg   GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
741b8e80941Smrg                 (GLfloat) ctx->Eval.MapGrid1un);
742848b8605Smrg   GLfloat u = i * du + ctx->Eval.MapGrid1u1;
743848b8605Smrg
744b8e80941Smrg   vbo_exec_EvalCoord1f(u);
745848b8605Smrg}
746848b8605Smrg
747848b8605Smrg
748b8e80941Smrgstatic void GLAPIENTRY
749b8e80941Smrgvbo_exec_EvalPoint2(GLint i, GLint j)
750848b8605Smrg{
751b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
752b8e80941Smrg   GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
753b8e80941Smrg                 (GLfloat) ctx->Eval.MapGrid2un);
754b8e80941Smrg   GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
755b8e80941Smrg                 (GLfloat) ctx->Eval.MapGrid2vn);
756848b8605Smrg   GLfloat u = i * du + ctx->Eval.MapGrid2u1;
757848b8605Smrg   GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
758848b8605Smrg
759b8e80941Smrg   vbo_exec_EvalCoord2f(u, v);
760848b8605Smrg}
761848b8605Smrg
762848b8605Smrg
763848b8605Smrg/**
764848b8605Smrg * Called via glBegin.
765848b8605Smrg */
766b8e80941Smrgstatic void GLAPIENTRY
767b8e80941Smrgvbo_exec_Begin(GLenum mode)
768848b8605Smrg{
769b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
770b8e80941Smrg   struct vbo_context *vbo = vbo_context(ctx);
771b8e80941Smrg   struct vbo_exec_context *exec = &vbo->exec;
772848b8605Smrg   int i;
773848b8605Smrg
774848b8605Smrg   if (_mesa_inside_begin_end(ctx)) {
775848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
776848b8605Smrg      return;
777848b8605Smrg   }
778848b8605Smrg
779848b8605Smrg   if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
780848b8605Smrg      return;
781848b8605Smrg   }
782848b8605Smrg
783848b8605Smrg   if (ctx->NewState) {
784b8e80941Smrg      _mesa_update_state(ctx);
785848b8605Smrg
786848b8605Smrg      CALL_Begin(ctx->Exec, (mode));
787848b8605Smrg      return;
788848b8605Smrg   }
789848b8605Smrg
790848b8605Smrg   if (!_mesa_valid_to_render(ctx, "glBegin")) {
791848b8605Smrg      return;
792848b8605Smrg   }
793848b8605Smrg
794b8e80941Smrg   /* Heuristic: attempt to isolate attributes occurring outside
795848b8605Smrg    * begin/end pairs.
796848b8605Smrg    */
797848b8605Smrg   if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
798848b8605Smrg      vbo_exec_FlushVertices_internal(exec, GL_FALSE);
799848b8605Smrg
800848b8605Smrg   i = exec->vtx.prim_count++;
801848b8605Smrg   exec->vtx.prim[i].mode = mode;
802848b8605Smrg   exec->vtx.prim[i].begin = 1;
803848b8605Smrg   exec->vtx.prim[i].end = 0;
804848b8605Smrg   exec->vtx.prim[i].indexed = 0;
805848b8605Smrg   exec->vtx.prim[i].pad = 0;
806848b8605Smrg   exec->vtx.prim[i].start = exec->vtx.vert_count;
807848b8605Smrg   exec->vtx.prim[i].count = 0;
808848b8605Smrg   exec->vtx.prim[i].num_instances = 1;
809848b8605Smrg   exec->vtx.prim[i].base_instance = 0;
810848b8605Smrg   exec->vtx.prim[i].is_indirect = 0;
811848b8605Smrg
812848b8605Smrg   ctx->Driver.CurrentExecPrimitive = mode;
813848b8605Smrg
814848b8605Smrg   ctx->Exec = ctx->BeginEnd;
815b8e80941Smrg
816848b8605Smrg   /* We may have been called from a display list, in which case we should
817848b8605Smrg    * leave dlist.c's dispatch table in place.
818848b8605Smrg    */
819b8e80941Smrg   if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
820b8e80941Smrg      ctx->CurrentServerDispatch = ctx->Exec;
821b8e80941Smrg   } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
822b8e80941Smrg      ctx->CurrentClientDispatch = ctx->Exec;
823b8e80941Smrg      _glapi_set_dispatch(ctx->CurrentClientDispatch);
824848b8605Smrg   } else {
825b8e80941Smrg      assert(ctx->CurrentClientDispatch == ctx->Save);
826848b8605Smrg   }
827848b8605Smrg}
828848b8605Smrg
829848b8605Smrg
830848b8605Smrg/**
831848b8605Smrg * Try to merge / concatenate the two most recent VBO primitives.
832848b8605Smrg */
833848b8605Smrgstatic void
834848b8605Smrgtry_vbo_merge(struct vbo_exec_context *exec)
835848b8605Smrg{
836848b8605Smrg   struct _mesa_prim *cur =  &exec->vtx.prim[exec->vtx.prim_count - 1];
837848b8605Smrg
838848b8605Smrg   assert(exec->vtx.prim_count >= 1);
839848b8605Smrg
840848b8605Smrg   vbo_try_prim_conversion(cur);
841848b8605Smrg
842848b8605Smrg   if (exec->vtx.prim_count >= 2) {
843848b8605Smrg      struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
844848b8605Smrg      assert(prev == cur - 1);
845848b8605Smrg
846848b8605Smrg      if (vbo_can_merge_prims(prev, cur)) {
847848b8605Smrg         assert(cur->begin);
848848b8605Smrg         assert(cur->end);
849848b8605Smrg         assert(prev->begin);
850848b8605Smrg         assert(prev->end);
851848b8605Smrg         vbo_merge_prims(prev, cur);
852848b8605Smrg         exec->vtx.prim_count--;  /* drop the last primitive */
853848b8605Smrg      }
854848b8605Smrg   }
855848b8605Smrg}
856848b8605Smrg
857848b8605Smrg
858848b8605Smrg/**
859848b8605Smrg * Called via glEnd.
860848b8605Smrg */
861b8e80941Smrgstatic void GLAPIENTRY
862b8e80941Smrgvbo_exec_End(void)
863848b8605Smrg{
864b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
865848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
866848b8605Smrg
867848b8605Smrg   if (!_mesa_inside_begin_end(ctx)) {
868848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
869848b8605Smrg      return;
870848b8605Smrg   }
871848b8605Smrg
872848b8605Smrg   ctx->Exec = ctx->OutsideBeginEnd;
873b8e80941Smrg
874b8e80941Smrg   if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
875b8e80941Smrg      ctx->CurrentServerDispatch = ctx->Exec;
876b8e80941Smrg   } else if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
877b8e80941Smrg      ctx->CurrentClientDispatch = ctx->Exec;
878b8e80941Smrg      _glapi_set_dispatch(ctx->CurrentClientDispatch);
879848b8605Smrg   }
880848b8605Smrg
881848b8605Smrg   if (exec->vtx.prim_count > 0) {
882848b8605Smrg      /* close off current primitive */
883b8e80941Smrg      struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
884b8e80941Smrg
885b8e80941Smrg      last_prim->end = 1;
886b8e80941Smrg      last_prim->count = exec->vtx.vert_count - last_prim->start;
887b8e80941Smrg
888b8e80941Smrg      /* Special handling for GL_LINE_LOOP */
889b8e80941Smrg      if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
890b8e80941Smrg         /* We're finishing drawing a line loop.  Append 0th vertex onto
891b8e80941Smrg          * end of vertex buffer so we can draw it as a line strip.
892b8e80941Smrg          */
893b8e80941Smrg         const fi_type *src = exec->vtx.buffer_map +
894b8e80941Smrg            last_prim->start * exec->vtx.vertex_size;
895b8e80941Smrg         fi_type *dst = exec->vtx.buffer_map +
896b8e80941Smrg            exec->vtx.vert_count * exec->vtx.vertex_size;
897848b8605Smrg
898b8e80941Smrg         /* copy 0th vertex to end of buffer */
899b8e80941Smrg         memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
900b8e80941Smrg
901b8e80941Smrg         last_prim->start++;  /* skip vertex0 */
902b8e80941Smrg         /* note that last_prim->count stays unchanged */
903b8e80941Smrg         last_prim->mode = GL_LINE_STRIP;
904b8e80941Smrg
905b8e80941Smrg         /* Increment the vertex count so the next primitive doesn't
906b8e80941Smrg          * overwrite the last vertex which we just added.
907b8e80941Smrg          */
908b8e80941Smrg         exec->vtx.vert_count++;
909b8e80941Smrg         exec->vtx.buffer_ptr += exec->vtx.vertex_size;
910b8e80941Smrg      }
911848b8605Smrg
912848b8605Smrg      try_vbo_merge(exec);
913848b8605Smrg   }
914848b8605Smrg
915848b8605Smrg   ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
916848b8605Smrg
917848b8605Smrg   if (exec->vtx.prim_count == VBO_MAX_PRIM)
918b8e80941Smrg      vbo_exec_vtx_flush(exec, GL_FALSE);
919848b8605Smrg
920848b8605Smrg   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
921848b8605Smrg      _mesa_flush(ctx);
922848b8605Smrg   }
923848b8605Smrg}
924848b8605Smrg
925848b8605Smrg
926848b8605Smrg/**
927848b8605Smrg * Called via glPrimitiveRestartNV()
928848b8605Smrg */
929848b8605Smrgstatic void GLAPIENTRY
930848b8605Smrgvbo_exec_PrimitiveRestartNV(void)
931848b8605Smrg{
932848b8605Smrg   GLenum curPrim;
933b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
934848b8605Smrg
935848b8605Smrg   curPrim = ctx->Driver.CurrentExecPrimitive;
936848b8605Smrg
937848b8605Smrg   if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
938b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV");
939848b8605Smrg   }
940848b8605Smrg   else {
941848b8605Smrg      vbo_exec_End();
942848b8605Smrg      vbo_exec_Begin(curPrim);
943848b8605Smrg   }
944848b8605Smrg}
945848b8605Smrg
946848b8605Smrg
947b8e80941Smrgstatic void
948b8e80941Smrgvbo_exec_vtxfmt_init(struct vbo_exec_context *exec)
949848b8605Smrg{
950848b8605Smrg   struct gl_context *ctx = exec->ctx;
951848b8605Smrg   GLvertexformat *vfmt = &exec->vtxfmt;
952848b8605Smrg
953848b8605Smrg   vfmt->ArrayElement = _ae_ArrayElement;
954848b8605Smrg
955848b8605Smrg   vfmt->Begin = vbo_exec_Begin;
956848b8605Smrg   vfmt->End = vbo_exec_End;
957848b8605Smrg   vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
958848b8605Smrg
959848b8605Smrg   vfmt->CallList = _mesa_CallList;
960848b8605Smrg   vfmt->CallLists = _mesa_CallLists;
961848b8605Smrg
962848b8605Smrg   vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
963848b8605Smrg   vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
964848b8605Smrg   vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
965848b8605Smrg   vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
966848b8605Smrg   vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
967848b8605Smrg   vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
968848b8605Smrg
969848b8605Smrg   /* from attrib_tmp.h:
970848b8605Smrg    */
971848b8605Smrg   vfmt->Color3f = vbo_Color3f;
972848b8605Smrg   vfmt->Color3fv = vbo_Color3fv;
973848b8605Smrg   vfmt->Color4f = vbo_Color4f;
974848b8605Smrg   vfmt->Color4fv = vbo_Color4fv;
975848b8605Smrg   vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
976848b8605Smrg   vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
977848b8605Smrg   vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
978848b8605Smrg   vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
979848b8605Smrg   vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
980848b8605Smrg   vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
981848b8605Smrg   vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
982848b8605Smrg   vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
983848b8605Smrg   vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
984848b8605Smrg   vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
985848b8605Smrg   vfmt->Normal3f = vbo_Normal3f;
986848b8605Smrg   vfmt->Normal3fv = vbo_Normal3fv;
987848b8605Smrg   vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
988848b8605Smrg   vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
989848b8605Smrg   vfmt->TexCoord1f = vbo_TexCoord1f;
990848b8605Smrg   vfmt->TexCoord1fv = vbo_TexCoord1fv;
991848b8605Smrg   vfmt->TexCoord2f = vbo_TexCoord2f;
992848b8605Smrg   vfmt->TexCoord2fv = vbo_TexCoord2fv;
993848b8605Smrg   vfmt->TexCoord3f = vbo_TexCoord3f;
994848b8605Smrg   vfmt->TexCoord3fv = vbo_TexCoord3fv;
995848b8605Smrg   vfmt->TexCoord4f = vbo_TexCoord4f;
996848b8605Smrg   vfmt->TexCoord4fv = vbo_TexCoord4fv;
997848b8605Smrg   vfmt->Vertex2f = vbo_Vertex2f;
998848b8605Smrg   vfmt->Vertex2fv = vbo_Vertex2fv;
999848b8605Smrg   vfmt->Vertex3f = vbo_Vertex3f;
1000848b8605Smrg   vfmt->Vertex3fv = vbo_Vertex3fv;
1001848b8605Smrg   vfmt->Vertex4f = vbo_Vertex4f;
1002848b8605Smrg   vfmt->Vertex4fv = vbo_Vertex4fv;
1003b8e80941Smrg
1004848b8605Smrg   if (ctx->API == API_OPENGLES2) {
1005848b8605Smrg      vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
1006848b8605Smrg      vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
1007848b8605Smrg      vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
1008848b8605Smrg      vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
1009848b8605Smrg      vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
1010848b8605Smrg      vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
1011848b8605Smrg      vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
1012848b8605Smrg      vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
1013848b8605Smrg   } else {
1014848b8605Smrg      vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
1015848b8605Smrg      vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
1016848b8605Smrg      vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
1017848b8605Smrg      vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
1018848b8605Smrg      vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
1019848b8605Smrg      vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
1020848b8605Smrg      vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
1021848b8605Smrg      vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
1022848b8605Smrg   }
1023848b8605Smrg
1024848b8605Smrg   /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
1025848b8605Smrg    * they can have a single entrypoint for updating any of the legacy
1026848b8605Smrg    * attribs.
1027848b8605Smrg    */
1028848b8605Smrg   vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
1029848b8605Smrg   vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
1030848b8605Smrg   vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
1031848b8605Smrg   vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
1032848b8605Smrg   vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
1033848b8605Smrg   vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
1034848b8605Smrg   vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
1035848b8605Smrg   vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
1036848b8605Smrg
1037848b8605Smrg   /* integer-valued */
1038848b8605Smrg   vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
1039848b8605Smrg   vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
1040848b8605Smrg   vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
1041848b8605Smrg   vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
1042848b8605Smrg   vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
1043848b8605Smrg   vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
1044848b8605Smrg   vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
1045848b8605Smrg
1046848b8605Smrg   /* unsigned integer-valued */
1047848b8605Smrg   vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
1048848b8605Smrg   vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
1049848b8605Smrg   vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
1050848b8605Smrg   vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
1051848b8605Smrg   vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
1052848b8605Smrg   vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
1053848b8605Smrg   vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
1054848b8605Smrg
1055848b8605Smrg   vfmt->Materialfv = vbo_Materialfv;
1056848b8605Smrg
1057848b8605Smrg   vfmt->EdgeFlag = vbo_EdgeFlag;
1058848b8605Smrg   vfmt->Indexf = vbo_Indexf;
1059848b8605Smrg   vfmt->Indexfv = vbo_Indexfv;
1060848b8605Smrg
1061848b8605Smrg   /* ARB_vertex_type_2_10_10_10_rev */
1062848b8605Smrg   vfmt->VertexP2ui = vbo_VertexP2ui;
1063848b8605Smrg   vfmt->VertexP2uiv = vbo_VertexP2uiv;
1064848b8605Smrg   vfmt->VertexP3ui = vbo_VertexP3ui;
1065848b8605Smrg   vfmt->VertexP3uiv = vbo_VertexP3uiv;
1066848b8605Smrg   vfmt->VertexP4ui = vbo_VertexP4ui;
1067848b8605Smrg   vfmt->VertexP4uiv = vbo_VertexP4uiv;
1068848b8605Smrg
1069848b8605Smrg   vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
1070848b8605Smrg   vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
1071848b8605Smrg   vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
1072848b8605Smrg   vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
1073848b8605Smrg   vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
1074848b8605Smrg   vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
1075848b8605Smrg   vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
1076848b8605Smrg   vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
1077848b8605Smrg
1078848b8605Smrg   vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
1079848b8605Smrg   vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
1080848b8605Smrg   vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
1081848b8605Smrg   vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
1082848b8605Smrg   vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
1083848b8605Smrg   vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
1084848b8605Smrg   vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
1085848b8605Smrg   vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
1086b8e80941Smrg
1087848b8605Smrg   vfmt->NormalP3ui = vbo_NormalP3ui;
1088848b8605Smrg   vfmt->NormalP3uiv = vbo_NormalP3uiv;
1089848b8605Smrg
1090848b8605Smrg   vfmt->ColorP3ui = vbo_ColorP3ui;
1091848b8605Smrg   vfmt->ColorP3uiv = vbo_ColorP3uiv;
1092848b8605Smrg   vfmt->ColorP4ui = vbo_ColorP4ui;
1093848b8605Smrg   vfmt->ColorP4uiv = vbo_ColorP4uiv;
1094848b8605Smrg
1095848b8605Smrg   vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
1096848b8605Smrg   vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
1097848b8605Smrg
1098848b8605Smrg   vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
1099848b8605Smrg   vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
1100848b8605Smrg   vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
1101848b8605Smrg   vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
1102848b8605Smrg   vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
1103848b8605Smrg   vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
1104848b8605Smrg   vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
1105848b8605Smrg   vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
1106b8e80941Smrg
1107b8e80941Smrg   vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
1108b8e80941Smrg   vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
1109b8e80941Smrg   vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
1110b8e80941Smrg   vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
1111b8e80941Smrg
1112b8e80941Smrg   vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
1113b8e80941Smrg   vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
1114b8e80941Smrg   vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
1115b8e80941Smrg   vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
1116b8e80941Smrg
1117b8e80941Smrg   vfmt->VertexAttribL1ui64ARB = vbo_VertexAttribL1ui64ARB;
1118b8e80941Smrg   vfmt->VertexAttribL1ui64vARB = vbo_VertexAttribL1ui64vARB;
1119848b8605Smrg}
1120848b8605Smrg
1121848b8605Smrg
1122848b8605Smrg/**
1123848b8605Smrg * Tell the VBO module to use a real OpenGL vertex buffer object to
1124848b8605Smrg * store accumulated immediate-mode vertex data.
1125848b8605Smrg * This replaces the malloced buffer which was created in
1126848b8605Smrg * vb_exec_vtx_init() below.
1127848b8605Smrg */
1128b8e80941Smrgvoid
1129b8e80941Smrgvbo_use_buffer_objects(struct gl_context *ctx)
1130848b8605Smrg{
1131848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1132848b8605Smrg   /* Any buffer name but 0 can be used here since this bufferobj won't
1133848b8605Smrg    * go into the bufferobj hashtable.
1134848b8605Smrg    */
1135848b8605Smrg   GLuint bufName = IMM_BUFFER_NAME;
1136848b8605Smrg   GLenum target = GL_ARRAY_BUFFER_ARB;
1137848b8605Smrg   GLenum usage = GL_STREAM_DRAW_ARB;
1138848b8605Smrg   GLsizei size = VBO_VERT_BUFFER_SIZE;
1139848b8605Smrg
1140848b8605Smrg   /* Make sure this func is only used once */
1141848b8605Smrg   assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1142848b8605Smrg
1143848b8605Smrg   _mesa_align_free(exec->vtx.buffer_map);
1144848b8605Smrg   exec->vtx.buffer_map = NULL;
1145848b8605Smrg   exec->vtx.buffer_ptr = NULL;
1146848b8605Smrg
1147848b8605Smrg   /* Allocate a real buffer object now */
1148848b8605Smrg   _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1149b8e80941Smrg   exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName);
1150848b8605Smrg   if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage,
1151848b8605Smrg                               GL_MAP_WRITE_BIT |
1152848b8605Smrg                               GL_DYNAMIC_STORAGE_BIT |
1153848b8605Smrg                               GL_CLIENT_STORAGE_BIT,
1154848b8605Smrg                               exec->vtx.bufferobj)) {
1155848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1156848b8605Smrg   }
1157848b8605Smrg}
1158848b8605Smrg
1159848b8605Smrg
1160848b8605Smrg/**
1161848b8605Smrg * If this function is called, all VBO buffers will be unmapped when
1162848b8605Smrg * we flush.
1163848b8605Smrg * Otherwise, if a simple command like glColor3f() is called and we flush,
1164848b8605Smrg * the current VBO may be left mapped.
1165848b8605Smrg */
1166848b8605Smrgvoid
1167848b8605Smrgvbo_always_unmap_buffers(struct gl_context *ctx)
1168848b8605Smrg{
1169848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1170848b8605Smrg   exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1171848b8605Smrg}
1172848b8605Smrg
1173848b8605Smrg
1174b8e80941Smrgvoid
1175b8e80941Smrgvbo_exec_vtx_init(struct vbo_exec_context *exec)
1176848b8605Smrg{
1177848b8605Smrg   struct gl_context *ctx = exec->ctx;
1178848b8605Smrg   GLuint i;
1179848b8605Smrg
1180848b8605Smrg   /* Allocate a buffer object.  Will just reuse this object
1181848b8605Smrg    * continuously, unless vbo_use_buffer_objects() is called to enable
1182848b8605Smrg    * use of real VBOs.
1183848b8605Smrg    */
1184848b8605Smrg   _mesa_reference_buffer_object(ctx,
1185848b8605Smrg                                 &exec->vtx.bufferobj,
1186848b8605Smrg                                 ctx->Shared->NullBufferObj);
1187848b8605Smrg
1188b8e80941Smrg   assert(!exec->vtx.buffer_map);
1189848b8605Smrg   exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
1190848b8605Smrg   exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1191848b8605Smrg
1192b8e80941Smrg   vbo_exec_vtxfmt_init(exec);
1193848b8605Smrg   _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1194848b8605Smrg
1195b8e80941Smrg   exec->vtx.enabled = 0;
1196848b8605Smrg   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1197b8e80941Smrg      assert(i < ARRAY_SIZE(exec->vtx.attrsz));
1198848b8605Smrg      exec->vtx.attrsz[i] = 0;
1199b8e80941Smrg      assert(i < ARRAY_SIZE(exec->vtx.attrtype));
1200848b8605Smrg      exec->vtx.attrtype[i] = GL_FLOAT;
1201b8e80941Smrg      assert(i < ARRAY_SIZE(exec->vtx.active_sz));
1202848b8605Smrg      exec->vtx.active_sz[i] = 0;
1203848b8605Smrg   }
1204848b8605Smrg
1205848b8605Smrg   exec->vtx.vertex_size = 0;
1206848b8605Smrg
1207848b8605Smrg   exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1208848b8605Smrg}
1209848b8605Smrg
1210848b8605Smrg
1211b8e80941Smrgvoid
1212b8e80941Smrgvbo_exec_vtx_destroy(struct vbo_exec_context *exec)
1213848b8605Smrg{
1214848b8605Smrg   /* using a real VBO for vertex data */
1215848b8605Smrg   struct gl_context *ctx = exec->ctx;
1216848b8605Smrg
1217848b8605Smrg   /* True VBOs should already be unmapped
1218848b8605Smrg    */
1219848b8605Smrg   if (exec->vtx.buffer_map) {
1220b8e80941Smrg      assert(exec->vtx.bufferobj->Name == 0 ||
1221848b8605Smrg             exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1222848b8605Smrg      if (exec->vtx.bufferobj->Name == 0) {
1223848b8605Smrg         _mesa_align_free(exec->vtx.buffer_map);
1224848b8605Smrg         exec->vtx.buffer_map = NULL;
1225848b8605Smrg         exec->vtx.buffer_ptr = NULL;
1226848b8605Smrg      }
1227848b8605Smrg   }
1228848b8605Smrg
1229848b8605Smrg   /* Free the vertex buffer.  Unmap first if needed.
1230848b8605Smrg    */
1231848b8605Smrg   if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1232848b8605Smrg      ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
1233848b8605Smrg   }
1234848b8605Smrg   _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1235848b8605Smrg}
1236848b8605Smrg
1237848b8605Smrg
1238848b8605Smrg/**
1239b8e80941Smrg * If inside glBegin()/glEnd(), it should assert(0).  Otherwise, if
1240b8e80941Smrg * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1241b8e80941Smrg * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1242b8e80941Smrg * __struct gl_contextRec::Current and gl_light_attrib::Material
1243b8e80941Smrg *
1244b8e80941Smrg * Note that the default T&L engine never clears the
1245b8e80941Smrg * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1246b8e80941Smrg *
1247848b8605Smrg * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1248848b8605Smrg */
1249b8e80941Smrgvoid
1250b8e80941Smrgvbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags)
1251848b8605Smrg{
1252848b8605Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1253848b8605Smrg
1254848b8605Smrg#ifdef DEBUG
1255848b8605Smrg   /* debug check: make sure we don't get called recursively */
1256848b8605Smrg   exec->flush_call_depth++;
1257848b8605Smrg   assert(exec->flush_call_depth == 1);
1258848b8605Smrg#endif
1259848b8605Smrg
1260848b8605Smrg   if (_mesa_inside_begin_end(ctx)) {
1261848b8605Smrg      /* We've had glBegin but not glEnd! */
1262848b8605Smrg#ifdef DEBUG
1263848b8605Smrg      exec->flush_call_depth--;
1264848b8605Smrg      assert(exec->flush_call_depth == 0);
1265848b8605Smrg#endif
1266848b8605Smrg      return;
1267848b8605Smrg   }
1268848b8605Smrg
1269848b8605Smrg   /* Flush (draw), and make sure VBO is left unmapped when done */
1270848b8605Smrg   vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1271848b8605Smrg
1272b8e80941Smrg   /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1273848b8605Smrg    */
1274848b8605Smrg   ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1275848b8605Smrg
1276848b8605Smrg#ifdef DEBUG
1277848b8605Smrg   exec->flush_call_depth--;
1278848b8605Smrg   assert(exec->flush_call_depth == 0);
1279848b8605Smrg#endif
1280848b8605Smrg}
1281848b8605Smrg
1282848b8605Smrg
1283b8e80941Smrg/**
1284b8e80941Smrg * Reset the vertex attribute by setting its size to zero.
1285b8e80941Smrg */
1286b8e80941Smrgstatic void
1287b8e80941Smrgvbo_reset_attr(struct vbo_exec_context *exec, GLuint attr)
1288b8e80941Smrg{
1289b8e80941Smrg   exec->vtx.attrsz[attr] = 0;
1290b8e80941Smrg   exec->vtx.attrtype[attr] = GL_FLOAT;
1291b8e80941Smrg   exec->vtx.active_sz[attr] = 0;
1292b8e80941Smrg}
1293848b8605Smrg
1294b8e80941Smrg
1295b8e80941Smrgstatic void
1296b8e80941Smrgvbo_reset_all_attr(struct vbo_exec_context *exec)
1297b8e80941Smrg{
1298b8e80941Smrg   while (exec->vtx.enabled) {
1299b8e80941Smrg      const int i = u_bit_scan64(&exec->vtx.enabled);
1300b8e80941Smrg      vbo_reset_attr(exec, i);
1301848b8605Smrg   }
1302848b8605Smrg
1303848b8605Smrg   exec->vtx.vertex_size = 0;
1304848b8605Smrg}
1305b8e80941Smrg
1306848b8605Smrg
1307848b8605Smrgvoid GLAPIENTRY
1308848b8605Smrg_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1309848b8605Smrg{
1310848b8605Smrg   vbo_Color4f(r, g, b, a);
1311848b8605Smrg}
1312848b8605Smrg
1313848b8605Smrg
1314848b8605Smrgvoid GLAPIENTRY
1315848b8605Smrg_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1316848b8605Smrg{
1317848b8605Smrg   vbo_Normal3f(x, y, z);
1318848b8605Smrg}
1319848b8605Smrg
1320848b8605Smrg
1321848b8605Smrgvoid GLAPIENTRY
1322848b8605Smrg_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1323848b8605Smrg{
1324848b8605Smrg   vbo_MultiTexCoord4f(target, s, t, r, q);
1325848b8605Smrg}
1326848b8605Smrg
1327848b8605Smrg
1328848b8605Smrgvoid GLAPIENTRY
1329848b8605Smrg_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1330848b8605Smrg{
1331848b8605Smrg   vbo_Materialfv(face, pname, params);
1332848b8605Smrg}
1333848b8605Smrg
1334848b8605Smrg
1335848b8605Smrgvoid GLAPIENTRY
1336848b8605Smrg_es_Materialf(GLenum face, GLenum pname, GLfloat param)
1337848b8605Smrg{
1338848b8605Smrg   GLfloat p[4];
1339848b8605Smrg   p[0] = param;
1340848b8605Smrg   p[1] = p[2] = p[3] = 0.0F;
1341848b8605Smrg   vbo_Materialfv(face, pname, p);
1342848b8605Smrg}
1343848b8605Smrg
1344848b8605Smrg
1345848b8605Smrg/**
1346848b8605Smrg * A special version of glVertexAttrib4f that does not treat index 0 as
1347848b8605Smrg * VBO_ATTRIB_POS.
1348848b8605Smrg */
1349848b8605Smrgstatic void
1350848b8605SmrgVertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1351848b8605Smrg{
1352848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1353848b8605Smrg   if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1354b8e80941Smrg      ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1355848b8605Smrg   else
1356848b8605Smrg      ERROR(GL_INVALID_VALUE);
1357848b8605Smrg}
1358848b8605Smrg
1359848b8605Smrgvoid GLAPIENTRY
1360848b8605Smrg_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1361848b8605Smrg{
1362848b8605Smrg   VertexAttrib4f_nopos(index, x, y, z, w);
1363848b8605Smrg}
1364848b8605Smrg
1365848b8605Smrg
1366848b8605Smrgvoid GLAPIENTRY
1367848b8605Smrg_es_VertexAttrib1f(GLuint indx, GLfloat x)
1368848b8605Smrg{
1369848b8605Smrg   VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1370848b8605Smrg}
1371848b8605Smrg
1372848b8605Smrg
1373848b8605Smrgvoid GLAPIENTRY
1374848b8605Smrg_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1375848b8605Smrg{
1376848b8605Smrg   VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1377848b8605Smrg}
1378848b8605Smrg
1379848b8605Smrg
1380848b8605Smrgvoid GLAPIENTRY
1381848b8605Smrg_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1382848b8605Smrg{
1383848b8605Smrg   VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1384848b8605Smrg}
1385848b8605Smrg
1386848b8605Smrg
1387848b8605Smrgvoid GLAPIENTRY
1388848b8605Smrg_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1389848b8605Smrg{
1390848b8605Smrg   VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1391848b8605Smrg}
1392848b8605Smrg
1393848b8605Smrg
1394848b8605Smrgvoid GLAPIENTRY
1395848b8605Smrg_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1396848b8605Smrg{
1397848b8605Smrg   VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1398848b8605Smrg}
1399848b8605Smrg
1400848b8605Smrg
1401848b8605Smrgvoid GLAPIENTRY
1402848b8605Smrg_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1403848b8605Smrg{
1404848b8605Smrg   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1405848b8605Smrg}
1406848b8605Smrg
1407848b8605Smrg
1408848b8605Smrgvoid GLAPIENTRY
1409848b8605Smrg_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1410848b8605Smrg{
1411848b8605Smrg   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1412848b8605Smrg}
1413