1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci
3bf215546Sopenharmony_ciCopyright 2002-2008 VMware, Inc.
4bf215546Sopenharmony_ci
5bf215546Sopenharmony_ciAll Rights Reserved.
6bf215546Sopenharmony_ci
7bf215546Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_cicopy of this software and associated documentation files (the "Software"),
9bf215546Sopenharmony_cito deal in the Software without restriction, including without limitation
10bf215546Sopenharmony_cion the rights to use, copy, modify, merge, publish, distribute, sub
11bf215546Sopenharmony_cilicense, and/or sell copies of the Software, and to permit persons to whom
12bf215546Sopenharmony_cithe Software is furnished to do so, subject to the following conditions:
13bf215546Sopenharmony_ci
14bf215546Sopenharmony_ciThe above copyright notice and this permission notice (including the next
15bf215546Sopenharmony_ciparagraph) shall be included in all copies or substantial portions of the
16bf215546Sopenharmony_ciSoftware.
17bf215546Sopenharmony_ci
18bf215546Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19bf215546Sopenharmony_ciIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20bf215546Sopenharmony_ciFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21bf215546Sopenharmony_ciVMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22bf215546Sopenharmony_ciDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23bf215546Sopenharmony_ciOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24bf215546Sopenharmony_ciUSE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci**************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/*
29bf215546Sopenharmony_ci * Authors:
30bf215546Sopenharmony_ci *   Keith Whitwell <keithw@vmware.com>
31bf215546Sopenharmony_ci */
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci/* Display list compiler attempts to store lists of vertices with the
36bf215546Sopenharmony_ci * same vertex layout.  Additionally it attempts to minimize the need
37bf215546Sopenharmony_ci * for execute-time fixup of these vertex lists, allowing them to be
38bf215546Sopenharmony_ci * cached on hardware.
39bf215546Sopenharmony_ci *
40bf215546Sopenharmony_ci * There are still some circumstances where this can be thwarted, for
41bf215546Sopenharmony_ci * example by building a list that consists of one very long primitive
42bf215546Sopenharmony_ci * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43bf215546Sopenharmony_ci * from inside a different begin/end object (Begin(Lines), CallList,
44bf215546Sopenharmony_ci * End).
45bf215546Sopenharmony_ci *
46bf215546Sopenharmony_ci * In that case the code will have to replay the list as individual
47bf215546Sopenharmony_ci * commands through the Exec dispatch table, or fix up the copied
48bf215546Sopenharmony_ci * vertices at execute-time.
49bf215546Sopenharmony_ci *
50bf215546Sopenharmony_ci * The other case where fixup is required is when a vertex attribute
51bf215546Sopenharmony_ci * is introduced in the middle of a primitive.  Eg:
52bf215546Sopenharmony_ci *  Begin(Lines)
53bf215546Sopenharmony_ci *  TexCoord1f()           Vertex2f()
54bf215546Sopenharmony_ci *  TexCoord1f() Color3f() Vertex2f()
55bf215546Sopenharmony_ci *  End()
56bf215546Sopenharmony_ci *
57bf215546Sopenharmony_ci *  If the current value of Color isn't known at compile-time, this
58bf215546Sopenharmony_ci *  primitive will require fixup.
59bf215546Sopenharmony_ci *
60bf215546Sopenharmony_ci *
61bf215546Sopenharmony_ci * The list compiler currently doesn't attempt to compile lists
62bf215546Sopenharmony_ci * containing EvalCoord or EvalPoint commands.  On encountering one of
63bf215546Sopenharmony_ci * these, compilation falls back to opcodes.
64bf215546Sopenharmony_ci *
65bf215546Sopenharmony_ci * This could be improved to fallback only when a mix of EvalCoord and
66bf215546Sopenharmony_ci * Vertex commands are issued within a single primitive.
67bf215546Sopenharmony_ci *
68bf215546Sopenharmony_ci * The compilation process works as follows. All vertex attributes
69bf215546Sopenharmony_ci * except position are copied to vbo_save_context::attrptr (see ATTR_UNION).
70bf215546Sopenharmony_ci * 'attrptr' are pointers to vbo_save_context::vertex ordered according to the enabled
71bf215546Sopenharmony_ci * attributes (se upgrade_vertex).
72bf215546Sopenharmony_ci * When the position attribute is received, all the attributes are then
73bf215546Sopenharmony_ci * copied to the vertex_store (see the end of ATTR_UNION).
74bf215546Sopenharmony_ci * The vertex_store is simply an extensible float array.
75bf215546Sopenharmony_ci * When the vertex list needs to be compiled (see compile_vertex_list),
76bf215546Sopenharmony_ci * several transformations are performed:
77bf215546Sopenharmony_ci *   - some primitives are merged together (eg: two consecutive GL_TRIANGLES
78bf215546Sopenharmony_ci * with 3 vertices can be merged in a single GL_TRIANGLES with 6 vertices).
79bf215546Sopenharmony_ci *   - an index buffer is built.
80bf215546Sopenharmony_ci *   - identical vertices are detected and only one is kept.
81bf215546Sopenharmony_ci * At the end of this transformation, the index buffer and the vertex buffer
82bf215546Sopenharmony_ci * are uploaded in vRAM in the same buffer object.
83bf215546Sopenharmony_ci * This buffer object is shared between multiple display list to allow
84bf215546Sopenharmony_ci * draw calls merging later.
85bf215546Sopenharmony_ci *
86bf215546Sopenharmony_ci * The layout of this buffer for two display lists is:
87bf215546Sopenharmony_ci *    V0A0|V0A1|V1A0|V1A1|P0I0|P0I1|V0A0V0A1V0A2|V1A1V1A1V1A2|...
88bf215546Sopenharmony_ci *                                 ` new list starts
89bf215546Sopenharmony_ci *        - VxAy: vertex x, attributes y
90bf215546Sopenharmony_ci *        - PxIy: draw x, index y
91bf215546Sopenharmony_ci *
92bf215546Sopenharmony_ci * To allow draw call merging, display list must use the same VAO, including
93bf215546Sopenharmony_ci * the same Offset in the buffer object. To achieve this, the start values of
94bf215546Sopenharmony_ci * the primitive are shifted and the indices adjusted (see offset_diff and
95bf215546Sopenharmony_ci * start_offset in compile_vertex_list).
96bf215546Sopenharmony_ci *
97bf215546Sopenharmony_ci * Display list using the loopback code (see vbo_save_playback_vertex_list_loopback),
98bf215546Sopenharmony_ci * can't be drawn with an index buffer so this transformation is disabled
99bf215546Sopenharmony_ci * in this case.
100bf215546Sopenharmony_ci */
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci#include "main/glheader.h"
104bf215546Sopenharmony_ci#include "main/arrayobj.h"
105bf215546Sopenharmony_ci#include "main/bufferobj.h"
106bf215546Sopenharmony_ci#include "main/context.h"
107bf215546Sopenharmony_ci#include "main/dlist.h"
108bf215546Sopenharmony_ci#include "main/enums.h"
109bf215546Sopenharmony_ci#include "main/eval.h"
110bf215546Sopenharmony_ci#include "main/macros.h"
111bf215546Sopenharmony_ci#include "main/draw_validate.h"
112bf215546Sopenharmony_ci#include "main/api_arrayelt.h"
113bf215546Sopenharmony_ci#include "main/dispatch.h"
114bf215546Sopenharmony_ci#include "main/state.h"
115bf215546Sopenharmony_ci#include "main/varray.h"
116bf215546Sopenharmony_ci#include "util/bitscan.h"
117bf215546Sopenharmony_ci#include "util/u_memory.h"
118bf215546Sopenharmony_ci#include "util/hash_table.h"
119bf215546Sopenharmony_ci#include "util/indices/u_indices.h"
120bf215546Sopenharmony_ci#include "util/u_prim.h"
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci#include "gallium/include/pipe/p_state.h"
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci#include "vbo_private.h"
125bf215546Sopenharmony_ci#include "api_exec_decl.h"
126bf215546Sopenharmony_ci#include "api_save.h"
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci#ifdef ERROR
129bf215546Sopenharmony_ci#undef ERROR
130bf215546Sopenharmony_ci#endif
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci/* An interesting VBO number/name to help with debugging */
133bf215546Sopenharmony_ci#define VBO_BUF_ID  12345
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_cistatic void GLAPIENTRY
136bf215546Sopenharmony_ci_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_cistatic void GLAPIENTRY
139bf215546Sopenharmony_ci_save_EvalCoord1f(GLfloat u);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_cistatic void GLAPIENTRY
142bf215546Sopenharmony_ci_save_EvalCoord2f(GLfloat u, GLfloat v);
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci/*
145bf215546Sopenharmony_ci * NOTE: Old 'parity' issue is gone, but copying can still be
146bf215546Sopenharmony_ci * wrong-footed on replay.
147bf215546Sopenharmony_ci */
148bf215546Sopenharmony_cistatic GLuint
149bf215546Sopenharmony_cicopy_vertices(struct gl_context *ctx,
150bf215546Sopenharmony_ci              const struct vbo_save_vertex_list *node,
151bf215546Sopenharmony_ci              const fi_type * src_buffer)
152bf215546Sopenharmony_ci{
153bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
154bf215546Sopenharmony_ci   struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
155bf215546Sopenharmony_ci   GLuint sz = save->vertex_size;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   if (prim->end || !prim->count || !sz)
158bf215546Sopenharmony_ci      return 0;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   const fi_type *src = src_buffer + prim->start * sz;
161bf215546Sopenharmony_ci   assert(save->copied.buffer == NULL);
162bf215546Sopenharmony_ci   save->copied.buffer = malloc(sizeof(fi_type) * sz * prim->count);
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   unsigned r = vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
165bf215546Sopenharmony_ci                                  prim->begin, sz, true, save->copied.buffer, src);
166bf215546Sopenharmony_ci   if (!r) {
167bf215546Sopenharmony_ci      free(save->copied.buffer);
168bf215546Sopenharmony_ci      save->copied.buffer = NULL;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci   return r;
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_cistatic struct vbo_save_primitive_store *
175bf215546Sopenharmony_cirealloc_prim_store(struct vbo_save_primitive_store *store, int prim_count)
176bf215546Sopenharmony_ci{
177bf215546Sopenharmony_ci   if (store == NULL)
178bf215546Sopenharmony_ci      store = CALLOC_STRUCT(vbo_save_primitive_store);
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   uint32_t old_size = store->size;
181bf215546Sopenharmony_ci   store->size = prim_count;
182bf215546Sopenharmony_ci   assert (old_size < store->size);
183bf215546Sopenharmony_ci   store->prims = realloc(store->prims, store->size * sizeof(struct _mesa_prim));
184bf215546Sopenharmony_ci   memset(&store->prims[old_size], 0, (store->size - old_size) * sizeof(struct _mesa_prim));
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   return store;
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic void
191bf215546Sopenharmony_cireset_counters(struct gl_context *ctx)
192bf215546Sopenharmony_ci{
193bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   save->vertex_store->used = 0;
196bf215546Sopenharmony_ci   save->prim_store->used = 0;
197bf215546Sopenharmony_ci   save->dangling_attr_ref = GL_FALSE;
198bf215546Sopenharmony_ci}
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci/**
201bf215546Sopenharmony_ci * For a list of prims, try merging prims that can just be extensions of the
202bf215546Sopenharmony_ci * previous prim.
203bf215546Sopenharmony_ci */
204bf215546Sopenharmony_cistatic void
205bf215546Sopenharmony_cimerge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
206bf215546Sopenharmony_ci            GLuint *prim_count)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   GLuint i;
209bf215546Sopenharmony_ci   struct _mesa_prim *prev_prim = prim_list;
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   for (i = 1; i < *prim_count; i++) {
212bf215546Sopenharmony_ci      struct _mesa_prim *this_prim = prim_list + i;
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci      vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci      if (vbo_merge_draws(ctx, true,
217bf215546Sopenharmony_ci                          prev_prim->mode, this_prim->mode,
218bf215546Sopenharmony_ci                          prev_prim->start, this_prim->start,
219bf215546Sopenharmony_ci                          &prev_prim->count, this_prim->count,
220bf215546Sopenharmony_ci                          prev_prim->basevertex, this_prim->basevertex,
221bf215546Sopenharmony_ci                          &prev_prim->end,
222bf215546Sopenharmony_ci                          this_prim->begin, this_prim->end)) {
223bf215546Sopenharmony_ci         /* We've found a prim that just extend the previous one.  Tack it
224bf215546Sopenharmony_ci          * onto the previous one, and let this primitive struct get dropped.
225bf215546Sopenharmony_ci          */
226bf215546Sopenharmony_ci         continue;
227bf215546Sopenharmony_ci      }
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci      /* If any previous primitives have been dropped, then we need to copy
230bf215546Sopenharmony_ci       * this later one into the next available slot.
231bf215546Sopenharmony_ci       */
232bf215546Sopenharmony_ci      prev_prim++;
233bf215546Sopenharmony_ci      if (prev_prim != this_prim)
234bf215546Sopenharmony_ci         *prev_prim = *this_prim;
235bf215546Sopenharmony_ci   }
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   *prim_count = prev_prim - prim_list + 1;
238bf215546Sopenharmony_ci}
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci/**
242bf215546Sopenharmony_ci * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
243bf215546Sopenharmony_ci * don't have to worry about handling the _mesa_prim::begin/end flags.
244bf215546Sopenharmony_ci * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
245bf215546Sopenharmony_ci */
246bf215546Sopenharmony_cistatic void
247bf215546Sopenharmony_ciconvert_line_loop_to_strip(struct vbo_save_context *save,
248bf215546Sopenharmony_ci                           struct vbo_save_vertex_list *node)
249bf215546Sopenharmony_ci{
250bf215546Sopenharmony_ci   struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   assert(prim->mode == GL_LINE_LOOP);
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   if (prim->end) {
255bf215546Sopenharmony_ci      /* Copy the 0th vertex to end of the buffer and extend the
256bf215546Sopenharmony_ci       * vertex count by one to finish the line loop.
257bf215546Sopenharmony_ci       */
258bf215546Sopenharmony_ci      const GLuint sz = save->vertex_size;
259bf215546Sopenharmony_ci      /* 0th vertex: */
260bf215546Sopenharmony_ci      const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz;
261bf215546Sopenharmony_ci      /* end of buffer: */
262bf215546Sopenharmony_ci      fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz;
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci      memcpy(dst, src, sz * sizeof(float));
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci      prim->count++;
267bf215546Sopenharmony_ci      node->cold->vertex_count++;
268bf215546Sopenharmony_ci      save->vertex_store->used += sz;
269bf215546Sopenharmony_ci   }
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   if (!prim->begin) {
272bf215546Sopenharmony_ci      /* Drawing the second or later section of a long line loop.
273bf215546Sopenharmony_ci       * Skip the 0th vertex.
274bf215546Sopenharmony_ci       */
275bf215546Sopenharmony_ci      prim->start++;
276bf215546Sopenharmony_ci      prim->count--;
277bf215546Sopenharmony_ci   }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   prim->mode = GL_LINE_STRIP;
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci/* Compare the present vao if it has the same setup. */
284bf215546Sopenharmony_cistatic bool
285bf215546Sopenharmony_cicompare_vao(gl_vertex_processing_mode mode,
286bf215546Sopenharmony_ci            const struct gl_vertex_array_object *vao,
287bf215546Sopenharmony_ci            const struct gl_buffer_object *bo, GLintptr buffer_offset,
288bf215546Sopenharmony_ci            GLuint stride, GLbitfield64 vao_enabled,
289bf215546Sopenharmony_ci            const GLubyte size[VBO_ATTRIB_MAX],
290bf215546Sopenharmony_ci            const GLenum16 type[VBO_ATTRIB_MAX],
291bf215546Sopenharmony_ci            const GLuint offset[VBO_ATTRIB_MAX])
292bf215546Sopenharmony_ci{
293bf215546Sopenharmony_ci   if (!vao)
294bf215546Sopenharmony_ci      return false;
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   /* If the enabled arrays are not the same we are not equal. */
297bf215546Sopenharmony_ci   if (vao_enabled != vao->Enabled)
298bf215546Sopenharmony_ci      return false;
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   /* Check the buffer binding at 0 */
301bf215546Sopenharmony_ci   if (vao->BufferBinding[0].BufferObj != bo)
302bf215546Sopenharmony_ci      return false;
303bf215546Sopenharmony_ci   /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
304bf215546Sopenharmony_ci   if (vao->BufferBinding[0].Stride != stride)
305bf215546Sopenharmony_ci      return false;
306bf215546Sopenharmony_ci   assert(vao->BufferBinding[0].InstanceDivisor == 0);
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
309bf215546Sopenharmony_ci   const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   /* Now check the enabled arrays */
312bf215546Sopenharmony_ci   GLbitfield mask = vao_enabled;
313bf215546Sopenharmony_ci   while (mask) {
314bf215546Sopenharmony_ci      const int attr = u_bit_scan(&mask);
315bf215546Sopenharmony_ci      const unsigned char vbo_attr = vao_to_vbo_map[attr];
316bf215546Sopenharmony_ci      const GLenum16 tp = type[vbo_attr];
317bf215546Sopenharmony_ci      const GLintptr off = offset[vbo_attr] + buffer_offset;
318bf215546Sopenharmony_ci      const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
319bf215546Sopenharmony_ci      if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
320bf215546Sopenharmony_ci         return false;
321bf215546Sopenharmony_ci      if (attrib->Format.Type != tp)
322bf215546Sopenharmony_ci         return false;
323bf215546Sopenharmony_ci      if (attrib->Format.Size != size[vbo_attr])
324bf215546Sopenharmony_ci         return false;
325bf215546Sopenharmony_ci      assert(attrib->Format.Format == GL_RGBA);
326bf215546Sopenharmony_ci      assert(attrib->Format.Normalized == GL_FALSE);
327bf215546Sopenharmony_ci      assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
328bf215546Sopenharmony_ci      assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
329bf215546Sopenharmony_ci      assert(attrib->BufferBindingIndex == 0);
330bf215546Sopenharmony_ci   }
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   return true;
333bf215546Sopenharmony_ci}
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci/* Create or reuse the vao for the vertex processing mode. */
337bf215546Sopenharmony_cistatic void
338bf215546Sopenharmony_ciupdate_vao(struct gl_context *ctx,
339bf215546Sopenharmony_ci           gl_vertex_processing_mode mode,
340bf215546Sopenharmony_ci           struct gl_vertex_array_object **vao,
341bf215546Sopenharmony_ci           struct gl_buffer_object *bo, GLintptr buffer_offset,
342bf215546Sopenharmony_ci           GLuint stride, GLbitfield64 vbo_enabled,
343bf215546Sopenharmony_ci           const GLubyte size[VBO_ATTRIB_MAX],
344bf215546Sopenharmony_ci           const GLenum16 type[VBO_ATTRIB_MAX],
345bf215546Sopenharmony_ci           const GLuint offset[VBO_ATTRIB_MAX])
346bf215546Sopenharmony_ci{
347bf215546Sopenharmony_ci   /* Compute the bitmasks of vao_enabled arrays */
348bf215546Sopenharmony_ci   GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   /*
351bf215546Sopenharmony_ci    * Check if we can possibly reuse the exisiting one.
352bf215546Sopenharmony_ci    * In the long term we should reset them when something changes.
353bf215546Sopenharmony_ci    */
354bf215546Sopenharmony_ci   if (compare_vao(mode, *vao, bo, buffer_offset, stride,
355bf215546Sopenharmony_ci                   vao_enabled, size, type, offset))
356bf215546Sopenharmony_ci      return;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   /* The initial refcount is 1 */
359bf215546Sopenharmony_ci   _mesa_reference_vao(ctx, vao, NULL);
360bf215546Sopenharmony_ci   *vao = _mesa_new_vao(ctx, ~((GLuint)0));
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   /*
363bf215546Sopenharmony_ci    * assert(stride <= ctx->Const.MaxVertexAttribStride);
364bf215546Sopenharmony_ci    * MaxVertexAttribStride is not set for drivers that does not
365bf215546Sopenharmony_ci    * expose GL 44 or GLES 31.
366bf215546Sopenharmony_ci    */
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   /* Bind the buffer object at binding point 0 */
369bf215546Sopenharmony_ci   _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
370bf215546Sopenharmony_ci                            false);
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
373bf215546Sopenharmony_ci    * Note that the position/generic0 aliasing is done in the VAO.
374bf215546Sopenharmony_ci    */
375bf215546Sopenharmony_ci   const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
376bf215546Sopenharmony_ci   /* Now set the enable arrays */
377bf215546Sopenharmony_ci   GLbitfield mask = vao_enabled;
378bf215546Sopenharmony_ci   while (mask) {
379bf215546Sopenharmony_ci      const int vao_attr = u_bit_scan(&mask);
380bf215546Sopenharmony_ci      const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
381bf215546Sopenharmony_ci      assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci      _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
384bf215546Sopenharmony_ci                             size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
385bf215546Sopenharmony_ci      _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
386bf215546Sopenharmony_ci   }
387bf215546Sopenharmony_ci   _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
388bf215546Sopenharmony_ci   assert(vao_enabled == (*vao)->Enabled);
389bf215546Sopenharmony_ci   assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci   /* Finalize and freeze the VAO */
392bf215546Sopenharmony_ci   _mesa_set_vao_immutable(ctx, *vao);
393bf215546Sopenharmony_ci}
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_cistatic void wrap_filled_vertex(struct gl_context *ctx);
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci/* Grow the vertex storage to accomodate for vertex_count new vertices */
398bf215546Sopenharmony_cistatic void
399bf215546Sopenharmony_cigrow_vertex_storage(struct gl_context *ctx, int vertex_count)
400bf215546Sopenharmony_ci{
401bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
402bf215546Sopenharmony_ci   assert (save->vertex_store);
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   int new_size = (save->vertex_store->used +
405bf215546Sopenharmony_ci                   vertex_count * save->vertex_size) * sizeof(GLfloat);
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci   /* Limit how much memory we allocate. */
408bf215546Sopenharmony_ci   if (save->prim_store->used > 0 &&
409bf215546Sopenharmony_ci       vertex_count > 0 &&
410bf215546Sopenharmony_ci       new_size > VBO_SAVE_BUFFER_SIZE) {
411bf215546Sopenharmony_ci      wrap_filled_vertex(ctx);
412bf215546Sopenharmony_ci      new_size = VBO_SAVE_BUFFER_SIZE;
413bf215546Sopenharmony_ci   }
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   if (new_size > save->vertex_store->buffer_in_ram_size) {
416bf215546Sopenharmony_ci      save->vertex_store->buffer_in_ram_size = new_size;
417bf215546Sopenharmony_ci      save->vertex_store->buffer_in_ram = realloc(save->vertex_store->buffer_in_ram,
418bf215546Sopenharmony_ci                                                  save->vertex_store->buffer_in_ram_size);
419bf215546Sopenharmony_ci      if (save->vertex_store->buffer_in_ram == NULL)
420bf215546Sopenharmony_ci         save->out_of_memory = true;
421bf215546Sopenharmony_ci   }
422bf215546Sopenharmony_ci}
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_cistruct vertex_key {
425bf215546Sopenharmony_ci   unsigned vertex_size;
426bf215546Sopenharmony_ci   fi_type *vertex_attributes;
427bf215546Sopenharmony_ci};
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_cistatic uint32_t _hash_vertex_key(const void *key)
430bf215546Sopenharmony_ci{
431bf215546Sopenharmony_ci   struct vertex_key *k = (struct vertex_key*)key;
432bf215546Sopenharmony_ci   unsigned sz = k->vertex_size;
433bf215546Sopenharmony_ci   assert(sz);
434bf215546Sopenharmony_ci   return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
435bf215546Sopenharmony_ci}
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_cistatic bool _compare_vertex_key(const void *key1, const void *key2)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci   struct vertex_key *k1 = (struct vertex_key*)key1;
440bf215546Sopenharmony_ci   struct vertex_key *k2 = (struct vertex_key*)key2;
441bf215546Sopenharmony_ci   /* All the compared vertices are going to be drawn with the same VAO,
442bf215546Sopenharmony_ci    * so we can compare the attributes. */
443bf215546Sopenharmony_ci   assert (k1->vertex_size == k2->vertex_size);
444bf215546Sopenharmony_ci   return memcmp(k1->vertex_attributes,
445bf215546Sopenharmony_ci                 k2->vertex_attributes,
446bf215546Sopenharmony_ci                 k1->vertex_size * sizeof(float)) == 0;
447bf215546Sopenharmony_ci}
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_cistatic void _free_entry(struct hash_entry *entry)
450bf215546Sopenharmony_ci{
451bf215546Sopenharmony_ci   free((void*)entry->key);
452bf215546Sopenharmony_ci}
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci/* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
455bf215546Sopenharmony_ci * of an existing vertex, return the original index instead.
456bf215546Sopenharmony_ci */
457bf215546Sopenharmony_cistatic uint32_t
458bf215546Sopenharmony_ciadd_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
459bf215546Sopenharmony_ci           uint32_t index, fi_type *new_buffer, uint32_t *max_index)
460bf215546Sopenharmony_ci{
461bf215546Sopenharmony_ci   /* If vertex deduplication is disabled return the original index. */
462bf215546Sopenharmony_ci   if (!hash_to_index)
463bf215546Sopenharmony_ci      return index;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index;
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci   struct vertex_key *key = malloc(sizeof(struct vertex_key));
468bf215546Sopenharmony_ci   key->vertex_size = save->vertex_size;
469bf215546Sopenharmony_ci   key->vertex_attributes = vert;
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
472bf215546Sopenharmony_ci   if (entry) {
473bf215546Sopenharmony_ci      free(key);
474bf215546Sopenharmony_ci      /* We found an existing vertex with the same hash, return its index. */
475bf215546Sopenharmony_ci      return (uintptr_t) entry->data;
476bf215546Sopenharmony_ci   } else {
477bf215546Sopenharmony_ci      /* This is a new vertex. Determine a new index and copy its attributes to the vertex
478bf215546Sopenharmony_ci       * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
479bf215546Sopenharmony_ci       * starting at index 0.
480bf215546Sopenharmony_ci       */
481bf215546Sopenharmony_ci      uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
482bf215546Sopenharmony_ci      *max_index = MAX2(n, *max_index);
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci      memcpy(&new_buffer[save->vertex_size * n],
485bf215546Sopenharmony_ci             vert,
486bf215546Sopenharmony_ci             save->vertex_size * sizeof(fi_type));
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci      _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n));
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci      /* The index buffer is shared between list compilations, so add the base index to get
491bf215546Sopenharmony_ci       * the final index.
492bf215546Sopenharmony_ci       */
493bf215546Sopenharmony_ci      return n;
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci}
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_cistatic uint32_t
499bf215546Sopenharmony_ciget_vertex_count(struct vbo_save_context *save)
500bf215546Sopenharmony_ci{
501bf215546Sopenharmony_ci   if (!save->vertex_size)
502bf215546Sopenharmony_ci      return 0;
503bf215546Sopenharmony_ci   return save->vertex_store->used / save->vertex_size;
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci/**
508bf215546Sopenharmony_ci * Insert the active immediate struct onto the display list currently
509bf215546Sopenharmony_ci * being built.
510bf215546Sopenharmony_ci */
511bf215546Sopenharmony_cistatic void
512bf215546Sopenharmony_cicompile_vertex_list(struct gl_context *ctx)
513bf215546Sopenharmony_ci{
514bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
515bf215546Sopenharmony_ci   struct vbo_save_vertex_list *node;
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   /* Allocate space for this structure in the display list currently
518bf215546Sopenharmony_ci    * being compiled.
519bf215546Sopenharmony_ci    */
520bf215546Sopenharmony_ci   node = (struct vbo_save_vertex_list *)
521bf215546Sopenharmony_ci      _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   if (!node)
524bf215546Sopenharmony_ci      return;
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   node->cold = calloc(1, sizeof(*node->cold));
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_ci   /* Make sure the pointer is aligned to the size of a pointer */
529bf215546Sopenharmony_ci   assert((GLintptr) node % sizeof(void *) == 0);
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   const GLsizei stride = save->vertex_size*sizeof(GLfloat);
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci   node->cold->vertex_count = get_vertex_count(save);
534bf215546Sopenharmony_ci   node->cold->wrap_count = save->copied.nr;
535bf215546Sopenharmony_ci   node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used);
536bf215546Sopenharmony_ci   memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used);
537bf215546Sopenharmony_ci   node->cold->ib.obj = NULL;
538bf215546Sopenharmony_ci   node->cold->prim_count = save->prim_store->used;
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci   if (save->no_current_update) {
541bf215546Sopenharmony_ci      node->cold->current_data = NULL;
542bf215546Sopenharmony_ci   }
543bf215546Sopenharmony_ci   else {
544bf215546Sopenharmony_ci      GLuint current_size = save->vertex_size - save->attrsz[0];
545bf215546Sopenharmony_ci      node->cold->current_data = NULL;
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci      if (current_size) {
548bf215546Sopenharmony_ci         node->cold->current_data = malloc(current_size * sizeof(GLfloat));
549bf215546Sopenharmony_ci         if (node->cold->current_data) {
550bf215546Sopenharmony_ci            const char *buffer = (const char *)save->vertex_store->buffer_in_ram;
551bf215546Sopenharmony_ci            unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
552bf215546Sopenharmony_ci            unsigned vertex_offset = 0;
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci            if (node->cold->vertex_count)
555bf215546Sopenharmony_ci               vertex_offset = (node->cold->vertex_count - 1) * stride;
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci            memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
558bf215546Sopenharmony_ci                   current_size * sizeof(GLfloat));
559bf215546Sopenharmony_ci         } else {
560bf215546Sopenharmony_ci            _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
561bf215546Sopenharmony_ci            save->out_of_memory = true;
562bf215546Sopenharmony_ci         }
563bf215546Sopenharmony_ci      }
564bf215546Sopenharmony_ci   }
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci   assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   if (save->dangling_attr_ref)
569bf215546Sopenharmony_ci      ctx->ListState.Current.UseLoopback = true;
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci   /* Copy duplicated vertices
572bf215546Sopenharmony_ci    */
573bf215546Sopenharmony_ci   save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram);
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_ci   if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
576bf215546Sopenharmony_ci      convert_line_loop_to_strip(save, node);
577bf215546Sopenharmony_ci   }
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci   merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci   GLintptr buffer_offset = 0;
582bf215546Sopenharmony_ci   GLuint start_offset = 0;
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci   /* Create an index buffer. */
585bf215546Sopenharmony_ci   node->cold->min_index = node->cold->max_index = 0;
586bf215546Sopenharmony_ci   if (node->cold->vertex_count == 0 || node->cold->prim_count == 0)
587bf215546Sopenharmony_ci      goto end;
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ci   /* We won't modify node->prims, so use a const alias to avoid unintended
590bf215546Sopenharmony_ci    * writes to it. */
591bf215546Sopenharmony_ci   const struct _mesa_prim *original_prims = node->cold->prims;
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci   int end = original_prims[node->cold->prim_count - 1].start +
594bf215546Sopenharmony_ci             original_prims[node->cold->prim_count - 1].count;
595bf215546Sopenharmony_ci   int total_vert_count = end - original_prims[0].start;
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   node->cold->min_index = node->cold->prims[0].start;
598bf215546Sopenharmony_ci   node->cold->max_index = end - 1;
599bf215546Sopenharmony_ci
600bf215546Sopenharmony_ci   /* converting primitive types may result in many more indices */
601bf215546Sopenharmony_ci   bool all_prims_supported = (ctx->Const.DriverSupportedPrimMask & BITFIELD_MASK(PIPE_PRIM_MAX)) == BITFIELD_MASK(PIPE_PRIM_MAX);
602bf215546Sopenharmony_ci   int max_index_count = total_vert_count * (all_prims_supported ? 2 : 3);
603bf215546Sopenharmony_ci   uint32_t* indices = (uint32_t*) malloc(max_index_count * sizeof(uint32_t));
604bf215546Sopenharmony_ci   void *tmp_indices = all_prims_supported ? NULL : malloc(max_index_count * sizeof(uint32_t));
605bf215546Sopenharmony_ci   struct _mesa_prim *merged_prims = NULL;
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci   int idx = 0;
608bf215546Sopenharmony_ci   struct hash_table *vertex_to_index = NULL;
609bf215546Sopenharmony_ci   fi_type *temp_vertices_buffer = NULL;
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci   /* The loopback replay code doesn't use the index buffer, so we can't
612bf215546Sopenharmony_ci    * dedup vertices in this case.
613bf215546Sopenharmony_ci    */
614bf215546Sopenharmony_ci   if (!ctx->ListState.Current.UseLoopback) {
615bf215546Sopenharmony_ci      vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
616bf215546Sopenharmony_ci      temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
617bf215546Sopenharmony_ci   }
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   uint32_t max_index = 0;
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_ci   int last_valid_prim = -1;
622bf215546Sopenharmony_ci   /* Construct indices array. */
623bf215546Sopenharmony_ci   for (unsigned i = 0; i < node->cold->prim_count; i++) {
624bf215546Sopenharmony_ci      assert(original_prims[i].basevertex == 0);
625bf215546Sopenharmony_ci      GLubyte mode = original_prims[i].mode;
626bf215546Sopenharmony_ci      bool converted_prim = false;
627bf215546Sopenharmony_ci      unsigned index_size;
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci      int vertex_count = original_prims[i].count;
630bf215546Sopenharmony_ci      if (!vertex_count) {
631bf215546Sopenharmony_ci         continue;
632bf215546Sopenharmony_ci      }
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci      /* Increase indices storage if the original estimation was too small. */
635bf215546Sopenharmony_ci      if (idx + 3 * vertex_count > max_index_count) {
636bf215546Sopenharmony_ci         max_index_count = max_index_count + 3 * vertex_count;
637bf215546Sopenharmony_ci         indices = (uint32_t*) realloc(indices, max_index_count * sizeof(uint32_t));
638bf215546Sopenharmony_ci         tmp_indices = all_prims_supported ? NULL : realloc(tmp_indices, max_index_count * sizeof(uint32_t));
639bf215546Sopenharmony_ci      }
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci      /* Line strips may get converted to lines */
642bf215546Sopenharmony_ci      if (mode == GL_LINE_STRIP)
643bf215546Sopenharmony_ci         mode = GL_LINES;
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci      if (!(ctx->Const.DriverSupportedPrimMask & BITFIELD_BIT(mode))) {
646bf215546Sopenharmony_ci         unsigned new_count;
647bf215546Sopenharmony_ci         u_generate_func trans_func;
648bf215546Sopenharmony_ci         enum pipe_prim_type pmode = (enum pipe_prim_type)mode;
649bf215546Sopenharmony_ci         u_index_generator(ctx->Const.DriverSupportedPrimMask,
650bf215546Sopenharmony_ci                           pmode, original_prims[i].start, vertex_count,
651bf215546Sopenharmony_ci                           PV_LAST, PV_LAST,
652bf215546Sopenharmony_ci                           &pmode, &index_size, &new_count,
653bf215546Sopenharmony_ci                           &trans_func);
654bf215546Sopenharmony_ci         if (new_count > 0)
655bf215546Sopenharmony_ci            trans_func(original_prims[i].start, new_count, tmp_indices);
656bf215546Sopenharmony_ci         vertex_count = new_count;
657bf215546Sopenharmony_ci         mode = (GLubyte)pmode;
658bf215546Sopenharmony_ci         converted_prim = true;
659bf215546Sopenharmony_ci      }
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci      /* If 2 consecutive prims use the same mode => merge them. */
662bf215546Sopenharmony_ci      bool merge_prims = last_valid_prim >= 0 &&
663bf215546Sopenharmony_ci                         mode == merged_prims[last_valid_prim].mode &&
664bf215546Sopenharmony_ci                         mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
665bf215546Sopenharmony_ci                         mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
666bf215546Sopenharmony_ci                         mode != GL_PATCHES;
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci/* index generation uses uint16_t if the index count is small enough */
669bf215546Sopenharmony_ci#define CAST_INDEX(BASE, SIZE, IDX) ((SIZE == 2 ? (uint32_t)(((uint16_t*)BASE)[IDX]) : ((uint32_t*)BASE)[IDX]))
670bf215546Sopenharmony_ci      /* To be able to merge consecutive triangle strips we need to insert
671bf215546Sopenharmony_ci       * a degenerate triangle.
672bf215546Sopenharmony_ci       */
673bf215546Sopenharmony_ci      if (merge_prims &&
674bf215546Sopenharmony_ci          mode == GL_TRIANGLE_STRIP) {
675bf215546Sopenharmony_ci         /* Insert a degenerate triangle */
676bf215546Sopenharmony_ci         assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
677bf215546Sopenharmony_ci         unsigned tri_count = merged_prims[last_valid_prim].count - 2;
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci         indices[idx] = indices[idx - 1];
680bf215546Sopenharmony_ci         indices[idx + 1] = add_vertex(save, vertex_to_index,
681bf215546Sopenharmony_ci                                       converted_prim ? CAST_INDEX(tmp_indices, index_size, 0) : original_prims[i].start,
682bf215546Sopenharmony_ci                                       temp_vertices_buffer, &max_index);
683bf215546Sopenharmony_ci         idx += 2;
684bf215546Sopenharmony_ci         merged_prims[last_valid_prim].count += 2;
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci         if (tri_count % 2) {
687bf215546Sopenharmony_ci            /* Add another index to preserve winding order */
688bf215546Sopenharmony_ci            indices[idx++] = add_vertex(save, vertex_to_index,
689bf215546Sopenharmony_ci                                        converted_prim ? CAST_INDEX(tmp_indices, index_size, 0) : original_prims[i].start,
690bf215546Sopenharmony_ci                                        temp_vertices_buffer, &max_index);
691bf215546Sopenharmony_ci            merged_prims[last_valid_prim].count++;
692bf215546Sopenharmony_ci         }
693bf215546Sopenharmony_ci      }
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_ci      int start = idx;
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci      /* Convert line strips to lines if it'll allow if the previous
698bf215546Sopenharmony_ci       * prim mode is GL_LINES (so merge_prims is true) or if the next
699bf215546Sopenharmony_ci       * primitive mode is GL_LINES or GL_LINE_LOOP.
700bf215546Sopenharmony_ci       */
701bf215546Sopenharmony_ci      if (original_prims[i].mode == GL_LINE_STRIP &&
702bf215546Sopenharmony_ci          (merge_prims ||
703bf215546Sopenharmony_ci           (i < node->cold->prim_count - 1 &&
704bf215546Sopenharmony_ci            (original_prims[i + 1].mode == GL_LINE_STRIP ||
705bf215546Sopenharmony_ci             original_prims[i + 1].mode == GL_LINES)))) {
706bf215546Sopenharmony_ci         for (unsigned j = 0; j < vertex_count; j++) {
707bf215546Sopenharmony_ci            indices[idx++] = add_vertex(save, vertex_to_index,
708bf215546Sopenharmony_ci                                        converted_prim ? CAST_INDEX(tmp_indices, index_size, j) : original_prims[i].start + j,
709bf215546Sopenharmony_ci                                        temp_vertices_buffer, &max_index);
710bf215546Sopenharmony_ci            /* Repeat all but the first/last indices. */
711bf215546Sopenharmony_ci            if (j && j != vertex_count - 1) {
712bf215546Sopenharmony_ci               indices[idx++] = add_vertex(save, vertex_to_index,
713bf215546Sopenharmony_ci                                           converted_prim ? CAST_INDEX(tmp_indices, index_size, j) : original_prims[i].start + j,
714bf215546Sopenharmony_ci                                           temp_vertices_buffer, &max_index);
715bf215546Sopenharmony_ci            }
716bf215546Sopenharmony_ci         }
717bf215546Sopenharmony_ci      } else {
718bf215546Sopenharmony_ci         /* We didn't convert to LINES, so restore the original mode */
719bf215546Sopenharmony_ci         if (!converted_prim)
720bf215546Sopenharmony_ci            mode = original_prims[i].mode;
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci         for (unsigned j = 0; j < vertex_count; j++) {
723bf215546Sopenharmony_ci            indices[idx++] = add_vertex(save, vertex_to_index,
724bf215546Sopenharmony_ci                                        converted_prim ? CAST_INDEX(tmp_indices, index_size, j) : original_prims[i].start + j,
725bf215546Sopenharmony_ci                                        temp_vertices_buffer, &max_index);
726bf215546Sopenharmony_ci         }
727bf215546Sopenharmony_ci      }
728bf215546Sopenharmony_ci
729bf215546Sopenharmony_ci      /* Duplicate the last vertex for incomplete primitives */
730bf215546Sopenharmony_ci      if (vertex_count > 0) {
731bf215546Sopenharmony_ci         unsigned min_vert = u_prim_vertex_count(mode)->min;
732bf215546Sopenharmony_ci         for (unsigned j = vertex_count; j < min_vert; j++) {
733bf215546Sopenharmony_ci            indices[idx++] = add_vertex(save, vertex_to_index,
734bf215546Sopenharmony_ci                                       converted_prim ? CAST_INDEX(tmp_indices, index_size, vertex_count - 1) :
735bf215546Sopenharmony_ci                                                         original_prims[i].start + vertex_count - 1,
736bf215546Sopenharmony_ci                                       temp_vertices_buffer, &max_index);
737bf215546Sopenharmony_ci         }
738bf215546Sopenharmony_ci      }
739bf215546Sopenharmony_ci
740bf215546Sopenharmony_ci#undef CAST_INDEX
741bf215546Sopenharmony_ci      if (merge_prims) {
742bf215546Sopenharmony_ci         /* Update vertex count. */
743bf215546Sopenharmony_ci         merged_prims[last_valid_prim].count += idx - start;
744bf215546Sopenharmony_ci      } else {
745bf215546Sopenharmony_ci         /* Keep this primitive */
746bf215546Sopenharmony_ci         last_valid_prim += 1;
747bf215546Sopenharmony_ci         assert(last_valid_prim <= i);
748bf215546Sopenharmony_ci         merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
749bf215546Sopenharmony_ci         merged_prims[last_valid_prim] = original_prims[i];
750bf215546Sopenharmony_ci         merged_prims[last_valid_prim].start = start;
751bf215546Sopenharmony_ci         merged_prims[last_valid_prim].count = idx - start;
752bf215546Sopenharmony_ci      }
753bf215546Sopenharmony_ci      merged_prims[last_valid_prim].mode = mode;
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci      /* converted prims will filter incomplete primitives and may have no indices */
756bf215546Sopenharmony_ci      assert((idx > 0 || converted_prim) && idx <= max_index_count);
757bf215546Sopenharmony_ci   }
758bf215546Sopenharmony_ci
759bf215546Sopenharmony_ci   unsigned merged_prim_count = last_valid_prim + 1;
760bf215546Sopenharmony_ci   node->cold->ib.ptr = NULL;
761bf215546Sopenharmony_ci   node->cold->ib.count = idx;
762bf215546Sopenharmony_ci   node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_ci   /* How many bytes do we need to store the indices and the vertices */
765bf215546Sopenharmony_ci   total_vert_count = vertex_to_index ? (max_index + 1) : idx;
766bf215546Sopenharmony_ci   unsigned total_bytes_needed = idx * sizeof(uint32_t) +
767bf215546Sopenharmony_ci                                 total_vert_count * save->vertex_size * sizeof(fi_type);
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci   const GLintptr old_offset = save->VAO[0] ?
770bf215546Sopenharmony_ci      save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0;
771bf215546Sopenharmony_ci   if (old_offset != save->current_bo_bytes_used && stride > 0) {
772bf215546Sopenharmony_ci      GLintptr offset_diff = save->current_bo_bytes_used - old_offset;
773bf215546Sopenharmony_ci      while (offset_diff > 0 &&
774bf215546Sopenharmony_ci             save->current_bo_bytes_used < save->current_bo->Size &&
775bf215546Sopenharmony_ci             offset_diff % stride != 0) {
776bf215546Sopenharmony_ci         save->current_bo_bytes_used++;
777bf215546Sopenharmony_ci         offset_diff = save->current_bo_bytes_used - old_offset;
778bf215546Sopenharmony_ci      }
779bf215546Sopenharmony_ci   }
780bf215546Sopenharmony_ci   buffer_offset = save->current_bo_bytes_used;
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_ci   /* Can we reuse the previous bo or should we allocate a new one? */
783bf215546Sopenharmony_ci   int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0;
784bf215546Sopenharmony_ci   if (total_bytes_needed > available_bytes) {
785bf215546Sopenharmony_ci      if (save->current_bo)
786bf215546Sopenharmony_ci         _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
787bf215546Sopenharmony_ci      save->current_bo = _mesa_bufferobj_alloc(ctx, VBO_BUF_ID + 1);
788bf215546Sopenharmony_ci      bool success = _mesa_bufferobj_data(ctx,
789bf215546Sopenharmony_ci                                          GL_ELEMENT_ARRAY_BUFFER_ARB,
790bf215546Sopenharmony_ci                                          MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE),
791bf215546Sopenharmony_ci                                          NULL,
792bf215546Sopenharmony_ci                                          GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT |
793bf215546Sopenharmony_ci                                          MESA_GALLIUM_VERTEX_STATE_STORAGE,
794bf215546Sopenharmony_ci                                          save->current_bo);
795bf215546Sopenharmony_ci      if (!success) {
796bf215546Sopenharmony_ci         _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
797bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
798bf215546Sopenharmony_ci         save->out_of_memory = true;
799bf215546Sopenharmony_ci      } else {
800bf215546Sopenharmony_ci         save->current_bo_bytes_used = 0;
801bf215546Sopenharmony_ci         available_bytes = save->current_bo->Size;
802bf215546Sopenharmony_ci      }
803bf215546Sopenharmony_ci      buffer_offset = 0;
804bf215546Sopenharmony_ci   } else {
805bf215546Sopenharmony_ci      assert(old_offset <= buffer_offset);
806bf215546Sopenharmony_ci      const GLintptr offset_diff = buffer_offset - old_offset;
807bf215546Sopenharmony_ci      if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
808bf215546Sopenharmony_ci         /* The vertex size is an exact multiple of the buffer offset.
809bf215546Sopenharmony_ci          * This means that we can use zero-based vertex attribute pointers
810bf215546Sopenharmony_ci          * and specify the start of the primitive with the _mesa_prim::start
811bf215546Sopenharmony_ci          * field.  This results in issuing several draw calls with identical
812bf215546Sopenharmony_ci          * vertex attribute information.  This can result in fewer state
813bf215546Sopenharmony_ci          * changes in drivers.  In particular, the Gallium CSO module will
814bf215546Sopenharmony_ci          * filter out redundant vertex buffer changes.
815bf215546Sopenharmony_ci          */
816bf215546Sopenharmony_ci         /* We cannot immediately update the primitives as some methods below
817bf215546Sopenharmony_ci          * still need the uncorrected start vertices
818bf215546Sopenharmony_ci          */
819bf215546Sopenharmony_ci         start_offset = offset_diff/stride;
820bf215546Sopenharmony_ci         assert(old_offset == buffer_offset - offset_diff);
821bf215546Sopenharmony_ci         buffer_offset = old_offset;
822bf215546Sopenharmony_ci      }
823bf215546Sopenharmony_ci
824bf215546Sopenharmony_ci      /* Correct the primitive starts, we can only do this here as copy_vertices
825bf215546Sopenharmony_ci       * and convert_line_loop_to_strip above consume the uncorrected starts.
826bf215546Sopenharmony_ci       * On the other hand the _vbo_loopback_vertex_list call below needs the
827bf215546Sopenharmony_ci       * primitives to be corrected already.
828bf215546Sopenharmony_ci       */
829bf215546Sopenharmony_ci      for (unsigned i = 0; i < node->cold->prim_count; i++) {
830bf215546Sopenharmony_ci         node->cold->prims[i].start += start_offset;
831bf215546Sopenharmony_ci      }
832bf215546Sopenharmony_ci      /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
833bf215546Sopenharmony_ci       * to apply this transformation to all indices and max_index.
834bf215546Sopenharmony_ci       */
835bf215546Sopenharmony_ci      for (unsigned i = 0; i < idx; i++)
836bf215546Sopenharmony_ci         indices[i] += start_offset;
837bf215546Sopenharmony_ci      max_index += start_offset;
838bf215546Sopenharmony_ci   }
839bf215546Sopenharmony_ci
840bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo);
841bf215546Sopenharmony_ci
842bf215546Sopenharmony_ci   /* Upload the vertices first (see buffer_offset) */
843bf215546Sopenharmony_ci   _mesa_bufferobj_subdata(ctx,
844bf215546Sopenharmony_ci                           save->current_bo_bytes_used,
845bf215546Sopenharmony_ci                           total_vert_count * save->vertex_size * sizeof(fi_type),
846bf215546Sopenharmony_ci                           vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram,
847bf215546Sopenharmony_ci                           node->cold->ib.obj);
848bf215546Sopenharmony_ci   save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type);
849bf215546Sopenharmony_ci
850bf215546Sopenharmony_ci  if (vertex_to_index) {
851bf215546Sopenharmony_ci      _mesa_hash_table_destroy(vertex_to_index, _free_entry);
852bf215546Sopenharmony_ci      free(temp_vertices_buffer);
853bf215546Sopenharmony_ci   }
854bf215546Sopenharmony_ci
855bf215546Sopenharmony_ci   /* Since we append the indices to an existing buffer, we need to adjust the start value of each
856bf215546Sopenharmony_ci    * primitive (not the indices themselves). */
857bf215546Sopenharmony_ci   if (!ctx->ListState.Current.UseLoopback) {
858bf215546Sopenharmony_ci      save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used;
859bf215546Sopenharmony_ci      int indices_offset = save->current_bo_bytes_used / 4;
860bf215546Sopenharmony_ci      for (int i = 0; i < merged_prim_count; i++) {
861bf215546Sopenharmony_ci         merged_prims[i].start += indices_offset;
862bf215546Sopenharmony_ci      }
863bf215546Sopenharmony_ci   }
864bf215546Sopenharmony_ci
865bf215546Sopenharmony_ci   /* Then upload the indices. */
866bf215546Sopenharmony_ci   if (node->cold->ib.obj) {
867bf215546Sopenharmony_ci      _mesa_bufferobj_subdata(ctx,
868bf215546Sopenharmony_ci                              save->current_bo_bytes_used,
869bf215546Sopenharmony_ci                              idx * sizeof(uint32_t),
870bf215546Sopenharmony_ci                              indices,
871bf215546Sopenharmony_ci                              node->cold->ib.obj);
872bf215546Sopenharmony_ci      save->current_bo_bytes_used += idx * sizeof(uint32_t);
873bf215546Sopenharmony_ci   } else {
874bf215546Sopenharmony_ci      node->cold->vertex_count = 0;
875bf215546Sopenharmony_ci      node->cold->prim_count = 0;
876bf215546Sopenharmony_ci   }
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci   /* Prepare for DrawGallium */
879bf215546Sopenharmony_ci   memset(&node->cold->info, 0, sizeof(struct pipe_draw_info));
880bf215546Sopenharmony_ci   /* The other info fields will be updated in vbo_save_playback_vertex_list */
881bf215546Sopenharmony_ci   node->cold->info.index_size = 4;
882bf215546Sopenharmony_ci   node->cold->info.instance_count = 1;
883bf215546Sopenharmony_ci   node->cold->info.index.gl_bo = node->cold->ib.obj;
884bf215546Sopenharmony_ci   if (merged_prim_count == 1) {
885bf215546Sopenharmony_ci      node->cold->info.mode = merged_prims[0].mode;
886bf215546Sopenharmony_ci      node->start_count.start = merged_prims[0].start;
887bf215546Sopenharmony_ci      node->start_count.count = merged_prims[0].count;
888bf215546Sopenharmony_ci      node->start_count.index_bias = 0;
889bf215546Sopenharmony_ci      node->modes = NULL;
890bf215546Sopenharmony_ci   } else {
891bf215546Sopenharmony_ci      node->modes = malloc(merged_prim_count * sizeof(unsigned char));
892bf215546Sopenharmony_ci      node->start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
893bf215546Sopenharmony_ci      for (unsigned i = 0; i < merged_prim_count; i++) {
894bf215546Sopenharmony_ci         node->start_counts[i].start = merged_prims[i].start;
895bf215546Sopenharmony_ci         node->start_counts[i].count = merged_prims[i].count;
896bf215546Sopenharmony_ci         node->start_counts[i].index_bias = 0;
897bf215546Sopenharmony_ci         node->modes[i] = merged_prims[i].mode;
898bf215546Sopenharmony_ci      }
899bf215546Sopenharmony_ci   }
900bf215546Sopenharmony_ci   node->num_draws = merged_prim_count;
901bf215546Sopenharmony_ci   if (node->num_draws > 1) {
902bf215546Sopenharmony_ci      bool same_mode = true;
903bf215546Sopenharmony_ci      for (unsigned i = 1; i < node->num_draws && same_mode; i++) {
904bf215546Sopenharmony_ci         same_mode = node->modes[i] == node->modes[0];
905bf215546Sopenharmony_ci      }
906bf215546Sopenharmony_ci      if (same_mode) {
907bf215546Sopenharmony_ci         /* All primitives use the same mode, so we can simplify a bit */
908bf215546Sopenharmony_ci         node->cold->info.mode = node->modes[0];
909bf215546Sopenharmony_ci         free(node->modes);
910bf215546Sopenharmony_ci         node->modes = NULL;
911bf215546Sopenharmony_ci      }
912bf215546Sopenharmony_ci   }
913bf215546Sopenharmony_ci
914bf215546Sopenharmony_ci   free(indices);
915bf215546Sopenharmony_ci   free(tmp_indices);
916bf215546Sopenharmony_ci   free(merged_prims);
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ciend:
919bf215546Sopenharmony_ci   node->draw_begins = node->cold->prims[0].begin;
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci   if (!save->current_bo) {
922bf215546Sopenharmony_ci      save->current_bo = _mesa_bufferobj_alloc(ctx, VBO_BUF_ID + 1);
923bf215546Sopenharmony_ci      bool success = _mesa_bufferobj_data(ctx,
924bf215546Sopenharmony_ci                                          GL_ELEMENT_ARRAY_BUFFER_ARB,
925bf215546Sopenharmony_ci                                          VBO_SAVE_BUFFER_SIZE,
926bf215546Sopenharmony_ci                                          NULL,
927bf215546Sopenharmony_ci                                          GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT |
928bf215546Sopenharmony_ci                                          MESA_GALLIUM_VERTEX_STATE_STORAGE,
929bf215546Sopenharmony_ci                                          save->current_bo);
930bf215546Sopenharmony_ci      if (!success)
931bf215546Sopenharmony_ci         save->out_of_memory = true;
932bf215546Sopenharmony_ci   }
933bf215546Sopenharmony_ci
934bf215546Sopenharmony_ci   GLuint offsets[VBO_ATTRIB_MAX];
935bf215546Sopenharmony_ci   for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
936bf215546Sopenharmony_ci      offsets[i] = offset;
937bf215546Sopenharmony_ci      offset += save->attrsz[i] * sizeof(GLfloat);
938bf215546Sopenharmony_ci   }
939bf215546Sopenharmony_ci   /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
940bf215546Sopenharmony_ci    * Note that this may reuse the previous one of possible.
941bf215546Sopenharmony_ci    */
942bf215546Sopenharmony_ci   for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
943bf215546Sopenharmony_ci      /* create or reuse the vao */
944bf215546Sopenharmony_ci      update_vao(ctx, vpm, &save->VAO[vpm],
945bf215546Sopenharmony_ci                 save->current_bo, buffer_offset, stride,
946bf215546Sopenharmony_ci                 save->enabled, save->attrsz, save->attrtype, offsets);
947bf215546Sopenharmony_ci      /* Reference the vao in the dlist */
948bf215546Sopenharmony_ci      node->cold->VAO[vpm] = NULL;
949bf215546Sopenharmony_ci      _mesa_reference_vao(ctx, &node->cold->VAO[vpm], save->VAO[vpm]);
950bf215546Sopenharmony_ci   }
951bf215546Sopenharmony_ci
952bf215546Sopenharmony_ci   /* Prepare for DrawGalliumVertexState */
953bf215546Sopenharmony_ci   if (node->num_draws && ctx->Driver.DrawGalliumVertexState) {
954bf215546Sopenharmony_ci      for (unsigned i = 0; i < VP_MODE_MAX; i++) {
955bf215546Sopenharmony_ci         uint32_t enabled_attribs = _vbo_get_vao_filter(i) &
956bf215546Sopenharmony_ci                                    node->cold->VAO[i]->_EnabledWithMapMode;
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci         node->state[i] =
959bf215546Sopenharmony_ci            ctx->Driver.CreateGalliumVertexState(ctx, node->cold->VAO[i],
960bf215546Sopenharmony_ci                                                 node->cold->ib.obj,
961bf215546Sopenharmony_ci                                                 enabled_attribs);
962bf215546Sopenharmony_ci         node->private_refcount[i] = 0;
963bf215546Sopenharmony_ci         node->enabled_attribs[i] = enabled_attribs;
964bf215546Sopenharmony_ci      }
965bf215546Sopenharmony_ci
966bf215546Sopenharmony_ci      node->ctx = ctx;
967bf215546Sopenharmony_ci      node->mode = node->cold->info.mode;
968bf215546Sopenharmony_ci      assert(node->cold->info.index_size == 4);
969bf215546Sopenharmony_ci   }
970bf215546Sopenharmony_ci
971bf215546Sopenharmony_ci   /* Deal with GL_COMPILE_AND_EXECUTE:
972bf215546Sopenharmony_ci    */
973bf215546Sopenharmony_ci   if (ctx->ExecuteFlag) {
974bf215546Sopenharmony_ci      struct _glapi_table *dispatch = GET_DISPATCH();
975bf215546Sopenharmony_ci
976bf215546Sopenharmony_ci      _glapi_set_dispatch(ctx->Exec);
977bf215546Sopenharmony_ci
978bf215546Sopenharmony_ci      /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to
979bf215546Sopenharmony_ci       * use buffer_in_ram (which contains all vertices) instead of current_bo
980bf215546Sopenharmony_ci       * (which contains deduplicated vertices *when* UseLoopback is false).
981bf215546Sopenharmony_ci       *
982bf215546Sopenharmony_ci       * The problem is that the VAO offset is based on current_bo's layout,
983bf215546Sopenharmony_ci       * so we have to use a temp value.
984bf215546Sopenharmony_ci       */
985bf215546Sopenharmony_ci      struct gl_vertex_array_object *vao = node->cold->VAO[VP_MODE_SHADER];
986bf215546Sopenharmony_ci      GLintptr original = vao->BufferBinding[0].Offset;
987bf215546Sopenharmony_ci      /* 'start_offset' has been added to all primitives 'start', so undo it here. */
988bf215546Sopenharmony_ci      vao->BufferBinding[0].Offset = -(GLintptr)(start_offset * stride);
989bf215546Sopenharmony_ci      _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
990bf215546Sopenharmony_ci      vao->BufferBinding[0].Offset = original;
991bf215546Sopenharmony_ci
992bf215546Sopenharmony_ci      _glapi_set_dispatch(dispatch);
993bf215546Sopenharmony_ci   }
994bf215546Sopenharmony_ci
995bf215546Sopenharmony_ci   /* Reset our structures for the next run of vertices:
996bf215546Sopenharmony_ci    */
997bf215546Sopenharmony_ci   reset_counters(ctx);
998bf215546Sopenharmony_ci}
999bf215546Sopenharmony_ci
1000bf215546Sopenharmony_ci
1001bf215546Sopenharmony_ci/**
1002bf215546Sopenharmony_ci * This is called when we fill a vertex buffer before we hit a glEnd().
1003bf215546Sopenharmony_ci * We
1004bf215546Sopenharmony_ci * TODO -- If no new vertices have been stored, don't bother saving it.
1005bf215546Sopenharmony_ci */
1006bf215546Sopenharmony_cistatic void
1007bf215546Sopenharmony_ciwrap_buffers(struct gl_context *ctx)
1008bf215546Sopenharmony_ci{
1009bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1010bf215546Sopenharmony_ci   GLint i = save->prim_store->used - 1;
1011bf215546Sopenharmony_ci   GLenum mode;
1012bf215546Sopenharmony_ci
1013bf215546Sopenharmony_ci   assert(i < (GLint) save->prim_store->size);
1014bf215546Sopenharmony_ci   assert(i >= 0);
1015bf215546Sopenharmony_ci
1016bf215546Sopenharmony_ci   /* Close off in-progress primitive.
1017bf215546Sopenharmony_ci    */
1018bf215546Sopenharmony_ci   save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
1019bf215546Sopenharmony_ci   mode = save->prim_store->prims[i].mode;
1020bf215546Sopenharmony_ci
1021bf215546Sopenharmony_ci   /* store the copied vertices, and allocate a new list.
1022bf215546Sopenharmony_ci    */
1023bf215546Sopenharmony_ci   compile_vertex_list(ctx);
1024bf215546Sopenharmony_ci
1025bf215546Sopenharmony_ci   /* Restart interrupted primitive
1026bf215546Sopenharmony_ci    */
1027bf215546Sopenharmony_ci   save->prim_store->prims[0].mode = mode;
1028bf215546Sopenharmony_ci   save->prim_store->prims[0].begin = 0;
1029bf215546Sopenharmony_ci   save->prim_store->prims[0].end = 0;
1030bf215546Sopenharmony_ci   save->prim_store->prims[0].start = 0;
1031bf215546Sopenharmony_ci   save->prim_store->prims[0].count = 0;
1032bf215546Sopenharmony_ci   save->prim_store->used = 1;
1033bf215546Sopenharmony_ci}
1034bf215546Sopenharmony_ci
1035bf215546Sopenharmony_ci
1036bf215546Sopenharmony_ci/**
1037bf215546Sopenharmony_ci * Called only when buffers are wrapped as the result of filling the
1038bf215546Sopenharmony_ci * vertex_store struct.
1039bf215546Sopenharmony_ci */
1040bf215546Sopenharmony_cistatic void
1041bf215546Sopenharmony_ciwrap_filled_vertex(struct gl_context *ctx)
1042bf215546Sopenharmony_ci{
1043bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1044bf215546Sopenharmony_ci   unsigned numComponents;
1045bf215546Sopenharmony_ci
1046bf215546Sopenharmony_ci   /* Emit a glEnd to close off the last vertex list.
1047bf215546Sopenharmony_ci    */
1048bf215546Sopenharmony_ci   wrap_buffers(ctx);
1049bf215546Sopenharmony_ci
1050bf215546Sopenharmony_ci   assert(save->vertex_store->used == 0 && save->vertex_store->used == 0);
1051bf215546Sopenharmony_ci
1052bf215546Sopenharmony_ci   /* Copy stored stored vertices to start of new list.
1053bf215546Sopenharmony_ci    */
1054bf215546Sopenharmony_ci   numComponents = save->copied.nr * save->vertex_size;
1055bf215546Sopenharmony_ci
1056bf215546Sopenharmony_ci   fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
1057bf215546Sopenharmony_ci   if (numComponents) {
1058bf215546Sopenharmony_ci      assert(save->copied.buffer);
1059bf215546Sopenharmony_ci      memcpy(buffer_ptr,
1060bf215546Sopenharmony_ci             save->copied.buffer,
1061bf215546Sopenharmony_ci             numComponents * sizeof(fi_type));
1062bf215546Sopenharmony_ci      free(save->copied.buffer);
1063bf215546Sopenharmony_ci      save->copied.buffer = NULL;
1064bf215546Sopenharmony_ci   }
1065bf215546Sopenharmony_ci   save->vertex_store->used = numComponents;
1066bf215546Sopenharmony_ci}
1067bf215546Sopenharmony_ci
1068bf215546Sopenharmony_ci
1069bf215546Sopenharmony_cistatic void
1070bf215546Sopenharmony_cicopy_to_current(struct gl_context *ctx)
1071bf215546Sopenharmony_ci{
1072bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1073bf215546Sopenharmony_ci   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1074bf215546Sopenharmony_ci
1075bf215546Sopenharmony_ci   while (enabled) {
1076bf215546Sopenharmony_ci      const int i = u_bit_scan64(&enabled);
1077bf215546Sopenharmony_ci      assert(save->attrsz[i]);
1078bf215546Sopenharmony_ci
1079bf215546Sopenharmony_ci      if (save->attrtype[i] == GL_DOUBLE ||
1080bf215546Sopenharmony_ci          save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
1081bf215546Sopenharmony_ci         memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
1082bf215546Sopenharmony_ci      else
1083bf215546Sopenharmony_ci         COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
1084bf215546Sopenharmony_ci                                     save->attrptr[i], save->attrtype[i]);
1085bf215546Sopenharmony_ci   }
1086bf215546Sopenharmony_ci}
1087bf215546Sopenharmony_ci
1088bf215546Sopenharmony_ci
1089bf215546Sopenharmony_cistatic void
1090bf215546Sopenharmony_cicopy_from_current(struct gl_context *ctx)
1091bf215546Sopenharmony_ci{
1092bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1093bf215546Sopenharmony_ci   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1094bf215546Sopenharmony_ci
1095bf215546Sopenharmony_ci   while (enabled) {
1096bf215546Sopenharmony_ci      const int i = u_bit_scan64(&enabled);
1097bf215546Sopenharmony_ci
1098bf215546Sopenharmony_ci      switch (save->attrsz[i]) {
1099bf215546Sopenharmony_ci      case 4:
1100bf215546Sopenharmony_ci         save->attrptr[i][3] = save->current[i][3];
1101bf215546Sopenharmony_ci         FALLTHROUGH;
1102bf215546Sopenharmony_ci      case 3:
1103bf215546Sopenharmony_ci         save->attrptr[i][2] = save->current[i][2];
1104bf215546Sopenharmony_ci         FALLTHROUGH;
1105bf215546Sopenharmony_ci      case 2:
1106bf215546Sopenharmony_ci         save->attrptr[i][1] = save->current[i][1];
1107bf215546Sopenharmony_ci         FALLTHROUGH;
1108bf215546Sopenharmony_ci      case 1:
1109bf215546Sopenharmony_ci         save->attrptr[i][0] = save->current[i][0];
1110bf215546Sopenharmony_ci         break;
1111bf215546Sopenharmony_ci      case 0:
1112bf215546Sopenharmony_ci         unreachable("Unexpected vertex attribute size");
1113bf215546Sopenharmony_ci      }
1114bf215546Sopenharmony_ci   }
1115bf215546Sopenharmony_ci}
1116bf215546Sopenharmony_ci
1117bf215546Sopenharmony_ci
1118bf215546Sopenharmony_ci/**
1119bf215546Sopenharmony_ci * Called when we increase the size of a vertex attribute.  For example,
1120bf215546Sopenharmony_ci * if we've seen one or more glTexCoord2f() calls and now we get a
1121bf215546Sopenharmony_ci * glTexCoord3f() call.
1122bf215546Sopenharmony_ci * Flush existing data, set new attrib size, replay copied vertices.
1123bf215546Sopenharmony_ci */
1124bf215546Sopenharmony_cistatic void
1125bf215546Sopenharmony_ciupgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1126bf215546Sopenharmony_ci{
1127bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1128bf215546Sopenharmony_ci   GLuint oldsz;
1129bf215546Sopenharmony_ci   GLuint i;
1130bf215546Sopenharmony_ci   fi_type *tmp;
1131bf215546Sopenharmony_ci
1132bf215546Sopenharmony_ci   /* Store the current run of vertices, and emit a GL_END.  Emit a
1133bf215546Sopenharmony_ci    * BEGIN in the new buffer.
1134bf215546Sopenharmony_ci    */
1135bf215546Sopenharmony_ci   if (save->vertex_store->used)
1136bf215546Sopenharmony_ci      wrap_buffers(ctx);
1137bf215546Sopenharmony_ci   else
1138bf215546Sopenharmony_ci      assert(save->copied.nr == 0);
1139bf215546Sopenharmony_ci
1140bf215546Sopenharmony_ci   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1141bf215546Sopenharmony_ci    * when the attribute already exists in the vertex and is having
1142bf215546Sopenharmony_ci    * its size increased.
1143bf215546Sopenharmony_ci    */
1144bf215546Sopenharmony_ci   copy_to_current(ctx);
1145bf215546Sopenharmony_ci
1146bf215546Sopenharmony_ci   /* Fix up sizes:
1147bf215546Sopenharmony_ci    */
1148bf215546Sopenharmony_ci   oldsz = save->attrsz[attr];
1149bf215546Sopenharmony_ci   save->attrsz[attr] = newsz;
1150bf215546Sopenharmony_ci   save->enabled |= BITFIELD64_BIT(attr);
1151bf215546Sopenharmony_ci
1152bf215546Sopenharmony_ci   save->vertex_size += newsz - oldsz;
1153bf215546Sopenharmony_ci
1154bf215546Sopenharmony_ci   /* Recalculate all the attrptr[] values:
1155bf215546Sopenharmony_ci    */
1156bf215546Sopenharmony_ci   tmp = save->vertex;
1157bf215546Sopenharmony_ci   for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1158bf215546Sopenharmony_ci      if (save->attrsz[i]) {
1159bf215546Sopenharmony_ci         save->attrptr[i] = tmp;
1160bf215546Sopenharmony_ci         tmp += save->attrsz[i];
1161bf215546Sopenharmony_ci      }
1162bf215546Sopenharmony_ci      else {
1163bf215546Sopenharmony_ci         save->attrptr[i] = NULL;       /* will not be dereferenced. */
1164bf215546Sopenharmony_ci      }
1165bf215546Sopenharmony_ci   }
1166bf215546Sopenharmony_ci
1167bf215546Sopenharmony_ci   /* Copy from current to repopulate the vertex with correct values.
1168bf215546Sopenharmony_ci    */
1169bf215546Sopenharmony_ci   copy_from_current(ctx);
1170bf215546Sopenharmony_ci
1171bf215546Sopenharmony_ci   /* Replay stored vertices to translate them to new format here.
1172bf215546Sopenharmony_ci    *
1173bf215546Sopenharmony_ci    * If there are copied vertices and the new (upgraded) attribute
1174bf215546Sopenharmony_ci    * has not been defined before, this list is somewhat degenerate,
1175bf215546Sopenharmony_ci    * and will need fixup at runtime.
1176bf215546Sopenharmony_ci    */
1177bf215546Sopenharmony_ci   if (save->copied.nr) {
1178bf215546Sopenharmony_ci      assert(save->copied.buffer);
1179bf215546Sopenharmony_ci      const fi_type *data = save->copied.buffer;
1180bf215546Sopenharmony_ci      grow_vertex_storage(ctx, save->copied.nr);
1181bf215546Sopenharmony_ci      fi_type *dest = save->vertex_store->buffer_in_ram;
1182bf215546Sopenharmony_ci
1183bf215546Sopenharmony_ci      /* Need to note this and fix up at runtime (or loopback):
1184bf215546Sopenharmony_ci       */
1185bf215546Sopenharmony_ci      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1186bf215546Sopenharmony_ci         assert(oldsz == 0);
1187bf215546Sopenharmony_ci         save->dangling_attr_ref = GL_TRUE;
1188bf215546Sopenharmony_ci      }
1189bf215546Sopenharmony_ci
1190bf215546Sopenharmony_ci      for (i = 0; i < save->copied.nr; i++) {
1191bf215546Sopenharmony_ci         GLbitfield64 enabled = save->enabled;
1192bf215546Sopenharmony_ci         while (enabled) {
1193bf215546Sopenharmony_ci            const int j = u_bit_scan64(&enabled);
1194bf215546Sopenharmony_ci            assert(save->attrsz[j]);
1195bf215546Sopenharmony_ci            if (j == attr) {
1196bf215546Sopenharmony_ci               int k;
1197bf215546Sopenharmony_ci               const fi_type *src = oldsz ? data : save->current[attr];
1198bf215546Sopenharmony_ci               int copy = oldsz ? oldsz : newsz;
1199bf215546Sopenharmony_ci               for (k = 0; k < copy; k++)
1200bf215546Sopenharmony_ci                  dest[k] = src[k];
1201bf215546Sopenharmony_ci               for (; k < newsz; k++) {
1202bf215546Sopenharmony_ci                  switch (save->attrtype[j]) {
1203bf215546Sopenharmony_ci                     case GL_FLOAT:
1204bf215546Sopenharmony_ci                        dest[k] = FLOAT_AS_UNION(k == 3);
1205bf215546Sopenharmony_ci                        break;
1206bf215546Sopenharmony_ci                     case GL_INT:
1207bf215546Sopenharmony_ci                        dest[k] = INT_AS_UNION(k == 3);
1208bf215546Sopenharmony_ci                        break;
1209bf215546Sopenharmony_ci                     case GL_UNSIGNED_INT:
1210bf215546Sopenharmony_ci                        dest[k] = UINT_AS_UNION(k == 3);
1211bf215546Sopenharmony_ci                        break;
1212bf215546Sopenharmony_ci                     default:
1213bf215546Sopenharmony_ci                        dest[k] = FLOAT_AS_UNION(k == 3);
1214bf215546Sopenharmony_ci                        assert(!"Unexpected type in upgrade_vertex");
1215bf215546Sopenharmony_ci                        break;
1216bf215546Sopenharmony_ci                  }
1217bf215546Sopenharmony_ci               }
1218bf215546Sopenharmony_ci               dest += newsz;
1219bf215546Sopenharmony_ci               data += oldsz;
1220bf215546Sopenharmony_ci            } else {
1221bf215546Sopenharmony_ci               GLint sz = save->attrsz[j];
1222bf215546Sopenharmony_ci               for (int k = 0; k < sz; k++)
1223bf215546Sopenharmony_ci                  dest[k] = data[k];
1224bf215546Sopenharmony_ci               data += sz;
1225bf215546Sopenharmony_ci               dest += sz;
1226bf215546Sopenharmony_ci            }
1227bf215546Sopenharmony_ci         }
1228bf215546Sopenharmony_ci      }
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci      save->vertex_store->used += save->vertex_size * save->copied.nr;
1231bf215546Sopenharmony_ci      free(save->copied.buffer);
1232bf215546Sopenharmony_ci      save->copied.buffer = NULL;
1233bf215546Sopenharmony_ci   }
1234bf215546Sopenharmony_ci}
1235bf215546Sopenharmony_ci
1236bf215546Sopenharmony_ci
1237bf215546Sopenharmony_ci/**
1238bf215546Sopenharmony_ci * This is called when the size of a vertex attribute changes.
1239bf215546Sopenharmony_ci * For example, after seeing one or more glTexCoord2f() calls we
1240bf215546Sopenharmony_ci * get a glTexCoord4f() or glTexCoord1f() call.
1241bf215546Sopenharmony_ci */
1242bf215546Sopenharmony_cistatic void
1243bf215546Sopenharmony_cifixup_vertex(struct gl_context *ctx, GLuint attr,
1244bf215546Sopenharmony_ci             GLuint sz, GLenum newType)
1245bf215546Sopenharmony_ci{
1246bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_ci   if (sz > save->attrsz[attr] ||
1249bf215546Sopenharmony_ci       newType != save->attrtype[attr]) {
1250bf215546Sopenharmony_ci      /* New size is larger.  Need to flush existing vertices and get
1251bf215546Sopenharmony_ci       * an enlarged vertex format.
1252bf215546Sopenharmony_ci       */
1253bf215546Sopenharmony_ci      upgrade_vertex(ctx, attr, sz);
1254bf215546Sopenharmony_ci   }
1255bf215546Sopenharmony_ci   else if (sz < save->active_sz[attr]) {
1256bf215546Sopenharmony_ci      GLuint i;
1257bf215546Sopenharmony_ci      const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1258bf215546Sopenharmony_ci
1259bf215546Sopenharmony_ci      /* New size is equal or smaller - just need to fill in some
1260bf215546Sopenharmony_ci       * zeros.
1261bf215546Sopenharmony_ci       */
1262bf215546Sopenharmony_ci      for (i = sz; i <= save->attrsz[attr]; i++)
1263bf215546Sopenharmony_ci         save->attrptr[attr][i - 1] = id[i - 1];
1264bf215546Sopenharmony_ci   }
1265bf215546Sopenharmony_ci
1266bf215546Sopenharmony_ci   save->active_sz[attr] = sz;
1267bf215546Sopenharmony_ci
1268bf215546Sopenharmony_ci   grow_vertex_storage(ctx, 1);
1269bf215546Sopenharmony_ci}
1270bf215546Sopenharmony_ci
1271bf215546Sopenharmony_ci
1272bf215546Sopenharmony_ci/**
1273bf215546Sopenharmony_ci * Reset the current size of all vertex attributes to the default
1274bf215546Sopenharmony_ci * value of 0.  This signals that we haven't yet seen any per-vertex
1275bf215546Sopenharmony_ci * commands such as glNormal3f() or glTexCoord2f().
1276bf215546Sopenharmony_ci */
1277bf215546Sopenharmony_cistatic void
1278bf215546Sopenharmony_cireset_vertex(struct gl_context *ctx)
1279bf215546Sopenharmony_ci{
1280bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1281bf215546Sopenharmony_ci
1282bf215546Sopenharmony_ci   while (save->enabled) {
1283bf215546Sopenharmony_ci      const int i = u_bit_scan64(&save->enabled);
1284bf215546Sopenharmony_ci      assert(save->attrsz[i]);
1285bf215546Sopenharmony_ci      save->attrsz[i] = 0;
1286bf215546Sopenharmony_ci      save->active_sz[i] = 0;
1287bf215546Sopenharmony_ci   }
1288bf215546Sopenharmony_ci
1289bf215546Sopenharmony_ci   save->vertex_size = 0;
1290bf215546Sopenharmony_ci}
1291bf215546Sopenharmony_ci
1292bf215546Sopenharmony_ci
1293bf215546Sopenharmony_ci/**
1294bf215546Sopenharmony_ci * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1295bf215546Sopenharmony_ci * It depends on a few things, including whether we're inside or outside
1296bf215546Sopenharmony_ci * of glBegin/glEnd.
1297bf215546Sopenharmony_ci */
1298bf215546Sopenharmony_cistatic inline bool
1299bf215546Sopenharmony_ciis_vertex_position(const struct gl_context *ctx, GLuint index)
1300bf215546Sopenharmony_ci{
1301bf215546Sopenharmony_ci   return (index == 0 &&
1302bf215546Sopenharmony_ci           _mesa_attr_zero_aliases_vertex(ctx) &&
1303bf215546Sopenharmony_ci           _mesa_inside_dlist_begin_end(ctx));
1304bf215546Sopenharmony_ci}
1305bf215546Sopenharmony_ci
1306bf215546Sopenharmony_ci
1307bf215546Sopenharmony_ci
1308bf215546Sopenharmony_ci#define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1309bf215546Sopenharmony_ci
1310bf215546Sopenharmony_ci
1311bf215546Sopenharmony_ci/* Only one size for each attribute may be active at once.  Eg. if
1312bf215546Sopenharmony_ci * Color3f is installed/active, then Color4f may not be, even if the
1313bf215546Sopenharmony_ci * vertex actually contains 4 color coordinates.  This is because the
1314bf215546Sopenharmony_ci * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1315bf215546Sopenharmony_ci * of the chooser function when switching between Color4f and Color3f.
1316bf215546Sopenharmony_ci */
1317bf215546Sopenharmony_ci#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1318bf215546Sopenharmony_cido {                                                            \
1319bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1320bf215546Sopenharmony_ci   int sz = (sizeof(C) / sizeof(GLfloat));                      \
1321bf215546Sopenharmony_ci                                                                \
1322bf215546Sopenharmony_ci   if (save->active_sz[A] != N)                                 \
1323bf215546Sopenharmony_ci      fixup_vertex(ctx, A, N * sz, T);                          \
1324bf215546Sopenharmony_ci                                                                \
1325bf215546Sopenharmony_ci   {                                                            \
1326bf215546Sopenharmony_ci      C *dest = (C *)save->attrptr[A];                          \
1327bf215546Sopenharmony_ci      if (N>0) dest[0] = V0;                                    \
1328bf215546Sopenharmony_ci      if (N>1) dest[1] = V1;                                    \
1329bf215546Sopenharmony_ci      if (N>2) dest[2] = V2;                                    \
1330bf215546Sopenharmony_ci      if (N>3) dest[3] = V3;                                    \
1331bf215546Sopenharmony_ci      save->attrtype[A] = T;                                    \
1332bf215546Sopenharmony_ci   }                                                            \
1333bf215546Sopenharmony_ci                                                                \
1334bf215546Sopenharmony_ci   if ((A) == VBO_ATTRIB_POS) {                                 \
1335bf215546Sopenharmony_ci      fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + \
1336bf215546Sopenharmony_ci                            save->vertex_store->used;           \
1337bf215546Sopenharmony_ci                                                                \
1338bf215546Sopenharmony_ci      for (int i = 0; i < save->vertex_size; i++)               \
1339bf215546Sopenharmony_ci        buffer_ptr[i] = save->vertex[i];                        \
1340bf215546Sopenharmony_ci                                                                \
1341bf215546Sopenharmony_ci      save->vertex_store->used += save->vertex_size;            \
1342bf215546Sopenharmony_ci      unsigned used_next = (save->vertex_store->used +          \
1343bf215546Sopenharmony_ci                            save->vertex_size) * sizeof(float); \
1344bf215546Sopenharmony_ci      if (used_next > save->vertex_store->buffer_in_ram_size) { \
1345bf215546Sopenharmony_ci         grow_vertex_storage(ctx, get_vertex_count(save));      \
1346bf215546Sopenharmony_ci         assert(used_next <=                                    \
1347bf215546Sopenharmony_ci                save->vertex_store->buffer_in_ram_size);        \
1348bf215546Sopenharmony_ci      }                                                         \
1349bf215546Sopenharmony_ci   }                                                            \
1350bf215546Sopenharmony_ci} while (0)
1351bf215546Sopenharmony_ci
1352bf215546Sopenharmony_ci#define TAG(x) _save_##x
1353bf215546Sopenharmony_ci
1354bf215546Sopenharmony_ci#include "vbo_attrib_tmp.h"
1355bf215546Sopenharmony_ci
1356bf215546Sopenharmony_ci
1357bf215546Sopenharmony_ci#define MAT( ATTR, N, face, params )                            \
1358bf215546Sopenharmony_cido {                                                            \
1359bf215546Sopenharmony_ci   if (face != GL_BACK)                                         \
1360bf215546Sopenharmony_ci      MAT_ATTR( ATTR, N, params ); /* front */                  \
1361bf215546Sopenharmony_ci   if (face != GL_FRONT)                                        \
1362bf215546Sopenharmony_ci      MAT_ATTR( ATTR + 1, N, params ); /* back */               \
1363bf215546Sopenharmony_ci} while (0)
1364bf215546Sopenharmony_ci
1365bf215546Sopenharmony_ci
1366bf215546Sopenharmony_ci/**
1367bf215546Sopenharmony_ci * Save a glMaterial call found between glBegin/End.
1368bf215546Sopenharmony_ci * glMaterial calls outside Begin/End are handled in dlist.c.
1369bf215546Sopenharmony_ci */
1370bf215546Sopenharmony_cistatic void GLAPIENTRY
1371bf215546Sopenharmony_ci_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1372bf215546Sopenharmony_ci{
1373bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1374bf215546Sopenharmony_ci
1375bf215546Sopenharmony_ci   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1376bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1377bf215546Sopenharmony_ci      return;
1378bf215546Sopenharmony_ci   }
1379bf215546Sopenharmony_ci
1380bf215546Sopenharmony_ci   switch (pname) {
1381bf215546Sopenharmony_ci   case GL_EMISSION:
1382bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1383bf215546Sopenharmony_ci      break;
1384bf215546Sopenharmony_ci   case GL_AMBIENT:
1385bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1386bf215546Sopenharmony_ci      break;
1387bf215546Sopenharmony_ci   case GL_DIFFUSE:
1388bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1389bf215546Sopenharmony_ci      break;
1390bf215546Sopenharmony_ci   case GL_SPECULAR:
1391bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1392bf215546Sopenharmony_ci      break;
1393bf215546Sopenharmony_ci   case GL_SHININESS:
1394bf215546Sopenharmony_ci      if (*params < 0 || *params > ctx->Const.MaxShininess) {
1395bf215546Sopenharmony_ci         _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1396bf215546Sopenharmony_ci      }
1397bf215546Sopenharmony_ci      else {
1398bf215546Sopenharmony_ci         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1399bf215546Sopenharmony_ci      }
1400bf215546Sopenharmony_ci      break;
1401bf215546Sopenharmony_ci   case GL_COLOR_INDEXES:
1402bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1403bf215546Sopenharmony_ci      break;
1404bf215546Sopenharmony_ci   case GL_AMBIENT_AND_DIFFUSE:
1405bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1406bf215546Sopenharmony_ci      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1407bf215546Sopenharmony_ci      break;
1408bf215546Sopenharmony_ci   default:
1409bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1410bf215546Sopenharmony_ci      return;
1411bf215546Sopenharmony_ci   }
1412bf215546Sopenharmony_ci}
1413bf215546Sopenharmony_ci
1414bf215546Sopenharmony_ci
1415bf215546Sopenharmony_cistatic void
1416bf215546Sopenharmony_civbo_install_save_vtxfmt(struct gl_context *ctx);
1417bf215546Sopenharmony_ci
1418bf215546Sopenharmony_ci
1419bf215546Sopenharmony_ci/* Cope with EvalCoord/CallList called within a begin/end object:
1420bf215546Sopenharmony_ci *     -- Flush current buffer
1421bf215546Sopenharmony_ci *     -- Fallback to opcodes for the rest of the begin/end object.
1422bf215546Sopenharmony_ci */
1423bf215546Sopenharmony_cistatic void
1424bf215546Sopenharmony_cidlist_fallback(struct gl_context *ctx)
1425bf215546Sopenharmony_ci{
1426bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1427bf215546Sopenharmony_ci
1428bf215546Sopenharmony_ci   if (save->vertex_store->used || save->prim_store->used) {
1429bf215546Sopenharmony_ci      if (save->prim_store->used > 0 && save->vertex_store->used > 0) {
1430bf215546Sopenharmony_ci         assert(save->vertex_size);
1431bf215546Sopenharmony_ci         /* Close off in-progress primitive. */
1432bf215546Sopenharmony_ci         GLint i = save->prim_store->used - 1;
1433bf215546Sopenharmony_ci         save->prim_store->prims[i].count =
1434bf215546Sopenharmony_ci            get_vertex_count(save) -
1435bf215546Sopenharmony_ci            save->prim_store->prims[i].start;
1436bf215546Sopenharmony_ci      }
1437bf215546Sopenharmony_ci
1438bf215546Sopenharmony_ci      /* Need to replay this display list with loopback,
1439bf215546Sopenharmony_ci       * unfortunately, otherwise this primitive won't be handled
1440bf215546Sopenharmony_ci       * properly:
1441bf215546Sopenharmony_ci       */
1442bf215546Sopenharmony_ci      save->dangling_attr_ref = GL_TRUE;
1443bf215546Sopenharmony_ci
1444bf215546Sopenharmony_ci      compile_vertex_list(ctx);
1445bf215546Sopenharmony_ci   }
1446bf215546Sopenharmony_ci
1447bf215546Sopenharmony_ci   copy_to_current(ctx);
1448bf215546Sopenharmony_ci   reset_vertex(ctx);
1449bf215546Sopenharmony_ci   if (save->out_of_memory) {
1450bf215546Sopenharmony_ci      vbo_install_save_vtxfmt_noop(ctx);
1451bf215546Sopenharmony_ci   }
1452bf215546Sopenharmony_ci   else {
1453bf215546Sopenharmony_ci      _mesa_install_save_vtxfmt(ctx);
1454bf215546Sopenharmony_ci   }
1455bf215546Sopenharmony_ci   ctx->Driver.SaveNeedFlush = GL_FALSE;
1456bf215546Sopenharmony_ci}
1457bf215546Sopenharmony_ci
1458bf215546Sopenharmony_ci
1459bf215546Sopenharmony_cistatic void GLAPIENTRY
1460bf215546Sopenharmony_ci_save_EvalCoord1f(GLfloat u)
1461bf215546Sopenharmony_ci{
1462bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1463bf215546Sopenharmony_ci   dlist_fallback(ctx);
1464bf215546Sopenharmony_ci   CALL_EvalCoord1f(ctx->Save, (u));
1465bf215546Sopenharmony_ci}
1466bf215546Sopenharmony_ci
1467bf215546Sopenharmony_cistatic void GLAPIENTRY
1468bf215546Sopenharmony_ci_save_EvalCoord1fv(const GLfloat * v)
1469bf215546Sopenharmony_ci{
1470bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1471bf215546Sopenharmony_ci   dlist_fallback(ctx);
1472bf215546Sopenharmony_ci   CALL_EvalCoord1fv(ctx->Save, (v));
1473bf215546Sopenharmony_ci}
1474bf215546Sopenharmony_ci
1475bf215546Sopenharmony_cistatic void GLAPIENTRY
1476bf215546Sopenharmony_ci_save_EvalCoord2f(GLfloat u, GLfloat v)
1477bf215546Sopenharmony_ci{
1478bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1479bf215546Sopenharmony_ci   dlist_fallback(ctx);
1480bf215546Sopenharmony_ci   CALL_EvalCoord2f(ctx->Save, (u, v));
1481bf215546Sopenharmony_ci}
1482bf215546Sopenharmony_ci
1483bf215546Sopenharmony_cistatic void GLAPIENTRY
1484bf215546Sopenharmony_ci_save_EvalCoord2fv(const GLfloat * v)
1485bf215546Sopenharmony_ci{
1486bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1487bf215546Sopenharmony_ci   dlist_fallback(ctx);
1488bf215546Sopenharmony_ci   CALL_EvalCoord2fv(ctx->Save, (v));
1489bf215546Sopenharmony_ci}
1490bf215546Sopenharmony_ci
1491bf215546Sopenharmony_cistatic void GLAPIENTRY
1492bf215546Sopenharmony_ci_save_EvalPoint1(GLint i)
1493bf215546Sopenharmony_ci{
1494bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1495bf215546Sopenharmony_ci   dlist_fallback(ctx);
1496bf215546Sopenharmony_ci   CALL_EvalPoint1(ctx->Save, (i));
1497bf215546Sopenharmony_ci}
1498bf215546Sopenharmony_ci
1499bf215546Sopenharmony_cistatic void GLAPIENTRY
1500bf215546Sopenharmony_ci_save_EvalPoint2(GLint i, GLint j)
1501bf215546Sopenharmony_ci{
1502bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1503bf215546Sopenharmony_ci   dlist_fallback(ctx);
1504bf215546Sopenharmony_ci   CALL_EvalPoint2(ctx->Save, (i, j));
1505bf215546Sopenharmony_ci}
1506bf215546Sopenharmony_ci
1507bf215546Sopenharmony_cistatic void GLAPIENTRY
1508bf215546Sopenharmony_ci_save_CallList(GLuint l)
1509bf215546Sopenharmony_ci{
1510bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1511bf215546Sopenharmony_ci   dlist_fallback(ctx);
1512bf215546Sopenharmony_ci   CALL_CallList(ctx->Save, (l));
1513bf215546Sopenharmony_ci}
1514bf215546Sopenharmony_ci
1515bf215546Sopenharmony_cistatic void GLAPIENTRY
1516bf215546Sopenharmony_ci_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1517bf215546Sopenharmony_ci{
1518bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1519bf215546Sopenharmony_ci   dlist_fallback(ctx);
1520bf215546Sopenharmony_ci   CALL_CallLists(ctx->Save, (n, type, v));
1521bf215546Sopenharmony_ci}
1522bf215546Sopenharmony_ci
1523bf215546Sopenharmony_ci
1524bf215546Sopenharmony_ci
1525bf215546Sopenharmony_ci/**
1526bf215546Sopenharmony_ci * Called when a glBegin is getting compiled into a display list.
1527bf215546Sopenharmony_ci * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1528bf215546Sopenharmony_ci */
1529bf215546Sopenharmony_civoid
1530bf215546Sopenharmony_civbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1531bf215546Sopenharmony_ci                     bool no_current_update)
1532bf215546Sopenharmony_ci{
1533bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1534bf215546Sopenharmony_ci   const GLuint i = save->prim_store->used++;
1535bf215546Sopenharmony_ci
1536bf215546Sopenharmony_ci   ctx->Driver.CurrentSavePrimitive = mode;
1537bf215546Sopenharmony_ci
1538bf215546Sopenharmony_ci   if (!save->prim_store || i >= save->prim_store->size) {
1539bf215546Sopenharmony_ci      save->prim_store = realloc_prim_store(save->prim_store, i * 2);
1540bf215546Sopenharmony_ci   }
1541bf215546Sopenharmony_ci   save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1542bf215546Sopenharmony_ci   save->prim_store->prims[i].begin = 1;
1543bf215546Sopenharmony_ci   save->prim_store->prims[i].end = 0;
1544bf215546Sopenharmony_ci   save->prim_store->prims[i].start = get_vertex_count(save);
1545bf215546Sopenharmony_ci   save->prim_store->prims[i].count = 0;
1546bf215546Sopenharmony_ci
1547bf215546Sopenharmony_ci   save->no_current_update = no_current_update;
1548bf215546Sopenharmony_ci
1549bf215546Sopenharmony_ci   vbo_install_save_vtxfmt(ctx);
1550bf215546Sopenharmony_ci
1551bf215546Sopenharmony_ci   /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1552bf215546Sopenharmony_ci   ctx->Driver.SaveNeedFlush = GL_TRUE;
1553bf215546Sopenharmony_ci}
1554bf215546Sopenharmony_ci
1555bf215546Sopenharmony_ci
1556bf215546Sopenharmony_cistatic void GLAPIENTRY
1557bf215546Sopenharmony_ci_save_End(void)
1558bf215546Sopenharmony_ci{
1559bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1560bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1561bf215546Sopenharmony_ci   const GLint i = save->prim_store->used - 1;
1562bf215546Sopenharmony_ci
1563bf215546Sopenharmony_ci   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1564bf215546Sopenharmony_ci   save->prim_store->prims[i].end = 1;
1565bf215546Sopenharmony_ci   save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
1566bf215546Sopenharmony_ci
1567bf215546Sopenharmony_ci   /* Swap out this vertex format while outside begin/end.  Any color,
1568bf215546Sopenharmony_ci    * etc. received between here and the next begin will be compiled
1569bf215546Sopenharmony_ci    * as opcodes.
1570bf215546Sopenharmony_ci    */
1571bf215546Sopenharmony_ci   if (save->out_of_memory) {
1572bf215546Sopenharmony_ci      vbo_install_save_vtxfmt_noop(ctx);
1573bf215546Sopenharmony_ci   }
1574bf215546Sopenharmony_ci   else {
1575bf215546Sopenharmony_ci      _mesa_install_save_vtxfmt(ctx);
1576bf215546Sopenharmony_ci   }
1577bf215546Sopenharmony_ci}
1578bf215546Sopenharmony_ci
1579bf215546Sopenharmony_ci
1580bf215546Sopenharmony_cistatic void GLAPIENTRY
1581bf215546Sopenharmony_ci_save_Begin(GLenum mode)
1582bf215546Sopenharmony_ci{
1583bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1584bf215546Sopenharmony_ci   (void) mode;
1585bf215546Sopenharmony_ci   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1586bf215546Sopenharmony_ci}
1587bf215546Sopenharmony_ci
1588bf215546Sopenharmony_ci
1589bf215546Sopenharmony_cistatic void GLAPIENTRY
1590bf215546Sopenharmony_ci_save_PrimitiveRestartNV(void)
1591bf215546Sopenharmony_ci{
1592bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1593bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1594bf215546Sopenharmony_ci
1595bf215546Sopenharmony_ci   if (save->prim_store->used == 0) {
1596bf215546Sopenharmony_ci      /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1597bf215546Sopenharmony_ci       * is an error.
1598bf215546Sopenharmony_ci       */
1599bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1600bf215546Sopenharmony_ci                          "glPrimitiveRestartNV called outside glBegin/End");
1601bf215546Sopenharmony_ci   } else {
1602bf215546Sopenharmony_ci      /* get current primitive mode */
1603bf215546Sopenharmony_ci      GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1604bf215546Sopenharmony_ci      bool no_current_update = save->no_current_update;
1605bf215546Sopenharmony_ci
1606bf215546Sopenharmony_ci      /* restart primitive */
1607bf215546Sopenharmony_ci      CALL_End(ctx->CurrentServerDispatch, ());
1608bf215546Sopenharmony_ci      vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1609bf215546Sopenharmony_ci   }
1610bf215546Sopenharmony_ci}
1611bf215546Sopenharmony_ci
1612bf215546Sopenharmony_ci
1613bf215546Sopenharmony_ci/* Unlike the functions above, these are to be hooked into the vtxfmt
1614bf215546Sopenharmony_ci * maintained in ctx->ListState, active when the list is known or
1615bf215546Sopenharmony_ci * suspected to be outside any begin/end primitive.
1616bf215546Sopenharmony_ci * Note: OBE = Outside Begin/End
1617bf215546Sopenharmony_ci */
1618bf215546Sopenharmony_civoid GLAPIENTRY
1619bf215546Sopenharmony_cisave_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1620bf215546Sopenharmony_ci{
1621bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1622bf215546Sopenharmony_ci   struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1623bf215546Sopenharmony_ci
1624bf215546Sopenharmony_ci   vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1625bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x1, y1));
1626bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x2, y1));
1627bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x2, y2));
1628bf215546Sopenharmony_ci   CALL_Vertex2f(dispatch, (x1, y2));
1629bf215546Sopenharmony_ci   CALL_End(dispatch, ());
1630bf215546Sopenharmony_ci}
1631bf215546Sopenharmony_ci
1632bf215546Sopenharmony_ci
1633bf215546Sopenharmony_civoid GLAPIENTRY
1634bf215546Sopenharmony_cisave_Rectdv(const GLdouble *v1, const GLdouble *v2)
1635bf215546Sopenharmony_ci{
1636bf215546Sopenharmony_ci   save_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1637bf215546Sopenharmony_ci}
1638bf215546Sopenharmony_ci
1639bf215546Sopenharmony_civoid GLAPIENTRY
1640bf215546Sopenharmony_cisave_Rectfv(const GLfloat *v1, const GLfloat *v2)
1641bf215546Sopenharmony_ci{
1642bf215546Sopenharmony_ci   save_Rectf(v1[0], v1[1], v2[0], v2[1]);
1643bf215546Sopenharmony_ci}
1644bf215546Sopenharmony_ci
1645bf215546Sopenharmony_civoid GLAPIENTRY
1646bf215546Sopenharmony_cisave_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1647bf215546Sopenharmony_ci{
1648bf215546Sopenharmony_ci   save_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1649bf215546Sopenharmony_ci}
1650bf215546Sopenharmony_ci
1651bf215546Sopenharmony_civoid GLAPIENTRY
1652bf215546Sopenharmony_cisave_Rectiv(const GLint *v1, const GLint *v2)
1653bf215546Sopenharmony_ci{
1654bf215546Sopenharmony_ci   save_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1655bf215546Sopenharmony_ci}
1656bf215546Sopenharmony_ci
1657bf215546Sopenharmony_civoid GLAPIENTRY
1658bf215546Sopenharmony_cisave_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1659bf215546Sopenharmony_ci{
1660bf215546Sopenharmony_ci   save_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1661bf215546Sopenharmony_ci}
1662bf215546Sopenharmony_ci
1663bf215546Sopenharmony_civoid GLAPIENTRY
1664bf215546Sopenharmony_cisave_Rectsv(const GLshort *v1, const GLshort *v2)
1665bf215546Sopenharmony_ci{
1666bf215546Sopenharmony_ci   save_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1667bf215546Sopenharmony_ci}
1668bf215546Sopenharmony_ci
1669bf215546Sopenharmony_civoid GLAPIENTRY
1670bf215546Sopenharmony_cisave_DrawArrays(GLenum mode, GLint start, GLsizei count)
1671bf215546Sopenharmony_ci{
1672bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1673bf215546Sopenharmony_ci   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1674bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1675bf215546Sopenharmony_ci   GLint i;
1676bf215546Sopenharmony_ci
1677bf215546Sopenharmony_ci   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1678bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1679bf215546Sopenharmony_ci      return;
1680bf215546Sopenharmony_ci   }
1681bf215546Sopenharmony_ci   if (count < 0) {
1682bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1683bf215546Sopenharmony_ci      return;
1684bf215546Sopenharmony_ci   }
1685bf215546Sopenharmony_ci
1686bf215546Sopenharmony_ci   if (save->out_of_memory)
1687bf215546Sopenharmony_ci      return;
1688bf215546Sopenharmony_ci
1689bf215546Sopenharmony_ci   grow_vertex_storage(ctx, count);
1690bf215546Sopenharmony_ci
1691bf215546Sopenharmony_ci   /* Make sure to process any VBO binding changes */
1692bf215546Sopenharmony_ci   _mesa_update_state(ctx);
1693bf215546Sopenharmony_ci
1694bf215546Sopenharmony_ci   _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1695bf215546Sopenharmony_ci
1696bf215546Sopenharmony_ci   vbo_save_NotifyBegin(ctx, mode, true);
1697bf215546Sopenharmony_ci
1698bf215546Sopenharmony_ci   for (i = 0; i < count; i++)
1699bf215546Sopenharmony_ci      _mesa_array_element(ctx, start + i);
1700bf215546Sopenharmony_ci   CALL_End(ctx->CurrentServerDispatch, ());
1701bf215546Sopenharmony_ci
1702bf215546Sopenharmony_ci   _mesa_vao_unmap_arrays(ctx, vao);
1703bf215546Sopenharmony_ci}
1704bf215546Sopenharmony_ci
1705bf215546Sopenharmony_ci
1706bf215546Sopenharmony_civoid GLAPIENTRY
1707bf215546Sopenharmony_cisave_MultiDrawArrays(GLenum mode, const GLint *first,
1708bf215546Sopenharmony_ci                      const GLsizei *count, GLsizei primcount)
1709bf215546Sopenharmony_ci{
1710bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1711bf215546Sopenharmony_ci   GLint i;
1712bf215546Sopenharmony_ci
1713bf215546Sopenharmony_ci   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1714bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1715bf215546Sopenharmony_ci      return;
1716bf215546Sopenharmony_ci   }
1717bf215546Sopenharmony_ci
1718bf215546Sopenharmony_ci   if (primcount < 0) {
1719bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1720bf215546Sopenharmony_ci                          "glMultiDrawArrays(primcount<0)");
1721bf215546Sopenharmony_ci      return;
1722bf215546Sopenharmony_ci   }
1723bf215546Sopenharmony_ci
1724bf215546Sopenharmony_ci   unsigned vertcount = 0;
1725bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1726bf215546Sopenharmony_ci      if (count[i] < 0) {
1727bf215546Sopenharmony_ci         _mesa_compile_error(ctx, GL_INVALID_VALUE,
1728bf215546Sopenharmony_ci                             "glMultiDrawArrays(count[i]<0)");
1729bf215546Sopenharmony_ci         return;
1730bf215546Sopenharmony_ci      }
1731bf215546Sopenharmony_ci      vertcount += count[i];
1732bf215546Sopenharmony_ci   }
1733bf215546Sopenharmony_ci
1734bf215546Sopenharmony_ci   grow_vertex_storage(ctx, vertcount);
1735bf215546Sopenharmony_ci
1736bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1737bf215546Sopenharmony_ci      if (count[i] > 0) {
1738bf215546Sopenharmony_ci         save_DrawArrays(mode, first[i], count[i]);
1739bf215546Sopenharmony_ci      }
1740bf215546Sopenharmony_ci   }
1741bf215546Sopenharmony_ci}
1742bf215546Sopenharmony_ci
1743bf215546Sopenharmony_ci
1744bf215546Sopenharmony_cistatic void
1745bf215546Sopenharmony_ciarray_element(struct gl_context *ctx,
1746bf215546Sopenharmony_ci              GLint basevertex, GLuint elt, unsigned index_size_shift)
1747bf215546Sopenharmony_ci{
1748bf215546Sopenharmony_ci   /* Section 10.3.5 Primitive Restart:
1749bf215546Sopenharmony_ci    * [...]
1750bf215546Sopenharmony_ci    *    When one of the *BaseVertex drawing commands specified in section 10.5
1751bf215546Sopenharmony_ci    * is used, the primitive restart comparison occurs before the basevertex
1752bf215546Sopenharmony_ci    * offset is added to the array index.
1753bf215546Sopenharmony_ci    */
1754bf215546Sopenharmony_ci   /* If PrimitiveRestart is enabled and the index is the RestartIndex
1755bf215546Sopenharmony_ci    * then we call PrimitiveRestartNV and return.
1756bf215546Sopenharmony_ci    */
1757bf215546Sopenharmony_ci   if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1758bf215546Sopenharmony_ci       elt == ctx->Array._RestartIndex[index_size_shift]) {
1759bf215546Sopenharmony_ci      CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1760bf215546Sopenharmony_ci      return;
1761bf215546Sopenharmony_ci   }
1762bf215546Sopenharmony_ci
1763bf215546Sopenharmony_ci   _mesa_array_element(ctx, basevertex + elt);
1764bf215546Sopenharmony_ci}
1765bf215546Sopenharmony_ci
1766bf215546Sopenharmony_ci
1767bf215546Sopenharmony_ci/* Could do better by copying the arrays and element list intact and
1768bf215546Sopenharmony_ci * then emitting an indexed prim at runtime.
1769bf215546Sopenharmony_ci */
1770bf215546Sopenharmony_civoid GLAPIENTRY
1771bf215546Sopenharmony_cisave_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1772bf215546Sopenharmony_ci                             const GLvoid * indices, GLint basevertex)
1773bf215546Sopenharmony_ci{
1774bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1775bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1776bf215546Sopenharmony_ci   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1777bf215546Sopenharmony_ci   struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1778bf215546Sopenharmony_ci   GLint i;
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_ci   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1781bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1782bf215546Sopenharmony_ci      return;
1783bf215546Sopenharmony_ci   }
1784bf215546Sopenharmony_ci   if (count < 0) {
1785bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1786bf215546Sopenharmony_ci      return;
1787bf215546Sopenharmony_ci   }
1788bf215546Sopenharmony_ci   if (type != GL_UNSIGNED_BYTE &&
1789bf215546Sopenharmony_ci       type != GL_UNSIGNED_SHORT &&
1790bf215546Sopenharmony_ci       type != GL_UNSIGNED_INT) {
1791bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1792bf215546Sopenharmony_ci      return;
1793bf215546Sopenharmony_ci   }
1794bf215546Sopenharmony_ci
1795bf215546Sopenharmony_ci   if (save->out_of_memory)
1796bf215546Sopenharmony_ci      return;
1797bf215546Sopenharmony_ci
1798bf215546Sopenharmony_ci   grow_vertex_storage(ctx, count);
1799bf215546Sopenharmony_ci
1800bf215546Sopenharmony_ci   /* Make sure to process any VBO binding changes */
1801bf215546Sopenharmony_ci   _mesa_update_state(ctx);
1802bf215546Sopenharmony_ci
1803bf215546Sopenharmony_ci   _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1804bf215546Sopenharmony_ci
1805bf215546Sopenharmony_ci   if (indexbuf)
1806bf215546Sopenharmony_ci      indices =
1807bf215546Sopenharmony_ci         ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1808bf215546Sopenharmony_ci
1809bf215546Sopenharmony_ci   vbo_save_NotifyBegin(ctx, mode, true);
1810bf215546Sopenharmony_ci
1811bf215546Sopenharmony_ci   switch (type) {
1812bf215546Sopenharmony_ci   case GL_UNSIGNED_BYTE:
1813bf215546Sopenharmony_ci      for (i = 0; i < count; i++)
1814bf215546Sopenharmony_ci         array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1815bf215546Sopenharmony_ci      break;
1816bf215546Sopenharmony_ci   case GL_UNSIGNED_SHORT:
1817bf215546Sopenharmony_ci      for (i = 0; i < count; i++)
1818bf215546Sopenharmony_ci         array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1819bf215546Sopenharmony_ci      break;
1820bf215546Sopenharmony_ci   case GL_UNSIGNED_INT:
1821bf215546Sopenharmony_ci      for (i = 0; i < count; i++)
1822bf215546Sopenharmony_ci         array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1823bf215546Sopenharmony_ci      break;
1824bf215546Sopenharmony_ci   default:
1825bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1826bf215546Sopenharmony_ci      break;
1827bf215546Sopenharmony_ci   }
1828bf215546Sopenharmony_ci
1829bf215546Sopenharmony_ci   CALL_End(ctx->CurrentServerDispatch, ());
1830bf215546Sopenharmony_ci
1831bf215546Sopenharmony_ci   _mesa_vao_unmap(ctx, vao);
1832bf215546Sopenharmony_ci}
1833bf215546Sopenharmony_ci
1834bf215546Sopenharmony_civoid GLAPIENTRY
1835bf215546Sopenharmony_cisave_DrawElements(GLenum mode, GLsizei count, GLenum type,
1836bf215546Sopenharmony_ci                   const GLvoid * indices)
1837bf215546Sopenharmony_ci{
1838bf215546Sopenharmony_ci   save_DrawElementsBaseVertex(mode, count, type, indices, 0);
1839bf215546Sopenharmony_ci}
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_ci
1842bf215546Sopenharmony_civoid GLAPIENTRY
1843bf215546Sopenharmony_cisave_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1844bf215546Sopenharmony_ci                            GLsizei count, GLenum type,
1845bf215546Sopenharmony_ci                            const GLvoid * indices)
1846bf215546Sopenharmony_ci{
1847bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1848bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1849bf215546Sopenharmony_ci
1850bf215546Sopenharmony_ci   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1851bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1852bf215546Sopenharmony_ci      return;
1853bf215546Sopenharmony_ci   }
1854bf215546Sopenharmony_ci   if (count < 0) {
1855bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1856bf215546Sopenharmony_ci                          "glDrawRangeElements(count<0)");
1857bf215546Sopenharmony_ci      return;
1858bf215546Sopenharmony_ci   }
1859bf215546Sopenharmony_ci   if (type != GL_UNSIGNED_BYTE &&
1860bf215546Sopenharmony_ci       type != GL_UNSIGNED_SHORT &&
1861bf215546Sopenharmony_ci       type != GL_UNSIGNED_INT) {
1862bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1863bf215546Sopenharmony_ci      return;
1864bf215546Sopenharmony_ci   }
1865bf215546Sopenharmony_ci   if (end < start) {
1866bf215546Sopenharmony_ci      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1867bf215546Sopenharmony_ci                          "glDrawRangeElements(end < start)");
1868bf215546Sopenharmony_ci      return;
1869bf215546Sopenharmony_ci   }
1870bf215546Sopenharmony_ci
1871bf215546Sopenharmony_ci   if (save->out_of_memory)
1872bf215546Sopenharmony_ci      return;
1873bf215546Sopenharmony_ci
1874bf215546Sopenharmony_ci   save_DrawElements(mode, count, type, indices);
1875bf215546Sopenharmony_ci}
1876bf215546Sopenharmony_ci
1877bf215546Sopenharmony_ci
1878bf215546Sopenharmony_civoid GLAPIENTRY
1879bf215546Sopenharmony_cisave_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
1880bf215546Sopenharmony_ci                           const GLvoid * const *indices, GLsizei primcount)
1881bf215546Sopenharmony_ci{
1882bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1883bf215546Sopenharmony_ci   struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1884bf215546Sopenharmony_ci   GLsizei i;
1885bf215546Sopenharmony_ci
1886bf215546Sopenharmony_ci   int vertcount = 0;
1887bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1888bf215546Sopenharmony_ci      vertcount += count[i];
1889bf215546Sopenharmony_ci   }
1890bf215546Sopenharmony_ci   grow_vertex_storage(ctx, vertcount);
1891bf215546Sopenharmony_ci
1892bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1893bf215546Sopenharmony_ci      if (count[i] > 0) {
1894bf215546Sopenharmony_ci         CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1895bf215546Sopenharmony_ci      }
1896bf215546Sopenharmony_ci   }
1897bf215546Sopenharmony_ci}
1898bf215546Sopenharmony_ci
1899bf215546Sopenharmony_ci
1900bf215546Sopenharmony_civoid GLAPIENTRY
1901bf215546Sopenharmony_cisave_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1902bf215546Sopenharmony_ci                                  GLenum type,
1903bf215546Sopenharmony_ci                                  const GLvoid * const *indices,
1904bf215546Sopenharmony_ci                                  GLsizei primcount,
1905bf215546Sopenharmony_ci                                  const GLint *basevertex)
1906bf215546Sopenharmony_ci{
1907bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1908bf215546Sopenharmony_ci   struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1909bf215546Sopenharmony_ci   GLsizei i;
1910bf215546Sopenharmony_ci
1911bf215546Sopenharmony_ci   int vertcount = 0;
1912bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1913bf215546Sopenharmony_ci      vertcount += count[i];
1914bf215546Sopenharmony_ci   }
1915bf215546Sopenharmony_ci   grow_vertex_storage(ctx, vertcount);
1916bf215546Sopenharmony_ci
1917bf215546Sopenharmony_ci   for (i = 0; i < primcount; i++) {
1918bf215546Sopenharmony_ci      if (count[i] > 0) {
1919bf215546Sopenharmony_ci         CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1920bf215546Sopenharmony_ci                                     indices[i],
1921bf215546Sopenharmony_ci                                     basevertex[i]));
1922bf215546Sopenharmony_ci      }
1923bf215546Sopenharmony_ci   }
1924bf215546Sopenharmony_ci}
1925bf215546Sopenharmony_ci
1926bf215546Sopenharmony_ci
1927bf215546Sopenharmony_cistatic void
1928bf215546Sopenharmony_civbo_install_save_vtxfmt(struct gl_context *ctx)
1929bf215546Sopenharmony_ci{
1930bf215546Sopenharmony_ci#define NAME_AE(x) _mesa_##x
1931bf215546Sopenharmony_ci#define NAME_CALLLIST(x) _save_##x
1932bf215546Sopenharmony_ci#define NAME(x) _save_##x
1933bf215546Sopenharmony_ci#define NAME_ES(x) _save_##x
1934bf215546Sopenharmony_ci
1935bf215546Sopenharmony_ci   struct _glapi_table *tab = ctx->Save;
1936bf215546Sopenharmony_ci   #include "api_vtxfmt_init.h"
1937bf215546Sopenharmony_ci}
1938bf215546Sopenharmony_ci
1939bf215546Sopenharmony_ci
1940bf215546Sopenharmony_civoid
1941bf215546Sopenharmony_civbo_save_SaveFlushVertices(struct gl_context *ctx)
1942bf215546Sopenharmony_ci{
1943bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1944bf215546Sopenharmony_ci
1945bf215546Sopenharmony_ci   /* Noop when we are actually active:
1946bf215546Sopenharmony_ci    */
1947bf215546Sopenharmony_ci   if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1948bf215546Sopenharmony_ci      return;
1949bf215546Sopenharmony_ci
1950bf215546Sopenharmony_ci   if (save->vertex_store->used || save->prim_store->used)
1951bf215546Sopenharmony_ci      compile_vertex_list(ctx);
1952bf215546Sopenharmony_ci
1953bf215546Sopenharmony_ci   copy_to_current(ctx);
1954bf215546Sopenharmony_ci   reset_vertex(ctx);
1955bf215546Sopenharmony_ci   ctx->Driver.SaveNeedFlush = GL_FALSE;
1956bf215546Sopenharmony_ci}
1957bf215546Sopenharmony_ci
1958bf215546Sopenharmony_ci
1959bf215546Sopenharmony_ci/**
1960bf215546Sopenharmony_ci * Called from glNewList when we're starting to compile a display list.
1961bf215546Sopenharmony_ci */
1962bf215546Sopenharmony_civoid
1963bf215546Sopenharmony_civbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1964bf215546Sopenharmony_ci{
1965bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1966bf215546Sopenharmony_ci
1967bf215546Sopenharmony_ci   (void) list;
1968bf215546Sopenharmony_ci   (void) mode;
1969bf215546Sopenharmony_ci
1970bf215546Sopenharmony_ci   if (!save->prim_store)
1971bf215546Sopenharmony_ci      save->prim_store = realloc_prim_store(NULL, 8);
1972bf215546Sopenharmony_ci
1973bf215546Sopenharmony_ci   if (!save->vertex_store)
1974bf215546Sopenharmony_ci      save->vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
1975bf215546Sopenharmony_ci
1976bf215546Sopenharmony_ci   reset_vertex(ctx);
1977bf215546Sopenharmony_ci   ctx->Driver.SaveNeedFlush = GL_FALSE;
1978bf215546Sopenharmony_ci}
1979bf215546Sopenharmony_ci
1980bf215546Sopenharmony_ci
1981bf215546Sopenharmony_ci/**
1982bf215546Sopenharmony_ci * Called from glEndList when we're finished compiling a display list.
1983bf215546Sopenharmony_ci */
1984bf215546Sopenharmony_civoid
1985bf215546Sopenharmony_civbo_save_EndList(struct gl_context *ctx)
1986bf215546Sopenharmony_ci{
1987bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
1988bf215546Sopenharmony_ci
1989bf215546Sopenharmony_ci   /* EndList called inside a (saved) Begin/End pair?
1990bf215546Sopenharmony_ci    */
1991bf215546Sopenharmony_ci   if (_mesa_inside_dlist_begin_end(ctx)) {
1992bf215546Sopenharmony_ci      if (save->prim_store->used > 0) {
1993bf215546Sopenharmony_ci         GLint i = save->prim_store->used - 1;
1994bf215546Sopenharmony_ci         ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1995bf215546Sopenharmony_ci         save->prim_store->prims[i].end = 0;
1996bf215546Sopenharmony_ci         save->prim_store->prims[i].count = get_vertex_count(save) - save->prim_store->prims[i].start;
1997bf215546Sopenharmony_ci      }
1998bf215546Sopenharmony_ci
1999bf215546Sopenharmony_ci      /* Make sure this vertex list gets replayed by the "loopback"
2000bf215546Sopenharmony_ci       * mechanism:
2001bf215546Sopenharmony_ci       */
2002bf215546Sopenharmony_ci      save->dangling_attr_ref = GL_TRUE;
2003bf215546Sopenharmony_ci      vbo_save_SaveFlushVertices(ctx);
2004bf215546Sopenharmony_ci
2005bf215546Sopenharmony_ci      /* Swap out this vertex format while outside begin/end.  Any color,
2006bf215546Sopenharmony_ci       * etc. received between here and the next begin will be compiled
2007bf215546Sopenharmony_ci       * as opcodes.
2008bf215546Sopenharmony_ci       */
2009bf215546Sopenharmony_ci      _mesa_install_save_vtxfmt(ctx);
2010bf215546Sopenharmony_ci   }
2011bf215546Sopenharmony_ci
2012bf215546Sopenharmony_ci   assert(save->vertex_size == 0);
2013bf215546Sopenharmony_ci}
2014bf215546Sopenharmony_ci
2015bf215546Sopenharmony_ci/**
2016bf215546Sopenharmony_ci * Called during context creation/init.
2017bf215546Sopenharmony_ci */
2018bf215546Sopenharmony_cistatic void
2019bf215546Sopenharmony_cicurrent_init(struct gl_context *ctx)
2020bf215546Sopenharmony_ci{
2021bf215546Sopenharmony_ci   struct vbo_save_context *save = &vbo_context(ctx)->save;
2022bf215546Sopenharmony_ci   GLint i;
2023bf215546Sopenharmony_ci
2024bf215546Sopenharmony_ci   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
2025bf215546Sopenharmony_ci      const GLuint j = i - VBO_ATTRIB_POS;
2026bf215546Sopenharmony_ci      assert(j < VERT_ATTRIB_MAX);
2027bf215546Sopenharmony_ci      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
2028bf215546Sopenharmony_ci      save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
2029bf215546Sopenharmony_ci   }
2030bf215546Sopenharmony_ci
2031bf215546Sopenharmony_ci   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
2032bf215546Sopenharmony_ci      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
2033bf215546Sopenharmony_ci      assert(j < MAT_ATTRIB_MAX);
2034bf215546Sopenharmony_ci      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2035bf215546Sopenharmony_ci      save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2036bf215546Sopenharmony_ci   }
2037bf215546Sopenharmony_ci}
2038bf215546Sopenharmony_ci
2039bf215546Sopenharmony_ci
2040bf215546Sopenharmony_ci/**
2041bf215546Sopenharmony_ci * Initialize the display list compiler.  Called during context creation.
2042bf215546Sopenharmony_ci */
2043bf215546Sopenharmony_civoid
2044bf215546Sopenharmony_civbo_save_api_init(struct vbo_save_context *save)
2045bf215546Sopenharmony_ci{
2046bf215546Sopenharmony_ci   struct gl_context *ctx = gl_context_from_vbo_save(save);
2047bf215546Sopenharmony_ci
2048bf215546Sopenharmony_ci   current_init(ctx);
2049bf215546Sopenharmony_ci}
2050