Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / vbo / vbo_exec_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.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/mfeatures.h"
38 #include "main/vtxfmt.h"
39 #include "main/dlist.h"
40 #include "main/eval.h"
41 #include "main/state.h"
42 #include "main/light.h"
43 #include "main/api_arrayelt.h"
44 #include "main/api_noop.h"
45 #include "main/dispatch.h"
46
47 #include "vbo_context.h"
48
49 #ifdef ERROR
50 #undef ERROR
51 #endif
52
53
54 /** ID/name for immediate-mode VBO */
55 #define IMM_BUFFER_NAME 0xaabbccdd
56
57
58 static void reset_attrfv( struct vbo_exec_context *exec );
59
60
61 /**
62  * Close off the last primitive, execute the buffer, restart the
63  * primitive.  
64  */
65 static void 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       GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
74       GLuint last_count;
75
76       if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
77          GLint i = exec->vtx.prim_count - 1;
78          assert(i >= 0);
79          exec->vtx.prim[i].count = (exec->vtx.vert_count - 
80                                     exec->vtx.prim[i].start);
81       }
82
83       last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
84
85       /* Execute the buffer and save copied vertices.
86        */
87       if (exec->vtx.vert_count)
88          vbo_exec_vtx_flush( exec, GL_FALSE );
89       else {
90          exec->vtx.prim_count = 0;
91          exec->vtx.copied.nr = 0;
92       }
93
94       /* Emit a glBegin to start the new list.
95        */
96       assert(exec->vtx.prim_count == 0);
97
98       if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
99          exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
100          exec->vtx.prim[0].start = 0;
101          exec->vtx.prim[0].count = 0;
102          exec->vtx.prim_count++;
103       
104          if (exec->vtx.copied.nr == last_count)
105             exec->vtx.prim[0].begin = last_begin;
106       }
107    }
108 }
109
110
111 /**
112  * Deal with buffer wrapping where provoked by the vertex buffer
113  * filling up, as opposed to upgrade_vertex().
114  */
115 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
116 {
117    GLfloat *data = exec->vtx.copied.buffer;
118    GLuint i;
119
120    /* Run pipeline on current vertices, copy wrapped vertices
121     * to exec->vtx.copied.
122     */
123    vbo_exec_wrap_buffers( exec );
124    
125    /* Copy stored stored vertices to start of new list. 
126     */
127    assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
128
129    for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
130       memcpy( exec->vtx.buffer_ptr, data, 
131               exec->vtx.vertex_size * sizeof(GLfloat));
132       exec->vtx.buffer_ptr += exec->vtx.vertex_size;
133       data += exec->vtx.vertex_size;
134       exec->vtx.vert_count++;
135    }
136
137    exec->vtx.copied.nr = 0;
138 }
139
140
141 /**
142  * Copy the active vertex's values to the ctx->Current fields.
143  */
144 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
145 {
146    struct gl_context *ctx = exec->ctx;
147    struct vbo_context *vbo = vbo_context(ctx);
148    GLuint i;
149
150    for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
151       if (exec->vtx.attrsz[i]) {
152          /* Note: the exec->vtx.current[i] pointers point into the
153           * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
154           */
155          GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
156          GLfloat tmp[4];
157
158          COPY_CLEAN_4V(tmp, 
159                        exec->vtx.attrsz[i], 
160                        exec->vtx.attrptr[i]);
161          
162          if (memcmp(current, tmp, sizeof(tmp)) != 0) { 
163             memcpy(current, tmp, sizeof(tmp));
164          
165             /* Given that we explicitly state size here, there is no need
166              * for the COPY_CLEAN above, could just copy 16 bytes and be
167              * done.  The only problem is when Mesa accesses ctx->Current
168              * directly.
169              */
170             vbo->currval[i].Size = exec->vtx.attrsz[i];
171             assert(vbo->currval[i].Type == GL_FLOAT);
172             vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
173
174             /* This triggers rather too much recalculation of Mesa state
175              * that doesn't get used (eg light positions).
176              */
177             if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
178                 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
179                ctx->NewState |= _NEW_LIGHT;
180             
181             ctx->NewState |= _NEW_CURRENT_ATTRIB;
182          }
183       }
184    }
185
186    /* Colormaterial -- this kindof sucks.
187     */
188    if (ctx->Light.ColorMaterialEnabled &&
189        exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
190       _mesa_update_color_material(ctx, 
191                                   ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
192    }
193 }
194
195
196 /**
197  * Copy current vertex attribute values into the current vertex.
198  */
199 static void
200 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
201 {
202    struct gl_context *ctx = exec->ctx;
203    struct vbo_context *vbo = vbo_context(ctx);
204    GLint i;
205
206    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
207       const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
208       switch (exec->vtx.attrsz[i]) {
209       case 4: exec->vtx.attrptr[i][3] = current[3];
210       case 3: exec->vtx.attrptr[i][2] = current[2];
211       case 2: exec->vtx.attrptr[i][1] = current[1];
212       case 1: exec->vtx.attrptr[i][0] = current[0];
213          break;
214       }
215    }
216 }
217
218
219 /**
220  * Flush existing data, set new attrib size, replay copied vertices.
221  * This is called when we transition from a small vertex attribute size
222  * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
223  * We need to go back over the previous 2-component texcoords and insert
224  * zero and one values.
225  */ 
226 static void
227 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
228                              GLuint attr, GLuint newSize )
229 {
230    struct gl_context *ctx = exec->ctx;
231    struct vbo_context *vbo = vbo_context(ctx);
232    const GLint lastcount = exec->vtx.vert_count;
233    GLfloat *old_attrptr[VBO_ATTRIB_MAX];
234    const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
235    const GLuint oldSize = exec->vtx.attrsz[attr];
236    GLuint i;
237
238    /* Run pipeline on current vertices, copy wrapped vertices
239     * to exec->vtx.copied.
240     */
241    vbo_exec_wrap_buffers( exec );
242
243    if (unlikely(exec->vtx.copied.nr)) {
244       /* We're in the middle of a primitive, keep the old vertex
245        * format around to be able to translate the copied vertices to
246        * the new format.
247        */
248       memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
249    }
250
251    if (unlikely(oldSize)) {
252       /* Do a COPY_TO_CURRENT to ensure back-copying works for the
253        * case when the attribute already exists in the vertex and is
254        * having its size increased.
255        */
256       vbo_exec_copy_to_current( exec );
257    }
258
259    /* Heuristic: Attempt to isolate attributes received outside
260     * begin/end so that they don't bloat the vertices.
261     */
262    if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
263        !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
264       vbo_exec_copy_to_current( exec );
265       reset_attrfv( exec );
266    }
267
268    /* Fix up sizes:
269     */
270    exec->vtx.attrsz[attr] = newSize;
271    exec->vtx.vertex_size += newSize - oldSize;
272    exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / 
273                          (exec->vtx.vertex_size * sizeof(GLfloat)));
274    exec->vtx.vert_count = 0;
275    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
276
277    if (unlikely(oldSize)) {
278       /* Size changed, recalculate all the attrptr[] values
279        */
280       GLfloat *tmp = exec->vtx.vertex;
281
282       for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
283          if (exec->vtx.attrsz[i]) {
284             exec->vtx.attrptr[i] = tmp;
285             tmp += exec->vtx.attrsz[i];
286          }
287          else
288             exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
289       }
290
291       /* Copy from current to repopulate the vertex with correct
292        * values.
293        */
294       vbo_exec_copy_from_current( exec );
295    }
296    else {
297       /* Just have to append the new attribute at the end */
298       exec->vtx.attrptr[attr] = exec->vtx.vertex +
299          exec->vtx.vertex_size - newSize;
300    }
301
302    /* Replay stored vertices to translate them
303     * to new format here.
304     *
305     * -- No need to replay - just copy piecewise
306     */
307    if (unlikely(exec->vtx.copied.nr)) {
308       GLfloat *data = exec->vtx.copied.buffer;
309       GLfloat *dest = exec->vtx.buffer_ptr;
310       GLuint j;
311
312       assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
313
314       for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
315          for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
316             GLuint sz = exec->vtx.attrsz[j];
317
318             if (sz) {
319                GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
320                GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
321
322                if (j == attr) {
323                   if (oldSize) {
324                      GLfloat tmp[4];
325                      COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
326                      COPY_SZ_4V(dest + new_offset, newSize, tmp);
327                   } else {
328                      GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
329                      COPY_SZ_4V(dest + new_offset, sz, current);
330                   }
331                }
332                else {
333                   COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
334                }
335             }
336          }
337
338          data += old_vtx_size;
339          dest += exec->vtx.vertex_size;
340       }
341
342       exec->vtx.buffer_ptr = dest;
343       exec->vtx.vert_count += exec->vtx.copied.nr;
344       exec->vtx.copied.nr = 0;
345    }
346 }
347
348
349 /**
350  * This is when a vertex attribute transitions to a different size.
351  * For example, we saw a bunch of glTexCoord2f() calls and now we got a
352  * glTexCoord4f() call.  We promote the array from size=2 to size=4.
353  */
354 static void
355 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
356 {
357    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
358
359    if (newSize > exec->vtx.attrsz[attr]) {
360       /* New size is larger.  Need to flush existing vertices and get
361        * an enlarged vertex format.
362        */
363       vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
364    }
365    else if (newSize < exec->vtx.active_sz[attr]) {
366       static const GLfloat id[4] = { 0, 0, 0, 1 };
367       GLuint i;
368
369       /* New size is smaller - just need to fill in some
370        * zeros.  Don't need to flush or wrap.
371        */
372       for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
373          exec->vtx.attrptr[attr][i-1] = id[i-1];
374    }
375
376    exec->vtx.active_sz[attr] = newSize;
377
378    /* Does setting NeedFlush belong here?  Necessitates resetting
379     * vtxfmt on each flush (otherwise flags won't get reset
380     * afterwards).
381     */
382    if (attr == 0) 
383       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
384 }
385
386
387 /**
388  * This macro is used to implement all the glVertex, glColor, glTexCoord,
389  * glVertexAttrib, etc functions.
390  */
391 #define ATTR( A, N, V0, V1, V2, V3 )                                    \
392 do {                                                                    \
393    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;             \
394                                                                         \
395    if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)))       \
396       ctx->Driver.BeginVertices( ctx );                                 \
397                                                                         \
398    if (unlikely(exec->vtx.active_sz[A] != N))                           \
399       vbo_exec_fixup_vertex(ctx, A, N);                                 \
400                                                                         \
401    {                                                                    \
402       GLfloat *dest = exec->vtx.attrptr[A];                             \
403       if (N>0) dest[0] = V0;                                            \
404       if (N>1) dest[1] = V1;                                            \
405       if (N>2) dest[2] = V2;                                            \
406       if (N>3) dest[3] = V3;                                            \
407    }                                                                    \
408                                                                         \
409    if ((A) == 0) {                                                      \
410       /* This is a glVertex call */                                     \
411       GLuint i;                                                         \
412                                                                         \
413       for (i = 0; i < exec->vtx.vertex_size; i++)                       \
414          exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];                 \
415                                                                         \
416       exec->vtx.buffer_ptr += exec->vtx.vertex_size;                    \
417                                                                         \
418       /* Set FLUSH_STORED_VERTICES to indicate that there's now */      \
419       /* something to draw (not just updating a color or texcoord).*/   \
420       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;                   \
421                                                                         \
422       if (++exec->vtx.vert_count >= exec->vtx.max_vert)                 \
423          vbo_exec_vtx_wrap( exec );                                     \
424    }                                                                    \
425 } while (0)
426
427
428 #define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
429 #define TAG(x) vbo_##x
430
431 #include "vbo_attrib_tmp.h"
432
433
434 #if FEATURE_beginend
435
436
437 #if FEATURE_evaluators
438
439 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
440 {
441    GET_CURRENT_CONTEXT( ctx );
442    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
443
444    {
445       GLint i;
446       if (exec->eval.recalculate_maps) 
447          vbo_exec_eval_update( exec );
448
449       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
450          if (exec->eval.map1[i].map) 
451             if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
452                vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
453       }
454    }
455
456
457    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 
458            exec->vtx.vertex_size * sizeof(GLfloat));
459
460    vbo_exec_do_EvalCoord1f( exec, u );
461
462    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
463            exec->vtx.vertex_size * sizeof(GLfloat));
464 }
465
466 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
467 {
468    GET_CURRENT_CONTEXT( ctx );
469    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
470
471    {
472       GLint i;
473       if (exec->eval.recalculate_maps) 
474          vbo_exec_eval_update( exec );
475
476       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
477          if (exec->eval.map2[i].map) 
478             if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
479                vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
480       }
481
482       if (ctx->Eval.AutoNormal) 
483          if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
484             vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
485    }
486
487    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, 
488            exec->vtx.vertex_size * sizeof(GLfloat));
489
490    vbo_exec_do_EvalCoord2f( exec, u, v );
491
492    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, 
493            exec->vtx.vertex_size * sizeof(GLfloat));
494 }
495
496 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
497 {
498    vbo_exec_EvalCoord1f( u[0] );
499 }
500
501 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
502 {
503    vbo_exec_EvalCoord2f( u[0], u[1] );
504 }
505
506 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
507 {
508    GET_CURRENT_CONTEXT( ctx );
509    GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
510                  (GLfloat) ctx->Eval.MapGrid1un);
511    GLfloat u = i * du + ctx->Eval.MapGrid1u1;
512
513    vbo_exec_EvalCoord1f( u );
514 }
515
516
517 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
518 {
519    GET_CURRENT_CONTEXT( ctx );
520    GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / 
521                  (GLfloat) ctx->Eval.MapGrid2un);
522    GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / 
523                  (GLfloat) ctx->Eval.MapGrid2vn);
524    GLfloat u = i * du + ctx->Eval.MapGrid2u1;
525    GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
526
527    vbo_exec_EvalCoord2f( u, v );
528 }
529
530 /* use noop eval mesh */
531 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
532 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
533
534 #endif /* FEATURE_evaluators */
535
536
537 /**
538  * Flush (draw) vertices.
539  * \param  unmap - leave VBO unmapped after flushing?
540  */
541 static void
542 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
543 {
544    if (exec->vtx.vert_count || unmap) {
545       vbo_exec_vtx_flush( exec, unmap );
546    }
547
548    if (exec->vtx.vertex_size) {
549       vbo_exec_copy_to_current( exec );
550       reset_attrfv( exec );
551    }
552 }
553
554
555 /**
556  * Called via glBegin.
557  */
558 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
559 {
560    GET_CURRENT_CONTEXT( ctx ); 
561
562    if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
563       struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
564       int i;
565
566       if (ctx->NewState) {
567          _mesa_update_state( ctx );
568
569          CALL_Begin(ctx->Exec, (mode));
570          return;
571       }
572
573       if (!_mesa_valid_to_render(ctx, "glBegin")) {
574          return;
575       }
576
577       /* Heuristic: attempt to isolate attributes occuring outside
578        * begin/end pairs.
579        */
580       if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 
581          vbo_exec_FlushVertices_internal(exec, GL_FALSE);
582
583       i = exec->vtx.prim_count++;
584       exec->vtx.prim[i].mode = mode;
585       exec->vtx.prim[i].begin = 1;
586       exec->vtx.prim[i].end = 0;
587       exec->vtx.prim[i].indexed = 0;
588       exec->vtx.prim[i].weak = 0;
589       exec->vtx.prim[i].pad = 0;
590       exec->vtx.prim[i].start = exec->vtx.vert_count;
591       exec->vtx.prim[i].count = 0;
592       exec->vtx.prim[i].num_instances = 1;
593
594       ctx->Driver.CurrentExecPrimitive = mode;
595    }
596    else 
597       _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
598       
599 }
600
601
602 /**
603  * Called via glEnd.
604  */
605 static void GLAPIENTRY vbo_exec_End( void )
606 {
607    GET_CURRENT_CONTEXT( ctx ); 
608
609    if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
610       struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
611
612       if (exec->vtx.prim_count > 0) {
613          /* close off current primitive */
614          int idx = exec->vtx.vert_count;
615          int i = exec->vtx.prim_count - 1;
616
617          exec->vtx.prim[i].end = 1; 
618          exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
619       }
620
621       ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
622
623       if (exec->vtx.prim_count == VBO_MAX_PRIM)
624          vbo_exec_vtx_flush( exec, GL_FALSE );
625    }
626    else 
627       _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
628 }
629
630
631 /**
632  * Called via glPrimitiveRestartNV()
633  */
634 static void GLAPIENTRY
635 vbo_exec_PrimitiveRestartNV(void)
636 {
637    GLenum curPrim;
638    GET_CURRENT_CONTEXT( ctx ); 
639
640    curPrim = ctx->Driver.CurrentExecPrimitive;
641
642    if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
643       _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
644    }
645    else {
646       vbo_exec_End();
647       vbo_exec_Begin(curPrim);
648    }
649 }
650
651
652
653 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
654 {
655    GLvertexformat *vfmt = &exec->vtxfmt;
656
657    _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
658
659    vfmt->Begin = vbo_exec_Begin;
660    vfmt->End = vbo_exec_End;
661    vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
662
663    _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
664    _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
665
666    vfmt->Rectf = _mesa_noop_Rectf;
667
668    /* from attrib_tmp.h:
669     */
670    vfmt->Color3f = vbo_Color3f;
671    vfmt->Color3fv = vbo_Color3fv;
672    vfmt->Color4f = vbo_Color4f;
673    vfmt->Color4fv = vbo_Color4fv;
674    vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
675    vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
676    vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
677    vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
678    vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
679    vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
680    vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
681    vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
682    vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
683    vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
684    vfmt->Normal3f = vbo_Normal3f;
685    vfmt->Normal3fv = vbo_Normal3fv;
686    vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
687    vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
688    vfmt->TexCoord1f = vbo_TexCoord1f;
689    vfmt->TexCoord1fv = vbo_TexCoord1fv;
690    vfmt->TexCoord2f = vbo_TexCoord2f;
691    vfmt->TexCoord2fv = vbo_TexCoord2fv;
692    vfmt->TexCoord3f = vbo_TexCoord3f;
693    vfmt->TexCoord3fv = vbo_TexCoord3fv;
694    vfmt->TexCoord4f = vbo_TexCoord4f;
695    vfmt->TexCoord4fv = vbo_TexCoord4fv;
696    vfmt->Vertex2f = vbo_Vertex2f;
697    vfmt->Vertex2fv = vbo_Vertex2fv;
698    vfmt->Vertex3f = vbo_Vertex3f;
699    vfmt->Vertex3fv = vbo_Vertex3fv;
700    vfmt->Vertex4f = vbo_Vertex4f;
701    vfmt->Vertex4fv = vbo_Vertex4fv;
702    
703    vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
704    vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
705    vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
706    vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
707    vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
708    vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
709    vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
710    vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
711
712    vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
713    vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
714    vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
715    vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
716    vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
717    vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
718    vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
719    vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
720
721    /* integer-valued */
722    vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
723    vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
724    vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
725    vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
726    vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
727    vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
728    vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
729
730    /* unsigned integer-valued */
731    vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
732    vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
733    vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
734    vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
735    vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
736    vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
737    vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
738
739    vfmt->Materialfv = vbo_Materialfv;
740
741    vfmt->EdgeFlag = vbo_EdgeFlag;
742    vfmt->Indexf = vbo_Indexf;
743    vfmt->Indexfv = vbo_Indexfv;
744
745 }
746
747
748 #else /* FEATURE_beginend */
749
750
751 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
752 {
753    /* silence warnings */
754    (void) vbo_Color3f;
755    (void) vbo_Color3fv;
756    (void) vbo_Color4f;
757    (void) vbo_Color4fv;
758    (void) vbo_FogCoordfEXT;
759    (void) vbo_FogCoordfvEXT;
760    (void) vbo_MultiTexCoord1f;
761    (void) vbo_MultiTexCoord1fv;
762    (void) vbo_MultiTexCoord2f;
763    (void) vbo_MultiTexCoord2fv;
764    (void) vbo_MultiTexCoord3f;
765    (void) vbo_MultiTexCoord3fv;
766    (void) vbo_MultiTexCoord4f;
767    (void) vbo_MultiTexCoord4fv;
768    (void) vbo_Normal3f;
769    (void) vbo_Normal3fv;
770    (void) vbo_SecondaryColor3fEXT;
771    (void) vbo_SecondaryColor3fvEXT;
772    (void) vbo_TexCoord1f;
773    (void) vbo_TexCoord1fv;
774    (void) vbo_TexCoord2f;
775    (void) vbo_TexCoord2fv;
776    (void) vbo_TexCoord3f;
777    (void) vbo_TexCoord3fv;
778    (void) vbo_TexCoord4f;
779    (void) vbo_TexCoord4fv;
780    (void) vbo_Vertex2f;
781    (void) vbo_Vertex2fv;
782    (void) vbo_Vertex3f;
783    (void) vbo_Vertex3fv;
784    (void) vbo_Vertex4f;
785    (void) vbo_Vertex4fv;
786
787    (void) vbo_VertexAttrib1fARB;
788    (void) vbo_VertexAttrib1fvARB;
789    (void) vbo_VertexAttrib2fARB;
790    (void) vbo_VertexAttrib2fvARB;
791    (void) vbo_VertexAttrib3fARB;
792    (void) vbo_VertexAttrib3fvARB;
793    (void) vbo_VertexAttrib4fARB;
794    (void) vbo_VertexAttrib4fvARB;
795
796    (void) vbo_VertexAttrib1fNV;
797    (void) vbo_VertexAttrib1fvNV;
798    (void) vbo_VertexAttrib2fNV;
799    (void) vbo_VertexAttrib2fvNV;
800    (void) vbo_VertexAttrib3fNV;
801    (void) vbo_VertexAttrib3fvNV;
802    (void) vbo_VertexAttrib4fNV;
803    (void) vbo_VertexAttrib4fvNV;
804
805    (void) vbo_Materialfv;
806
807    (void) vbo_EdgeFlag;
808    (void) vbo_Indexf;
809    (void) vbo_Indexfv;
810 }
811
812
813 #endif /* FEATURE_beginend */
814
815
816 /**
817  * Tell the VBO module to use a real OpenGL vertex buffer object to
818  * store accumulated immediate-mode vertex data.
819  * This replaces the malloced buffer which was created in
820  * vb_exec_vtx_init() below.
821  */
822 void vbo_use_buffer_objects(struct gl_context *ctx)
823 {
824    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
825    /* Any buffer name but 0 can be used here since this bufferobj won't
826     * go into the bufferobj hashtable.
827     */
828    GLuint bufName = IMM_BUFFER_NAME;
829    GLenum target = GL_ARRAY_BUFFER_ARB;
830    GLenum usage = GL_STREAM_DRAW_ARB;
831    GLsizei size = VBO_VERT_BUFFER_SIZE;
832
833    /* Make sure this func is only used once */
834    assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
835    if (exec->vtx.buffer_map) {
836       _mesa_align_free(exec->vtx.buffer_map);
837       exec->vtx.buffer_map = NULL;
838       exec->vtx.buffer_ptr = NULL;
839    }
840
841    /* Allocate a real buffer object now */
842    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
843    exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
844    ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
845 }
846
847
848 /**
849  * If this function is called, all VBO buffers will be unmapped when
850  * we flush.
851  * Otherwise, if a simple command like glColor3f() is called and we flush,
852  * the current VBO may be left mapped.
853  */
854 void
855 vbo_always_unmap_buffers(struct gl_context *ctx)
856 {
857    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
858    exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
859 }
860
861
862 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
863 {
864    struct gl_context *ctx = exec->ctx;
865    struct vbo_context *vbo = vbo_context(ctx);
866    GLuint i;
867
868    /* Allocate a buffer object.  Will just reuse this object
869     * continuously, unless vbo_use_buffer_objects() is called to enable
870     * use of real VBOs.
871     */
872    _mesa_reference_buffer_object(ctx,
873                                  &exec->vtx.bufferobj,
874                                  ctx->Shared->NullBufferObj);
875
876    ASSERT(!exec->vtx.buffer_map);
877    exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
878    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
879
880    vbo_exec_vtxfmt_init( exec );
881
882    /* Hook our functions into the dispatch table.
883     */
884    _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
885
886    for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
887       ASSERT(i < Elements(exec->vtx.attrsz));
888       exec->vtx.attrsz[i] = 0;
889       ASSERT(i < Elements(exec->vtx.active_sz));
890       exec->vtx.active_sz[i] = 0;
891    }
892    for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
893       ASSERT(i < Elements(exec->vtx.inputs));
894       ASSERT(i < Elements(exec->vtx.arrays));
895       exec->vtx.inputs[i] = &exec->vtx.arrays[i];
896    }
897    
898    {
899       struct gl_client_array *arrays = exec->vtx.arrays;
900       unsigned i;
901
902       memcpy(arrays,      vbo->legacy_currval,  16 * sizeof(arrays[0]));
903       memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
904
905       for (i = 0; i < 16; ++i) {
906          arrays[i     ].BufferObj = NULL;
907          arrays[i + 16].BufferObj = NULL;
908          _mesa_reference_buffer_object(ctx, &arrays[i     ].BufferObj,
909                                        vbo->legacy_currval[i].BufferObj);
910          _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
911                                        vbo->generic_currval[i].BufferObj);
912       }
913    }
914
915    exec->vtx.vertex_size = 0;
916
917    exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
918 }
919
920
921 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
922 {
923    /* using a real VBO for vertex data */
924    struct gl_context *ctx = exec->ctx;
925    unsigned i;
926
927    /* True VBOs should already be unmapped
928     */
929    if (exec->vtx.buffer_map) {
930       ASSERT(exec->vtx.bufferobj->Name == 0 ||
931              exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
932       if (exec->vtx.bufferobj->Name == 0) {
933          _mesa_align_free(exec->vtx.buffer_map);
934          exec->vtx.buffer_map = NULL;
935          exec->vtx.buffer_ptr = NULL;
936       }
937    }
938
939    /* Drop any outstanding reference to the vertex buffer
940     */
941    for (i = 0; i < Elements(exec->vtx.arrays); i++) {
942       _mesa_reference_buffer_object(ctx,
943                                     &exec->vtx.arrays[i].BufferObj,
944                                     NULL);
945    }
946
947    /* Free the vertex buffer.  Unmap first if needed.
948     */
949    if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
950       ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
951    }
952    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
953 }
954
955
956 /**
957  * Called upon first glVertex, glColor, glTexCoord, etc.
958  */
959 void vbo_exec_BeginVertices( struct gl_context *ctx )
960 {
961    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
962
963    vbo_exec_vtx_map( exec );
964
965    assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
966    assert(exec->begin_vertices_flags);
967
968    ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
969 }
970
971
972 /**
973  * Called via ctx->Driver.FlushVertices()
974  * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
975  */
976 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
977 {
978    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
979
980 #ifdef DEBUG
981    /* debug check: make sure we don't get called recursively */
982    exec->flush_call_depth++;
983    assert(exec->flush_call_depth == 1);
984 #endif
985
986    if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
987       /* We've had glBegin but not glEnd! */
988 #ifdef DEBUG
989       exec->flush_call_depth--;
990       assert(exec->flush_call_depth == 0);
991 #endif
992       return;
993    }
994
995    /* Flush (draw), and make sure VBO is left unmapped when done */
996    vbo_exec_FlushVertices_internal(exec, GL_TRUE);
997
998    /* Need to do this to ensure BeginVertices gets called again:
999     */
1000    ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1001
1002 #ifdef DEBUG
1003    exec->flush_call_depth--;
1004    assert(exec->flush_call_depth == 0);
1005 #endif
1006 }
1007
1008
1009 static void reset_attrfv( struct vbo_exec_context *exec )
1010 {   
1011    GLuint i;
1012
1013    for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1014       exec->vtx.attrsz[i] = 0;
1015       exec->vtx.active_sz[i] = 0;
1016    }
1017
1018    exec->vtx.vertex_size = 0;
1019 }
1020       
1021
1022 void GLAPIENTRY
1023 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1024 {
1025    vbo_Color4f(r, g, b, a);
1026 }
1027
1028
1029 void GLAPIENTRY
1030 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1031 {
1032    vbo_Normal3f(x, y, z);
1033 }
1034
1035
1036 void GLAPIENTRY
1037 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1038 {
1039    vbo_MultiTexCoord4f(target, s, t, r, q);
1040 }
1041
1042
1043 void GLAPIENTRY
1044 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1045 {
1046    vbo_Materialfv(face, pname, params);
1047 }
1048
1049
1050 void GLAPIENTRY
1051 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1052 {
1053    GLfloat p[4];
1054    p[0] = param;
1055    p[1] = p[2] = p[3] = 0.0F;
1056    vbo_Materialfv(face, pname, p);
1057 }
1058
1059
1060 /**
1061  * A special version of glVertexAttrib4f that does not treat index 0 as
1062  * VBO_ATTRIB_POS.
1063  */
1064 static void
1065 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1066 {
1067    GET_CURRENT_CONTEXT(ctx);
1068    if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1069       ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1070    else
1071       ERROR(GL_INVALID_VALUE);
1072 }
1073
1074 void GLAPIENTRY
1075 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1076 {
1077    VertexAttrib4f_nopos(index, x, y, z, w);
1078 }
1079
1080
1081 void GLAPIENTRY
1082 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1083 {
1084    VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1085 }
1086
1087
1088 void GLAPIENTRY
1089 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1090 {
1091    VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1092 }
1093
1094
1095 void GLAPIENTRY
1096 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1097 {
1098    VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1099 }
1100
1101
1102 void GLAPIENTRY
1103 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1104 {
1105    VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1106 }
1107
1108
1109 void GLAPIENTRY
1110 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1111 {
1112    VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1113 }
1114
1115
1116 void GLAPIENTRY
1117 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1118 {
1119    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1120 }
1121
1122
1123 void GLAPIENTRY
1124 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1125 {
1126    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1127 }