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/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_noop.h"
44 #include "main/dispatch.h"
46 #include "vbo_context.h"
53 /** ID/name for immediate-mode VBO */
54 #define IMM_BUFFER_NAME 0xaabbccdd
57 static void reset_attrfv( struct vbo_exec_context
*exec
);
61 * Close off the last primitive, execute the buffer, restart the
64 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
66 if (exec
->vtx
.prim_count
== 0) {
67 exec
->vtx
.copied
.nr
= 0;
68 exec
->vtx
.vert_count
= 0;
69 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
72 GLuint last_begin
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].begin
;
75 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
76 GLint i
= exec
->vtx
.prim_count
- 1;
78 exec
->vtx
.prim
[i
].count
= (exec
->vtx
.vert_count
-
79 exec
->vtx
.prim
[i
].start
);
82 last_count
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].count
;
84 /* Execute the buffer and save copied vertices.
86 if (exec
->vtx
.vert_count
)
87 vbo_exec_vtx_flush( exec
, GL_FALSE
);
89 exec
->vtx
.prim_count
= 0;
90 exec
->vtx
.copied
.nr
= 0;
93 /* Emit a glBegin to start the new list.
95 assert(exec
->vtx
.prim_count
== 0);
97 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
98 exec
->vtx
.prim
[0].mode
= exec
->ctx
->Driver
.CurrentExecPrimitive
;
99 exec
->vtx
.prim
[0].start
= 0;
100 exec
->vtx
.prim
[0].count
= 0;
101 exec
->vtx
.prim_count
++;
103 if (exec
->vtx
.copied
.nr
== last_count
)
104 exec
->vtx
.prim
[0].begin
= last_begin
;
111 * Deal with buffer wrapping where provoked by the vertex buffer
112 * filling up, as opposed to upgrade_vertex().
114 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
116 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
119 /* Run pipeline on current vertices, copy wrapped vertices
120 * to exec->vtx.copied.
122 vbo_exec_wrap_buffers( exec
);
124 /* Copy stored stored vertices to start of new list.
126 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
128 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
129 memcpy( exec
->vtx
.buffer_ptr
, data
,
130 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
131 exec
->vtx
.buffer_ptr
+= exec
->vtx
.vertex_size
;
132 data
+= exec
->vtx
.vertex_size
;
133 exec
->vtx
.vert_count
++;
136 exec
->vtx
.copied
.nr
= 0;
141 * Copy the active vertex's values to the ctx->Current fields.
143 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
145 GLcontext
*ctx
= exec
->ctx
;
146 struct vbo_context
*vbo
= vbo_context(ctx
);
149 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
150 if (exec
->vtx
.attrsz
[i
]) {
151 /* Note: the exec->vtx.current[i] pointers point into the
152 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
154 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
159 exec
->vtx
.attrptr
[i
]);
161 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
]);
194 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
196 GLcontext
*ctx
= exec
->ctx
;
197 struct vbo_context
*vbo
= vbo_context(ctx
);
200 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
201 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
202 switch (exec
->vtx
.attrsz
[i
]) {
203 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
204 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
205 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
206 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
214 * Flush existing data, set new attrib size, replay copied vertices.
216 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
220 GLcontext
*ctx
= exec
->ctx
;
221 struct vbo_context
*vbo
= vbo_context(ctx
);
222 GLint lastcount
= exec
->vtx
.vert_count
;
227 /* Run pipeline on current vertices, copy wrapped vertices
228 * to exec->vtx.copied.
230 vbo_exec_wrap_buffers( exec
);
233 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
234 * when the attribute already exists in the vertex and is having
235 * its size increased.
237 vbo_exec_copy_to_current( exec
);
240 /* Heuristic: Attempt to isolate attributes received outside
241 * begin/end so that they don't bloat the vertices.
243 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
244 exec
->vtx
.attrsz
[attr
] == 0 &&
246 exec
->vtx
.vertex_size
) {
247 reset_attrfv( exec
);
252 oldsz
= exec
->vtx
.attrsz
[attr
];
253 exec
->vtx
.attrsz
[attr
] = newsz
;
255 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
256 exec
->vtx
.max_vert
= ((VBO_VERT_BUFFER_SIZE
- exec
->vtx
.buffer_used
) /
257 (exec
->vtx
.vertex_size
* sizeof(GLfloat
)));
258 exec
->vtx
.vert_count
= 0;
259 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
262 /* Recalculate all the attrptr[] values
264 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
265 if (exec
->vtx
.attrsz
[i
]) {
266 exec
->vtx
.attrptr
[i
] = tmp
;
267 tmp
+= exec
->vtx
.attrsz
[i
];
270 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
273 /* Copy from current to repopulate the vertex with correct values.
275 vbo_exec_copy_from_current( exec
);
277 /* Replay stored vertices to translate them
278 * to new format here.
280 * -- No need to replay - just copy piecewise
282 if (exec
->vtx
.copied
.nr
)
284 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
285 GLfloat
*dest
= exec
->vtx
.buffer_ptr
;
288 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
290 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
291 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
292 if (exec
->vtx
.attrsz
[j
]) {
295 COPY_CLEAN_4V( dest
, oldsz
, data
);
299 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
300 COPY_SZ_4V( dest
, newsz
, current
);
305 GLuint sz
= exec
->vtx
.attrsz
[j
];
306 COPY_SZ_4V( dest
, sz
, data
);
314 exec
->vtx
.buffer_ptr
= dest
;
315 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
316 exec
->vtx
.copied
.nr
= 0;
321 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
322 GLuint attr
, GLuint sz
)
324 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
327 if (sz
> exec
->vtx
.attrsz
[attr
]) {
328 /* New size is larger. Need to flush existing vertices and get
329 * an enlarged vertex format.
331 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
333 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
334 static const GLfloat id
[4] = { 0, 0, 0, 1 };
336 /* New size is smaller - just need to fill in some
337 * zeros. Don't need to flush or wrap.
339 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
340 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
343 exec
->vtx
.active_sz
[attr
] = sz
;
345 /* Does setting NeedFlush belong here? Necessitates resetting
346 * vtxfmt on each flush (otherwise flags won't get reset
350 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
358 #define ATTR( A, N, V0, V1, V2, V3 ) \
360 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
362 if (exec->vtx.active_sz[A] != N) \
363 vbo_exec_fixup_vertex(ctx, A, N); \
366 GLfloat *dest = exec->vtx.attrptr[A]; \
367 if (N>0) dest[0] = V0; \
368 if (N>1) dest[1] = V1; \
369 if (N>2) dest[2] = V2; \
370 if (N>3) dest[3] = V3; \
376 for (i = 0; i < exec->vtx.vertex_size; i++) \
377 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
379 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
380 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
382 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
383 vbo_exec_vtx_wrap( exec ); \
388 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
389 #define TAG(x) vbo_##x
391 #include "vbo_attrib_tmp.h"
397 #if FEATURE_evaluators
399 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
401 GET_CURRENT_CONTEXT( ctx
);
402 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
406 if (exec
->eval
.recalculate_maps
)
407 vbo_exec_eval_update( exec
);
409 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
410 if (exec
->eval
.map1
[i
].map
)
411 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
412 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
417 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
418 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
420 vbo_exec_do_EvalCoord1f( exec
, u
);
422 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
423 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
426 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
428 GET_CURRENT_CONTEXT( ctx
);
429 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
433 if (exec
->eval
.recalculate_maps
)
434 vbo_exec_eval_update( exec
);
436 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
437 if (exec
->eval
.map2
[i
].map
)
438 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
439 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
442 if (ctx
->Eval
.AutoNormal
)
443 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
444 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
447 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
448 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
450 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
452 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
453 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
456 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
458 vbo_exec_EvalCoord1f( u
[0] );
461 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
463 vbo_exec_EvalCoord2f( u
[0], u
[1] );
466 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
468 GET_CURRENT_CONTEXT( ctx
);
469 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
470 (GLfloat
) ctx
->Eval
.MapGrid1un
);
471 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
473 vbo_exec_EvalCoord1f( u
);
477 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
479 GET_CURRENT_CONTEXT( ctx
);
480 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
481 (GLfloat
) ctx
->Eval
.MapGrid2un
);
482 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
483 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
484 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
485 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
487 vbo_exec_EvalCoord2f( u
, v
);
490 /* use noop eval mesh */
491 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
492 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
494 #endif /* FEATURE_evaluators */
498 * Called via glBegin.
500 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
502 GET_CURRENT_CONTEXT( ctx
);
504 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
505 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
509 _mesa_update_state( ctx
);
511 CALL_Begin(ctx
->Exec
, (mode
));
515 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
519 /* Heuristic: attempt to isolate attributes occuring outside
522 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
523 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
525 i
= exec
->vtx
.prim_count
++;
526 exec
->vtx
.prim
[i
].mode
= mode
;
527 exec
->vtx
.prim
[i
].begin
= 1;
528 exec
->vtx
.prim
[i
].end
= 0;
529 exec
->vtx
.prim
[i
].indexed
= 0;
530 exec
->vtx
.prim
[i
].weak
= 0;
531 exec
->vtx
.prim
[i
].pad
= 0;
532 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
533 exec
->vtx
.prim
[i
].count
= 0;
534 exec
->vtx
.prim
[i
].num_instances
= 1;
536 ctx
->Driver
.CurrentExecPrimitive
= mode
;
539 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
547 static void GLAPIENTRY
vbo_exec_End( void )
549 GET_CURRENT_CONTEXT( ctx
);
551 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
552 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
553 int idx
= exec
->vtx
.vert_count
;
554 int i
= exec
->vtx
.prim_count
- 1;
556 exec
->vtx
.prim
[i
].end
= 1;
557 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
559 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
561 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
562 vbo_exec_vtx_flush( exec
, GL_FALSE
);
565 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
569 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
571 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
573 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
575 vfmt
->Begin
= vbo_exec_Begin
;
576 vfmt
->End
= vbo_exec_End
;
578 _MESA_INIT_DLIST_VTXFMT(vfmt
, _mesa_
);
579 _MESA_INIT_EVAL_VTXFMT(vfmt
, vbo_exec_
);
581 vfmt
->Rectf
= _mesa_noop_Rectf
;
583 /* from attrib_tmp.h:
585 vfmt
->Color3f
= vbo_Color3f
;
586 vfmt
->Color3fv
= vbo_Color3fv
;
587 vfmt
->Color4f
= vbo_Color4f
;
588 vfmt
->Color4fv
= vbo_Color4fv
;
589 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
590 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
591 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
592 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
593 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
594 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
595 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
596 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
597 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
598 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
599 vfmt
->Normal3f
= vbo_Normal3f
;
600 vfmt
->Normal3fv
= vbo_Normal3fv
;
601 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
602 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
603 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
604 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
605 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
606 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
607 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
608 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
609 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
610 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
611 vfmt
->Vertex2f
= vbo_Vertex2f
;
612 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
613 vfmt
->Vertex3f
= vbo_Vertex3f
;
614 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
615 vfmt
->Vertex4f
= vbo_Vertex4f
;
616 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
618 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
619 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
620 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
621 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
622 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
623 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
624 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
625 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
627 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
628 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
629 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
630 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
631 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
632 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
633 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
634 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
636 vfmt
->Materialfv
= vbo_Materialfv
;
638 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
639 vfmt
->Indexf
= vbo_Indexf
;
640 vfmt
->Indexfv
= vbo_Indexfv
;
645 #else /* FEATURE_beginend */
648 #define ATTR( A, N, V0, V1, V2, V3 ) \
650 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
652 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
653 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
655 if (exec->vtx.active_sz[A] != N) \
656 vbo_exec_fixup_vertex(ctx, A, N); \
659 GLfloat *dest = exec->vtx.attrptr[A]; \
660 if (N>0) dest[0] = V0; \
661 if (N>1) dest[1] = V1; \
662 if (N>2) dest[2] = V2; \
663 if (N>3) dest[3] = V3; \
667 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
668 #define TAG(x) vbo_##x
670 #include "vbo_attrib_tmp.h"
672 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
674 /* silence warnings */
679 (void) vbo_FogCoordfEXT
;
680 (void) vbo_FogCoordfvEXT
;
681 (void) vbo_MultiTexCoord1f
;
682 (void) vbo_MultiTexCoord1fv
;
683 (void) vbo_MultiTexCoord2f
;
684 (void) vbo_MultiTexCoord2fv
;
685 (void) vbo_MultiTexCoord3f
;
686 (void) vbo_MultiTexCoord3fv
;
687 (void) vbo_MultiTexCoord4f
;
688 (void) vbo_MultiTexCoord4fv
;
690 (void) vbo_Normal3fv
;
691 (void) vbo_SecondaryColor3fEXT
;
692 (void) vbo_SecondaryColor3fvEXT
;
693 (void) vbo_TexCoord1f
;
694 (void) vbo_TexCoord1fv
;
695 (void) vbo_TexCoord2f
;
696 (void) vbo_TexCoord2fv
;
697 (void) vbo_TexCoord3f
;
698 (void) vbo_TexCoord3fv
;
699 (void) vbo_TexCoord4f
;
700 (void) vbo_TexCoord4fv
;
702 (void) vbo_Vertex2fv
;
704 (void) vbo_Vertex3fv
;
706 (void) vbo_Vertex4fv
;
708 (void) vbo_VertexAttrib1fARB
;
709 (void) vbo_VertexAttrib1fvARB
;
710 (void) vbo_VertexAttrib2fARB
;
711 (void) vbo_VertexAttrib2fvARB
;
712 (void) vbo_VertexAttrib3fARB
;
713 (void) vbo_VertexAttrib3fvARB
;
714 (void) vbo_VertexAttrib4fARB
;
715 (void) vbo_VertexAttrib4fvARB
;
717 (void) vbo_VertexAttrib1fNV
;
718 (void) vbo_VertexAttrib1fvNV
;
719 (void) vbo_VertexAttrib2fNV
;
720 (void) vbo_VertexAttrib2fvNV
;
721 (void) vbo_VertexAttrib3fNV
;
722 (void) vbo_VertexAttrib3fvNV
;
723 (void) vbo_VertexAttrib4fNV
;
724 (void) vbo_VertexAttrib4fvNV
;
726 (void) vbo_Materialfv
;
734 #endif /* FEATURE_beginend */
738 * Tell the VBO module to use a real OpenGL vertex buffer object to
739 * store accumulated immediate-mode vertex data.
740 * This replaces the malloced buffer which was created in
741 * vb_exec_vtx_init() below.
743 void vbo_use_buffer_objects(GLcontext
*ctx
)
745 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
746 /* Any buffer name but 0 can be used here since this bufferobj won't
747 * go into the bufferobj hashtable.
749 GLuint bufName
= IMM_BUFFER_NAME
;
750 GLenum target
= GL_ARRAY_BUFFER_ARB
;
751 GLenum usage
= GL_STREAM_DRAW_ARB
;
752 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
754 /* Make sure this func is only used once */
755 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
756 if (exec
->vtx
.buffer_map
) {
757 _mesa_align_free(exec
->vtx
.buffer_map
);
758 exec
->vtx
.buffer_map
= NULL
;
759 exec
->vtx
.buffer_ptr
= NULL
;
762 /* Allocate a real buffer object now */
763 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
764 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
765 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
770 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
772 GLcontext
*ctx
= exec
->ctx
;
773 struct vbo_context
*vbo
= vbo_context(ctx
);
776 /* Allocate a buffer object. Will just reuse this object
777 * continuously, unless vbo_use_buffer_objects() is called to enable
780 _mesa_reference_buffer_object(ctx
,
781 &exec
->vtx
.bufferobj
,
782 ctx
->Shared
->NullBufferObj
);
784 ASSERT(!exec
->vtx
.buffer_map
);
785 exec
->vtx
.buffer_map
= (GLfloat
*)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE
, 64);
786 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
788 vbo_exec_vtxfmt_init( exec
);
790 /* Hook our functions into the dispatch table.
792 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
794 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
795 ASSERT(i
< Elements(exec
->vtx
.attrsz
));
796 exec
->vtx
.attrsz
[i
] = 0;
797 ASSERT(i
< Elements(exec
->vtx
.active_sz
));
798 exec
->vtx
.active_sz
[i
] = 0;
800 for (i
= 0 ; i
< VERT_ATTRIB_MAX
; i
++) {
801 ASSERT(i
< Elements(exec
->vtx
.inputs
));
802 ASSERT(i
< Elements(exec
->vtx
.arrays
));
803 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
807 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
810 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
811 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
813 for (i
= 0; i
< 16; ++i
) {
814 arrays
[i
].BufferObj
= NULL
;
815 arrays
[i
+ 16].BufferObj
= NULL
;
816 _mesa_reference_buffer_object(ctx
, &arrays
[i
].BufferObj
,
817 vbo
->legacy_currval
[i
].BufferObj
);
818 _mesa_reference_buffer_object(ctx
, &arrays
[i
+ 16].BufferObj
,
819 vbo
->generic_currval
[i
].BufferObj
);
823 exec
->vtx
.vertex_size
= 0;
827 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
829 /* using a real VBO for vertex data */
830 GLcontext
*ctx
= exec
->ctx
;
833 /* True VBOs should already be unmapped
835 if (exec
->vtx
.buffer_map
) {
836 ASSERT(exec
->vtx
.bufferobj
->Name
== 0 ||
837 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
838 if (exec
->vtx
.bufferobj
->Name
== 0) {
839 _mesa_align_free(exec
->vtx
.buffer_map
);
840 exec
->vtx
.buffer_map
= NULL
;
841 exec
->vtx
.buffer_ptr
= NULL
;
845 /* Drop any outstanding reference to the vertex buffer
847 for (i
= 0; i
< Elements(exec
->vtx
.arrays
); i
++) {
848 _mesa_reference_buffer_object(ctx
,
849 &exec
->vtx
.arrays
[i
].BufferObj
,
853 /* Free the vertex buffer. Unmap first if needed.
855 if (_mesa_bufferobj_mapped(exec
->vtx
.bufferobj
)) {
856 ctx
->Driver
.UnmapBuffer(ctx
, GL_ARRAY_BUFFER
, exec
->vtx
.bufferobj
);
858 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
861 void vbo_exec_BeginVertices( GLcontext
*ctx
)
863 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
864 if (0) printf("%s\n", __FUNCTION__
);
865 vbo_exec_vtx_map( exec
);
867 assert((exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
868 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
871 void vbo_exec_FlushVertices_internal( GLcontext
*ctx
, GLboolean unmap
)
873 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
875 if (exec
->vtx
.vert_count
|| unmap
) {
876 vbo_exec_vtx_flush( exec
, unmap
);
879 if (exec
->vtx
.vertex_size
) {
880 vbo_exec_copy_to_current( exec
);
881 reset_attrfv( exec
);
887 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
889 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
891 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
894 /* debug check: make sure we don't get called recursively */
895 exec
->flush_call_depth
++;
896 assert(exec
->flush_call_depth
== 1);
899 if (0) printf("%s\n", __FUNCTION__
);
901 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
902 if (0) printf("%s - inside begin/end\n", __FUNCTION__
);
904 exec
->flush_call_depth
--;
905 assert(exec
->flush_call_depth
== 0);
910 vbo_exec_FlushVertices_internal( ctx
, GL_TRUE
);
912 /* Need to do this to ensure BeginVertices gets called again:
914 if (exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) {
915 _mesa_restore_exec_vtxfmt( ctx
);
916 exec
->ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
919 exec
->ctx
->Driver
.NeedFlush
&= ~flags
;
922 exec
->flush_call_depth
--;
923 assert(exec
->flush_call_depth
== 0);
928 static void reset_attrfv( struct vbo_exec_context
*exec
)
932 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
933 exec
->vtx
.attrsz
[i
] = 0;
934 exec
->vtx
.active_sz
[i
] = 0;
937 exec
->vtx
.vertex_size
= 0;
942 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
944 vbo_Color4f(r
, g
, b
, a
);
949 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
951 vbo_Normal3f(x
, y
, z
);
956 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
958 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
962 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
964 vbo_Materialfv(face
, pname
, params
);
969 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
971 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);