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 struct gl_context
*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 struct gl_context
*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 struct gl_context
*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( struct gl_context
*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 (unlikely(!(exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
363 ctx->Driver.BeginVertices( ctx ); \
364 if (unlikely(exec->vtx.active_sz[A] != N)) \
365 vbo_exec_fixup_vertex(ctx, A, N); \
368 GLfloat *dest = exec->vtx.attrptr[A]; \
369 if (N>0) dest[0] = V0; \
370 if (N>1) dest[1] = V1; \
371 if (N>2) dest[2] = V2; \
372 if (N>3) dest[3] = V3; \
378 for (i = 0; i < exec->vtx.vertex_size; i++) \
379 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
381 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
382 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
384 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
385 vbo_exec_vtx_wrap( exec ); \
390 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
391 #define TAG(x) vbo_##x
393 #include "vbo_attrib_tmp.h"
399 #if FEATURE_evaluators
401 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
403 GET_CURRENT_CONTEXT( ctx
);
404 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
408 if (exec
->eval
.recalculate_maps
)
409 vbo_exec_eval_update( exec
);
411 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
412 if (exec
->eval
.map1
[i
].map
)
413 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
414 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
419 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
420 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
422 vbo_exec_do_EvalCoord1f( exec
, u
);
424 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
425 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
428 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
430 GET_CURRENT_CONTEXT( ctx
);
431 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
435 if (exec
->eval
.recalculate_maps
)
436 vbo_exec_eval_update( exec
);
438 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
439 if (exec
->eval
.map2
[i
].map
)
440 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
441 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
444 if (ctx
->Eval
.AutoNormal
)
445 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
446 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
449 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
450 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
452 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
454 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
455 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
458 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
460 vbo_exec_EvalCoord1f( u
[0] );
463 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
465 vbo_exec_EvalCoord2f( u
[0], u
[1] );
468 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
470 GET_CURRENT_CONTEXT( ctx
);
471 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
472 (GLfloat
) ctx
->Eval
.MapGrid1un
);
473 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
475 vbo_exec_EvalCoord1f( u
);
479 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
481 GET_CURRENT_CONTEXT( ctx
);
482 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
483 (GLfloat
) ctx
->Eval
.MapGrid2un
);
484 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
485 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
486 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
487 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
489 vbo_exec_EvalCoord2f( u
, v
);
492 /* use noop eval mesh */
493 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
494 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
496 #endif /* FEATURE_evaluators */
500 * Called via glBegin.
502 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
504 GET_CURRENT_CONTEXT( ctx
);
506 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
507 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
511 _mesa_update_state( ctx
);
513 CALL_Begin(ctx
->Exec
, (mode
));
517 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
521 /* Heuristic: attempt to isolate attributes occuring outside
524 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
525 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
527 i
= exec
->vtx
.prim_count
++;
528 exec
->vtx
.prim
[i
].mode
= mode
;
529 exec
->vtx
.prim
[i
].begin
= 1;
530 exec
->vtx
.prim
[i
].end
= 0;
531 exec
->vtx
.prim
[i
].indexed
= 0;
532 exec
->vtx
.prim
[i
].weak
= 0;
533 exec
->vtx
.prim
[i
].pad
= 0;
534 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
535 exec
->vtx
.prim
[i
].count
= 0;
536 exec
->vtx
.prim
[i
].num_instances
= 1;
538 ctx
->Driver
.CurrentExecPrimitive
= mode
;
541 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
549 static void GLAPIENTRY
vbo_exec_End( void )
551 GET_CURRENT_CONTEXT( ctx
);
553 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
554 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
555 int idx
= exec
->vtx
.vert_count
;
556 int i
= exec
->vtx
.prim_count
- 1;
558 exec
->vtx
.prim
[i
].end
= 1;
559 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
561 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
563 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
564 vbo_exec_vtx_flush( exec
, GL_FALSE
);
567 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
572 * Called via glPrimitiveRestartNV()
574 static void GLAPIENTRY
575 vbo_exec_PrimitiveRestartNV(void)
578 GET_CURRENT_CONTEXT( ctx
);
580 curPrim
= ctx
->Driver
.CurrentExecPrimitive
;
582 if (curPrim
== PRIM_OUTSIDE_BEGIN_END
) {
583 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glPrimitiveRestartNV" );
587 vbo_exec_Begin(curPrim
);
593 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
595 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
597 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
599 vfmt
->Begin
= vbo_exec_Begin
;
600 vfmt
->End
= vbo_exec_End
;
601 vfmt
->PrimitiveRestartNV
= vbo_exec_PrimitiveRestartNV
;
603 _MESA_INIT_DLIST_VTXFMT(vfmt
, _mesa_
);
604 _MESA_INIT_EVAL_VTXFMT(vfmt
, vbo_exec_
);
606 vfmt
->Rectf
= _mesa_noop_Rectf
;
608 /* from attrib_tmp.h:
610 vfmt
->Color3f
= vbo_Color3f
;
611 vfmt
->Color3fv
= vbo_Color3fv
;
612 vfmt
->Color4f
= vbo_Color4f
;
613 vfmt
->Color4fv
= vbo_Color4fv
;
614 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
615 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
616 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
617 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
618 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
619 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
620 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
621 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
622 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
623 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
624 vfmt
->Normal3f
= vbo_Normal3f
;
625 vfmt
->Normal3fv
= vbo_Normal3fv
;
626 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
627 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
628 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
629 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
630 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
631 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
632 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
633 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
634 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
635 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
636 vfmt
->Vertex2f
= vbo_Vertex2f
;
637 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
638 vfmt
->Vertex3f
= vbo_Vertex3f
;
639 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
640 vfmt
->Vertex4f
= vbo_Vertex4f
;
641 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
643 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
644 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
645 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
646 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
647 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
648 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
649 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
650 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
652 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
653 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
654 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
655 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
656 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
657 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
658 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
659 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
661 vfmt
->Materialfv
= vbo_Materialfv
;
663 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
664 vfmt
->Indexf
= vbo_Indexf
;
665 vfmt
->Indexfv
= vbo_Indexfv
;
670 #else /* FEATURE_beginend */
673 #define ATTR( A, N, V0, V1, V2, V3 ) \
675 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
677 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
678 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
680 if (exec->vtx.active_sz[A] != N) \
681 vbo_exec_fixup_vertex(ctx, A, N); \
684 GLfloat *dest = exec->vtx.attrptr[A]; \
685 if (N>0) dest[0] = V0; \
686 if (N>1) dest[1] = V1; \
687 if (N>2) dest[2] = V2; \
688 if (N>3) dest[3] = V3; \
692 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
693 #define TAG(x) vbo_##x
695 #include "vbo_attrib_tmp.h"
697 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
699 /* silence warnings */
704 (void) vbo_FogCoordfEXT
;
705 (void) vbo_FogCoordfvEXT
;
706 (void) vbo_MultiTexCoord1f
;
707 (void) vbo_MultiTexCoord1fv
;
708 (void) vbo_MultiTexCoord2f
;
709 (void) vbo_MultiTexCoord2fv
;
710 (void) vbo_MultiTexCoord3f
;
711 (void) vbo_MultiTexCoord3fv
;
712 (void) vbo_MultiTexCoord4f
;
713 (void) vbo_MultiTexCoord4fv
;
715 (void) vbo_Normal3fv
;
716 (void) vbo_SecondaryColor3fEXT
;
717 (void) vbo_SecondaryColor3fvEXT
;
718 (void) vbo_TexCoord1f
;
719 (void) vbo_TexCoord1fv
;
720 (void) vbo_TexCoord2f
;
721 (void) vbo_TexCoord2fv
;
722 (void) vbo_TexCoord3f
;
723 (void) vbo_TexCoord3fv
;
724 (void) vbo_TexCoord4f
;
725 (void) vbo_TexCoord4fv
;
727 (void) vbo_Vertex2fv
;
729 (void) vbo_Vertex3fv
;
731 (void) vbo_Vertex4fv
;
733 (void) vbo_VertexAttrib1fARB
;
734 (void) vbo_VertexAttrib1fvARB
;
735 (void) vbo_VertexAttrib2fARB
;
736 (void) vbo_VertexAttrib2fvARB
;
737 (void) vbo_VertexAttrib3fARB
;
738 (void) vbo_VertexAttrib3fvARB
;
739 (void) vbo_VertexAttrib4fARB
;
740 (void) vbo_VertexAttrib4fvARB
;
742 (void) vbo_VertexAttrib1fNV
;
743 (void) vbo_VertexAttrib1fvNV
;
744 (void) vbo_VertexAttrib2fNV
;
745 (void) vbo_VertexAttrib2fvNV
;
746 (void) vbo_VertexAttrib3fNV
;
747 (void) vbo_VertexAttrib3fvNV
;
748 (void) vbo_VertexAttrib4fNV
;
749 (void) vbo_VertexAttrib4fvNV
;
751 (void) vbo_Materialfv
;
759 #endif /* FEATURE_beginend */
763 * Tell the VBO module to use a real OpenGL vertex buffer object to
764 * store accumulated immediate-mode vertex data.
765 * This replaces the malloced buffer which was created in
766 * vb_exec_vtx_init() below.
768 void vbo_use_buffer_objects(struct gl_context
*ctx
)
770 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
771 /* Any buffer name but 0 can be used here since this bufferobj won't
772 * go into the bufferobj hashtable.
774 GLuint bufName
= IMM_BUFFER_NAME
;
775 GLenum target
= GL_ARRAY_BUFFER_ARB
;
776 GLenum usage
= GL_STREAM_DRAW_ARB
;
777 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
779 /* Make sure this func is only used once */
780 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
781 if (exec
->vtx
.buffer_map
) {
782 _mesa_align_free(exec
->vtx
.buffer_map
);
783 exec
->vtx
.buffer_map
= NULL
;
784 exec
->vtx
.buffer_ptr
= NULL
;
787 /* Allocate a real buffer object now */
788 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
789 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
790 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
795 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
797 struct gl_context
*ctx
= exec
->ctx
;
798 struct vbo_context
*vbo
= vbo_context(ctx
);
801 /* Allocate a buffer object. Will just reuse this object
802 * continuously, unless vbo_use_buffer_objects() is called to enable
805 _mesa_reference_buffer_object(ctx
,
806 &exec
->vtx
.bufferobj
,
807 ctx
->Shared
->NullBufferObj
);
809 ASSERT(!exec
->vtx
.buffer_map
);
810 exec
->vtx
.buffer_map
= (GLfloat
*)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE
, 64);
811 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
813 vbo_exec_vtxfmt_init( exec
);
815 /* Hook our functions into the dispatch table.
817 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
819 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
820 ASSERT(i
< Elements(exec
->vtx
.attrsz
));
821 exec
->vtx
.attrsz
[i
] = 0;
822 ASSERT(i
< Elements(exec
->vtx
.active_sz
));
823 exec
->vtx
.active_sz
[i
] = 0;
825 for (i
= 0 ; i
< VERT_ATTRIB_MAX
; i
++) {
826 ASSERT(i
< Elements(exec
->vtx
.inputs
));
827 ASSERT(i
< Elements(exec
->vtx
.arrays
));
828 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
832 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
835 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
836 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
838 for (i
= 0; i
< 16; ++i
) {
839 arrays
[i
].BufferObj
= NULL
;
840 arrays
[i
+ 16].BufferObj
= NULL
;
841 _mesa_reference_buffer_object(ctx
, &arrays
[i
].BufferObj
,
842 vbo
->legacy_currval
[i
].BufferObj
);
843 _mesa_reference_buffer_object(ctx
, &arrays
[i
+ 16].BufferObj
,
844 vbo
->generic_currval
[i
].BufferObj
);
848 exec
->vtx
.vertex_size
= 0;
852 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
854 /* using a real VBO for vertex data */
855 struct gl_context
*ctx
= exec
->ctx
;
858 /* True VBOs should already be unmapped
860 if (exec
->vtx
.buffer_map
) {
861 ASSERT(exec
->vtx
.bufferobj
->Name
== 0 ||
862 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
863 if (exec
->vtx
.bufferobj
->Name
== 0) {
864 _mesa_align_free(exec
->vtx
.buffer_map
);
865 exec
->vtx
.buffer_map
= NULL
;
866 exec
->vtx
.buffer_ptr
= NULL
;
870 /* Drop any outstanding reference to the vertex buffer
872 for (i
= 0; i
< Elements(exec
->vtx
.arrays
); i
++) {
873 _mesa_reference_buffer_object(ctx
,
874 &exec
->vtx
.arrays
[i
].BufferObj
,
878 /* Free the vertex buffer. Unmap first if needed.
880 if (_mesa_bufferobj_mapped(exec
->vtx
.bufferobj
)) {
881 ctx
->Driver
.UnmapBuffer(ctx
, GL_ARRAY_BUFFER
, exec
->vtx
.bufferobj
);
883 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
886 void vbo_exec_BeginVertices( struct gl_context
*ctx
)
888 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
889 if (0) printf("%s\n", __FUNCTION__
);
890 vbo_exec_vtx_map( exec
);
892 assert((exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
893 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
896 void vbo_exec_FlushVertices_internal( struct gl_context
*ctx
, GLboolean unmap
)
898 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
900 if (exec
->vtx
.vert_count
|| unmap
) {
901 vbo_exec_vtx_flush( exec
, unmap
);
904 if (exec
->vtx
.vertex_size
) {
905 vbo_exec_copy_to_current( exec
);
906 reset_attrfv( exec
);
912 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
914 void vbo_exec_FlushVertices( struct gl_context
*ctx
, GLuint flags
)
916 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
919 /* debug check: make sure we don't get called recursively */
920 exec
->flush_call_depth
++;
921 assert(exec
->flush_call_depth
== 1);
924 if (0) printf("%s\n", __FUNCTION__
);
926 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
927 if (0) printf("%s - inside begin/end\n", __FUNCTION__
);
929 exec
->flush_call_depth
--;
930 assert(exec
->flush_call_depth
== 0);
935 vbo_exec_FlushVertices_internal( ctx
, GL_TRUE
);
937 /* Need to do this to ensure BeginVertices gets called again:
939 if (exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
)
940 exec
->ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
942 exec
->ctx
->Driver
.NeedFlush
&= ~flags
;
945 exec
->flush_call_depth
--;
946 assert(exec
->flush_call_depth
== 0);
951 static void reset_attrfv( struct vbo_exec_context
*exec
)
955 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
956 exec
->vtx
.attrsz
[i
] = 0;
957 exec
->vtx
.active_sz
[i
] = 0;
960 exec
->vtx
.vertex_size
= 0;
965 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
967 vbo_Color4f(r
, g
, b
, a
);
972 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
974 vbo_Normal3f(x
, y
, z
);
979 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
981 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
986 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
988 vbo_Materialfv(face
, pname
, params
);
993 _vbo_Materialf(GLenum face
, GLenum pname
, GLfloat param
)
997 p
[1] = p
[2] = p
[3] = 0.0F
;
998 vbo_Materialfv(face
, pname
, p
);
1003 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1005 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);
1010 _vbo_VertexAttrib1f(GLuint indx
, GLfloat x
)
1012 vbo_VertexAttrib1fARB(indx
, x
);
1017 _vbo_VertexAttrib1fv(GLuint indx
, const GLfloat
* values
)
1019 vbo_VertexAttrib1fvARB(indx
, values
);
1024 _vbo_VertexAttrib2f(GLuint indx
, GLfloat x
, GLfloat y
)
1026 vbo_VertexAttrib2fARB(indx
, x
, y
);
1031 _vbo_VertexAttrib2fv(GLuint indx
, const GLfloat
* values
)
1033 vbo_VertexAttrib2fvARB(indx
, values
);
1038 _vbo_VertexAttrib3f(GLuint indx
, GLfloat x
, GLfloat y
, GLfloat z
)
1040 vbo_VertexAttrib3fARB(indx
, x
, y
, z
);
1045 _vbo_VertexAttrib3fv(GLuint indx
, const GLfloat
* values
)
1047 vbo_VertexAttrib3fvARB(indx
, values
);
1052 _vbo_VertexAttrib4fv(GLuint indx
, const GLfloat
* values
)
1054 vbo_VertexAttrib4fvARB(indx
, values
);