1 /**************************************************************************
3 Copyright 2002 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/context.h"
35 #include "main/macros.h"
36 #include "main/vtxfmt.h"
38 #include "main/dlist.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 static void reset_attrfv( struct vbo_exec_context
*exec
);
56 /* Close off the last primitive, execute the buffer, restart the
59 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
61 if (exec
->vtx
.prim_count
== 0) {
62 exec
->vtx
.copied
.nr
= 0;
63 exec
->vtx
.vert_count
= 0;
64 exec
->vtx
.vbptr
= (GLfloat
*)exec
->vtx
.buffer_map
;
67 GLuint last_begin
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].begin
;
70 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
71 GLint i
= exec
->vtx
.prim_count
- 1;
73 exec
->vtx
.prim
[i
].count
= (exec
->vtx
.vert_count
-
74 exec
->vtx
.prim
[i
].start
);
77 last_count
= exec
->vtx
.prim
[exec
->vtx
.prim_count
-1].count
;
79 /* Execute the buffer and save copied vertices.
81 if (exec
->vtx
.vert_count
)
82 vbo_exec_vtx_flush( exec
);
84 exec
->vtx
.prim_count
= 0;
85 exec
->vtx
.copied
.nr
= 0;
88 /* Emit a glBegin to start the new list.
90 assert(exec
->vtx
.prim_count
== 0);
92 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
93 exec
->vtx
.prim
[0].mode
= exec
->ctx
->Driver
.CurrentExecPrimitive
;
94 exec
->vtx
.prim
[0].start
= 0;
95 exec
->vtx
.prim
[0].count
= 0;
96 exec
->vtx
.prim_count
++;
98 if (exec
->vtx
.copied
.nr
== last_count
)
99 exec
->vtx
.prim
[0].begin
= last_begin
;
105 /* Deal with buffer wrapping where provoked by the vertex buffer
106 * filling up, as opposed to upgrade_vertex().
108 void vbo_exec_vtx_wrap( struct vbo_exec_context
*exec
)
110 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
113 /* Run pipeline on current vertices, copy wrapped vertices
114 * to exec->vtx.copied.
116 vbo_exec_wrap_buffers( exec
);
118 /* Copy stored stored vertices to start of new list.
120 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
122 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
123 _mesa_memcpy( exec
->vtx
.vbptr
, data
,
124 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
125 exec
->vtx
.vbptr
+= exec
->vtx
.vertex_size
;
126 data
+= exec
->vtx
.vertex_size
;
127 exec
->vtx
.vert_count
++;
130 exec
->vtx
.copied
.nr
= 0;
135 * Copy the active vertex's values to the ctx->Current fields.
137 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
139 GLcontext
*ctx
= exec
->ctx
;
140 struct vbo_context
*vbo
= vbo_context(ctx
);
143 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
144 if (exec
->vtx
.attrsz
[i
]) {
145 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
147 /* Note: the exec->vtx.current[i] pointers point into the
148 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
150 COPY_CLEAN_4V(current
,
152 exec
->vtx
.attrptr
[i
]);
155 /* Given that we explicitly state size here, there is no need
156 * for the COPY_CLEAN above, could just copy 16 bytes and be
157 * done. The only problem is when Mesa accesses ctx->Current
160 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
];
162 /* This triggers rather too much recalculation of Mesa state
163 * that doesn't get used (eg light positions).
165 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
166 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
167 ctx
->NewState
|= _NEW_LIGHT
;
171 /* Colormaterial -- this kindof sucks.
173 if (ctx
->Light
.ColorMaterialEnabled
&&
174 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
175 _mesa_update_color_material(ctx
,
176 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
179 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
183 static void vbo_exec_copy_from_current( struct vbo_exec_context
*exec
)
185 GLcontext
*ctx
= exec
->ctx
;
186 struct vbo_context
*vbo
= vbo_context(ctx
);
189 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
190 const GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
191 switch (exec
->vtx
.attrsz
[i
]) {
192 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
193 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
194 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
195 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
200 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
204 /* Flush existing data, set new attrib size, replay copied vertices.
206 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context
*exec
,
210 GLcontext
*ctx
= exec
->ctx
;
211 struct vbo_context
*vbo
= vbo_context(ctx
);
212 GLint lastcount
= exec
->vtx
.vert_count
;
217 /* Run pipeline on current vertices, copy wrapped vertices
218 * to exec->vtx.copied.
220 vbo_exec_wrap_buffers( exec
);
223 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
224 * when the attribute already exists in the vertex and is having
225 * its size increased.
227 vbo_exec_copy_to_current( exec
);
230 /* Heuristic: Attempt to isolate attributes received outside
231 * begin/end so that they don't bloat the vertices.
233 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
234 exec
->vtx
.attrsz
[attr
] == 0 &&
236 exec
->vtx
.vertex_size
) {
237 reset_attrfv( exec
);
242 oldsz
= exec
->vtx
.attrsz
[attr
];
243 exec
->vtx
.attrsz
[attr
] = newsz
;
245 exec
->vtx
.vertex_size
+= newsz
- oldsz
;
246 exec
->vtx
.max_vert
= VBO_VERT_BUFFER_SIZE
/ exec
->vtx
.vertex_size
;
247 exec
->vtx
.vert_count
= 0;
248 exec
->vtx
.vbptr
= (GLfloat
*)exec
->vtx
.buffer_map
;
251 /* Recalculate all the attrptr[] values
253 for (i
= 0, tmp
= exec
->vtx
.vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
254 if (exec
->vtx
.attrsz
[i
]) {
255 exec
->vtx
.attrptr
[i
] = tmp
;
256 tmp
+= exec
->vtx
.attrsz
[i
];
259 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
262 /* Copy from current to repopulate the vertex with correct values.
264 vbo_exec_copy_from_current( exec
);
266 /* Replay stored vertices to translate them
267 * to new format here.
269 * -- No need to replay - just copy piecewise
271 if (exec
->vtx
.copied
.nr
)
273 GLfloat
*data
= exec
->vtx
.copied
.buffer
;
274 GLfloat
*dest
= exec
->vtx
.vbptr
;
277 assert(exec
->vtx
.vbptr
== (GLfloat
*)exec
->vtx
.buffer_map
);
279 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
280 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
281 if (exec
->vtx
.attrsz
[j
]) {
284 COPY_CLEAN_4V( dest
, oldsz
, data
);
288 const GLfloat
*current
= (const GLfloat
*)vbo
->currval
[j
].Ptr
;
289 COPY_SZ_4V( dest
, newsz
, current
);
294 GLuint sz
= exec
->vtx
.attrsz
[j
];
295 COPY_SZ_4V( dest
, sz
, data
);
303 exec
->vtx
.vbptr
= dest
;
304 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
305 exec
->vtx
.copied
.nr
= 0;
310 static void vbo_exec_fixup_vertex( GLcontext
*ctx
,
311 GLuint attr
, GLuint sz
)
313 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
316 if (sz
> exec
->vtx
.attrsz
[attr
]) {
317 /* New size is larger. Need to flush existing vertices and get
318 * an enlarged vertex format.
320 vbo_exec_wrap_upgrade_vertex( exec
, attr
, sz
);
322 else if (sz
< exec
->vtx
.active_sz
[attr
]) {
323 static const GLfloat id
[4] = { 0, 0, 0, 1 };
325 /* New size is smaller - just need to fill in some
326 * zeros. Don't need to flush or wrap.
328 for (i
= sz
; i
<= exec
->vtx
.attrsz
[attr
] ; i
++)
329 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
332 exec
->vtx
.active_sz
[attr
] = sz
;
334 /* Does setting NeedFlush belong here? Necessitates resetting
335 * vtxfmt on each flush (otherwise flags won't get reset
339 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
341 exec
->ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
349 #define ATTR( A, N, V0, V1, V2, V3 ) \
351 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
353 if (exec->vtx.active_sz[A] != N) \
354 vbo_exec_fixup_vertex(ctx, A, N); \
357 GLfloat *dest = exec->vtx.attrptr[A]; \
358 if (N>0) dest[0] = V0; \
359 if (N>1) dest[1] = V1; \
360 if (N>2) dest[2] = V2; \
361 if (N>3) dest[3] = V3; \
367 for (i = 0; i < exec->vtx.vertex_size; i++) \
368 exec->vtx.vbptr[i] = exec->vtx.vertex[i]; \
370 exec->vtx.vbptr += exec->vtx.vertex_size; \
371 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
373 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
374 vbo_exec_vtx_wrap( exec ); \
379 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
380 #define TAG(x) vbo_##x
382 #include "vbo_attrib_tmp.h"
390 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
392 GET_CURRENT_CONTEXT( ctx
);
393 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
397 if (exec
->eval
.recalculate_maps
)
398 vbo_exec_eval_update( exec
);
400 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
401 if (exec
->eval
.map1
[i
].map
)
402 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
403 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
);
408 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
409 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
411 vbo_exec_do_EvalCoord1f( exec
, u
);
413 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
414 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
417 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
419 GET_CURRENT_CONTEXT( ctx
);
420 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
424 if (exec
->eval
.recalculate_maps
)
425 vbo_exec_eval_update( exec
);
427 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
428 if (exec
->eval
.map2
[i
].map
)
429 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
430 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
);
433 if (ctx
->Eval
.AutoNormal
)
434 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
435 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3 );
438 _mesa_memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
439 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
441 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
443 _mesa_memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
444 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
447 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
449 vbo_exec_EvalCoord1f( u
[0] );
452 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
454 vbo_exec_EvalCoord2f( u
[0], u
[1] );
457 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
459 GET_CURRENT_CONTEXT( ctx
);
460 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
461 (GLfloat
) ctx
->Eval
.MapGrid1un
);
462 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
464 vbo_exec_EvalCoord1f( u
);
468 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
470 GET_CURRENT_CONTEXT( ctx
);
471 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
472 (GLfloat
) ctx
->Eval
.MapGrid2un
);
473 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
474 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
475 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
476 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
478 vbo_exec_EvalCoord2f( u
, v
);
483 * Check if programs/shaders are enabled and valid at glBegin time.
486 vbo_validate_shaders(GLcontext
*ctx
)
488 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
489 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
492 if (ctx
->Shader
.CurrentProgram
&& !ctx
->Shader
.CurrentProgram
->LinkStatus
) {
499 /* Build a list of primitives on the fly. Keep
500 * ctx->Driver.CurrentExecPrimitive uptodate as well.
502 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
504 GET_CURRENT_CONTEXT( ctx
);
506 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
507 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
511 _mesa_update_state( ctx
);
513 CALL_Begin(ctx
->Exec
, (mode
));
517 if (!vbo_validate_shaders(ctx
)) {
518 _mesa_error(ctx
, GL_INVALID_OPERATION
,
519 "glBegin (invalid vertex/fragment program)");
523 /* Heuristic: attempt to isolate attributes occuring outside
526 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
527 vbo_exec_FlushVertices( ctx
, ~0 );
529 i
= exec
->vtx
.prim_count
++;
530 exec
->vtx
.prim
[i
].mode
= mode
;
531 exec
->vtx
.prim
[i
].begin
= 1;
532 exec
->vtx
.prim
[i
].end
= 0;
533 exec
->vtx
.prim
[i
].indexed
= 0;
534 exec
->vtx
.prim
[i
].weak
= 0;
535 exec
->vtx
.prim
[i
].pad
= 0;
536 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
537 exec
->vtx
.prim
[i
].count
= 0;
539 ctx
->Driver
.CurrentExecPrimitive
= mode
;
542 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
546 static void GLAPIENTRY
vbo_exec_End( void )
548 GET_CURRENT_CONTEXT( ctx
);
550 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
551 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
552 int idx
= exec
->vtx
.vert_count
;
553 int i
= exec
->vtx
.prim_count
- 1;
555 exec
->vtx
.prim
[i
].end
= 1;
556 exec
->vtx
.prim
[i
].count
= idx
- exec
->vtx
.prim
[i
].start
;
558 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
560 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
561 vbo_exec_vtx_flush( exec
);
564 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
568 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
570 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
572 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
573 vfmt
->Begin
= vbo_exec_Begin
;
575 vfmt
->CallList
= _mesa_CallList
;
576 vfmt
->CallLists
= _mesa_CallLists
;
578 vfmt
->End
= vbo_exec_End
;
579 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
580 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
581 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
582 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
583 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
584 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
586 vfmt
->Rectf
= _mesa_noop_Rectf
;
587 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
588 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
591 /* from attrib_tmp.h:
593 vfmt
->Color3f
= vbo_Color3f
;
594 vfmt
->Color3fv
= vbo_Color3fv
;
595 vfmt
->Color4f
= vbo_Color4f
;
596 vfmt
->Color4fv
= vbo_Color4fv
;
597 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
598 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
599 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
600 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
601 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
602 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
603 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
604 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
605 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
606 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
607 vfmt
->Normal3f
= vbo_Normal3f
;
608 vfmt
->Normal3fv
= vbo_Normal3fv
;
609 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
610 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
611 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
612 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
613 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
614 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
615 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
616 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
617 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
618 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
619 vfmt
->Vertex2f
= vbo_Vertex2f
;
620 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
621 vfmt
->Vertex3f
= vbo_Vertex3f
;
622 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
623 vfmt
->Vertex4f
= vbo_Vertex4f
;
624 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
626 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
627 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
628 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
629 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
630 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
631 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
632 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
633 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
635 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
636 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
637 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
638 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
639 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
640 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
641 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
642 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
644 vfmt
->Materialfv
= vbo_Materialfv
;
646 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
647 vfmt
->Indexf
= vbo_Indexf
;
648 vfmt
->Indexfv
= vbo_Indexfv
;
654 * Tell the VBO module to use a real OpenGL vertex buffer object to
655 * store accumulated immediate-mode vertex data.
656 * This replaces the malloced buffer which was created in
657 * vb_exec_vtx_init() below.
659 void vbo_use_buffer_objects(GLcontext
*ctx
)
661 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
662 /* Any buffer name but 0 can be used here since this bufferobj won't
663 * go into the bufferobj hashtable.
665 GLuint bufName
= 0xaabbccdd;
666 GLenum target
= GL_ARRAY_BUFFER_ARB
;
667 GLenum access
= GL_READ_WRITE_ARB
;
668 GLenum usage
= GL_STREAM_DRAW_ARB
;
669 GLsizei size
= VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
);
671 /* Make sure this func is only used once */
672 assert(exec
->vtx
.bufferobj
== ctx
->Array
.NullBufferObj
);
673 if (exec
->vtx
.buffer_map
) {
674 _mesa_align_free(exec
->vtx
.buffer_map
);
677 /* Allocate a real buffer object now */
678 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
, target
);
679 ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
, exec
->vtx
.bufferobj
);
683 = ctx
->Driver
.MapBuffer(ctx
, target
, access
, 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 exec
->vtx
.bufferobj
= ctx
->Array
.NullBufferObj
;
699 exec
->vtx
.buffer_map
= ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE
* sizeof(GLfloat
), 64);
701 vbo_exec_vtxfmt_init( exec
);
703 /* Hook our functions into the dispatch table.
705 _mesa_install_exec_vtxfmt( exec
->ctx
, &exec
->vtxfmt
);
707 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
708 exec
->vtx
.attrsz
[i
] = 0;
709 exec
->vtx
.active_sz
[i
] = 0;
710 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
714 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
715 memcpy(arrays
, vbo
->legacy_currval
, 16 * sizeof(arrays
[0]));
716 memcpy(arrays
+ 16, vbo
->generic_currval
, 16 * sizeof(arrays
[0]));
719 exec
->vtx
.vertex_size
= 0;
723 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
725 GLcontext
*ctx
= exec
->ctx
;
726 if (exec
->vtx
.bufferobj
->Name
) {
727 ctx
->Driver
.UnmapBuffer(ctx
, GL_ARRAY_BUFFER_ARB
, exec
->vtx
.bufferobj
);
728 ctx
->Driver
.DeleteBuffer(ctx
, exec
->vtx
.bufferobj
);
729 exec
->vtx
.bufferobj
= NULL
;
732 if (exec
->vtx
.buffer_map
) {
733 ALIGN_FREE(exec
->vtx
.buffer_map
);
734 exec
->vtx
.buffer_map
= NULL
;
740 void vbo_exec_FlushVertices( GLcontext
*ctx
, GLuint flags
)
742 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
744 if (exec
->ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
747 if (exec
->vtx
.vert_count
) {
748 vbo_exec_vtx_flush( exec
);
751 if (exec
->vtx
.vertex_size
) {
752 vbo_exec_copy_to_current( exec
);
753 reset_attrfv( exec
);
756 exec
->ctx
->Driver
.NeedFlush
= 0;
760 static void reset_attrfv( struct vbo_exec_context
*exec
)
764 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
765 exec
->vtx
.attrsz
[i
] = 0;
766 exec
->vtx
.active_sz
[i
] = 0;
769 exec
->vtx
.vertex_size
= 0;
774 _vbo_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
776 vbo_Color4f(r
, g
, b
, a
);
781 _vbo_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
783 vbo_Normal3f(x
, y
, z
);
788 _vbo_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
790 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
794 _vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
796 vbo_Materialfv(face
, pname
, params
);
801 _vbo_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
803 vbo_VertexAttrib4fARB(index
, x
, y
, z
, w
);