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"
39 #include "main/dlist.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 "glapi/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
);
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
;
110 /* Deal with buffer wrapping where provoked by the vertex buffer
111 * filling up, as opposed to upgrade_vertex().
113 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
115 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
118 /* Run pipeline on current vertices, copy wrapped vertices
119 * to exec->vtx.copied.
121 vbo_exec_wrap_buffers( exec
);
123 /* Copy stored stored vertices to start of new list.
125 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
127 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
128 _mesa_memcpy( exec
->vtx
.buffer_ptr
, data
,
129 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
130 exec
->vtx
.buffer_ptr
+= exec
->vtx
.vertex_size
;
131 data
+= exec
->vtx
.vertex_size
;
132 exec
->vtx
.vert_count
++;
135 exec
->vtx
.copied
.nr
= 0;
140 * Copy the active vertex's values to the ctx->Current fields.
142 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
144 GLcontext
*ctx
= exec
->ctx
;
145 struct vbo_context
*vbo
= vbo_context(ctx
);
148 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
149 if (exec
->vtx
.attrsz
[i
]) {
150 /* Note: the exec->vtx.current[i] pointers point into the
151 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
153 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
158 exec
->vtx
.attrptr
[i
]);
160 if (memcmp(current
, tmp
, sizeof(tmp
)) != 0)
162 memcpy(current
, tmp
, sizeof(tmp
));
164 /* Given that we explicitly state size here, there is no need
165 * for the COPY_CLEAN above, could just copy 16 bytes and be
166 * done. The only problem is when Mesa accesses ctx->Current
169 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
171 /* This triggers rather too much recalculation of Mesa state
172 * that doesn't get used (eg light positions).
174 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
175 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
176 ctx
->NewState
|= _NEW_LIGHT
;
178 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
183 /* Colormaterial -- this kindof sucks.
185 if (ctx
->Light
.ColorMaterialEnabled
&&
186 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
187 _mesa_update_color_material(ctx
,
188 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
193 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
195 GLcontext
*ctx
= exec
->ctx
;
196 struct vbo_context
*vbo
= vbo_context(ctx
);
199 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
200 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
201 switch (exec
->vtx
.attrsz
[i
]) {
202 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
203 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
204 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
205 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
212 /* Flush existing data, set new attrib size, replay copied vertices.
214 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
218 GLcontext
*ctx
= exec
->ctx
;
219 struct vbo_context
*vbo
= vbo_context(ctx
);
220 GLint lastcount
= exec
->vtx
.vert_count
;
225 /* Run pipeline on current vertices, copy wrapped vertices
226 * to exec->vtx.copied.
228 vbo_exec_wrap_buffers( exec
);
231 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
232 * when the attribute already exists in the vertex and is having
233 * its size increased.
235 vbo_exec_copy_to_current( exec
);
238 /* Heuristic: Attempt to isolate attributes received outside
239 * begin/end so that they don't bloat the vertices.
241 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
242 exec
->vtx
.attrsz
[attr
] == 0 &&
244 exec
->vtx
.vertex_size
) {
245 reset_attrfv( exec
);
250 oldsz
= exec
->vtx
.attrsz
[attr
];
251 exec
->vtx
.attrsz
[attr
] = newsz
;
253 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
254 exec
->vtx
.max_vert
= ((VBO_VERT_BUFFER_SIZE
- exec
->vtx
.buffer_used
) /
255 (exec
->vtx
.vertex_size
* sizeof(GLfloat
)));
256 exec
->vtx
.vert_count
= 0;
257 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
260 /* Recalculate all the attrptr[] values
262 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
263 if (exec
->vtx
.attrsz
[i
]) {
264 exec
->vtx
.attrptr
[i
] = tmp
;
265 tmp
+= exec
->vtx
.attrsz
[i
];
268 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
271 /* Copy from current to repopulate the vertex with correct values.
273 vbo_exec_copy_from_current( exec
);
275 /* Replay stored vertices to translate them
276 * to new format here.
278 * -- No need to replay - just copy piecewise
280 if (exec
->vtx
.copied
.nr
)
282 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
283 GLfloat
*dest
= exec
->vtx
.buffer_ptr
;
286 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
288 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
289 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
290 if (exec
->vtx
.attrsz
[j
]) {
293 COPY_CLEAN_4V( dest
, oldsz
, data
);
297 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
298 COPY_SZ_4V( dest
, newsz
, current
);
303 GLuint sz
= exec
->vtx
.attrsz
[j
];
304 COPY_SZ_4V( dest
, sz
, data
);
312 exec
->vtx
.buffer_ptr
= dest
;
313 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
314 exec
->vtx
.copied
.nr
= 0;
319 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
320 GLuint attr
, GLuint sz
)
322 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
325 if (sz
> exec
->vtx
.attrsz
[attr
]) {
326 /* New size is larger. Need to flush existing vertices and get
327 * an enlarged vertex format.
329 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
331 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
332 static const GLfloat id
[4] = { 0, 0, 0, 1 };
334 /* New size is smaller - just need to fill in some
335 * zeros. Don't need to flush or wrap.
337 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
338 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
341 exec
->vtx
.active_sz
[attr
] = sz
;
343 /* Does setting NeedFlush belong here? Necessitates resetting
344 * vtxfmt on each flush (otherwise flags won't get reset
348 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
356 #define ATTR( A, N, V0, V1, V2, V3 ) \
358 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
360 if (exec->vtx.active_sz[A] != N) \
361 vbo_exec_fixup_vertex(ctx, A, N); \
364 GLfloat *dest = exec->vtx.attrptr[A]; \
365 if (N>0) dest[0] = V0; \
366 if (N>1) dest[1] = V1; \
367 if (N>2) dest[2] = V2; \
368 if (N>3) dest[3] = V3; \
374 for (i = 0; i < exec->vtx.vertex_size; i++) \
375 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
377 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
378 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
380 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
381 vbo_exec_vtx_wrap( exec ); \
386 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
387 #define TAG(x) vbo_##x
389 #include "vbo_attrib_tmp.h"
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
);
489 /* Build a list of primitives on the fly. Keep
490 * ctx->Driver.CurrentExecPrimitive uptodate as well.
492 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
494 GET_CURRENT_CONTEXT( ctx
);
496 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
497 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
501 _mesa_update_state( ctx
);
503 CALL_Begin(ctx
->Exec
, (mode
));
507 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
511 /* Heuristic: attempt to isolate attributes occuring outside
514 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
515 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
517 i
= exec
->vtx
.prim_count
++;
518 exec
->vtx
.prim
[i
].mode
= mode
;
519 exec
->vtx
.prim
[i
].begin
= 1;
520 exec
->vtx
.prim
[i
].end
= 0;
521 exec
->vtx
.prim
[i
].indexed
= 0;
522 exec
->vtx
.prim
[i
].weak
= 0;
523 exec
->vtx
.prim
[i
].pad
= 0;
524 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
525 exec
->vtx
.prim
[i
].count
= 0;
527 ctx
->Driver
.CurrentExecPrimitive
= mode
;
530 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
534 static void GLAPIENTRY
vbo_exec_End( void )
536 GET_CURRENT_CONTEXT( ctx
);
538 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
539 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
540 int idx
= exec
->vtx
.vert_count
;
541 int i
= exec
->vtx
.prim_count
- 1;
543 exec
->vtx
.prim
[i
].end
= 1;
544 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
546 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
548 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
549 vbo_exec_vtx_flush( exec
, GL_FALSE
);
552 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
556 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
558 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
560 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
562 vfmt
->Begin
= vbo_exec_Begin
;
564 vfmt
->CallList
= _mesa_CallList
;
565 vfmt
->CallLists
= _mesa_CallLists
;
567 vfmt
->End
= vbo_exec_End
;
568 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
569 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
570 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
571 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
572 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
573 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
575 vfmt
->Rectf
= _mesa_noop_Rectf
;
576 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
577 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
580 /* from attrib_tmp.h:
582 vfmt
->Color3f
= vbo_Color3f
;
583 vfmt
->Color3fv
= vbo_Color3fv
;
584 vfmt
->Color4f
= vbo_Color4f
;
585 vfmt
->Color4fv
= vbo_Color4fv
;
586 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
587 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
588 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
589 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
590 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
591 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
592 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
593 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
594 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
595 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
596 vfmt
->Normal3f
= vbo_Normal3f
;
597 vfmt
->Normal3fv
= vbo_Normal3fv
;
598 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
599 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
600 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
601 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
602 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
603 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
604 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
605 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
606 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
607 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
608 vfmt
->Vertex2f
= vbo_Vertex2f
;
609 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
610 vfmt
->Vertex3f
= vbo_Vertex3f
;
611 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
612 vfmt
->Vertex4f
= vbo_Vertex4f
;
613 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
615 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
616 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
617 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
618 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
619 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
620 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
621 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
622 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
624 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
625 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
626 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
627 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
628 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
629 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
630 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
631 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
633 vfmt
->Materialfv
= vbo_Materialfv
;
635 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
636 vfmt
->Indexf
= vbo_Indexf
;
637 vfmt
->Indexfv
= vbo_Indexfv
;
643 * Tell the VBO module to use a real OpenGL vertex buffer object to
644 * store accumulated immediate-mode vertex data.
645 * This replaces the malloced buffer which was created in
646 * vb_exec_vtx_init() below.
648 void vbo_use_buffer_objects(GLcontext
*ctx
)
650 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
651 /* Any buffer name but 0 can be used here since this bufferobj won't
652 * go into the bufferobj hashtable.
654 GLuint bufName
= IMM_BUFFER_NAME
;
655 GLenum target
= GL_ARRAY_BUFFER_ARB
;
656 GLenum usage
= GL_STREAM_DRAW_ARB
;
657 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
659 /* Make sure this func is only used once */
660 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
661 if (exec
->vtx
.buffer_map
) {
662 _mesa_align_free(exec
->vtx
.buffer_map
);
663 exec
->vtx
.buffer_map
= NULL
;
664 exec
->vtx
.buffer_ptr
= NULL
;
667 /* Allocate a real buffer object now */
668 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
669 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
674 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
676 GLcontext
*ctx
= exec
->ctx
;
677 struct vbo_context
*vbo
= vbo_context(ctx
);
680 /* Allocate a buffer object. Will just reuse this object
681 * continuously, unless vbo_use_buffer_objects() is called to enable
684 _mesa_reference_buffer_object(ctx
,
685 &exec
->vtx
.bufferobj
,
686 ctx
->Shared
->NullBufferObj
);
688 ASSERT(!exec
->vtx
.buffer_map
);
689 exec
->vtx
.buffer_map
= (GLfloat
*)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
, 64);
690 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
692 vbo_exec_vtxfmt_init( exec
);
694 /* Hook our functions into the dispatch table.
696 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
698 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
699 exec
->vtx
.attrsz
[i
] = 0;
700 exec
->vtx
.active_sz
[i
] = 0;
701 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
705 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
706 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
707 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
710 exec
->vtx
.vertex_size
= 0;
714 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
716 /* using a real VBO for vertex data */
717 GLcontext
*ctx
= exec
->ctx
;
720 /* True VBOs should already be unmapped
722 if (exec
->vtx
.buffer_map
) {
723 ASSERT(exec
->vtx
.bufferobj
->Name
== 0 ||
724 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
725 if (exec
->vtx
.bufferobj
->Name
== 0) {
726 ALIGN_FREE(exec
->vtx
.buffer_map
);
727 exec
->vtx
.buffer_map
= NULL
;
728 exec
->vtx
.buffer_ptr
= NULL
;
732 /* Drop any outstanding reference to the vertex buffer
734 for (i
= 0; i
< Elements(exec
->vtx
.arrays
); i
++) {
735 _mesa_reference_buffer_object(ctx
,
736 &exec
->vtx
.arrays
[i
].BufferObj
,
740 /* Free the vertex buffer:
742 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
745 void vbo_exec_BeginVertices( GLcontext
*ctx
)
747 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
748 if (0) _mesa_printf("%s\n", __FUNCTION__
);
749 vbo_exec_vtx_map( exec
);
751 assert((exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
752 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
755 void vbo_exec_FlushVertices_internal( GLcontext
*ctx
, GLboolean unmap
)
757 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
759 if (exec
->vtx
.vert_count
|| unmap
) {
760 vbo_exec_vtx_flush( exec
, unmap
);
763 if (exec
->vtx
.vertex_size
) {
764 vbo_exec_copy_to_current( exec
);
765 reset_attrfv( exec
);
771 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
773 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
775 if (0) _mesa_printf("%s\n", __FUNCTION__
);
777 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
778 if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__
);
782 vbo_exec_FlushVertices_internal( ctx
, GL_TRUE
);
784 /* Need to do this to ensure BeginVertices gets called again:
786 if (exec
->ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) {
787 _mesa_restore_exec_vtxfmt( ctx
);
788 exec
->ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
791 exec
->ctx
->Driver
.NeedFlush
&= ~flags
;
795 static void reset_attrfv( struct vbo_exec_context
*exec
)
799 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
800 exec
->vtx
.attrsz
[i
] = 0;
801 exec
->vtx
.active_sz
[i
] = 0;
804 exec
->vtx
.vertex_size
= 0;
809 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
811 vbo_Color4f(r
, g
, b
, a
);
816 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
818 vbo_Normal3f(x
, y
, z
);
823 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
825 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
829 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
831 vbo_Materialfv(face
, pname
, params
);
836 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
838 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);