• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2 
3 Copyright 2002-2008 VMware, Inc.
4 
5 All Rights Reserved.
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26 **************************************************************************/
27 
28 /*
29  * Authors:
30  *   Keith Whitwell <keithw@vmware.com>
31  */
32 
33 #include "main/glheader.h"
34 #include "main/bufferobj.h"
35 #include "main/context.h"
36 #include "main/macros.h"
37 #include "main/vtxfmt.h"
38 #include "main/dlist.h"
39 #include "main/eval.h"
40 #include "main/state.h"
41 #include "main/light.h"
42 #include "main/api_arrayelt.h"
43 #include "main/api_validate.h"
44 #include "main/dispatch.h"
45 #include "util/bitscan.h"
46 
47 #include "vbo_context.h"
48 #include "vbo_noop.h"
49 
50 
51 /** ID/name for immediate-mode VBO */
52 #define IMM_BUFFER_NAME 0xaabbccdd
53 
54 
55 static void
56 vbo_reset_all_attr(struct vbo_exec_context *exec);
57 
58 
59 /**
60  * Close off the last primitive, execute the buffer, restart the
61  * primitive.  This is called when we fill a vertex buffer before
62  * hitting glEnd.
63  */
64 static void
vbo_exec_wrap_buffers(struct vbo_exec_context * exec)65 vbo_exec_wrap_buffers(struct vbo_exec_context *exec)
66 {
67    if (exec->vtx.prim_count == 0) {
68       exec->vtx.copied.nr = 0;
69       exec->vtx.vert_count = 0;
70       exec->vtx.buffer_ptr = exec->vtx.buffer_map;
71    }
72    else {
73       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
74       const GLuint last_begin = last_prim->begin;
75       GLuint last_count;
76 
77       if (_mesa_inside_begin_end(exec->ctx)) {
78 	 last_prim->count = exec->vtx.vert_count - last_prim->start;
79       }
80 
81       last_count = last_prim->count;
82 
83       /* Special handling for wrapping GL_LINE_LOOP */
84       if (last_prim->mode == GL_LINE_LOOP &&
85           last_count > 0 &&
86           !last_prim->end) {
87          /* draw this section of the incomplete line loop as a line strip */
88          last_prim->mode = GL_LINE_STRIP;
89          if (!last_prim->begin) {
90             /* This is not the first section of the line loop, so don't
91              * draw the 0th vertex.  We're saving it until we draw the
92              * very last section of the loop.
93              */
94             last_prim->start++;
95             last_prim->count--;
96          }
97       }
98 
99       /* Execute the buffer and save copied vertices.
100        */
101       if (exec->vtx.vert_count)
102 	 vbo_exec_vtx_flush( exec, GL_FALSE );
103       else {
104 	 exec->vtx.prim_count = 0;
105 	 exec->vtx.copied.nr = 0;
106       }
107 
108       /* Emit a glBegin to start the new list.
109        */
110       assert(exec->vtx.prim_count == 0);
111 
112       if (_mesa_inside_begin_end(exec->ctx)) {
113 	 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
114 	 exec->vtx.prim[0].begin = 0;
115          exec->vtx.prim[0].end = 0;
116 	 exec->vtx.prim[0].start = 0;
117 	 exec->vtx.prim[0].count = 0;
118 	 exec->vtx.prim_count++;
119 
120 	 if (exec->vtx.copied.nr == last_count)
121 	    exec->vtx.prim[0].begin = last_begin;
122       }
123    }
124 }
125 
126 
127 /**
128  * Deal with buffer wrapping where provoked by the vertex buffer
129  * filling up, as opposed to upgrade_vertex().
130  */
131 static void
vbo_exec_vtx_wrap(struct vbo_exec_context * exec)132 vbo_exec_vtx_wrap(struct vbo_exec_context *exec)
133 {
134    unsigned numComponents;
135 
136    /* Run pipeline on current vertices, copy wrapped vertices
137     * to exec->vtx.copied.
138     */
139    vbo_exec_wrap_buffers( exec );
140 
141    if (!exec->vtx.buffer_ptr) {
142       /* probably ran out of memory earlier when allocating the VBO */
143       return;
144    }
145 
146    /* Copy stored stored vertices to start of new list.
147     */
148    assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
149 
150    numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
151    memcpy(exec->vtx.buffer_ptr,
152           exec->vtx.copied.buffer,
153           numComponents * sizeof(fi_type));
154    exec->vtx.buffer_ptr += numComponents;
155    exec->vtx.vert_count += exec->vtx.copied.nr;
156 
157    exec->vtx.copied.nr = 0;
158 }
159 
160 
161 /**
162  * Copy the active vertex's values to the ctx->Current fields.
163  */
164 static void
vbo_exec_copy_to_current(struct vbo_exec_context * exec)165 vbo_exec_copy_to_current(struct vbo_exec_context *exec)
166 {
167    struct gl_context *ctx = exec->ctx;
168    struct vbo_context *vbo = vbo_context(ctx);
169    GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
170 
171    while (enabled) {
172       const int i = u_bit_scan64(&enabled);
173 
174       /* Note: the exec->vtx.current[i] pointers point into the
175        * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
176        */
177       GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
178       fi_type tmp[8]; /* space for doubles */
179       int dmul = exec->vtx.attrtype[i] == GL_DOUBLE ? 2 : 1;
180 
181       assert(exec->vtx.attrsz[i]);
182 
183       if (exec->vtx.attrtype[i] == GL_DOUBLE) {
184          memset(tmp, 0, sizeof(tmp));
185          memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat));
186       } else {
187          COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
188                                      exec->vtx.attrsz[i],
189                                      exec->vtx.attrptr[i],
190                                      exec->vtx.attrtype[i]);
191       }
192 
193       if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
194           memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
195          memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
196 
197          /* Given that we explicitly state size here, there is no need
198           * for the COPY_CLEAN above, could just copy 16 bytes and be
199           * done.  The only problem is when Mesa accesses ctx->Current
200           * directly.
201           */
202          /* Size here is in components - not bytes */
203          vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul;
204          vbo->currval[i]._ElementSize =
205             vbo->currval[i].Size * sizeof(GLfloat) * dmul;
206          vbo->currval[i].Type = exec->vtx.attrtype[i];
207          vbo->currval[i].Integer =
208             vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
209          vbo->currval[i].Doubles =
210             vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]);
211 
212          /* This triggers rather too much recalculation of Mesa state
213           * that doesn't get used (eg light positions).
214           */
215          if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
216              i <= VBO_ATTRIB_MAT_BACK_INDEXES)
217             ctx->NewState |= _NEW_LIGHT;
218 
219          ctx->NewState |= _NEW_CURRENT_ATTRIB;
220       }
221    }
222 
223    /* Colormaterial -- this kindof sucks.
224     */
225    if (ctx->Light.ColorMaterialEnabled &&
226        exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
227       _mesa_update_color_material(ctx,
228 				  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
229    }
230 }
231 
232 
233 /**
234  * Copy current vertex attribute values into the current vertex.
235  */
236 static void
vbo_exec_copy_from_current(struct vbo_exec_context * exec)237 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
238 {
239    struct gl_context *ctx = exec->ctx;
240    struct vbo_context *vbo = vbo_context(ctx);
241    GLint i;
242 
243    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
244       if (exec->vtx.attrtype[i] == GL_DOUBLE) {
245          memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr,
246                 exec->vtx.attrsz[i] * sizeof(GLfloat));
247       } else {
248          const fi_type *current = (fi_type *) vbo->currval[i].Ptr;
249          switch (exec->vtx.attrsz[i]) {
250          case 4: exec->vtx.attrptr[i][3] = current[3];
251          case 3: exec->vtx.attrptr[i][2] = current[2];
252          case 2: exec->vtx.attrptr[i][1] = current[1];
253          case 1: exec->vtx.attrptr[i][0] = current[0];
254             break;
255          }
256       }
257    }
258 }
259 
260 
261 /**
262  * Flush existing data, set new attrib size, replay copied vertices.
263  * This is called when we transition from a small vertex attribute size
264  * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
265  * We need to go back over the previous 2-component texcoords and insert
266  * zero and one values.
267  */
268 static void
vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context * exec,GLuint attr,GLuint newSize)269 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
270                              GLuint attr, GLuint newSize )
271 {
272    struct gl_context *ctx = exec->ctx;
273    struct vbo_context *vbo = vbo_context(ctx);
274    const GLint lastcount = exec->vtx.vert_count;
275    fi_type *old_attrptr[VBO_ATTRIB_MAX];
276    const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
277    const GLuint oldSize = exec->vtx.attrsz[attr];
278    GLuint i;
279 
280    /* Run pipeline on current vertices, copy wrapped vertices
281     * to exec->vtx.copied.
282     */
283    vbo_exec_wrap_buffers( exec );
284 
285    if (unlikely(exec->vtx.copied.nr)) {
286       /* We're in the middle of a primitive, keep the old vertex
287        * format around to be able to translate the copied vertices to
288        * the new format.
289        */
290       memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
291    }
292 
293    if (unlikely(oldSize)) {
294       /* Do a COPY_TO_CURRENT to ensure back-copying works for the
295        * case when the attribute already exists in the vertex and is
296        * having its size increased.
297        */
298       vbo_exec_copy_to_current( exec );
299    }
300 
301    /* Heuristic: Attempt to isolate attributes received outside
302     * begin/end so that they don't bloat the vertices.
303     */
304    if (!_mesa_inside_begin_end(ctx) &&
305        !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
306       vbo_exec_copy_to_current( exec );
307       vbo_reset_all_attr(exec);
308    }
309 
310    /* Fix up sizes:
311     */
312    exec->vtx.attrsz[attr] = newSize;
313    exec->vtx.vertex_size += newSize - oldSize;
314    exec->vtx.max_vert = vbo_compute_max_verts(exec);
315    exec->vtx.vert_count = 0;
316    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
317    exec->vtx.enabled |= BITFIELD64_BIT(attr);
318 
319    if (unlikely(oldSize)) {
320       /* Size changed, recalculate all the attrptr[] values
321        */
322       fi_type *tmp = exec->vtx.vertex;
323 
324       for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
325 	 if (exec->vtx.attrsz[i]) {
326 	    exec->vtx.attrptr[i] = tmp;
327 	    tmp += exec->vtx.attrsz[i];
328 	 }
329 	 else
330 	    exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
331       }
332 
333       /* Copy from current to repopulate the vertex with correct
334        * values.
335        */
336       vbo_exec_copy_from_current( exec );
337    }
338    else {
339       /* Just have to append the new attribute at the end */
340       exec->vtx.attrptr[attr] = exec->vtx.vertex +
341         exec->vtx.vertex_size - newSize;
342    }
343 
344    /* Replay stored vertices to translate them
345     * to new format here.
346     *
347     * -- No need to replay - just copy piecewise
348     */
349    if (unlikely(exec->vtx.copied.nr)) {
350       fi_type *data = exec->vtx.copied.buffer;
351       fi_type *dest = exec->vtx.buffer_ptr;
352 
353       assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
354 
355       for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
356          GLbitfield64 enabled = exec->vtx.enabled;
357          while (enabled) {
358             const int j = u_bit_scan64(&enabled);
359 	    GLuint sz = exec->vtx.attrsz[j];
360             GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
361             GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
362 
363             assert(sz);
364 
365             if (j == attr) {
366                if (oldSize) {
367                   fi_type tmp[4];
368                   COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
369                                               data + old_offset,
370                                               exec->vtx.attrtype[j]);
371                   COPY_SZ_4V(dest + new_offset, newSize, tmp);
372                } else {
373                   fi_type *current = (fi_type *)vbo->currval[j].Ptr;
374                   COPY_SZ_4V(dest + new_offset, sz, current);
375                }
376             }
377             else {
378                COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
379             }
380 	 }
381 
382 	 data += old_vtx_size;
383 	 dest += exec->vtx.vertex_size;
384       }
385 
386       exec->vtx.buffer_ptr = dest;
387       exec->vtx.vert_count += exec->vtx.copied.nr;
388       exec->vtx.copied.nr = 0;
389    }
390 }
391 
392 
393 /**
394  * This is when a vertex attribute transitions to a different size.
395  * For example, we saw a bunch of glTexCoord2f() calls and now we got a
396  * glTexCoord4f() call.  We promote the array from size=2 to size=4.
397  * \param newSize  size of new vertex (number of 32-bit words).
398  */
399 static void
vbo_exec_fixup_vertex(struct gl_context * ctx,GLuint attr,GLuint newSize,GLenum newType)400 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
401                       GLuint newSize, GLenum newType)
402 {
403    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
404 
405    if (newSize > exec->vtx.attrsz[attr] ||
406        newType != exec->vtx.attrtype[attr]) {
407       /* New size is larger.  Need to flush existing vertices and get
408        * an enlarged vertex format.
409        */
410       vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
411    }
412    else if (newSize < exec->vtx.active_sz[attr]) {
413       GLuint i;
414       const fi_type *id =
415             vbo_get_default_vals_as_union(exec->vtx.attrtype[attr]);
416 
417       /* New size is smaller - just need to fill in some
418        * zeros.  Don't need to flush or wrap.
419        */
420       for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
421          exec->vtx.attrptr[attr][i-1] = id[i-1];
422    }
423 
424    exec->vtx.active_sz[attr] = newSize;
425    exec->vtx.attrtype[attr] = newType;
426 
427    /* Does setting NeedFlush belong here?  Necessitates resetting
428     * vtxfmt on each flush (otherwise flags won't get reset
429     * afterwards).
430     */
431    if (attr == 0)
432       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
433 }
434 
435 
436 /**
437  * Called upon first glVertex, glColor, glTexCoord, etc.
438  */
439 static void
vbo_exec_begin_vertices(struct gl_context * ctx)440 vbo_exec_begin_vertices(struct gl_context *ctx)
441 {
442    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
443 
444    vbo_exec_vtx_map( exec );
445 
446    assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
447    assert(exec->begin_vertices_flags);
448 
449    ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
450 }
451 
452 
453 /**
454  * This macro is used to implement all the glVertex, glColor, glTexCoord,
455  * glVertexAttrib, etc functions.
456  * \param A  attribute index
457  * \param N  attribute size (1..4)
458  * \param T  type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
459  * \param C  cast type (fi_type or double)
460  * \param V0, V1, v2, V3  attribute value
461  */
462 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 )                        \
463 do {									\
464    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;		\
465    int sz = (sizeof(C) / sizeof(GLfloat));                              \
466                                                                         \
467    assert(sz == 1 || sz == 2);                                          \
468                                                                         \
469    /* check if attribute size or type is changing */                    \
470    if (unlikely(exec->vtx.active_sz[A] != N * sz) ||                    \
471        unlikely(exec->vtx.attrtype[A] != T)) {                          \
472       vbo_exec_fixup_vertex(ctx, A, N * sz, T);                         \
473    }									\
474                                                                         \
475    /* store vertex attribute in vertex buffer */                        \
476    {									\
477       C *dest = (C *)exec->vtx.attrptr[A];                              \
478       if (N>0) dest[0] = V0;						\
479       if (N>1) dest[1] = V1;						\
480       if (N>2) dest[2] = V2;						\
481       if (N>3) dest[3] = V3;						\
482       assert(exec->vtx.attrtype[A] == T);                               \
483    }									\
484 									\
485    if ((A) == 0) {							\
486       /* This is a glVertex call */					\
487       GLuint i;								\
488 									\
489       if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
490          vbo_exec_begin_vertices(ctx);                                  \
491       }                                                                 \
492                                                                         \
493       if (unlikely(!exec->vtx.buffer_ptr)) {                            \
494          vbo_exec_vtx_map(exec);                                        \
495       }                                                                 \
496       assert(exec->vtx.buffer_ptr);                                     \
497                                                                         \
498       /* copy 32-bit words */                                           \
499       for (i = 0; i < exec->vtx.vertex_size; i++)			\
500 	 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];			\
501 									\
502       exec->vtx.buffer_ptr += exec->vtx.vertex_size;			\
503 									\
504       /* Set FLUSH_STORED_VERTICES to indicate that there's now */	\
505       /* something to draw (not just updating a color or texcoord).*/	\
506       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;			\
507 									\
508       if (++exec->vtx.vert_count >= exec->vtx.max_vert)			\
509 	 vbo_exec_vtx_wrap( exec );					\
510    } else {                                                             \
511       /* we now have accumulated per-vertex attributes */               \
512       ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;                    \
513    }                                                                    \
514 } while (0)
515 
516 
517 #undef ERROR
518 #define ERROR(err) _mesa_error( ctx, err, __func__ )
519 #define TAG(x) vbo_##x
520 
521 #include "vbo_attrib_tmp.h"
522 
523 
524 
525 /**
526  * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
527  * this may be a (partial) no-op.
528  */
529 static void GLAPIENTRY
vbo_Materialfv(GLenum face,GLenum pname,const GLfloat * params)530 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
531 {
532    GLbitfield updateMats;
533    GET_CURRENT_CONTEXT(ctx);
534 
535    /* This function should be a no-op when it tries to update material
536     * attributes which are currently tracking glColor via glColorMaterial.
537     * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
538     * indicating which material attributes can actually be updated below.
539     */
540    if (ctx->Light.ColorMaterialEnabled) {
541       updateMats = ~ctx->Light._ColorMaterialBitmask;
542    }
543    else {
544       /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
545       updateMats = ALL_MATERIAL_BITS;
546    }
547 
548    if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
549       updateMats &= FRONT_MATERIAL_BITS;
550    }
551    else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
552       updateMats &= BACK_MATERIAL_BITS;
553    }
554    else if (face != GL_FRONT_AND_BACK) {
555       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
556       return;
557    }
558 
559    switch (pname) {
560    case GL_EMISSION:
561       if (updateMats & MAT_BIT_FRONT_EMISSION)
562          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
563       if (updateMats & MAT_BIT_BACK_EMISSION)
564          MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
565       break;
566    case GL_AMBIENT:
567       if (updateMats & MAT_BIT_FRONT_AMBIENT)
568          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
569       if (updateMats & MAT_BIT_BACK_AMBIENT)
570          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
571       break;
572    case GL_DIFFUSE:
573       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
574          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
575       if (updateMats & MAT_BIT_BACK_DIFFUSE)
576          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
577       break;
578    case GL_SPECULAR:
579       if (updateMats & MAT_BIT_FRONT_SPECULAR)
580          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
581       if (updateMats & MAT_BIT_BACK_SPECULAR)
582          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
583       break;
584    case GL_SHININESS:
585       if (*params < 0 || *params > ctx->Const.MaxShininess) {
586          _mesa_error(ctx, GL_INVALID_VALUE,
587                      "glMaterial(invalid shininess: %f out range [0, %f])",
588 		     *params, ctx->Const.MaxShininess);
589          return;
590       }
591       if (updateMats & MAT_BIT_FRONT_SHININESS)
592          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
593       if (updateMats & MAT_BIT_BACK_SHININESS)
594          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
595       break;
596    case GL_COLOR_INDEXES:
597       if (ctx->API != API_OPENGL_COMPAT) {
598          _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
599          return;
600       }
601       if (updateMats & MAT_BIT_FRONT_INDEXES)
602          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
603       if (updateMats & MAT_BIT_BACK_INDEXES)
604          MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
605       break;
606    case GL_AMBIENT_AND_DIFFUSE:
607       if (updateMats & MAT_BIT_FRONT_AMBIENT)
608          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
609       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
610          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
611       if (updateMats & MAT_BIT_BACK_AMBIENT)
612          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
613       if (updateMats & MAT_BIT_BACK_DIFFUSE)
614          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
615       break;
616    default:
617       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
618       return;
619    }
620 }
621 
622 
623 /**
624  * Flush (draw) vertices.
625  * \param  unmap - leave VBO unmapped after flushing?
626  */
627 static void
vbo_exec_FlushVertices_internal(struct vbo_exec_context * exec,GLboolean unmap)628 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
629 {
630    if (exec->vtx.vert_count || unmap) {
631       vbo_exec_vtx_flush( exec, unmap );
632    }
633 
634    if (exec->vtx.vertex_size) {
635       vbo_exec_copy_to_current( exec );
636       vbo_reset_all_attr(exec);
637    }
638 }
639 
640 
641 static void GLAPIENTRY
vbo_exec_EvalCoord1f(GLfloat u)642 vbo_exec_EvalCoord1f(GLfloat u)
643 {
644    GET_CURRENT_CONTEXT( ctx );
645    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
646 
647    {
648       GLint i;
649       if (exec->eval.recalculate_maps)
650 	 vbo_exec_eval_update( exec );
651 
652       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
653 	 if (exec->eval.map1[i].map)
654 	    if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
655 	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz, GL_FLOAT );
656       }
657    }
658 
659 
660    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
661            exec->vtx.vertex_size * sizeof(GLfloat));
662 
663    vbo_exec_do_EvalCoord1f( exec, u );
664 
665    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
666            exec->vtx.vertex_size * sizeof(GLfloat));
667 }
668 
669 
670 static void GLAPIENTRY
vbo_exec_EvalCoord2f(GLfloat u,GLfloat v)671 vbo_exec_EvalCoord2f(GLfloat u, GLfloat v)
672 {
673    GET_CURRENT_CONTEXT( ctx );
674    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
675 
676    {
677       GLint i;
678       if (exec->eval.recalculate_maps)
679 	 vbo_exec_eval_update( exec );
680 
681       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
682 	 if (exec->eval.map2[i].map)
683 	    if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
684 	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz, GL_FLOAT );
685       }
686 
687       if (ctx->Eval.AutoNormal)
688 	 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
689 	    vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT );
690    }
691 
692    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
693            exec->vtx.vertex_size * sizeof(GLfloat));
694 
695    vbo_exec_do_EvalCoord2f( exec, u, v );
696 
697    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
698            exec->vtx.vertex_size * sizeof(GLfloat));
699 }
700 
701 
702 static void GLAPIENTRY
vbo_exec_EvalCoord1fv(const GLfloat * u)703 vbo_exec_EvalCoord1fv(const GLfloat *u)
704 {
705    vbo_exec_EvalCoord1f( u[0] );
706 }
707 
708 
709 static void GLAPIENTRY
vbo_exec_EvalCoord2fv(const GLfloat * u)710 vbo_exec_EvalCoord2fv(const GLfloat *u)
711 {
712    vbo_exec_EvalCoord2f( u[0], u[1] );
713 }
714 
715 
716 static void GLAPIENTRY
vbo_exec_EvalPoint1(GLint i)717 vbo_exec_EvalPoint1(GLint i)
718 {
719    GET_CURRENT_CONTEXT( ctx );
720    GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
721 		 (GLfloat) ctx->Eval.MapGrid1un);
722    GLfloat u = i * du + ctx->Eval.MapGrid1u1;
723 
724    vbo_exec_EvalCoord1f( u );
725 }
726 
727 
728 static void GLAPIENTRY
vbo_exec_EvalPoint2(GLint i,GLint j)729 vbo_exec_EvalPoint2(GLint i, GLint j)
730 {
731    GET_CURRENT_CONTEXT( ctx );
732    GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
733 		 (GLfloat) ctx->Eval.MapGrid2un);
734    GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
735 		 (GLfloat) ctx->Eval.MapGrid2vn);
736    GLfloat u = i * du + ctx->Eval.MapGrid2u1;
737    GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
738 
739    vbo_exec_EvalCoord2f( u, v );
740 }
741 
742 
743 /**
744  * Called via glBegin.
745  */
746 static void GLAPIENTRY
vbo_exec_Begin(GLenum mode)747 vbo_exec_Begin(GLenum mode)
748 {
749    GET_CURRENT_CONTEXT( ctx );
750    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
751    int i;
752 
753    if (_mesa_inside_begin_end(ctx)) {
754       _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
755       return;
756    }
757 
758    if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
759       return;
760    }
761 
762    vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
763 
764    if (ctx->NewState) {
765       _mesa_update_state( ctx );
766 
767       CALL_Begin(ctx->Exec, (mode));
768       return;
769    }
770 
771    if (!_mesa_valid_to_render(ctx, "glBegin")) {
772       return;
773    }
774 
775    /* Heuristic: attempt to isolate attributes occurring outside
776     * begin/end pairs.
777     */
778    if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
779       vbo_exec_FlushVertices_internal(exec, GL_FALSE);
780 
781    i = exec->vtx.prim_count++;
782    exec->vtx.prim[i].mode = mode;
783    exec->vtx.prim[i].begin = 1;
784    exec->vtx.prim[i].end = 0;
785    exec->vtx.prim[i].indexed = 0;
786    exec->vtx.prim[i].weak = 0;
787    exec->vtx.prim[i].pad = 0;
788    exec->vtx.prim[i].start = exec->vtx.vert_count;
789    exec->vtx.prim[i].count = 0;
790    exec->vtx.prim[i].num_instances = 1;
791    exec->vtx.prim[i].base_instance = 0;
792    exec->vtx.prim[i].is_indirect = 0;
793 
794    ctx->Driver.CurrentExecPrimitive = mode;
795 
796    ctx->Exec = ctx->BeginEnd;
797    /* We may have been called from a display list, in which case we should
798     * leave dlist.c's dispatch table in place.
799     */
800    if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
801       ctx->CurrentDispatch = ctx->BeginEnd;
802       _glapi_set_dispatch(ctx->CurrentDispatch);
803    } else {
804       assert(ctx->CurrentDispatch == ctx->Save);
805    }
806 }
807 
808 
809 /**
810  * Try to merge / concatenate the two most recent VBO primitives.
811  */
812 static void
try_vbo_merge(struct vbo_exec_context * exec)813 try_vbo_merge(struct vbo_exec_context *exec)
814 {
815    struct _mesa_prim *cur =  &exec->vtx.prim[exec->vtx.prim_count - 1];
816 
817    assert(exec->vtx.prim_count >= 1);
818 
819    vbo_try_prim_conversion(cur);
820 
821    if (exec->vtx.prim_count >= 2) {
822       struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
823       assert(prev == cur - 1);
824 
825       if (vbo_can_merge_prims(prev, cur)) {
826          assert(cur->begin);
827          assert(cur->end);
828          assert(prev->begin);
829          assert(prev->end);
830          vbo_merge_prims(prev, cur);
831          exec->vtx.prim_count--;  /* drop the last primitive */
832       }
833    }
834 }
835 
836 
837 /**
838  * Called via glEnd.
839  */
840 static void GLAPIENTRY
vbo_exec_End(void)841 vbo_exec_End(void)
842 {
843    GET_CURRENT_CONTEXT( ctx );
844    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
845 
846    if (!_mesa_inside_begin_end(ctx)) {
847       _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
848       return;
849    }
850 
851    ctx->Exec = ctx->OutsideBeginEnd;
852    if (ctx->CurrentDispatch == ctx->BeginEnd) {
853       ctx->CurrentDispatch = ctx->OutsideBeginEnd;
854       _glapi_set_dispatch(ctx->CurrentDispatch);
855    }
856 
857    if (exec->vtx.prim_count > 0) {
858       /* close off current primitive */
859       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
860 
861       last_prim->end = 1;
862       last_prim->count = exec->vtx.vert_count - last_prim->start;
863 
864       /* Special handling for GL_LINE_LOOP */
865       if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
866          /* We're finishing drawing a line loop.  Append 0th vertex onto
867           * end of vertex buffer so we can draw it as a line strip.
868           */
869          const fi_type *src = exec->vtx.buffer_map +
870             last_prim->start * exec->vtx.vertex_size;
871          fi_type *dst = exec->vtx.buffer_map +
872             exec->vtx.vert_count * exec->vtx.vertex_size;
873 
874          /* copy 0th vertex to end of buffer */
875          memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
876 
877          last_prim->start++;  /* skip vertex0 */
878          /* note that last_prim->count stays unchanged */
879          last_prim->mode = GL_LINE_STRIP;
880 
881          /* Increment the vertex count so the next primitive doesn't
882           * overwrite the last vertex which we just added.
883           */
884          exec->vtx.vert_count++;
885          exec->vtx.buffer_ptr += exec->vtx.vertex_size;
886       }
887 
888       try_vbo_merge(exec);
889    }
890 
891    ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
892 
893    if (exec->vtx.prim_count == VBO_MAX_PRIM)
894       vbo_exec_vtx_flush( exec, GL_FALSE );
895 
896    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
897       _mesa_flush(ctx);
898    }
899 }
900 
901 
902 /**
903  * Called via glPrimitiveRestartNV()
904  */
905 static void GLAPIENTRY
vbo_exec_PrimitiveRestartNV(void)906 vbo_exec_PrimitiveRestartNV(void)
907 {
908    GLenum curPrim;
909    GET_CURRENT_CONTEXT(ctx);
910 
911    curPrim = ctx->Driver.CurrentExecPrimitive;
912 
913    if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
914       _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
915    }
916    else {
917       vbo_exec_End();
918       vbo_exec_Begin(curPrim);
919    }
920 }
921 
922 
923 static void
vbo_exec_vtxfmt_init(struct vbo_exec_context * exec)924 vbo_exec_vtxfmt_init(struct vbo_exec_context *exec)
925 {
926    struct gl_context *ctx = exec->ctx;
927    GLvertexformat *vfmt = &exec->vtxfmt;
928 
929    vfmt->ArrayElement = _ae_ArrayElement;
930 
931    vfmt->Begin = vbo_exec_Begin;
932    vfmt->End = vbo_exec_End;
933    vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
934 
935    vfmt->CallList = _mesa_CallList;
936    vfmt->CallLists = _mesa_CallLists;
937 
938    vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
939    vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
940    vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
941    vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
942    vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
943    vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
944 
945    /* from attrib_tmp.h:
946     */
947    vfmt->Color3f = vbo_Color3f;
948    vfmt->Color3fv = vbo_Color3fv;
949    vfmt->Color4f = vbo_Color4f;
950    vfmt->Color4fv = vbo_Color4fv;
951    vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
952    vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
953    vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
954    vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
955    vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
956    vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
957    vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
958    vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
959    vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
960    vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
961    vfmt->Normal3f = vbo_Normal3f;
962    vfmt->Normal3fv = vbo_Normal3fv;
963    vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
964    vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
965    vfmt->TexCoord1f = vbo_TexCoord1f;
966    vfmt->TexCoord1fv = vbo_TexCoord1fv;
967    vfmt->TexCoord2f = vbo_TexCoord2f;
968    vfmt->TexCoord2fv = vbo_TexCoord2fv;
969    vfmt->TexCoord3f = vbo_TexCoord3f;
970    vfmt->TexCoord3fv = vbo_TexCoord3fv;
971    vfmt->TexCoord4f = vbo_TexCoord4f;
972    vfmt->TexCoord4fv = vbo_TexCoord4fv;
973    vfmt->Vertex2f = vbo_Vertex2f;
974    vfmt->Vertex2fv = vbo_Vertex2fv;
975    vfmt->Vertex3f = vbo_Vertex3f;
976    vfmt->Vertex3fv = vbo_Vertex3fv;
977    vfmt->Vertex4f = vbo_Vertex4f;
978    vfmt->Vertex4fv = vbo_Vertex4fv;
979 
980    if (ctx->API == API_OPENGLES2) {
981       vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
982       vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
983       vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
984       vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
985       vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
986       vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
987       vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
988       vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
989    } else {
990       vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
991       vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
992       vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
993       vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
994       vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
995       vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
996       vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
997       vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
998    }
999 
1000    /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
1001     * they can have a single entrypoint for updating any of the legacy
1002     * attribs.
1003     */
1004    vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
1005    vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
1006    vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
1007    vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
1008    vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
1009    vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
1010    vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
1011    vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
1012 
1013    /* integer-valued */
1014    vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
1015    vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
1016    vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
1017    vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
1018    vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
1019    vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
1020    vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
1021 
1022    /* unsigned integer-valued */
1023    vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
1024    vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
1025    vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
1026    vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
1027    vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
1028    vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
1029    vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
1030 
1031    vfmt->Materialfv = vbo_Materialfv;
1032 
1033    vfmt->EdgeFlag = vbo_EdgeFlag;
1034    vfmt->Indexf = vbo_Indexf;
1035    vfmt->Indexfv = vbo_Indexfv;
1036 
1037    /* ARB_vertex_type_2_10_10_10_rev */
1038    vfmt->VertexP2ui = vbo_VertexP2ui;
1039    vfmt->VertexP2uiv = vbo_VertexP2uiv;
1040    vfmt->VertexP3ui = vbo_VertexP3ui;
1041    vfmt->VertexP3uiv = vbo_VertexP3uiv;
1042    vfmt->VertexP4ui = vbo_VertexP4ui;
1043    vfmt->VertexP4uiv = vbo_VertexP4uiv;
1044 
1045    vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
1046    vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
1047    vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
1048    vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
1049    vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
1050    vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
1051    vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
1052    vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
1053 
1054    vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
1055    vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
1056    vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
1057    vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
1058    vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
1059    vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
1060    vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
1061    vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
1062 
1063    vfmt->NormalP3ui = vbo_NormalP3ui;
1064    vfmt->NormalP3uiv = vbo_NormalP3uiv;
1065 
1066    vfmt->ColorP3ui = vbo_ColorP3ui;
1067    vfmt->ColorP3uiv = vbo_ColorP3uiv;
1068    vfmt->ColorP4ui = vbo_ColorP4ui;
1069    vfmt->ColorP4uiv = vbo_ColorP4uiv;
1070 
1071    vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
1072    vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
1073 
1074    vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
1075    vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
1076    vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
1077    vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
1078    vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
1079    vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
1080    vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
1081    vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
1082 
1083    vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
1084    vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
1085    vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
1086    vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
1087 
1088    vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
1089    vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
1090    vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
1091    vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
1092 }
1093 
1094 
1095 /**
1096  * Tell the VBO module to use a real OpenGL vertex buffer object to
1097  * store accumulated immediate-mode vertex data.
1098  * This replaces the malloced buffer which was created in
1099  * vb_exec_vtx_init() below.
1100  */
1101 void
vbo_use_buffer_objects(struct gl_context * ctx)1102 vbo_use_buffer_objects(struct gl_context *ctx)
1103 {
1104    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1105    /* Any buffer name but 0 can be used here since this bufferobj won't
1106     * go into the bufferobj hashtable.
1107     */
1108    GLuint bufName = IMM_BUFFER_NAME;
1109    GLenum target = GL_ARRAY_BUFFER_ARB;
1110    GLenum usage = GL_STREAM_DRAW_ARB;
1111    GLsizei size = VBO_VERT_BUFFER_SIZE;
1112 
1113    /* Make sure this func is only used once */
1114    assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1115 
1116    _mesa_align_free(exec->vtx.buffer_map);
1117    exec->vtx.buffer_map = NULL;
1118    exec->vtx.buffer_ptr = NULL;
1119 
1120    /* Allocate a real buffer object now */
1121    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1122    exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName);
1123    if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage,
1124                                GL_MAP_WRITE_BIT |
1125                                GL_DYNAMIC_STORAGE_BIT |
1126                                GL_CLIENT_STORAGE_BIT,
1127                                exec->vtx.bufferobj)) {
1128       _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1129    }
1130 }
1131 
1132 
1133 /**
1134  * If this function is called, all VBO buffers will be unmapped when
1135  * we flush.
1136  * Otherwise, if a simple command like glColor3f() is called and we flush,
1137  * the current VBO may be left mapped.
1138  */
1139 void
vbo_always_unmap_buffers(struct gl_context * ctx)1140 vbo_always_unmap_buffers(struct gl_context *ctx)
1141 {
1142    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1143    exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1144 }
1145 
1146 
1147 void
vbo_exec_vtx_init(struct vbo_exec_context * exec)1148 vbo_exec_vtx_init(struct vbo_exec_context *exec)
1149 {
1150    struct gl_context *ctx = exec->ctx;
1151    struct vbo_context *vbo = vbo_context(ctx);
1152    GLuint i;
1153 
1154    /* Allocate a buffer object.  Will just reuse this object
1155     * continuously, unless vbo_use_buffer_objects() is called to enable
1156     * use of real VBOs.
1157     */
1158    _mesa_reference_buffer_object(ctx,
1159                                  &exec->vtx.bufferobj,
1160                                  ctx->Shared->NullBufferObj);
1161 
1162    assert(!exec->vtx.buffer_map);
1163    exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
1164    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1165 
1166    vbo_exec_vtxfmt_init( exec );
1167    _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1168 
1169    exec->vtx.enabled = 0;
1170    for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1171       assert(i < ARRAY_SIZE(exec->vtx.attrsz));
1172       exec->vtx.attrsz[i] = 0;
1173       assert(i < ARRAY_SIZE(exec->vtx.attrtype));
1174       exec->vtx.attrtype[i] = GL_FLOAT;
1175       assert(i < ARRAY_SIZE(exec->vtx.active_sz));
1176       exec->vtx.active_sz[i] = 0;
1177    }
1178    for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
1179       assert(i < ARRAY_SIZE(exec->vtx.inputs));
1180       assert(i < ARRAY_SIZE(exec->vtx.arrays));
1181       exec->vtx.inputs[i] = &exec->vtx.arrays[i];
1182    }
1183 
1184    {
1185       struct gl_vertex_array *arrays = exec->vtx.arrays;
1186       unsigned i;
1187 
1188       memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
1189              VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
1190       for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
1191          struct gl_vertex_array *array;
1192          array = &arrays[VERT_ATTRIB_FF(i)];
1193          array->BufferObj = NULL;
1194          _mesa_reference_buffer_object(ctx, &array->BufferObj,
1195                                  vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
1196       }
1197 
1198       memcpy(arrays + VERT_ATTRIB_GENERIC(0),
1199              &vbo->currval[VBO_ATTRIB_GENERIC0],
1200              VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
1201 
1202       for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
1203          struct gl_vertex_array *array;
1204          array = &arrays[VERT_ATTRIB_GENERIC(i)];
1205          array->BufferObj = NULL;
1206          _mesa_reference_buffer_object(ctx, &array->BufferObj,
1207                            vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
1208       }
1209    }
1210 
1211    exec->vtx.vertex_size = 0;
1212 
1213    exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1214 }
1215 
1216 
1217 void
vbo_exec_vtx_destroy(struct vbo_exec_context * exec)1218 vbo_exec_vtx_destroy(struct vbo_exec_context *exec)
1219 {
1220    /* using a real VBO for vertex data */
1221    struct gl_context *ctx = exec->ctx;
1222    unsigned i;
1223 
1224    /* True VBOs should already be unmapped
1225     */
1226    if (exec->vtx.buffer_map) {
1227       assert(exec->vtx.bufferobj->Name == 0 ||
1228              exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1229       if (exec->vtx.bufferobj->Name == 0) {
1230          _mesa_align_free(exec->vtx.buffer_map);
1231          exec->vtx.buffer_map = NULL;
1232          exec->vtx.buffer_ptr = NULL;
1233       }
1234    }
1235 
1236    /* Drop any outstanding reference to the vertex buffer
1237     */
1238    for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) {
1239       _mesa_reference_buffer_object(ctx,
1240                                     &exec->vtx.arrays[i].BufferObj,
1241                                     NULL);
1242    }
1243 
1244    /* Free the vertex buffer.  Unmap first if needed.
1245     */
1246    if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1247       ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
1248    }
1249    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1250 }
1251 
1252 
1253 /**
1254  * If inside glBegin()/glEnd(), it should assert(0).  Otherwise, if
1255  * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1256  * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1257  * __struct gl_contextRec::Current and gl_light_attrib::Material
1258  *
1259  * Note that the default T&L engine never clears the
1260  * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1261  *
1262  * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1263  */
1264 void
vbo_exec_FlushVertices(struct gl_context * ctx,GLuint flags)1265 vbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags)
1266 {
1267    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1268 
1269 #ifdef DEBUG
1270    /* debug check: make sure we don't get called recursively */
1271    exec->flush_call_depth++;
1272    assert(exec->flush_call_depth == 1);
1273 #endif
1274 
1275    if (_mesa_inside_begin_end(ctx)) {
1276       /* We've had glBegin but not glEnd! */
1277 #ifdef DEBUG
1278       exec->flush_call_depth--;
1279       assert(exec->flush_call_depth == 0);
1280 #endif
1281       return;
1282    }
1283 
1284    /* Flush (draw), and make sure VBO is left unmapped when done */
1285    vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1286 
1287    /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1288     */
1289    ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1290 
1291 #ifdef DEBUG
1292    exec->flush_call_depth--;
1293    assert(exec->flush_call_depth == 0);
1294 #endif
1295 }
1296 
1297 
1298 /**
1299  * Reset the vertex attribute by setting its size to zero.
1300  */
1301 static void
vbo_reset_attr(struct vbo_exec_context * exec,GLuint attr)1302 vbo_reset_attr(struct vbo_exec_context *exec, GLuint attr)
1303 {
1304    exec->vtx.attrsz[attr] = 0;
1305    exec->vtx.attrtype[attr] = GL_FLOAT;
1306    exec->vtx.active_sz[attr] = 0;
1307 }
1308 
1309 
1310 static void
vbo_reset_all_attr(struct vbo_exec_context * exec)1311 vbo_reset_all_attr(struct vbo_exec_context *exec)
1312 {
1313    while (exec->vtx.enabled) {
1314       const int i = u_bit_scan64(&exec->vtx.enabled);
1315       vbo_reset_attr(exec, i);
1316    }
1317 
1318    exec->vtx.vertex_size = 0;
1319 }
1320 
1321 
1322 void GLAPIENTRY
_es_Color4f(GLfloat r,GLfloat g,GLfloat b,GLfloat a)1323 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1324 {
1325    vbo_Color4f(r, g, b, a);
1326 }
1327 
1328 
1329 void GLAPIENTRY
_es_Normal3f(GLfloat x,GLfloat y,GLfloat z)1330 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1331 {
1332    vbo_Normal3f(x, y, z);
1333 }
1334 
1335 
1336 void GLAPIENTRY
_es_MultiTexCoord4f(GLenum target,GLfloat s,GLfloat t,GLfloat r,GLfloat q)1337 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1338 {
1339    vbo_MultiTexCoord4f(target, s, t, r, q);
1340 }
1341 
1342 
1343 void GLAPIENTRY
_es_Materialfv(GLenum face,GLenum pname,const GLfloat * params)1344 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1345 {
1346    vbo_Materialfv(face, pname, params);
1347 }
1348 
1349 
1350 void GLAPIENTRY
_es_Materialf(GLenum face,GLenum pname,GLfloat param)1351 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1352 {
1353    GLfloat p[4];
1354    p[0] = param;
1355    p[1] = p[2] = p[3] = 0.0F;
1356    vbo_Materialfv(face, pname, p);
1357 }
1358 
1359 
1360 /**
1361  * A special version of glVertexAttrib4f that does not treat index 0 as
1362  * VBO_ATTRIB_POS.
1363  */
1364 static void
VertexAttrib4f_nopos(GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)1365 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1366 {
1367    GET_CURRENT_CONTEXT(ctx);
1368    if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1369       ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1370    else
1371       ERROR(GL_INVALID_VALUE);
1372 }
1373 
1374 void GLAPIENTRY
_es_VertexAttrib4f(GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)1375 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1376 {
1377    VertexAttrib4f_nopos(index, x, y, z, w);
1378 }
1379 
1380 
1381 void GLAPIENTRY
_es_VertexAttrib1f(GLuint indx,GLfloat x)1382 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1383 {
1384    VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1385 }
1386 
1387 
1388 void GLAPIENTRY
_es_VertexAttrib1fv(GLuint indx,const GLfloat * values)1389 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1390 {
1391    VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1392 }
1393 
1394 
1395 void GLAPIENTRY
_es_VertexAttrib2f(GLuint indx,GLfloat x,GLfloat y)1396 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1397 {
1398    VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1399 }
1400 
1401 
1402 void GLAPIENTRY
_es_VertexAttrib2fv(GLuint indx,const GLfloat * values)1403 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1404 {
1405    VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1406 }
1407 
1408 
1409 void GLAPIENTRY
_es_VertexAttrib3f(GLuint indx,GLfloat x,GLfloat y,GLfloat z)1410 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1411 {
1412    VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1413 }
1414 
1415 
1416 void GLAPIENTRY
_es_VertexAttrib3fv(GLuint indx,const GLfloat * values)1417 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1418 {
1419    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1420 }
1421 
1422 
1423 void GLAPIENTRY
_es_VertexAttrib4fv(GLuint indx,const GLfloat * values)1424 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1425 {
1426    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1427 }
1428