1 /**************************************************************************
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
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:
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
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.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
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"
47 #include "vbo_context.h"
54 /** ID/name for immediate-mode VBO */
55 #define IMM_BUFFER_NAME 0xaabbccdd
58 static void reset_attrfv( struct vbo_exec_context
*exec
);
62 * Close off the last primitive, execute the buffer, restart the
65 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
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
;
73 GLuint last_begin
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].begin
;
76 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
77 GLint i
= exec
->vtx
.prim_count
- 1;
79 exec
->vtx
.prim
[i
].count
= (exec
->vtx
.vert_count
-
80 exec
->vtx
.prim
[i
].start
);
83 last_count
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].count
;
85 /* Execute the buffer and save copied vertices.
87 if (exec
->vtx
.vert_count
)
88 vbo_exec_vtx_flush( exec
, GL_FALSE
);
90 exec
->vtx
.prim_count
= 0;
91 exec
->vtx
.copied
.nr
= 0;
94 /* Emit a glBegin to start the new list.
96 assert(exec
->vtx
.prim_count
== 0);
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
++;
104 if (exec
->vtx
.copied
.nr
== last_count
)
105 exec
->vtx
.prim
[0].begin
= last_begin
;
112 * Deal with buffer wrapping where provoked by the vertex buffer
113 * filling up, as opposed to upgrade_vertex().
115 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
117 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
120 /* Run pipeline on current vertices, copy wrapped vertices
121 * to exec->vtx.copied.
123 vbo_exec_wrap_buffers( exec
);
125 /* Copy stored stored vertices to start of new list.
127 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
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
++;
137 exec
->vtx
.copied
.nr
= 0;
142 * Copy the active vertex's values to the ctx->Current fields.
144 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
146 struct gl_context
*ctx
= exec
->ctx
;
147 struct vbo_context
*vbo
= vbo_context(ctx
);
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.
155 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
160 exec
->vtx
.attrptr
[i
]);
162 if (memcmp(current
, tmp
, sizeof(tmp
)) != 0) {
163 memcpy(current
, tmp
, sizeof(tmp
));
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
170 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
172 /* This triggers rather too much recalculation of Mesa state
173 * that doesn't get used (eg light positions).
175 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
176 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
177 ctx
->NewState
|= _NEW_LIGHT
;
179 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
184 /* Colormaterial -- this kindof sucks.
186 if (ctx
->Light
.ColorMaterialEnabled
&&
187 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
188 _mesa_update_color_material(ctx
,
189 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
195 * Copy current vertex attribute values into the current vertex.
198 vbo_exec_copy_from_current(struct vbo_exec_context
*exec
)
200 struct gl_context
*ctx
= exec
->ctx
;
201 struct vbo_context
*vbo
= vbo_context(ctx
);
204 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
205 const GLfloat
*current
= (GLfloat
*) vbo
->currval
[i
].Ptr
;
206 switch (exec
->vtx
.attrsz
[i
]) {
207 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
208 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
209 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
210 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
218 * Flush existing data, set new attrib size, replay copied vertices.
219 * This is called when we transition from a small vertex attribute size
220 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
221 * We need to go back over the previous 2-component texcoords and insert
222 * zero and one values.
225 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context
*exec
,
226 GLuint attr
, GLuint newSize
)
228 struct gl_context
*ctx
= exec
->ctx
;
229 struct vbo_context
*vbo
= vbo_context(ctx
);
230 const GLint lastcount
= exec
->vtx
.vert_count
;
231 GLfloat
*old_attrptr
[VBO_ATTRIB_MAX
];
232 const GLuint old_vtx_size
= exec
->vtx
.vertex_size
; /* floats per vertex */
233 const GLuint oldSize
= exec
->vtx
.attrsz
[attr
];
236 /* Run pipeline on current vertices, copy wrapped vertices
237 * to exec->vtx.copied.
239 vbo_exec_wrap_buffers( exec
);
241 if (unlikely(exec
->vtx
.copied
.nr
)) {
242 /* We're in the middle of a primitive, keep the old vertex
243 * format around to be able to translate the copied vertices to
246 memcpy(old_attrptr
, exec
->vtx
.attrptr
, sizeof(old_attrptr
));
249 if (unlikely(oldSize
)) {
250 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
251 * case when the attribute already exists in the vertex and is
252 * having its size increased.
254 vbo_exec_copy_to_current( exec
);
257 /* Heuristic: Attempt to isolate attributes received outside
258 * begin/end so that they don't bloat the vertices.
260 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
261 !oldSize
&& lastcount
> 8 && exec
->vtx
.vertex_size
) {
262 vbo_exec_copy_to_current( exec
);
263 reset_attrfv( exec
);
268 exec
->vtx
.attrsz
[attr
] = newSize
;
269 exec
->vtx
.vertex_size
+= newSize
- oldSize
;
270 exec
->vtx
.max_vert
= ((VBO_VERT_BUFFER_SIZE
- exec
->vtx
.buffer_used
) /
271 (exec
->vtx
.vertex_size
* sizeof(GLfloat
)));
272 exec
->vtx
.vert_count
= 0;
273 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
275 if (unlikely(oldSize
)) {
276 /* Size changed, recalculate all the attrptr[] values
278 GLfloat
*tmp
= exec
->vtx
.vertex
;
280 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
281 if (exec
->vtx
.attrsz
[i
]) {
282 exec
->vtx
.attrptr
[i
] = tmp
;
283 tmp
+= exec
->vtx
.attrsz
[i
];
286 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
289 /* Copy from current to repopulate the vertex with correct
292 vbo_exec_copy_from_current( exec
);
295 /* Just have to append the new attribute at the end */
296 exec
->vtx
.attrptr
[attr
] = exec
->vtx
.vertex
+
297 exec
->vtx
.vertex_size
- newSize
;
300 /* Replay stored vertices to translate them
301 * to new format here.
303 * -- No need to replay - just copy piecewise
305 if (unlikely(exec
->vtx
.copied
.nr
)) {
306 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
307 GLfloat
*dest
= exec
->vtx
.buffer_ptr
;
310 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
312 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
313 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
314 GLuint sz
= exec
->vtx
.attrsz
[j
];
317 GLint old_offset
= old_attrptr
[j
] - exec
->vtx
.vertex
;
318 GLint new_offset
= exec
->vtx
.attrptr
[j
] - exec
->vtx
.vertex
;
323 COPY_CLEAN_4V(tmp
, oldSize
, data
+ old_offset
);
324 COPY_SZ_4V(dest
+ new_offset
, newSize
, tmp
);
326 GLfloat
*current
= (GLfloat
*)vbo
->currval
[j
].Ptr
;
327 COPY_SZ_4V(dest
+ new_offset
, sz
, current
);
331 COPY_SZ_4V(dest
+ new_offset
, sz
, data
+ old_offset
);
336 data
+= old_vtx_size
;
337 dest
+= exec
->vtx
.vertex_size
;
340 exec
->vtx
.buffer_ptr
= dest
;
341 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
342 exec
->vtx
.copied
.nr
= 0;
348 * This is when a vertex attribute transitions to a different size.
349 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
350 * glTexCoord4f() call. We promote the array from size=2 to size=4.
353 vbo_exec_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newSize
)
355 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
357 if (newSize
> exec
->vtx
.attrsz
[attr
]) {
358 /* New size is larger. Need to flush existing vertices and get
359 * an enlarged vertex format.
361 vbo_exec_wrap_upgrade_vertex( exec
, attr
, newSize
);
363 else if (newSize
< exec
->vtx
.active_sz
[attr
]) {
364 static const GLfloat id
[4] = { 0, 0, 0, 1 };
367 /* New size is smaller - just need to fill in some
368 * zeros. Don't need to flush or wrap.
370 for (i
= newSize
; i
<= exec
->vtx
.attrsz
[attr
]; i
++)
371 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
374 exec
->vtx
.active_sz
[attr
] = newSize
;
376 /* Does setting NeedFlush belong here? Necessitates resetting
377 * vtxfmt on each flush (otherwise flags won't get reset
381 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
386 * This macro is used to implement all the glVertex, glColor, glTexCoord,
387 * glVertexAttrib, etc functions.
389 #define ATTR( A, N, V0, V1, V2, V3 ) \
391 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
393 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
394 ctx->Driver.BeginVertices( ctx ); \
396 if (unlikely(exec->vtx.active_sz[A] != N)) \
397 vbo_exec_fixup_vertex(ctx, A, N); \
400 GLfloat *dest = exec->vtx.attrptr[A]; \
401 if (N>0) dest[0] = V0; \
402 if (N>1) dest[1] = V1; \
403 if (N>2) dest[2] = V2; \
404 if (N>3) dest[3] = V3; \
408 /* This is a glVertex call */ \
411 for (i = 0; i < exec->vtx.vertex_size; i++) \
412 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
414 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
416 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
417 /* something to draw (not just updating a color or texcoord).*/ \
418 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
420 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
421 vbo_exec_vtx_wrap( exec ); \
426 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
427 #define TAG(x) vbo_##x
429 #include "vbo_attrib_tmp.h"
435 #if FEATURE_evaluators
437 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
439 GET_CURRENT_CONTEXT( ctx
);
440 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
444 if (exec
->eval
.recalculate_maps
)
445 vbo_exec_eval_update( exec
);
447 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
448 if (exec
->eval
.map1
[i
].map
)
449 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
450 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
455 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
456 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
458 vbo_exec_do_EvalCoord1f( exec
, u
);
460 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
461 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
464 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
466 GET_CURRENT_CONTEXT( ctx
);
467 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
471 if (exec
->eval
.recalculate_maps
)
472 vbo_exec_eval_update( exec
);
474 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
475 if (exec
->eval
.map2
[i
].map
)
476 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
477 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
480 if (ctx
->Eval
.AutoNormal
)
481 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
482 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
485 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
486 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
488 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
490 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
491 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
494 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
496 vbo_exec_EvalCoord1f( u
[0] );
499 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
501 vbo_exec_EvalCoord2f( u
[0], u
[1] );
504 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
506 GET_CURRENT_CONTEXT( ctx
);
507 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
508 (GLfloat
) ctx
->Eval
.MapGrid1un
);
509 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
511 vbo_exec_EvalCoord1f( u
);
515 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
517 GET_CURRENT_CONTEXT( ctx
);
518 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
519 (GLfloat
) ctx
->Eval
.MapGrid2un
);
520 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
521 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
522 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
523 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
525 vbo_exec_EvalCoord2f( u
, v
);
528 /* use noop eval mesh */
529 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
530 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
532 #endif /* FEATURE_evaluators */
536 * Called via glBegin.
538 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
540 GET_CURRENT_CONTEXT( ctx
);
542 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
543 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
547 _mesa_update_state( ctx
);
549 CALL_Begin(ctx
->Exec
, (mode
));
553 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
557 /* Heuristic: attempt to isolate attributes occuring outside
560 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
561 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
563 i
= exec
->vtx
.prim_count
++;
564 exec
->vtx
.prim
[i
].mode
= mode
;
565 exec
->vtx
.prim
[i
].begin
= 1;
566 exec
->vtx
.prim
[i
].end
= 0;
567 exec
->vtx
.prim
[i
].indexed
= 0;
568 exec
->vtx
.prim
[i
].weak
= 0;
569 exec
->vtx
.prim
[i
].pad
= 0;
570 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
571 exec
->vtx
.prim
[i
].count
= 0;
572 exec
->vtx
.prim
[i
].num_instances
= 1;
574 ctx
->Driver
.CurrentExecPrimitive
= mode
;
577 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
585 static void GLAPIENTRY
vbo_exec_End( void )
587 GET_CURRENT_CONTEXT( ctx
);
589 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
590 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
591 int idx
= exec
->vtx
.vert_count
;
592 int i
= exec
->vtx
.prim_count
- 1;
594 exec
->vtx
.prim
[i
].end
= 1;
595 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
597 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
599 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
600 vbo_exec_vtx_flush( exec
, GL_FALSE
);
603 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
608 * Called via glPrimitiveRestartNV()
610 static void GLAPIENTRY
611 vbo_exec_PrimitiveRestartNV(void)
614 GET_CURRENT_CONTEXT( ctx
);
616 curPrim
= ctx
->Driver
.CurrentExecPrimitive
;
618 if (curPrim
== PRIM_OUTSIDE_BEGIN_END
) {
619 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glPrimitiveRestartNV" );
623 vbo_exec_Begin(curPrim
);
629 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
631 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
633 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
635 vfmt
->Begin
= vbo_exec_Begin
;
636 vfmt
->End
= vbo_exec_End
;
637 vfmt
->PrimitiveRestartNV
= vbo_exec_PrimitiveRestartNV
;
639 _MESA_INIT_DLIST_VTXFMT(vfmt
, _mesa_
);
640 _MESA_INIT_EVAL_VTXFMT(vfmt
, vbo_exec_
);
642 vfmt
->Rectf
= _mesa_noop_Rectf
;
644 /* from attrib_tmp.h:
646 vfmt
->Color3f
= vbo_Color3f
;
647 vfmt
->Color3fv
= vbo_Color3fv
;
648 vfmt
->Color4f
= vbo_Color4f
;
649 vfmt
->Color4fv
= vbo_Color4fv
;
650 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
651 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
652 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
653 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
654 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
655 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
656 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
657 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
658 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
659 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
660 vfmt
->Normal3f
= vbo_Normal3f
;
661 vfmt
->Normal3fv
= vbo_Normal3fv
;
662 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
663 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
664 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
665 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
666 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
667 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
668 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
669 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
670 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
671 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
672 vfmt
->Vertex2f
= vbo_Vertex2f
;
673 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
674 vfmt
->Vertex3f
= vbo_Vertex3f
;
675 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
676 vfmt
->Vertex4f
= vbo_Vertex4f
;
677 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
679 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
680 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
681 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
682 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
683 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
684 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
685 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
686 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
688 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
689 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
690 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
691 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
692 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
693 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
694 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
695 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
698 vfmt
->VertexAttribI1i
= vbo_VertexAttribI1i
;
699 vfmt
->VertexAttribI2i
= vbo_VertexAttribI2i
;
700 vfmt
->VertexAttribI3i
= vbo_VertexAttribI3i
;
701 vfmt
->VertexAttribI4i
= vbo_VertexAttribI4i
;
702 vfmt
->VertexAttribI2iv
= vbo_VertexAttribI2iv
;
703 vfmt
->VertexAttribI3iv
= vbo_VertexAttribI3iv
;
704 vfmt
->VertexAttribI4iv
= vbo_VertexAttribI4iv
;
706 /* unsigned integer-valued */
707 vfmt
->VertexAttribI1ui
= vbo_VertexAttribI1ui
;
708 vfmt
->VertexAttribI2ui
= vbo_VertexAttribI2ui
;
709 vfmt
->VertexAttribI3ui
= vbo_VertexAttribI3ui
;
710 vfmt
->VertexAttribI4ui
= vbo_VertexAttribI4ui
;
711 vfmt
->VertexAttribI2uiv
= vbo_VertexAttribI2uiv
;
712 vfmt
->VertexAttribI3uiv
= vbo_VertexAttribI3uiv
;
713 vfmt
->VertexAttribI4uiv
= vbo_VertexAttribI4uiv
;
715 vfmt
->Materialfv
= vbo_Materialfv
;
717 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
718 vfmt
->Indexf
= vbo_Indexf
;
719 vfmt
->Indexfv
= vbo_Indexfv
;
724 #else /* FEATURE_beginend */
727 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
729 /* silence warnings */
734 (void) vbo_FogCoordfEXT
;
735 (void) vbo_FogCoordfvEXT
;
736 (void) vbo_MultiTexCoord1f
;
737 (void) vbo_MultiTexCoord1fv
;
738 (void) vbo_MultiTexCoord2f
;
739 (void) vbo_MultiTexCoord2fv
;
740 (void) vbo_MultiTexCoord3f
;
741 (void) vbo_MultiTexCoord3fv
;
742 (void) vbo_MultiTexCoord4f
;
743 (void) vbo_MultiTexCoord4fv
;
745 (void) vbo_Normal3fv
;
746 (void) vbo_SecondaryColor3fEXT
;
747 (void) vbo_SecondaryColor3fvEXT
;
748 (void) vbo_TexCoord1f
;
749 (void) vbo_TexCoord1fv
;
750 (void) vbo_TexCoord2f
;
751 (void) vbo_TexCoord2fv
;
752 (void) vbo_TexCoord3f
;
753 (void) vbo_TexCoord3fv
;
754 (void) vbo_TexCoord4f
;
755 (void) vbo_TexCoord4fv
;
757 (void) vbo_Vertex2fv
;
759 (void) vbo_Vertex3fv
;
761 (void) vbo_Vertex4fv
;
763 (void) vbo_VertexAttrib1fARB
;
764 (void) vbo_VertexAttrib1fvARB
;
765 (void) vbo_VertexAttrib2fARB
;
766 (void) vbo_VertexAttrib2fvARB
;
767 (void) vbo_VertexAttrib3fARB
;
768 (void) vbo_VertexAttrib3fvARB
;
769 (void) vbo_VertexAttrib4fARB
;
770 (void) vbo_VertexAttrib4fvARB
;
772 (void) vbo_VertexAttrib1fNV
;
773 (void) vbo_VertexAttrib1fvNV
;
774 (void) vbo_VertexAttrib2fNV
;
775 (void) vbo_VertexAttrib2fvNV
;
776 (void) vbo_VertexAttrib3fNV
;
777 (void) vbo_VertexAttrib3fvNV
;
778 (void) vbo_VertexAttrib4fNV
;
779 (void) vbo_VertexAttrib4fvNV
;
781 (void) vbo_Materialfv
;
789 #endif /* FEATURE_beginend */
793 * Tell the VBO module to use a real OpenGL vertex buffer object to
794 * store accumulated immediate-mode vertex data.
795 * This replaces the malloced buffer which was created in
796 * vb_exec_vtx_init() below.
798 void vbo_use_buffer_objects(struct gl_context
*ctx
)
800 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
801 /* Any buffer name but 0 can be used here since this bufferobj won't
802 * go into the bufferobj hashtable.
804 GLuint bufName
= IMM_BUFFER_NAME
;
805 GLenum target
= GL_ARRAY_BUFFER_ARB
;
806 GLenum usage
= GL_STREAM_DRAW_ARB
;
807 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
809 /* Make sure this func is only used once */
810 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
811 if (exec
->vtx
.buffer_map
) {
812 _mesa_align_free(exec
->vtx
.buffer_map
);
813 exec
->vtx
.buffer_map
= NULL
;
814 exec
->vtx
.buffer_ptr
= NULL
;
817 /* Allocate a real buffer object now */
818 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
819 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
820 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
825 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
827 struct gl_context
*ctx
= exec
->ctx
;
828 struct vbo_context
*vbo
= vbo_context(ctx
);
831 /* Allocate a buffer object. Will just reuse this object
832 * continuously, unless vbo_use_buffer_objects() is called to enable
835 _mesa_reference_buffer_object(ctx
,
836 &exec
->vtx
.bufferobj
,
837 ctx
->Shared
->NullBufferObj
);
839 ASSERT(!exec
->vtx
.buffer_map
);
840 exec
->vtx
.buffer_map
= (GLfloat
*)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE
, 64);
841 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
843 vbo_exec_vtxfmt_init( exec
);
845 /* Hook our functions into the dispatch table.
847 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
849 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
850 ASSERT(i
< Elements(exec
->vtx
.attrsz
));
851 exec
->vtx
.attrsz
[i
] = 0;
852 ASSERT(i
< Elements(exec
->vtx
.active_sz
));
853 exec
->vtx
.active_sz
[i
] = 0;
855 for (i
= 0 ; i
< VERT_ATTRIB_MAX
; i
++) {
856 ASSERT(i
< Elements(exec
->vtx
.inputs
));
857 ASSERT(i
< Elements(exec
->vtx
.arrays
));
858 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
862 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
865 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
866 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
868 for (i
= 0; i
< 16; ++i
) {
869 arrays
[i
].BufferObj
= NULL
;
870 arrays
[i
+ 16].BufferObj
= NULL
;
871 _mesa_reference_buffer_object(ctx
, &arrays
[i
].BufferObj
,
872 vbo
->legacy_currval
[i
].BufferObj
);
873 _mesa_reference_buffer_object(ctx
, &arrays
[i
+ 16].BufferObj
,
874 vbo
->generic_currval
[i
].BufferObj
);
878 exec
->vtx
.vertex_size
= 0;
882 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
884 /* using a real VBO for vertex data */
885 struct gl_context
*ctx
= exec
->ctx
;
888 /* True VBOs should already be unmapped
890 if (exec
->vtx
.buffer_map
) {
891 ASSERT(exec
->vtx
.bufferobj
->Name
== 0 ||
892 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
893 if (exec
->vtx
.bufferobj
->Name
== 0) {
894 _mesa_align_free(exec
->vtx
.buffer_map
);
895 exec
->vtx
.buffer_map
= NULL
;
896 exec
->vtx
.buffer_ptr
= NULL
;
900 /* Drop any outstanding reference to the vertex buffer
902 for (i
= 0; i
< Elements(exec
->vtx
.arrays
); i
++) {
903 _mesa_reference_buffer_object(ctx
,
904 &exec
->vtx
.arrays
[i
].BufferObj
,
908 /* Free the vertex buffer. Unmap first if needed.
910 if (_mesa_bufferobj_mapped(exec
->vtx
.bufferobj
)) {
911 ctx
->Driver
.UnmapBuffer(ctx
, GL_ARRAY_BUFFER
, exec
->vtx
.bufferobj
);
913 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
917 void vbo_exec_BeginVertices( struct gl_context
*ctx
)
919 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
921 vbo_exec_vtx_map( exec
);
923 assert((exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
924 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
929 * Flush (draw) vertices.
930 * \param unmap - leave VBO unmapped after flushing?
932 void vbo_exec_FlushVertices_internal( struct gl_context
*ctx
, GLboolean unmap
)
934 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
936 if (exec
->vtx
.vert_count
|| unmap
) {
937 vbo_exec_vtx_flush( exec
, unmap
);
940 if (exec
->vtx
.vertex_size
) {
941 vbo_exec_copy_to_current( exec
);
942 reset_attrfv( exec
);
948 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
950 void vbo_exec_FlushVertices( struct gl_context
*ctx
, GLuint flags
)
952 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
955 /* debug check: make sure we don't get called recursively */
956 exec
->flush_call_depth
++;
957 assert(exec
->flush_call_depth
== 1);
960 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
962 exec
->flush_call_depth
--;
963 assert(exec
->flush_call_depth
== 0);
968 /* Flush (draw), and make sure VBO is left unmapped when done */
969 vbo_exec_FlushVertices_internal( ctx
, GL_TRUE
);
971 /* Need to do this to ensure BeginVertices gets called again:
973 if (exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
)
974 exec
->ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
976 exec
->ctx
->Driver
.NeedFlush
&= ~flags
;
979 exec
->flush_call_depth
--;
980 assert(exec
->flush_call_depth
== 0);
985 static void reset_attrfv( struct vbo_exec_context
*exec
)
989 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
990 exec
->vtx
.attrsz
[i
] = 0;
991 exec
->vtx
.active_sz
[i
] = 0;
994 exec
->vtx
.vertex_size
= 0;
999 _es_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
1001 vbo_Color4f(r
, g
, b
, a
);
1006 _es_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
1008 vbo_Normal3f(x
, y
, z
);
1013 _es_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
1015 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
1020 _es_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
1022 vbo_Materialfv(face
, pname
, params
);
1027 _es_Materialf(GLenum face
, GLenum pname
, GLfloat param
)
1031 p
[1] = p
[2] = p
[3] = 0.0F
;
1032 vbo_Materialfv(face
, pname
, p
);
1037 * A special version of glVertexAttrib4f that does not treat index 0 as
1041 VertexAttrib4f_nopos(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1043 GET_CURRENT_CONTEXT(ctx
);
1044 if (index
< MAX_VERTEX_GENERIC_ATTRIBS
)
1045 ATTR(VBO_ATTRIB_GENERIC0
+ index
, 4, x
, y
, z
, w
);
1051 _es_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1053 VertexAttrib4f_nopos(index
, x
, y
, z
, w
);
1058 _es_VertexAttrib1f(GLuint indx
, GLfloat x
)
1060 VertexAttrib4f_nopos(indx
, x
, 0.0f
, 0.0f
, 1.0f
);
1065 _es_VertexAttrib1fv(GLuint indx
, const GLfloat
* values
)
1067 VertexAttrib4f_nopos(indx
, values
[0], 0.0f
, 0.0f
, 1.0f
);
1072 _es_VertexAttrib2f(GLuint indx
, GLfloat x
, GLfloat y
)
1074 VertexAttrib4f_nopos(indx
, x
, y
, 0.0f
, 1.0f
);
1079 _es_VertexAttrib2fv(GLuint indx
, const GLfloat
* values
)
1081 VertexAttrib4f_nopos(indx
, values
[0], values
[1], 0.0f
, 1.0f
);
1086 _es_VertexAttrib3f(GLuint indx
, GLfloat x
, GLfloat y
, GLfloat z
)
1088 VertexAttrib4f_nopos(indx
, x
, y
, z
, 1.0f
);
1093 _es_VertexAttrib3fv(GLuint indx
, const GLfloat
* values
)
1095 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], 1.0f
);
1100 _es_VertexAttrib4fv(GLuint indx
, const GLfloat
* values
)
1102 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], values
[3]);