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
.buffer_ptr
= 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
, GL_FALSE
);
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
.buffer_ptr
, data
,
125 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
126 exec
->vtx
.buffer_ptr
+= 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
));
160 /* Given that we explicitly state size here, there is no need
161 * for the COPY_CLEAN above, could just copy 16 bytes and be
162 * done. The only problem is when Mesa accesses ctx->Current
165 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
167 /* This triggers rather too much recalculation of Mesa state
168 * that doesn't get used (eg light positions).
170 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
171 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
172 ctx
->NewState
|= _NEW_LIGHT
;
174 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
179 /* Colormaterial -- this kindof sucks.
181 if (ctx
->Light
.ColorMaterialEnabled
&&
182 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
183 _mesa_update_color_material(ctx
,
184 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
189 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
191 GLcontext
*ctx
= exec
->ctx
;
192 struct vbo_context
*vbo
= vbo_context(ctx
);
195 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
196 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
197 switch (exec
->vtx
.attrsz
[i
]) {
198 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
199 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
200 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
201 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
208 /* Flush existing data, set new attrib size, replay copied vertices.
210 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
214 GLcontext
*ctx
= exec
->ctx
;
215 struct vbo_context
*vbo
= vbo_context(ctx
);
216 GLint lastcount
= exec
->vtx
.vert_count
;
221 /* Run pipeline on current vertices, copy wrapped vertices
222 * to exec->vtx.copied.
224 vbo_exec_wrap_buffers( exec
);
227 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
228 * when the attribute already exists in the vertex and is having
229 * its size increased.
231 vbo_exec_copy_to_current( exec
);
234 /* Heuristic: Attempt to isolate attributes received outside
235 * begin/end so that they don't bloat the vertices.
237 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
238 exec
->vtx
.attrsz
[attr
] == 0 &&
240 exec
->vtx
.vertex_size
) {
241 reset_attrfv( exec
);
246 oldsz
= exec
->vtx
.attrsz
[attr
];
247 exec
->vtx
.attrsz
[attr
] = newsz
;
249 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
250 exec
->vtx
.max_vert
= ((VBO_VERT_BUFFER_SIZE
- exec
->vtx
.buffer_used
) /
251 (exec
->vtx
.vertex_size
* sizeof(GLfloat
)));
252 exec
->vtx
.vert_count
= 0;
253 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
256 /* Recalculate all the attrptr[] values
258 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
259 if (exec
->vtx
.attrsz
[i
]) {
260 exec
->vtx
.attrptr
[i
] = tmp
;
261 tmp
+= exec
->vtx
.attrsz
[i
];
264 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
267 /* Copy from current to repopulate the vertex with correct values.
269 vbo_exec_copy_from_current( exec
);
271 /* Replay stored vertices to translate them
272 * to new format here.
274 * -- No need to replay - just copy piecewise
276 if (exec
->vtx
.copied
.nr
)
278 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
279 GLfloat
*dest
= exec
->vtx
.buffer_ptr
;
282 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
284 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
285 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
286 if (exec
->vtx
.attrsz
[j
]) {
289 COPY_CLEAN_4V( dest
, oldsz
, data
);
293 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
294 COPY_SZ_4V( dest
, newsz
, current
);
299 GLuint sz
= exec
->vtx
.attrsz
[j
];
300 COPY_SZ_4V( dest
, sz
, data
);
308 exec
->vtx
.buffer_ptr
= dest
;
309 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
310 exec
->vtx
.copied
.nr
= 0;
315 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
316 GLuint attr
, GLuint sz
)
318 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
321 if (sz
> exec
->vtx
.attrsz
[attr
]) {
322 /* New size is larger. Need to flush existing vertices and get
323 * an enlarged vertex format.
325 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
327 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
328 static const GLfloat id
[4] = { 0, 0, 0, 1 };
330 /* New size is smaller - just need to fill in some
331 * zeros. Don't need to flush or wrap.
333 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
334 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
337 exec
->vtx
.active_sz
[attr
] = sz
;
339 /* Does setting NeedFlush belong here? Necessitates resetting
340 * vtxfmt on each flush (otherwise flags won't get reset
344 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
352 #define ATTR( A, N, V0, V1, V2, V3 ) \
354 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
356 if (exec->vtx.active_sz[A] != N) \
357 vbo_exec_fixup_vertex(ctx, A, N); \
360 GLfloat *dest = exec->vtx.attrptr[A]; \
361 if (N>0) dest[0] = V0; \
362 if (N>1) dest[1] = V1; \
363 if (N>2) dest[2] = V2; \
364 if (N>3) dest[3] = V3; \
370 for (i = 0; i < exec->vtx.vertex_size; i++) \
371 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
373 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
374 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
376 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
377 vbo_exec_vtx_wrap( exec ); \
382 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
383 #define TAG(x) vbo_##x
385 #include "vbo_attrib_tmp.h"
393 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
395 GET_CURRENT_CONTEXT( ctx
);
396 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
400 if (exec
->eval
.recalculate_maps
)
401 vbo_exec_eval_update( exec
);
403 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
404 if (exec
->eval
.map1
[i
].map
)
405 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
406 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
411 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
412 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
414 vbo_exec_do_EvalCoord1f( exec
, u
);
416 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
417 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
420 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
422 GET_CURRENT_CONTEXT( ctx
);
423 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
427 if (exec
->eval
.recalculate_maps
)
428 vbo_exec_eval_update( exec
);
430 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
431 if (exec
->eval
.map2
[i
].map
)
432 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
433 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
436 if (ctx
->Eval
.AutoNormal
)
437 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
438 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
441 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
442 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
444 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
446 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
447 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
450 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
452 vbo_exec_EvalCoord1f( u
[0] );
455 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
457 vbo_exec_EvalCoord2f( u
[0], u
[1] );
460 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
462 GET_CURRENT_CONTEXT( ctx
);
463 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
464 (GLfloat
) ctx
->Eval
.MapGrid1un
);
465 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
467 vbo_exec_EvalCoord1f( u
);
471 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
473 GET_CURRENT_CONTEXT( ctx
);
474 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
475 (GLfloat
) ctx
->Eval
.MapGrid2un
);
476 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
477 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
478 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
479 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
481 vbo_exec_EvalCoord2f( u
, v
);
486 * Check if programs/shaders are enabled and valid at glBegin time.
489 vbo_validate_shaders(GLcontext
*ctx
)
491 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
492 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
495 if (ctx
->Shader
.CurrentProgram
&& !ctx
->Shader
.CurrentProgram
->LinkStatus
) {
502 /* Build a list of primitives on the fly. Keep
503 * ctx->Driver.CurrentExecPrimitive uptodate as well.
505 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
507 GET_CURRENT_CONTEXT( ctx
);
509 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
510 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
514 _mesa_update_state( ctx
);
516 CALL_Begin(ctx
->Exec
, (mode
));
520 if (!vbo_validate_shaders(ctx
)) {
521 _mesa_error(ctx
, GL_INVALID_OPERATION
,
522 "glBegin (invalid vertex/fragment program)");
526 /* Heuristic: attempt to isolate attributes occuring outside
529 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
530 vbo_exec_FlushVertices_internal( ctx
, GL_FALSE
);
532 i
= exec
->vtx
.prim_count
++;
533 exec
->vtx
.prim
[i
].mode
= mode
;
534 exec
->vtx
.prim
[i
].begin
= 1;
535 exec
->vtx
.prim
[i
].end
= 0;
536 exec
->vtx
.prim
[i
].indexed
= 0;
537 exec
->vtx
.prim
[i
].weak
= 0;
538 exec
->vtx
.prim
[i
].pad
= 0;
539 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
540 exec
->vtx
.prim
[i
].count
= 0;
542 ctx
->Driver
.CurrentExecPrimitive
= mode
;
545 _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" );
571 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
573 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
575 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
576 vfmt
->Begin
= vbo_exec_Begin
;
578 vfmt
->CallList
= _mesa_CallList
;
579 vfmt
->CallLists
= _mesa_CallLists
;
581 vfmt
->End
= vbo_exec_End
;
582 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
583 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
584 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
585 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
586 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
587 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
589 vfmt
->Rectf
= _mesa_noop_Rectf
;
590 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
591 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
594 /* from attrib_tmp.h:
596 vfmt
->Color3f
= vbo_Color3f
;
597 vfmt
->Color3fv
= vbo_Color3fv
;
598 vfmt
->Color4f
= vbo_Color4f
;
599 vfmt
->Color4fv
= vbo_Color4fv
;
600 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
601 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
602 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
603 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
604 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
605 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
606 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
607 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
608 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
609 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
610 vfmt
->Normal3f
= vbo_Normal3f
;
611 vfmt
->Normal3fv
= vbo_Normal3fv
;
612 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
613 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
614 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
615 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
616 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
617 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
618 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
619 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
620 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
621 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
622 vfmt
->Vertex2f
= vbo_Vertex2f
;
623 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
624 vfmt
->Vertex3f
= vbo_Vertex3f
;
625 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
626 vfmt
->Vertex4f
= vbo_Vertex4f
;
627 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
629 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
630 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
631 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
632 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
633 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
634 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
635 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
636 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
638 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
639 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
640 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
641 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
642 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
643 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
644 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
645 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
647 vfmt
->Materialfv
= vbo_Materialfv
;
649 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
650 vfmt
->Indexf
= vbo_Indexf
;
651 vfmt
->Indexfv
= vbo_Indexfv
;
657 * Tell the VBO module to use a real OpenGL vertex buffer object to
658 * store accumulated immediate-mode vertex data.
659 * This replaces the malloced buffer which was created in
660 * vb_exec_vtx_init() below.
662 void vbo_use_buffer_objects(GLcontext
*ctx
)
664 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
665 /* Any buffer name but 0 can be used here since this bufferobj won't
666 * go into the bufferobj hashtable.
668 GLuint bufName
= 0xaabbccdd;
669 GLenum target
= GL_ARRAY_BUFFER_ARB
;
670 GLenum usage
= GL_STREAM_DRAW_ARB
;
671 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
673 /* Make sure this func is only used once */
674 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
675 if (exec
->vtx
.buffer_map
) {
676 _mesa_align_free(exec
->vtx
.buffer_map
);
677 exec
->vtx
.buffer_map
= NULL
;
678 exec
->vtx
.buffer_ptr
= NULL
;
681 /* Allocate a real buffer object now */
682 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
683 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
688 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
690 GLcontext
*ctx
= exec
->ctx
;
691 struct vbo_context
*vbo
= vbo_context(ctx
);
694 /* Allocate a buffer object. Will just reuse this object
695 * continuously, unless vbo_use_buffer_objects() is called to enable
698 _mesa_reference_buffer_object(ctx
,
699 &exec
->vtx
.bufferobj
,
700 ctx
->Shared
->NullBufferObj
);
702 ASSERT(!exec
->vtx
.buffer_map
);
703 exec
->vtx
.buffer_map
= (GLfloat
*)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
, 64);
704 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
706 vbo_exec_vtxfmt_init( exec
);
708 /* Hook our functions into the dispatch table.
710 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
712 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
713 exec
->vtx
.attrsz
[i
] = 0;
714 exec
->vtx
.active_sz
[i
] = 0;
715 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
719 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
720 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
721 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
724 exec
->vtx
.vertex_size
= 0;
728 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
730 if (exec
->vtx
.bufferobj
->Name
) {
731 /* using a real VBO for vertex data */
732 GLcontext
*ctx
= exec
->ctx
;
733 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
736 /* just using malloc'd space for vertex data */
737 if (exec
->vtx
.buffer_map
) {
738 ALIGN_FREE(exec
->vtx
.buffer_map
);
739 exec
->vtx
.buffer_map
= NULL
;
740 exec
->vtx
.buffer_ptr
= 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
);