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 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
148 /* Note: the exec->vtx.current[i] pointers point into the
149 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
151 COPY_CLEAN_4V(current
,
153 exec
->vtx
.attrptr
[i
]);
156 /* Given that we explicitly state size here, there is no need
157 * for the COPY_CLEAN above, could just copy 16 bytes and be
158 * done. The only problem is when Mesa accesses ctx->Current
161 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
163 /* This triggers rather too much recalculation of Mesa state
164 * that doesn't get used (eg light positions).
166 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
167 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
168 ctx
->NewState
|= _NEW_LIGHT
;
172 /* Colormaterial -- this kindof sucks.
174 if (ctx
->Light
.ColorMaterialEnabled
&&
175 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
176 _mesa_update_color_material(ctx
,
177 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
180 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
184 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
186 GLcontext
*ctx
= exec
->ctx
;
187 struct vbo_context
*vbo
= vbo_context(ctx
);
190 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
191 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
192 switch (exec
->vtx
.attrsz
[i
]) {
193 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
194 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
195 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
196 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
201 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
205 /* Flush existing data, set new attrib size, replay copied vertices.
207 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
211 GLcontext
*ctx
= exec
->ctx
;
212 struct vbo_context
*vbo
= vbo_context(ctx
);
213 GLint lastcount
= exec
->vtx
.vert_count
;
218 /* Run pipeline on current vertices, copy wrapped vertices
219 * to exec->vtx.copied.
221 vbo_exec_wrap_buffers( exec
);
224 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
225 * when the attribute already exists in the vertex and is having
226 * its size increased.
228 vbo_exec_copy_to_current( exec
);
231 /* Heuristic: Attempt to isolate attributes received outside
232 * begin/end so that they don't bloat the vertices.
234 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
235 exec
->vtx
.attrsz
[attr
] == 0 &&
237 exec
->vtx
.vertex_size
) {
238 reset_attrfv( exec
);
243 oldsz
= exec
->vtx
.attrsz
[attr
];
244 exec
->vtx
.attrsz
[attr
] = newsz
;
246 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
247 exec
->vtx
.max_vert
= VBO_VERT_BUFFER_SIZE
/ exec
->vtx
.vertex_size
;
248 exec
->vtx
.vert_count
= 0;
249 exec
->vtx
.vbptr
= (GLfloat
*)exec
->vtx
.buffer_map
;
252 /* Recalculate all the attrptr[] values
254 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
255 if (exec
->vtx
.attrsz
[i
]) {
256 exec
->vtx
.attrptr
[i
] = tmp
;
257 tmp
+= exec
->vtx
.attrsz
[i
];
260 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
263 /* Copy from current to repopulate the vertex with correct values.
265 vbo_exec_copy_from_current( exec
);
267 /* Replay stored vertices to translate them
268 * to new format here.
270 * -- No need to replay - just copy piecewise
272 if (exec
->vtx
.copied
.nr
)
274 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
275 GLfloat
*dest
= exec
->vtx
.vbptr
;
278 assert(exec
->vtx
.vbptr
== (GLfloat
*)exec
->vtx
.buffer_map
);
280 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
281 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
282 if (exec
->vtx
.attrsz
[j
]) {
285 COPY_CLEAN_4V( dest
, oldsz
, data
);
289 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
290 COPY_SZ_4V( dest
, newsz
, current
);
295 GLuint sz
= exec
->vtx
.attrsz
[j
];
296 COPY_SZ_4V( dest
, sz
, data
);
304 exec
->vtx
.vbptr
= dest
;
305 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
306 exec
->vtx
.copied
.nr
= 0;
311 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
312 GLuint attr
, GLuint sz
)
314 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
317 if (sz
> exec
->vtx
.attrsz
[attr
]) {
318 /* New size is larger. Need to flush existing vertices and get
319 * an enlarged vertex format.
321 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
323 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
324 static const GLfloat id
[4] = { 0, 0, 0, 1 };
326 /* New size is smaller - just need to fill in some
327 * zeros. Don't need to flush or wrap.
329 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
330 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
333 exec
->vtx
.active_sz
[attr
] = sz
;
335 /* Does setting NeedFlush belong here? Necessitates resetting
336 * vtxfmt on each flush (otherwise flags won't get reset
340 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
342 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
350 #define ATTR( A, N, V0, V1, V2, V3 ) \
352 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
354 if (exec->vtx.active_sz[A] != N) \
355 vbo_exec_fixup_vertex(ctx, A, N); \
358 GLfloat *dest = exec->vtx.attrptr[A]; \
359 if (N>0) dest[0] = V0; \
360 if (N>1) dest[1] = V1; \
361 if (N>2) dest[2] = V2; \
362 if (N>3) dest[3] = V3; \
368 for (i = 0; i < exec->vtx.vertex_size; i++) \
369 exec->vtx.vbptr[i] = exec->vtx.vertex[i]; \
371 exec->vtx.vbptr += exec->vtx.vertex_size; \
372 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
374 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
375 vbo_exec_vtx_wrap( exec ); \
380 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
381 #define TAG(x) vbo_##x
383 #include "vbo_attrib_tmp.h"
391 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
393 GET_CURRENT_CONTEXT( ctx
);
394 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
398 if (exec
->eval
.recalculate_maps
)
399 vbo_exec_eval_update( exec
);
401 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
402 if (exec
->eval
.map1
[i
].map
)
403 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
404 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
409 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
410 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
412 vbo_exec_do_EvalCoord1f( exec
, u
);
414 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
415 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
418 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
420 GET_CURRENT_CONTEXT( ctx
);
421 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
425 if (exec
->eval
.recalculate_maps
)
426 vbo_exec_eval_update( exec
);
428 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
429 if (exec
->eval
.map2
[i
].map
)
430 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
431 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
434 if (ctx
->Eval
.AutoNormal
)
435 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
436 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
439 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
440 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
442 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
444 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
445 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
448 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
450 vbo_exec_EvalCoord1f( u
[0] );
453 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
455 vbo_exec_EvalCoord2f( u
[0], u
[1] );
458 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
460 GET_CURRENT_CONTEXT( ctx
);
461 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
462 (GLfloat
) ctx
->Eval
.MapGrid1un
);
463 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
465 vbo_exec_EvalCoord1f( u
);
469 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
471 GET_CURRENT_CONTEXT( ctx
);
472 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
473 (GLfloat
) ctx
->Eval
.MapGrid2un
);
474 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
475 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
476 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
477 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
479 vbo_exec_EvalCoord2f( u
, v
);
484 * Check if programs/shaders are enabled and valid at glBegin time.
487 vbo_validate_shaders(GLcontext
*ctx
)
489 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
490 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
493 if (ctx
->Shader
.CurrentProgram
&& !ctx
->Shader
.CurrentProgram
->LinkStatus
) {
500 /* Build a list of primitives on the fly. Keep
501 * ctx->Driver.CurrentExecPrimitive uptodate as well.
503 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
505 GET_CURRENT_CONTEXT( ctx
);
507 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
508 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
512 _mesa_update_state( ctx
);
514 CALL_Begin(ctx
->Exec
, (mode
));
518 if (!vbo_validate_shaders(ctx
)) {
519 _mesa_error(ctx
, GL_INVALID_OPERATION
,
520 "glBegin (invalid vertex/fragment program)");
524 /* Heuristic: attempt to isolate attributes occuring outside
527 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
528 vbo_exec_FlushVertices( ctx
, ~0 );
530 i
= exec
->vtx
.prim_count
++;
531 exec
->vtx
.prim
[i
].mode
= mode
;
532 exec
->vtx
.prim
[i
].begin
= 1;
533 exec
->vtx
.prim
[i
].end
= 0;
534 exec
->vtx
.prim
[i
].indexed
= 0;
535 exec
->vtx
.prim
[i
].weak
= 0;
536 exec
->vtx
.prim
[i
].pad
= 0;
537 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
538 exec
->vtx
.prim
[i
].count
= 0;
540 ctx
->Driver
.CurrentExecPrimitive
= mode
;
543 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
547 static void GLAPIENTRY
vbo_exec_End( void )
549 GET_CURRENT_CONTEXT( ctx
);
551 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
552 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
553 int idx
= exec
->vtx
.vert_count
;
554 int i
= exec
->vtx
.prim_count
- 1;
556 exec
->vtx
.prim
[i
].end
= 1;
557 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
559 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
561 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
562 vbo_exec_vtx_flush( exec
);
565 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
569 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
571 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
573 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
574 vfmt
->Begin
= vbo_exec_Begin
;
576 vfmt
->CallList
= _mesa_CallList
;
577 vfmt
->CallLists
= _mesa_CallLists
;
579 vfmt
->End
= vbo_exec_End
;
580 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
581 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
582 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
583 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
584 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
585 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
587 vfmt
->Rectf
= _mesa_noop_Rectf
;
588 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
589 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
592 /* from attrib_tmp.h:
594 vfmt
->Color3f
= vbo_Color3f
;
595 vfmt
->Color3fv
= vbo_Color3fv
;
596 vfmt
->Color4f
= vbo_Color4f
;
597 vfmt
->Color4fv
= vbo_Color4fv
;
598 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
599 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
600 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
601 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
602 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
603 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
604 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
605 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
606 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
607 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
608 vfmt
->Normal3f
= vbo_Normal3f
;
609 vfmt
->Normal3fv
= vbo_Normal3fv
;
610 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
611 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
612 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
613 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
614 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
615 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
616 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
617 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
618 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
619 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
620 vfmt
->Vertex2f
= vbo_Vertex2f
;
621 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
622 vfmt
->Vertex3f
= vbo_Vertex3f
;
623 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
624 vfmt
->Vertex4f
= vbo_Vertex4f
;
625 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
627 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
628 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
629 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
630 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
631 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
632 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
633 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
634 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
636 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
637 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
638 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
639 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
640 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
641 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
642 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
643 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
645 vfmt
->Materialfv
= vbo_Materialfv
;
647 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
648 vfmt
->Indexf
= vbo_Indexf
;
649 vfmt
->Indexfv
= vbo_Indexfv
;
655 * Tell the VBO module to use a real OpenGL vertex buffer object to
656 * store accumulated immediate-mode vertex data.
657 * This replaces the malloced buffer which was created in
658 * vb_exec_vtx_init() below.
660 void vbo_use_buffer_objects(GLcontext
*ctx
)
662 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
663 /* Any buffer name but 0 can be used here since this bufferobj won't
664 * go into the bufferobj hashtable.
666 GLuint bufName
= 0xaabbccdd;
667 GLenum target
= GL_ARRAY_BUFFER_ARB
;
668 GLenum access
= GL_READ_WRITE_ARB
;
669 GLenum usage
= GL_STREAM_DRAW_ARB
;
670 GLsizei size
= VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
);
672 /* Make sure this func is only used once */
673 assert(exec
->vtx
.bufferobj
== ctx
->Array
.NullBufferObj
);
674 if (exec
->vtx
.buffer_map
) {
675 _mesa_align_free(exec
->vtx
.buffer_map
);
678 /* Allocate a real buffer object now */
679 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
680 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
684 = ctx
->Driver
.MapBuffer(ctx
, target
, access
, exec
->vtx
.bufferobj
);
689 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
691 GLcontext
*ctx
= exec
->ctx
;
692 struct vbo_context
*vbo
= vbo_context(ctx
);
695 /* Allocate a buffer object. Will just reuse this object
698 _mesa_reference_buffer_object(ctx
,
699 &exec
->vtx
.bufferobj
,
700 ctx
->Array
.NullBufferObj
);
702 exec
->vtx
.buffer_map
= ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
), 64);
704 vbo_exec_vtxfmt_init( exec
);
706 /* Hook our functions into the dispatch table.
708 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
710 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
711 exec
->vtx
.attrsz
[i
] = 0;
712 exec
->vtx
.active_sz
[i
] = 0;
713 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
717 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
718 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
719 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
722 exec
->vtx
.vertex_size
= 0;
726 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
728 if (exec
->vtx
.buffer_map
) {
729 ALIGN_FREE(exec
->vtx
.buffer_map
);
730 exec
->vtx
.buffer_map
= NULL
;
735 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
737 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
739 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
742 if (exec
->vtx
.vert_count
) {
743 vbo_exec_vtx_flush( exec
);
746 if (exec
->vtx
.vertex_size
) {
747 vbo_exec_copy_to_current( exec
);
748 reset_attrfv( exec
);
751 exec
->ctx
->Driver
.NeedFlush
= 0;
755 static void reset_attrfv( struct vbo_exec_context
*exec
)
759 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
760 exec
->vtx
.attrsz
[i
] = 0;
761 exec
->vtx
.active_sz
[i
] = 0;
764 exec
->vtx
.vertex_size
= 0;