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 static void reset_attrfv( struct vbo_exec_context
*exec
);
57 /* Close off the last primitive, execute the buffer, restart the
60 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
62 if (exec
->vtx
.prim_count
== 0) {
63 exec
->vtx
.copied
.nr
= 0;
64 exec
->vtx
.vert_count
= 0;
65 exec
->vtx
.vbptr
= (GLfloat
*)exec
->vtx
.buffer_map
;
68 GLuint last_begin
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].begin
;
71 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
72 GLint i
= exec
->vtx
.prim_count
- 1;
74 exec
->vtx
.prim
[i
].count
= (exec
->vtx
.vert_count
-
75 exec
->vtx
.prim
[i
].start
);
78 last_count
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].count
;
80 /* Execute the buffer and save copied vertices.
82 if (exec
->vtx
.vert_count
)
83 vbo_exec_vtx_flush( exec
);
85 exec
->vtx
.prim_count
= 0;
86 exec
->vtx
.copied
.nr
= 0;
89 /* Emit a glBegin to start the new list.
91 assert(exec
->vtx
.prim_count
== 0);
93 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
94 exec
->vtx
.prim
[0].mode
= exec
->ctx
->Driver
.CurrentExecPrimitive
;
95 exec
->vtx
.prim
[0].start
= 0;
96 exec
->vtx
.prim
[0].count
= 0;
97 exec
->vtx
.prim_count
++;
99 if (exec
->vtx
.copied
.nr
== last_count
)
100 exec
->vtx
.prim
[0].begin
= last_begin
;
106 /* Deal with buffer wrapping where provoked by the vertex buffer
107 * filling up, as opposed to upgrade_vertex().
109 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
111 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
114 /* Run pipeline on current vertices, copy wrapped vertices
115 * to exec->vtx.copied.
117 vbo_exec_wrap_buffers( exec
);
119 /* Copy stored stored vertices to start of new list.
121 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
123 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
124 _mesa_memcpy( exec
->vtx
.vbptr
, data
,
125 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
126 exec
->vtx
.vbptr
+= exec
->vtx
.vertex_size
;
127 data
+= exec
->vtx
.vertex_size
;
128 exec
->vtx
.vert_count
++;
131 exec
->vtx
.copied
.nr
= 0;
136 * Copy the active vertex's values to the ctx->Current fields.
138 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
140 GLcontext
*ctx
= exec
->ctx
;
141 struct vbo_context
*vbo
= vbo_context(ctx
);
144 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
145 if (exec
->vtx
.attrsz
[i
]) {
146 /* Note: the exec->vtx.current[i] pointers point into the
147 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
149 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
154 exec
->vtx
.attrptr
[i
]);
156 if (memcmp(current
, tmp
, sizeof(tmp
)) != 0)
158 memcpy(current
, tmp
, sizeof(tmp
));
161 /* Given that we explicitly state size here, there is no need
162 * for the COPY_CLEAN above, could just copy 16 bytes and be
163 * done. The only problem is when Mesa accesses ctx->Current
166 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
168 /* This triggers rather too much recalculation of Mesa state
169 * that doesn't get used (eg light positions).
171 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
172 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
173 ctx
->NewState
|= _NEW_LIGHT
;
175 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
180 /* Colormaterial -- this kindof sucks.
182 if (ctx
->Light
.ColorMaterialEnabled
&&
183 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
184 _mesa_update_color_material(ctx
,
185 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
188 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
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];
209 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
213 /* Flush existing data, set new attrib size, replay copied vertices.
215 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
219 GLcontext
*ctx
= exec
->ctx
;
220 struct vbo_context
*vbo
= vbo_context(ctx
);
221 GLint lastcount
= exec
->vtx
.vert_count
;
226 /* Run pipeline on current vertices, copy wrapped vertices
227 * to exec->vtx.copied.
229 vbo_exec_wrap_buffers( exec
);
232 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
233 * when the attribute already exists in the vertex and is having
234 * its size increased.
236 vbo_exec_copy_to_current( exec
);
239 /* Heuristic: Attempt to isolate attributes received outside
240 * begin/end so that they don't bloat the vertices.
242 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
243 exec
->vtx
.attrsz
[attr
] == 0 &&
245 exec
->vtx
.vertex_size
) {
246 reset_attrfv( exec
);
251 oldsz
= exec
->vtx
.attrsz
[attr
];
252 exec
->vtx
.attrsz
[attr
] = newsz
;
254 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
255 exec
->vtx
.max_vert
= VBO_VERT_BUFFER_SIZE
/ exec
->vtx
.vertex_size
;
256 exec
->vtx
.vert_count
= 0;
257 exec
->vtx
.vbptr
= (GLfloat
*)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
.vbptr
;
286 assert(exec
->vtx
.vbptr
== (GLfloat
*)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
.vbptr
= 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
;
350 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
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.vbptr[i] = exec->vtx.vertex[i]; \
379 exec->vtx.vbptr += 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"
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 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
418 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
420 vbo_exec_do_EvalCoord1f( exec
, u
);
422 _mesa_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 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
448 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
450 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
452 _mesa_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
);
492 * Check if programs/shaders are enabled and valid at glBegin time.
495 vbo_validate_shaders(GLcontext
*ctx
)
497 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
498 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
501 if (ctx
->Shader
.CurrentProgram
&& !ctx
->Shader
.CurrentProgram
->LinkStatus
) {
508 /* Build a list of primitives on the fly. Keep
509 * ctx->Driver.CurrentExecPrimitive uptodate as well.
511 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
513 GET_CURRENT_CONTEXT( ctx
);
515 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
516 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
520 _mesa_update_state( ctx
);
522 CALL_Begin(ctx
->Exec
, (mode
));
526 if (!vbo_validate_shaders(ctx
)) {
527 _mesa_error(ctx
, GL_INVALID_OPERATION
,
528 "glBegin (invalid vertex/fragment program)");
532 /* Heuristic: attempt to isolate attributes occuring outside
535 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
536 vbo_exec_FlushVertices( ctx
, ~0 );
538 i
= exec
->vtx
.prim_count
++;
539 exec
->vtx
.prim
[i
].mode
= mode
;
540 exec
->vtx
.prim
[i
].begin
= 1;
541 exec
->vtx
.prim
[i
].end
= 0;
542 exec
->vtx
.prim
[i
].indexed
= 0;
543 exec
->vtx
.prim
[i
].weak
= 0;
544 exec
->vtx
.prim
[i
].pad
= 0;
545 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
546 exec
->vtx
.prim
[i
].count
= 0;
548 ctx
->Driver
.CurrentExecPrimitive
= mode
;
551 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
555 static void GLAPIENTRY
vbo_exec_End( void )
557 GET_CURRENT_CONTEXT( ctx
);
559 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
560 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
561 int idx
= exec
->vtx
.vert_count
;
562 int i
= exec
->vtx
.prim_count
- 1;
564 exec
->vtx
.prim
[i
].end
= 1;
565 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
567 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
569 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
570 vbo_exec_vtx_flush( exec
);
573 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
577 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
579 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
581 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
582 vfmt
->Begin
= vbo_exec_Begin
;
584 vfmt
->CallList
= _mesa_CallList
;
585 vfmt
->CallLists
= _mesa_CallLists
;
587 vfmt
->End
= vbo_exec_End
;
588 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
589 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
590 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
591 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
592 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
593 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
595 vfmt
->Rectf
= _mesa_noop_Rectf
;
596 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
597 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
600 /* from attrib_tmp.h:
602 vfmt
->Color3f
= vbo_Color3f
;
603 vfmt
->Color3fv
= vbo_Color3fv
;
604 vfmt
->Color4f
= vbo_Color4f
;
605 vfmt
->Color4fv
= vbo_Color4fv
;
606 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
607 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
608 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
609 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
610 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
611 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
612 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
613 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
614 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
615 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
616 vfmt
->Normal3f
= vbo_Normal3f
;
617 vfmt
->Normal3fv
= vbo_Normal3fv
;
618 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
619 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
620 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
621 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
622 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
623 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
624 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
625 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
626 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
627 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
628 vfmt
->Vertex2f
= vbo_Vertex2f
;
629 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
630 vfmt
->Vertex3f
= vbo_Vertex3f
;
631 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
632 vfmt
->Vertex4f
= vbo_Vertex4f
;
633 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
635 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
636 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
637 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
638 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
639 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
640 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
641 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
642 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
644 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
645 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
646 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
647 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
648 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
649 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
650 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
651 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
653 vfmt
->Materialfv
= vbo_Materialfv
;
655 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
656 vfmt
->Indexf
= vbo_Indexf
;
657 vfmt
->Indexfv
= vbo_Indexfv
;
663 * Tell the VBO module to use a real OpenGL vertex buffer object to
664 * store accumulated immediate-mode vertex data.
665 * This replaces the malloced buffer which was created in
666 * vb_exec_vtx_init() below.
668 void vbo_use_buffer_objects(GLcontext
*ctx
)
670 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
671 /* Any buffer name but 0 can be used here since this bufferobj won't
672 * go into the bufferobj hashtable.
674 GLuint bufName
= 0xaabbccdd;
675 GLenum target
= GL_ARRAY_BUFFER_ARB
;
676 GLenum access
= GL_READ_WRITE_ARB
;
677 GLenum usage
= GL_STREAM_DRAW_ARB
;
678 GLsizei size
= VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
);
680 /* Make sure this func is only used once */
681 assert(exec
->vtx
.bufferobj
== ctx
->Array
.NullBufferObj
);
682 if (exec
->vtx
.buffer_map
) {
683 _mesa_align_free(exec
->vtx
.buffer_map
);
686 /* Allocate a real buffer object now */
687 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
688 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
692 = ctx
->Driver
.MapBuffer(ctx
, target
, access
, exec
->vtx
.bufferobj
);
697 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
699 GLcontext
*ctx
= exec
->ctx
;
700 struct vbo_context
*vbo
= vbo_context(ctx
);
703 /* Allocate a buffer object. Will just reuse this object
704 * continuously, unless vbo_use_buffer_objects() is called to enable
707 _mesa_reference_buffer_object(ctx
,
708 &exec
->vtx
.bufferobj
,
709 ctx
->Array
.NullBufferObj
);
711 ASSERT(!exec
->vtx
.buffer_map
);
712 exec
->vtx
.buffer_map
= ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
), 64);
713 vbo_exec_vtxfmt_init( exec
);
715 /* Hook our functions into the dispatch table.
717 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
719 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
720 exec
->vtx
.attrsz
[i
] = 0;
721 exec
->vtx
.active_sz
[i
] = 0;
722 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
726 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
727 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
728 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
731 exec
->vtx
.vertex_size
= 0;
735 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
737 if (exec
->vtx
.bufferobj
->Name
) {
738 /* using a real VBO for vertex data */
739 GLcontext
*ctx
= exec
->ctx
;
740 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
743 /* just using malloc'd space for vertex data */
744 if (exec
->vtx
.buffer_map
) {
745 ALIGN_FREE(exec
->vtx
.buffer_map
);
746 exec
->vtx
.buffer_map
= NULL
;
752 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
754 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
756 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
759 if (exec
->vtx
.vert_count
) {
760 vbo_exec_vtx_flush( exec
);
763 if (exec
->vtx
.vertex_size
) {
764 vbo_exec_copy_to_current( exec
);
765 reset_attrfv( exec
);
768 exec
->ctx
->Driver
.NeedFlush
= 0;
772 static void reset_attrfv( struct vbo_exec_context
*exec
)
776 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
777 exec
->vtx
.attrsz
[i
] = 0;
778 exec
->vtx
.active_sz
[i
] = 0;
781 exec
->vtx
.vertex_size
= 0;
786 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
788 vbo_Color4f(r
, g
, b
, a
);
793 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
795 vbo_Normal3f(x
, y
, z
);
800 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
802 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
806 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
808 vbo_Materialfv(face
, pname
, params
);
813 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
815 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);