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 "glapi/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
);
60 /* Close off the last primitive, execute the buffer, restart the
63 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
65 if (exec
->vtx
.prim_count
== 0) {
66 exec
->vtx
.copied
.nr
= 0;
67 exec
->vtx
.vert_count
= 0;
68 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
71 GLuint last_begin
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].begin
;
74 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
75 GLint i
= exec
->vtx
.prim_count
- 1;
77 exec
->vtx
.prim
[i
].count
= (exec
->vtx
.vert_count
-
78 exec
->vtx
.prim
[i
].start
);
81 last_count
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].count
;
83 /* Execute the buffer and save copied vertices.
85 if (exec
->vtx
.vert_count
)
86 vbo_exec_vtx_flush( exec
, GL_FALSE
);
88 exec
->vtx
.prim_count
= 0;
89 exec
->vtx
.copied
.nr
= 0;
92 /* Emit a glBegin to start the new list.
94 assert(exec
->vtx
.prim_count
== 0);
96 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
97 exec
->vtx
.prim
[0].mode
= exec
->ctx
->Driver
.CurrentExecPrimitive
;
98 exec
->vtx
.prim
[0].start
= 0;
99 exec
->vtx
.prim
[0].count
= 0;
100 exec
->vtx
.prim_count
++;
102 if (exec
->vtx
.copied
.nr
== last_count
)
103 exec
->vtx
.prim
[0].begin
= last_begin
;
109 /* Deal with buffer wrapping where provoked by the vertex buffer
110 * filling up, as opposed to upgrade_vertex().
112 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
114 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
117 /* Run pipeline on current vertices, copy wrapped vertices
118 * to exec->vtx.copied.
120 vbo_exec_wrap_buffers( exec
);
122 /* Copy stored stored vertices to start of new list.
124 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
126 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
127 _mesa_memcpy( exec
->vtx
.buffer_ptr
, data
,
128 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
129 exec
->vtx
.buffer_ptr
+= exec
->vtx
.vertex_size
;
130 data
+= exec
->vtx
.vertex_size
;
131 exec
->vtx
.vert_count
++;
134 exec
->vtx
.copied
.nr
= 0;
139 * Copy the active vertex's values to the ctx->Current fields.
141 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
143 GLcontext
*ctx
= exec
->ctx
;
144 struct vbo_context
*vbo
= vbo_context(ctx
);
147 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
148 if (exec
->vtx
.attrsz
[i
]) {
149 /* Note: the exec->vtx.current[i] pointers point into the
150 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
152 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
157 exec
->vtx
.attrptr
[i
]);
159 if (memcmp(current
, tmp
, sizeof(tmp
)) != 0)
161 memcpy(current
, tmp
, sizeof(tmp
));
163 /* Given that we explicitly state size here, there is no need
164 * for the COPY_CLEAN above, could just copy 16 bytes and be
165 * done. The only problem is when Mesa accesses ctx->Current
168 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
170 /* This triggers rather too much recalculation of Mesa state
171 * that doesn't get used (eg light positions).
173 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
174 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
175 ctx
->NewState
|= _NEW_LIGHT
;
177 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
182 /* Colormaterial -- this kindof sucks.
184 if (ctx
->Light
.ColorMaterialEnabled
&&
185 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
186 _mesa_update_color_material(ctx
,
187 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
192 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
194 GLcontext
*ctx
= exec
->ctx
;
195 struct vbo_context
*vbo
= vbo_context(ctx
);
198 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
199 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
200 switch (exec
->vtx
.attrsz
[i
]) {
201 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
202 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
203 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
204 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
211 /* Flush existing data, set new attrib size, replay copied vertices.
213 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
217 GLcontext
*ctx
= exec
->ctx
;
218 struct vbo_context
*vbo
= vbo_context(ctx
);
219 GLint lastcount
= exec
->vtx
.vert_count
;
224 /* Run pipeline on current vertices, copy wrapped vertices
225 * to exec->vtx.copied.
227 vbo_exec_wrap_buffers( exec
);
230 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
231 * when the attribute already exists in the vertex and is having
232 * its size increased.
234 vbo_exec_copy_to_current( exec
);
237 /* Heuristic: Attempt to isolate attributes received outside
238 * begin/end so that they don't bloat the vertices.
240 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
241 exec
->vtx
.attrsz
[attr
] == 0 &&
243 exec
->vtx
.vertex_size
) {
244 reset_attrfv( exec
);
249 oldsz
= exec
->vtx
.attrsz
[attr
];
250 exec
->vtx
.attrsz
[attr
] = newsz
;
252 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
253 exec
->vtx
.max_vert
= ((VBO_VERT_BUFFER_SIZE
- exec
->vtx
.buffer_used
) /
254 (exec
->vtx
.vertex_size
* sizeof(GLfloat
)));
255 exec
->vtx
.vert_count
= 0;
256 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
259 /* Recalculate all the attrptr[] values
261 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
262 if (exec
->vtx
.attrsz
[i
]) {
263 exec
->vtx
.attrptr
[i
] = tmp
;
264 tmp
+= exec
->vtx
.attrsz
[i
];
267 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
270 /* Copy from current to repopulate the vertex with correct values.
272 vbo_exec_copy_from_current( exec
);
274 /* Replay stored vertices to translate them
275 * to new format here.
277 * -- No need to replay - just copy piecewise
279 if (exec
->vtx
.copied
.nr
)
281 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
282 GLfloat
*dest
= exec
->vtx
.buffer_ptr
;
285 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
287 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
288 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
289 if (exec
->vtx
.attrsz
[j
]) {
292 COPY_CLEAN_4V( dest
, oldsz
, data
);
296 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
297 COPY_SZ_4V( dest
, newsz
, current
);
302 GLuint sz
= exec
->vtx
.attrsz
[j
];
303 COPY_SZ_4V( dest
, sz
, data
);
311 exec
->vtx
.buffer_ptr
= dest
;
312 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
313 exec
->vtx
.copied
.nr
= 0;
318 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
319 GLuint attr
, GLuint sz
)
321 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
324 if (sz
> exec
->vtx
.attrsz
[attr
]) {
325 /* New size is larger. Need to flush existing vertices and get
326 * an enlarged vertex format.
328 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
330 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
331 static const GLfloat id
[4] = { 0, 0, 0, 1 };
333 /* New size is smaller - just need to fill in some
334 * zeros. Don't need to flush or wrap.
336 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
337 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
340 exec
->vtx
.active_sz
[attr
] = sz
;
342 /* Does setting NeedFlush belong here? Necessitates resetting
343 * vtxfmt on each flush (otherwise flags won't get reset
347 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
355 #define ATTR( A, N, V0, V1, V2, V3 ) \
357 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
359 if (exec->vtx.active_sz[A] != N) \
360 vbo_exec_fixup_vertex(ctx, A, N); \
363 GLfloat *dest = exec->vtx.attrptr[A]; \
364 if (N>0) dest[0] = V0; \
365 if (N>1) dest[1] = V1; \
366 if (N>2) dest[2] = V2; \
367 if (N>3) dest[3] = V3; \
373 for (i = 0; i < exec->vtx.vertex_size; i++) \
374 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
376 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
377 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
379 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
380 vbo_exec_vtx_wrap( exec ); \
385 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
386 #define TAG(x) vbo_##x
388 #include "vbo_attrib_tmp.h"
394 #if FEATURE_evaluators
397 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
399 GET_CURRENT_CONTEXT( ctx
);
400 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
404 if (exec
->eval
.recalculate_maps
)
405 vbo_exec_eval_update( exec
);
407 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
408 if (exec
->eval
.map1
[i
].map
)
409 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
410 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
415 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
416 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
418 vbo_exec_do_EvalCoord1f( exec
, u
);
420 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
421 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
424 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
426 GET_CURRENT_CONTEXT( ctx
);
427 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
431 if (exec
->eval
.recalculate_maps
)
432 vbo_exec_eval_update( exec
);
434 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
435 if (exec
->eval
.map2
[i
].map
)
436 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
437 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
440 if (ctx
->Eval
.AutoNormal
)
441 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
442 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
445 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
446 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
448 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
450 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
451 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
454 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
456 vbo_exec_EvalCoord1f( u
[0] );
459 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
461 vbo_exec_EvalCoord2f( u
[0], u
[1] );
464 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
466 GET_CURRENT_CONTEXT( ctx
);
467 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
468 (GLfloat
) ctx
->Eval
.MapGrid1un
);
469 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
471 vbo_exec_EvalCoord1f( u
);
475 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
477 GET_CURRENT_CONTEXT( ctx
);
478 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
479 (GLfloat
) ctx
->Eval
.MapGrid2un
);
480 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
481 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
482 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
483 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
485 vbo_exec_EvalCoord2f( u
, v
);
488 /* use noop eval mesh */
489 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
490 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
492 #endif /* FEATURE_evaluators */
495 /* Build a list of primitives on the fly. Keep
496 * ctx->Driver.CurrentExecPrimitive uptodate as well.
498 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
500 GET_CURRENT_CONTEXT( ctx
);
502 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
503 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
507 _mesa_update_state( ctx
);
509 CALL_Begin(ctx
->Exec
, (mode
));
513 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
517 /* Heuristic: attempt to isolate attributes occuring outside
520 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
521 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
523 i
= exec
->vtx
.prim_count
++;
524 exec
->vtx
.prim
[i
].mode
= mode
;
525 exec
->vtx
.prim
[i
].begin
= 1;
526 exec
->vtx
.prim
[i
].end
= 0;
527 exec
->vtx
.prim
[i
].indexed
= 0;
528 exec
->vtx
.prim
[i
].weak
= 0;
529 exec
->vtx
.prim
[i
].pad
= 0;
530 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
531 exec
->vtx
.prim
[i
].count
= 0;
533 ctx
->Driver
.CurrentExecPrimitive
= mode
;
536 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
540 static void GLAPIENTRY
vbo_exec_End( void )
542 GET_CURRENT_CONTEXT( ctx
);
544 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
545 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
546 int idx
= exec
->vtx
.vert_count
;
547 int i
= exec
->vtx
.prim_count
- 1;
549 exec
->vtx
.prim
[i
].end
= 1;
550 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
552 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
554 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
555 vbo_exec_vtx_flush( exec
, GL_FALSE
);
558 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
562 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
564 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
566 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
568 vfmt
->Begin
= vbo_exec_Begin
;
569 vfmt
->End
= vbo_exec_End
;
571 _MESA_INIT_DLIST_VTXFMT(vfmt
, _mesa_
);
572 _MESA_INIT_EVAL_VTXFMT(vfmt
, vbo_exec_
);
574 vfmt
->Rectf
= _mesa_noop_Rectf
;
576 /* from attrib_tmp.h:
578 vfmt
->Color3f
= vbo_Color3f
;
579 vfmt
->Color3fv
= vbo_Color3fv
;
580 vfmt
->Color4f
= vbo_Color4f
;
581 vfmt
->Color4fv
= vbo_Color4fv
;
582 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
583 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
584 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
585 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
586 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
587 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
588 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
589 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
590 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
591 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
592 vfmt
->Normal3f
= vbo_Normal3f
;
593 vfmt
->Normal3fv
= vbo_Normal3fv
;
594 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
595 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
596 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
597 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
598 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
599 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
600 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
601 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
602 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
603 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
604 vfmt
->Vertex2f
= vbo_Vertex2f
;
605 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
606 vfmt
->Vertex3f
= vbo_Vertex3f
;
607 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
608 vfmt
->Vertex4f
= vbo_Vertex4f
;
609 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
611 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
612 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
613 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
614 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
615 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
616 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
617 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
618 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
620 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
621 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
622 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
623 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
624 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
625 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
626 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
627 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
629 vfmt
->Materialfv
= vbo_Materialfv
;
631 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
632 vfmt
->Indexf
= vbo_Indexf
;
633 vfmt
->Indexfv
= vbo_Indexfv
;
638 #else /* FEATURE_beginend */
641 #define ATTR( A, N, V0, V1, V2, V3 ) \
643 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
645 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
646 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
648 if (exec->vtx.active_sz[A] != N) \
649 vbo_exec_fixup_vertex(ctx, A, N); \
652 GLfloat *dest = exec->vtx.attrptr[A]; \
653 if (N>0) dest[0] = V0; \
654 if (N>1) dest[1] = V1; \
655 if (N>2) dest[2] = V2; \
656 if (N>3) dest[3] = V3; \
660 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
661 #define TAG(x) vbo_##x
663 #include "vbo_attrib_tmp.h"
665 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
667 /* silence warnings */
672 (void) vbo_FogCoordfEXT
;
673 (void) vbo_FogCoordfvEXT
;
674 (void) vbo_MultiTexCoord1f
;
675 (void) vbo_MultiTexCoord1fv
;
676 (void) vbo_MultiTexCoord2f
;
677 (void) vbo_MultiTexCoord2fv
;
678 (void) vbo_MultiTexCoord3f
;
679 (void) vbo_MultiTexCoord3fv
;
680 (void) vbo_MultiTexCoord4f
;
681 (void) vbo_MultiTexCoord4fv
;
683 (void) vbo_Normal3fv
;
684 (void) vbo_SecondaryColor3fEXT
;
685 (void) vbo_SecondaryColor3fvEXT
;
686 (void) vbo_TexCoord1f
;
687 (void) vbo_TexCoord1fv
;
688 (void) vbo_TexCoord2f
;
689 (void) vbo_TexCoord2fv
;
690 (void) vbo_TexCoord3f
;
691 (void) vbo_TexCoord3fv
;
692 (void) vbo_TexCoord4f
;
693 (void) vbo_TexCoord4fv
;
695 (void) vbo_Vertex2fv
;
697 (void) vbo_Vertex3fv
;
699 (void) vbo_Vertex4fv
;
701 (void) vbo_VertexAttrib1fARB
;
702 (void) vbo_VertexAttrib1fvARB
;
703 (void) vbo_VertexAttrib2fARB
;
704 (void) vbo_VertexAttrib2fvARB
;
705 (void) vbo_VertexAttrib3fARB
;
706 (void) vbo_VertexAttrib3fvARB
;
707 (void) vbo_VertexAttrib4fARB
;
708 (void) vbo_VertexAttrib4fvARB
;
710 (void) vbo_VertexAttrib1fNV
;
711 (void) vbo_VertexAttrib1fvNV
;
712 (void) vbo_VertexAttrib2fNV
;
713 (void) vbo_VertexAttrib2fvNV
;
714 (void) vbo_VertexAttrib3fNV
;
715 (void) vbo_VertexAttrib3fvNV
;
716 (void) vbo_VertexAttrib4fNV
;
717 (void) vbo_VertexAttrib4fvNV
;
719 (void) vbo_Materialfv
;
727 #endif /* FEATURE_beginend */
731 * Tell the VBO module to use a real OpenGL vertex buffer object to
732 * store accumulated immediate-mode vertex data.
733 * This replaces the malloced buffer which was created in
734 * vb_exec_vtx_init() below.
736 void vbo_use_buffer_objects(GLcontext
*ctx
)
738 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
739 /* Any buffer name but 0 can be used here since this bufferobj won't
740 * go into the bufferobj hashtable.
742 GLuint bufName
= IMM_BUFFER_NAME
;
743 GLenum target
= GL_ARRAY_BUFFER_ARB
;
744 GLenum usage
= GL_STREAM_DRAW_ARB
;
745 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
747 /* Make sure this func is only used once */
748 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
749 if (exec
->vtx
.buffer_map
) {
750 _mesa_align_free(exec
->vtx
.buffer_map
);
751 exec
->vtx
.buffer_map
= NULL
;
752 exec
->vtx
.buffer_ptr
= NULL
;
755 /* Allocate a real buffer object now */
756 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
757 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
762 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
764 GLcontext
*ctx
= exec
->ctx
;
765 struct vbo_context
*vbo
= vbo_context(ctx
);
768 /* Allocate a buffer object. Will just reuse this object
769 * continuously, unless vbo_use_buffer_objects() is called to enable
772 _mesa_reference_buffer_object(ctx
,
773 &exec
->vtx
.bufferobj
,
774 ctx
->Shared
->NullBufferObj
);
776 ASSERT(!exec
->vtx
.buffer_map
);
777 exec
->vtx
.buffer_map
= (GLfloat
*)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
, 64);
778 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
780 vbo_exec_vtxfmt_init( exec
);
782 /* Hook our functions into the dispatch table.
784 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
786 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
787 exec
->vtx
.attrsz
[i
] = 0;
788 exec
->vtx
.active_sz
[i
] = 0;
789 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
793 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
794 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
795 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
798 exec
->vtx
.vertex_size
= 0;
802 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
804 /* using a real VBO for vertex data */
805 GLcontext
*ctx
= exec
->ctx
;
808 /* True VBOs should already be unmapped
810 if (exec
->vtx
.buffer_map
) {
811 ASSERT(exec
->vtx
.bufferobj
->Name
== 0 ||
812 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
813 if (exec
->vtx
.bufferobj
->Name
== 0) {
814 ALIGN_FREE(exec
->vtx
.buffer_map
);
815 exec
->vtx
.buffer_map
= NULL
;
816 exec
->vtx
.buffer_ptr
= NULL
;
820 /* Drop any outstanding reference to the vertex buffer
822 for (i
= 0; i
< Elements(exec
->vtx
.arrays
); i
++) {
823 _mesa_reference_buffer_object(ctx
,
824 &exec
->vtx
.arrays
[i
].BufferObj
,
828 /* Free the vertex buffer:
830 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
833 void vbo_exec_BeginVertices( GLcontext
*ctx
)
835 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
836 if (0) _mesa_printf("%s\n", __FUNCTION__
);
837 vbo_exec_vtx_map( exec
);
839 assert((exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
840 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
843 void vbo_exec_FlushVertices_internal( GLcontext
*ctx
, GLboolean unmap
)
845 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
847 if (exec
->vtx
.vert_count
|| unmap
) {
848 vbo_exec_vtx_flush( exec
, unmap
);
851 if (exec
->vtx
.vertex_size
) {
852 vbo_exec_copy_to_current( exec
);
853 reset_attrfv( exec
);
859 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
861 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
863 if (0) _mesa_printf("%s\n", __FUNCTION__
);
865 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
866 if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__
);
870 vbo_exec_FlushVertices_internal( ctx
, GL_TRUE
);
872 /* Need to do this to ensure BeginVertices gets called again:
874 if (exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) {
875 _mesa_restore_exec_vtxfmt( ctx
);
876 exec
->ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
879 exec
->ctx
->Driver
.NeedFlush
&= ~flags
;
883 static void reset_attrfv( struct vbo_exec_context
*exec
)
887 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
888 exec
->vtx
.attrsz
[i
] = 0;
889 exec
->vtx
.active_sz
[i
] = 0;
892 exec
->vtx
.vertex_size
= 0;
897 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
899 vbo_Color4f(r
, g
, b
, a
);
904 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
906 vbo_Normal3f(x
, y
, z
);
911 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
913 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
917 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
919 vbo_Materialfv(face
, pname
, params
);
924 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
926 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);