1 /**************************************************************************
3 Copyright 2002-2008 VMware, Inc.
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 VMWARE 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 <keithw@vmware.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"
38 #include "main/dlist.h"
39 #include "main/eval.h"
40 #include "main/state.h"
41 #include "main/light.h"
42 #include "main/api_arrayelt.h"
43 #include "main/api_validate.h"
44 #include "main/dispatch.h"
46 #include "vbo_context.h"
55 /** ID/name for immediate-mode VBO */
56 #define IMM_BUFFER_NAME 0xaabbccdd
59 static void reset_attrfv( struct vbo_exec_context
*exec
);
63 * Close off the last primitive, execute the buffer, restart the
64 * primitive. This is called when we fill a vertex buffer before
67 static void vbo_exec_wrap_buffers( struct vbo_exec_context
*exec
)
69 if (exec
->vtx
.prim_count
== 0) {
70 exec
->vtx
.copied
.nr
= 0;
71 exec
->vtx
.vert_count
= 0;
72 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
75 struct _mesa_prim
*last_prim
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 1];
76 const GLuint last_begin
= last_prim
->begin
;
79 if (_mesa_inside_begin_end(exec
->ctx
)) {
80 last_prim
->count
= exec
->vtx
.vert_count
- last_prim
->start
;
83 last_count
= last_prim
->count
;
85 /* Special handling for wrapping GL_LINE_LOOP */
86 if (last_prim
->mode
== GL_LINE_LOOP
&&
89 /* draw this section of the incomplete line loop as a line strip */
90 last_prim
->mode
= GL_LINE_STRIP
;
91 if (!last_prim
->begin
) {
92 /* This is not the first section of the line loop, so don't
93 * draw the 0th vertex. We're saving it until we draw the
94 * very last section of the loop.
101 /* Execute the buffer and save copied vertices.
103 if (exec
->vtx
.vert_count
)
104 vbo_exec_vtx_flush( exec
, GL_FALSE
);
106 exec
->vtx
.prim_count
= 0;
107 exec
->vtx
.copied
.nr
= 0;
110 /* Emit a glBegin to start the new list.
112 assert(exec
->vtx
.prim_count
== 0);
114 if (_mesa_inside_begin_end(exec
->ctx
)) {
115 exec
->vtx
.prim
[0].mode
= exec
->ctx
->Driver
.CurrentExecPrimitive
;
116 exec
->vtx
.prim
[0].begin
= 0;
117 exec
->vtx
.prim
[0].start
= 0;
118 exec
->vtx
.prim
[0].count
= 0;
119 exec
->vtx
.prim_count
++;
121 if (exec
->vtx
.copied
.nr
== last_count
)
122 exec
->vtx
.prim
[0].begin
= last_begin
;
129 * Deal with buffer wrapping where provoked by the vertex buffer
130 * filling up, as opposed to upgrade_vertex().
133 vbo_exec_vtx_wrap(struct vbo_exec_context
*exec
)
135 fi_type
*data
= exec
->vtx
.copied
.buffer
;
138 /* Run pipeline on current vertices, copy wrapped vertices
139 * to exec->vtx.copied.
141 vbo_exec_wrap_buffers( exec
);
143 if (!exec
->vtx
.buffer_ptr
) {
144 /* probably ran out of memory earlier when allocating the VBO */
148 /* Copy stored stored vertices to start of new list.
150 assert(exec
->vtx
.max_vert
- exec
->vtx
.vert_count
> exec
->vtx
.copied
.nr
);
152 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
153 memcpy( exec
->vtx
.buffer_ptr
, data
,
154 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
155 exec
->vtx
.buffer_ptr
+= exec
->vtx
.vertex_size
;
156 data
+= exec
->vtx
.vertex_size
;
157 exec
->vtx
.vert_count
++;
160 exec
->vtx
.copied
.nr
= 0;
165 * Copy the active vertex's values to the ctx->Current fields.
167 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
169 struct gl_context
*ctx
= exec
->ctx
;
170 struct vbo_context
*vbo
= vbo_context(ctx
);
173 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
174 if (exec
->vtx
.attrsz
[i
]) {
175 /* Note: the exec->vtx.current[i] pointers point into the
176 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
178 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
179 fi_type tmp
[8]; /* space for doubles */
180 int dmul
= exec
->vtx
.attrtype
[i
] == GL_DOUBLE
? 2 : 1;
182 if (exec
->vtx
.attrtype
[i
] == GL_DOUBLE
) {
183 memset(tmp
, 0, sizeof(tmp
));
184 memcpy(tmp
, exec
->vtx
.attrptr
[i
], exec
->vtx
.attrsz
[i
] * sizeof(GLfloat
));
186 COPY_CLEAN_4V_TYPE_AS_UNION(tmp
,
188 exec
->vtx
.attrptr
[i
],
189 exec
->vtx
.attrtype
[i
]);
192 if (exec
->vtx
.attrtype
[i
] != vbo
->currval
[i
].Type
||
193 memcmp(current
, tmp
, 4 * sizeof(GLfloat
) * dmul
) != 0) {
194 memcpy(current
, tmp
, 4 * sizeof(GLfloat
) * dmul
);
196 /* Given that we explicitly state size here, there is no need
197 * for the COPY_CLEAN above, could just copy 16 bytes and be
198 * done. The only problem is when Mesa accesses ctx->Current
201 /* Size here is in components - not bytes */
202 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
] / dmul
;
203 vbo
->currval
[i
]._ElementSize
= vbo
->currval
[i
].Size
* sizeof(GLfloat
) * dmul
;
204 vbo
->currval
[i
].Type
= exec
->vtx
.attrtype
[i
];
205 vbo
->currval
[i
].Integer
=
206 vbo_attrtype_to_integer_flag(exec
->vtx
.attrtype
[i
]);
207 vbo
->currval
[i
].Doubles
=
208 vbo_attrtype_to_double_flag(exec
->vtx
.attrtype
[i
]);
210 /* This triggers rather too much recalculation of Mesa state
211 * that doesn't get used (eg light positions).
213 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
214 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
215 ctx
->NewState
|= _NEW_LIGHT
;
217 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
222 /* Colormaterial -- this kindof sucks.
224 if (ctx
->Light
.ColorMaterialEnabled
&&
225 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
226 _mesa_update_color_material(ctx
,
227 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
233 * Copy current vertex attribute values into the current vertex.
236 vbo_exec_copy_from_current(struct vbo_exec_context
*exec
)
238 struct gl_context
*ctx
= exec
->ctx
;
239 struct vbo_context
*vbo
= vbo_context(ctx
);
242 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
243 if (exec
->vtx
.attrtype
[i
] == GL_DOUBLE
) {
244 memcpy(exec
->vtx
.attrptr
[i
], vbo
->currval
[i
].Ptr
, exec
->vtx
.attrsz
[i
] * sizeof(GLfloat
));
246 const fi_type
*current
= (fi_type
*) vbo
->currval
[i
].Ptr
;
247 switch (exec
->vtx
.attrsz
[i
]) {
248 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
249 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
250 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
251 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
260 * Flush existing data, set new attrib size, replay copied vertices.
261 * This is called when we transition from a small vertex attribute size
262 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
263 * We need to go back over the previous 2-component texcoords and insert
264 * zero and one values.
267 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context
*exec
,
268 GLuint attr
, GLuint newSize
)
270 struct gl_context
*ctx
= exec
->ctx
;
271 struct vbo_context
*vbo
= vbo_context(ctx
);
272 const GLint lastcount
= exec
->vtx
.vert_count
;
273 fi_type
*old_attrptr
[VBO_ATTRIB_MAX
];
274 const GLuint old_vtx_size
= exec
->vtx
.vertex_size
; /* floats per vertex */
275 const GLuint oldSize
= exec
->vtx
.attrsz
[attr
];
278 /* Run pipeline on current vertices, copy wrapped vertices
279 * to exec->vtx.copied.
281 vbo_exec_wrap_buffers( exec
);
283 if (unlikely(exec
->vtx
.copied
.nr
)) {
284 /* We're in the middle of a primitive, keep the old vertex
285 * format around to be able to translate the copied vertices to
288 memcpy(old_attrptr
, exec
->vtx
.attrptr
, sizeof(old_attrptr
));
291 if (unlikely(oldSize
)) {
292 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
293 * case when the attribute already exists in the vertex and is
294 * having its size increased.
296 vbo_exec_copy_to_current( exec
);
299 /* Heuristic: Attempt to isolate attributes received outside
300 * begin/end so that they don't bloat the vertices.
302 if (!_mesa_inside_begin_end(ctx
) &&
303 !oldSize
&& lastcount
> 8 && exec
->vtx
.vertex_size
) {
304 vbo_exec_copy_to_current( exec
);
305 reset_attrfv( exec
);
310 exec
->vtx
.attrsz
[attr
] = newSize
;
311 exec
->vtx
.vertex_size
+= newSize
- oldSize
;
312 exec
->vtx
.max_vert
= vbo_compute_max_verts(exec
);
313 exec
->vtx
.vert_count
= 0;
314 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
316 if (unlikely(oldSize
)) {
317 /* Size changed, recalculate all the attrptr[] values
319 fi_type
*tmp
= exec
->vtx
.vertex
;
321 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
322 if (exec
->vtx
.attrsz
[i
]) {
323 exec
->vtx
.attrptr
[i
] = tmp
;
324 tmp
+= exec
->vtx
.attrsz
[i
];
327 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
330 /* Copy from current to repopulate the vertex with correct
333 vbo_exec_copy_from_current( exec
);
336 /* Just have to append the new attribute at the end */
337 exec
->vtx
.attrptr
[attr
] = exec
->vtx
.vertex
+
338 exec
->vtx
.vertex_size
- newSize
;
341 /* Replay stored vertices to translate them
342 * to new format here.
344 * -- No need to replay - just copy piecewise
346 if (unlikely(exec
->vtx
.copied
.nr
)) {
347 fi_type
*data
= exec
->vtx
.copied
.buffer
;
348 fi_type
*dest
= exec
->vtx
.buffer_ptr
;
351 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
353 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
354 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
355 GLuint sz
= exec
->vtx
.attrsz
[j
];
358 GLint old_offset
= old_attrptr
[j
] - exec
->vtx
.vertex
;
359 GLint new_offset
= exec
->vtx
.attrptr
[j
] - exec
->vtx
.vertex
;
364 COPY_CLEAN_4V_TYPE_AS_UNION(tmp
, oldSize
,
366 exec
->vtx
.attrtype
[j
]);
367 COPY_SZ_4V(dest
+ new_offset
, newSize
, tmp
);
369 fi_type
*current
= (fi_type
*)vbo
->currval
[j
].Ptr
;
370 COPY_SZ_4V(dest
+ new_offset
, sz
, current
);
374 COPY_SZ_4V(dest
+ new_offset
, sz
, data
+ old_offset
);
379 data
+= old_vtx_size
;
380 dest
+= exec
->vtx
.vertex_size
;
383 exec
->vtx
.buffer_ptr
= dest
;
384 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
385 exec
->vtx
.copied
.nr
= 0;
391 * This is when a vertex attribute transitions to a different size.
392 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
393 * glTexCoord4f() call. We promote the array from size=2 to size=4.
394 * \param newSize size of new vertex (number of 32-bit words).
397 vbo_exec_fixup_vertex(struct gl_context
*ctx
, GLuint attr
,
398 GLuint newSize
, GLenum newType
)
400 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
402 if (newSize
> exec
->vtx
.attrsz
[attr
] ||
403 newType
!= exec
->vtx
.attrtype
[attr
]) {
404 /* New size is larger. Need to flush existing vertices and get
405 * an enlarged vertex format.
407 vbo_exec_wrap_upgrade_vertex( exec
, attr
, newSize
);
409 else if (newSize
< exec
->vtx
.active_sz
[attr
]) {
412 vbo_get_default_vals_as_union(exec
->vtx
.attrtype
[attr
]);
414 /* New size is smaller - just need to fill in some
415 * zeros. Don't need to flush or wrap.
417 for (i
= newSize
; i
<= exec
->vtx
.attrsz
[attr
]; i
++)
418 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
421 exec
->vtx
.active_sz
[attr
] = newSize
;
423 /* Does setting NeedFlush belong here? Necessitates resetting
424 * vtxfmt on each flush (otherwise flags won't get reset
428 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
433 * Called upon first glVertex, glColor, glTexCoord, etc.
436 vbo_exec_begin_vertices(struct gl_context
*ctx
)
438 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
440 vbo_exec_vtx_map( exec
);
442 assert((ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
443 assert(exec
->begin_vertices_flags
);
445 ctx
->Driver
.NeedFlush
|= exec
->begin_vertices_flags
;
450 * This macro is used to implement all the glVertex, glColor, glTexCoord,
451 * glVertexAttrib, etc functions.
452 * \param A attribute index
453 * \param N attribute size (1..4)
454 * \param T type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
455 * \param C cast type (fi_type or double)
456 * \param V0, V1, v2, V3 attribute value
458 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 ) \
460 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
461 int sz = (sizeof(C) / sizeof(GLfloat)); \
463 assert(sz == 1 || sz == 2); \
465 /* check if attribute size or type is changing */ \
466 if (unlikely(exec->vtx.active_sz[A] != N * sz) || \
467 unlikely(exec->vtx.attrtype[A] != T)) { \
468 vbo_exec_fixup_vertex(ctx, A, N * sz, T); \
471 /* store vertex attribute in vertex buffer */ \
473 C *dest = (C *)exec->vtx.attrptr[A]; \
474 if (N>0) dest[0] = V0; \
475 if (N>1) dest[1] = V1; \
476 if (N>2) dest[2] = V2; \
477 if (N>3) dest[3] = V3; \
478 exec->vtx.attrtype[A] = T; \
482 /* This is a glVertex call */ \
485 if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
486 vbo_exec_begin_vertices(ctx); \
489 if (unlikely(!exec->vtx.buffer_ptr)) { \
490 vbo_exec_vtx_map(exec); \
492 assert(exec->vtx.buffer_ptr); \
494 /* copy 32-bit words */ \
495 for (i = 0; i < exec->vtx.vertex_size; i++) \
496 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
498 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
500 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
501 /* something to draw (not just updating a color or texcoord).*/ \
502 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
504 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
505 vbo_exec_vtx_wrap( exec ); \
507 /* we now have accumulated per-vertex attributes */ \
508 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
512 #define ERROR(err) _mesa_error( ctx, err, __func__ )
513 #define TAG(x) vbo_##x
515 #include "vbo_attrib_tmp.h"
520 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
521 * this may be a (partial) no-op.
523 static void GLAPIENTRY
524 vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
526 GLbitfield updateMats
;
527 GET_CURRENT_CONTEXT(ctx
);
529 /* This function should be a no-op when it tries to update material
530 * attributes which are currently tracking glColor via glColorMaterial.
531 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
532 * indicating which material attributes can actually be updated below.
534 if (ctx
->Light
.ColorMaterialEnabled
) {
535 updateMats
= ~ctx
->Light
._ColorMaterialBitmask
;
538 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
539 updateMats
= ALL_MATERIAL_BITS
;
542 if (ctx
->API
== API_OPENGL_COMPAT
&& face
== GL_FRONT
) {
543 updateMats
&= FRONT_MATERIAL_BITS
;
545 else if (ctx
->API
== API_OPENGL_COMPAT
&& face
== GL_BACK
) {
546 updateMats
&= BACK_MATERIAL_BITS
;
548 else if (face
!= GL_FRONT_AND_BACK
) {
549 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterial(invalid face)");
555 if (updateMats
& MAT_BIT_FRONT_EMISSION
)
556 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, params
);
557 if (updateMats
& MAT_BIT_BACK_EMISSION
)
558 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION
, 4, params
);
561 if (updateMats
& MAT_BIT_FRONT_AMBIENT
)
562 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, params
);
563 if (updateMats
& MAT_BIT_BACK_AMBIENT
)
564 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT
, 4, params
);
567 if (updateMats
& MAT_BIT_FRONT_DIFFUSE
)
568 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, params
);
569 if (updateMats
& MAT_BIT_BACK_DIFFUSE
)
570 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE
, 4, params
);
573 if (updateMats
& MAT_BIT_FRONT_SPECULAR
)
574 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, params
);
575 if (updateMats
& MAT_BIT_BACK_SPECULAR
)
576 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR
, 4, params
);
579 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
580 _mesa_error(ctx
, GL_INVALID_VALUE
,
581 "glMaterial(invalid shininess: %f out range [0, %f])",
582 *params
, ctx
->Const
.MaxShininess
);
585 if (updateMats
& MAT_BIT_FRONT_SHININESS
)
586 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, params
);
587 if (updateMats
& MAT_BIT_BACK_SHININESS
)
588 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS
, 1, params
);
590 case GL_COLOR_INDEXES
:
591 if (ctx
->API
!= API_OPENGL_COMPAT
) {
592 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterialfv(pname)");
595 if (updateMats
& MAT_BIT_FRONT_INDEXES
)
596 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, params
);
597 if (updateMats
& MAT_BIT_BACK_INDEXES
)
598 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES
, 3, params
);
600 case GL_AMBIENT_AND_DIFFUSE
:
601 if (updateMats
& MAT_BIT_FRONT_AMBIENT
)
602 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, params
);
603 if (updateMats
& MAT_BIT_FRONT_DIFFUSE
)
604 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, params
);
605 if (updateMats
& MAT_BIT_BACK_AMBIENT
)
606 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT
, 4, params
);
607 if (updateMats
& MAT_BIT_BACK_DIFFUSE
)
608 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE
, 4, params
);
611 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterialfv(pname)");
618 * Flush (draw) vertices.
619 * \param unmap - leave VBO unmapped after flushing?
622 vbo_exec_FlushVertices_internal(struct vbo_exec_context
*exec
, GLboolean unmap
)
624 if (exec
->vtx
.vert_count
|| unmap
) {
625 vbo_exec_vtx_flush( exec
, unmap
);
628 if (exec
->vtx
.vertex_size
) {
629 vbo_exec_copy_to_current( exec
);
630 reset_attrfv( exec
);
635 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
637 GET_CURRENT_CONTEXT( ctx
);
638 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
642 if (exec
->eval
.recalculate_maps
)
643 vbo_exec_eval_update( exec
);
645 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
646 if (exec
->eval
.map1
[i
].map
)
647 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
648 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
, GL_FLOAT
);
653 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
654 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
656 vbo_exec_do_EvalCoord1f( exec
, u
);
658 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
659 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
662 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
664 GET_CURRENT_CONTEXT( ctx
);
665 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
669 if (exec
->eval
.recalculate_maps
)
670 vbo_exec_eval_update( exec
);
672 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
673 if (exec
->eval
.map2
[i
].map
)
674 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
675 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
, GL_FLOAT
);
678 if (ctx
->Eval
.AutoNormal
)
679 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
680 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3, GL_FLOAT
);
683 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
684 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
686 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
688 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
689 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
692 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
694 vbo_exec_EvalCoord1f( u
[0] );
697 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
699 vbo_exec_EvalCoord2f( u
[0], u
[1] );
702 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
704 GET_CURRENT_CONTEXT( ctx
);
705 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
706 (GLfloat
) ctx
->Eval
.MapGrid1un
);
707 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
709 vbo_exec_EvalCoord1f( u
);
713 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
715 GET_CURRENT_CONTEXT( ctx
);
716 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
717 (GLfloat
) ctx
->Eval
.MapGrid2un
);
718 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
719 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
720 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
721 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
723 vbo_exec_EvalCoord2f( u
, v
);
728 * Called via glBegin.
730 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
732 GET_CURRENT_CONTEXT( ctx
);
733 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
736 if (_mesa_inside_begin_end(ctx
)) {
737 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBegin");
741 if (!_mesa_valid_prim_mode(ctx
, mode
, "glBegin")) {
745 vbo_draw_method(vbo_context(ctx
), DRAW_BEGIN_END
);
748 _mesa_update_state( ctx
);
750 CALL_Begin(ctx
->Exec
, (mode
));
754 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
758 /* Heuristic: attempt to isolate attributes occurring outside
761 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
762 vbo_exec_FlushVertices_internal(exec
, GL_FALSE
);
764 i
= exec
->vtx
.prim_count
++;
765 exec
->vtx
.prim
[i
].mode
= mode
;
766 exec
->vtx
.prim
[i
].begin
= 1;
767 exec
->vtx
.prim
[i
].end
= 0;
768 exec
->vtx
.prim
[i
].indexed
= 0;
769 exec
->vtx
.prim
[i
].weak
= 0;
770 exec
->vtx
.prim
[i
].pad
= 0;
771 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
772 exec
->vtx
.prim
[i
].count
= 0;
773 exec
->vtx
.prim
[i
].num_instances
= 1;
774 exec
->vtx
.prim
[i
].base_instance
= 0;
775 exec
->vtx
.prim
[i
].is_indirect
= 0;
777 ctx
->Driver
.CurrentExecPrimitive
= mode
;
779 ctx
->Exec
= ctx
->BeginEnd
;
780 /* We may have been called from a display list, in which case we should
781 * leave dlist.c's dispatch table in place.
783 if (ctx
->CurrentDispatch
== ctx
->OutsideBeginEnd
) {
784 ctx
->CurrentDispatch
= ctx
->BeginEnd
;
785 _glapi_set_dispatch(ctx
->CurrentDispatch
);
787 assert(ctx
->CurrentDispatch
== ctx
->Save
);
793 * Try to merge / concatenate the two most recent VBO primitives.
796 try_vbo_merge(struct vbo_exec_context
*exec
)
798 struct _mesa_prim
*cur
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 1];
800 assert(exec
->vtx
.prim_count
>= 1);
802 vbo_try_prim_conversion(cur
);
804 if (exec
->vtx
.prim_count
>= 2) {
805 struct _mesa_prim
*prev
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 2];
806 assert(prev
== cur
- 1);
808 if (vbo_can_merge_prims(prev
, cur
)) {
813 vbo_merge_prims(prev
, cur
);
814 exec
->vtx
.prim_count
--; /* drop the last primitive */
823 static void GLAPIENTRY
vbo_exec_End( void )
825 GET_CURRENT_CONTEXT( ctx
);
826 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
828 if (!_mesa_inside_begin_end(ctx
)) {
829 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEnd");
833 ctx
->Exec
= ctx
->OutsideBeginEnd
;
834 if (ctx
->CurrentDispatch
== ctx
->BeginEnd
) {
835 ctx
->CurrentDispatch
= ctx
->OutsideBeginEnd
;
836 _glapi_set_dispatch(ctx
->CurrentDispatch
);
839 if (exec
->vtx
.prim_count
> 0) {
840 /* close off current primitive */
841 struct _mesa_prim
*last_prim
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 1];
844 last_prim
->count
= exec
->vtx
.vert_count
- last_prim
->start
;
846 /* Special handling for GL_LINE_LOOP */
847 if (last_prim
->mode
== GL_LINE_LOOP
&& last_prim
->begin
== 0) {
848 /* We're finishing drawing a line loop. Append 0th vertex onto
849 * end of vertex buffer so we can draw it as a line strip.
851 const fi_type
*src
= exec
->vtx
.buffer_map
;
852 fi_type
*dst
= exec
->vtx
.buffer_map
+
853 exec
->vtx
.vert_count
* exec
->vtx
.vertex_size
;
855 /* copy 0th vertex to end of buffer */
856 memcpy(dst
, src
, exec
->vtx
.vertex_size
* sizeof(fi_type
));
858 assert(last_prim
->start
== 0);
859 last_prim
->start
++; /* skip vertex0 */
860 /* note that last_prim->count stays unchanged */
861 last_prim
->mode
= GL_LINE_STRIP
;
867 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
869 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
870 vbo_exec_vtx_flush( exec
, GL_FALSE
);
872 if (MESA_DEBUG_FLAGS
& DEBUG_ALWAYS_FLUSH
) {
879 * Called via glPrimitiveRestartNV()
881 static void GLAPIENTRY
882 vbo_exec_PrimitiveRestartNV(void)
885 GET_CURRENT_CONTEXT( ctx
);
887 curPrim
= ctx
->Driver
.CurrentExecPrimitive
;
889 if (curPrim
== PRIM_OUTSIDE_BEGIN_END
) {
890 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glPrimitiveRestartNV" );
894 vbo_exec_Begin(curPrim
);
900 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
902 struct gl_context
*ctx
= exec
->ctx
;
903 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
905 vfmt
->ArrayElement
= _ae_ArrayElement
;
907 vfmt
->Begin
= vbo_exec_Begin
;
908 vfmt
->End
= vbo_exec_End
;
909 vfmt
->PrimitiveRestartNV
= vbo_exec_PrimitiveRestartNV
;
911 vfmt
->CallList
= _mesa_CallList
;
912 vfmt
->CallLists
= _mesa_CallLists
;
914 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
915 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
916 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
917 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
918 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
919 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
921 /* from attrib_tmp.h:
923 vfmt
->Color3f
= vbo_Color3f
;
924 vfmt
->Color3fv
= vbo_Color3fv
;
925 vfmt
->Color4f
= vbo_Color4f
;
926 vfmt
->Color4fv
= vbo_Color4fv
;
927 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
928 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
929 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
930 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
931 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
932 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
933 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
934 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
935 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
936 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
937 vfmt
->Normal3f
= vbo_Normal3f
;
938 vfmt
->Normal3fv
= vbo_Normal3fv
;
939 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
940 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
941 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
942 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
943 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
944 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
945 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
946 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
947 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
948 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
949 vfmt
->Vertex2f
= vbo_Vertex2f
;
950 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
951 vfmt
->Vertex3f
= vbo_Vertex3f
;
952 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
953 vfmt
->Vertex4f
= vbo_Vertex4f
;
954 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
956 if (ctx
->API
== API_OPENGLES2
) {
957 vfmt
->VertexAttrib1fARB
= _es_VertexAttrib1f
;
958 vfmt
->VertexAttrib1fvARB
= _es_VertexAttrib1fv
;
959 vfmt
->VertexAttrib2fARB
= _es_VertexAttrib2f
;
960 vfmt
->VertexAttrib2fvARB
= _es_VertexAttrib2fv
;
961 vfmt
->VertexAttrib3fARB
= _es_VertexAttrib3f
;
962 vfmt
->VertexAttrib3fvARB
= _es_VertexAttrib3fv
;
963 vfmt
->VertexAttrib4fARB
= _es_VertexAttrib4f
;
964 vfmt
->VertexAttrib4fvARB
= _es_VertexAttrib4fv
;
966 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
967 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
968 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
969 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
970 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
971 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
972 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
973 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
976 /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
977 * they can have a single entrypoint for updating any of the legacy
980 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
981 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
982 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
983 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
984 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
985 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
986 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
987 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
990 vfmt
->VertexAttribI1i
= vbo_VertexAttribI1i
;
991 vfmt
->VertexAttribI2i
= vbo_VertexAttribI2i
;
992 vfmt
->VertexAttribI3i
= vbo_VertexAttribI3i
;
993 vfmt
->VertexAttribI4i
= vbo_VertexAttribI4i
;
994 vfmt
->VertexAttribI2iv
= vbo_VertexAttribI2iv
;
995 vfmt
->VertexAttribI3iv
= vbo_VertexAttribI3iv
;
996 vfmt
->VertexAttribI4iv
= vbo_VertexAttribI4iv
;
998 /* unsigned integer-valued */
999 vfmt
->VertexAttribI1ui
= vbo_VertexAttribI1ui
;
1000 vfmt
->VertexAttribI2ui
= vbo_VertexAttribI2ui
;
1001 vfmt
->VertexAttribI3ui
= vbo_VertexAttribI3ui
;
1002 vfmt
->VertexAttribI4ui
= vbo_VertexAttribI4ui
;
1003 vfmt
->VertexAttribI2uiv
= vbo_VertexAttribI2uiv
;
1004 vfmt
->VertexAttribI3uiv
= vbo_VertexAttribI3uiv
;
1005 vfmt
->VertexAttribI4uiv
= vbo_VertexAttribI4uiv
;
1007 vfmt
->Materialfv
= vbo_Materialfv
;
1009 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
1010 vfmt
->Indexf
= vbo_Indexf
;
1011 vfmt
->Indexfv
= vbo_Indexfv
;
1013 /* ARB_vertex_type_2_10_10_10_rev */
1014 vfmt
->VertexP2ui
= vbo_VertexP2ui
;
1015 vfmt
->VertexP2uiv
= vbo_VertexP2uiv
;
1016 vfmt
->VertexP3ui
= vbo_VertexP3ui
;
1017 vfmt
->VertexP3uiv
= vbo_VertexP3uiv
;
1018 vfmt
->VertexP4ui
= vbo_VertexP4ui
;
1019 vfmt
->VertexP4uiv
= vbo_VertexP4uiv
;
1021 vfmt
->TexCoordP1ui
= vbo_TexCoordP1ui
;
1022 vfmt
->TexCoordP1uiv
= vbo_TexCoordP1uiv
;
1023 vfmt
->TexCoordP2ui
= vbo_TexCoordP2ui
;
1024 vfmt
->TexCoordP2uiv
= vbo_TexCoordP2uiv
;
1025 vfmt
->TexCoordP3ui
= vbo_TexCoordP3ui
;
1026 vfmt
->TexCoordP3uiv
= vbo_TexCoordP3uiv
;
1027 vfmt
->TexCoordP4ui
= vbo_TexCoordP4ui
;
1028 vfmt
->TexCoordP4uiv
= vbo_TexCoordP4uiv
;
1030 vfmt
->MultiTexCoordP1ui
= vbo_MultiTexCoordP1ui
;
1031 vfmt
->MultiTexCoordP1uiv
= vbo_MultiTexCoordP1uiv
;
1032 vfmt
->MultiTexCoordP2ui
= vbo_MultiTexCoordP2ui
;
1033 vfmt
->MultiTexCoordP2uiv
= vbo_MultiTexCoordP2uiv
;
1034 vfmt
->MultiTexCoordP3ui
= vbo_MultiTexCoordP3ui
;
1035 vfmt
->MultiTexCoordP3uiv
= vbo_MultiTexCoordP3uiv
;
1036 vfmt
->MultiTexCoordP4ui
= vbo_MultiTexCoordP4ui
;
1037 vfmt
->MultiTexCoordP4uiv
= vbo_MultiTexCoordP4uiv
;
1039 vfmt
->NormalP3ui
= vbo_NormalP3ui
;
1040 vfmt
->NormalP3uiv
= vbo_NormalP3uiv
;
1042 vfmt
->ColorP3ui
= vbo_ColorP3ui
;
1043 vfmt
->ColorP3uiv
= vbo_ColorP3uiv
;
1044 vfmt
->ColorP4ui
= vbo_ColorP4ui
;
1045 vfmt
->ColorP4uiv
= vbo_ColorP4uiv
;
1047 vfmt
->SecondaryColorP3ui
= vbo_SecondaryColorP3ui
;
1048 vfmt
->SecondaryColorP3uiv
= vbo_SecondaryColorP3uiv
;
1050 vfmt
->VertexAttribP1ui
= vbo_VertexAttribP1ui
;
1051 vfmt
->VertexAttribP1uiv
= vbo_VertexAttribP1uiv
;
1052 vfmt
->VertexAttribP2ui
= vbo_VertexAttribP2ui
;
1053 vfmt
->VertexAttribP2uiv
= vbo_VertexAttribP2uiv
;
1054 vfmt
->VertexAttribP3ui
= vbo_VertexAttribP3ui
;
1055 vfmt
->VertexAttribP3uiv
= vbo_VertexAttribP3uiv
;
1056 vfmt
->VertexAttribP4ui
= vbo_VertexAttribP4ui
;
1057 vfmt
->VertexAttribP4uiv
= vbo_VertexAttribP4uiv
;
1059 vfmt
->VertexAttribL1d
= vbo_VertexAttribL1d
;
1060 vfmt
->VertexAttribL2d
= vbo_VertexAttribL2d
;
1061 vfmt
->VertexAttribL3d
= vbo_VertexAttribL3d
;
1062 vfmt
->VertexAttribL4d
= vbo_VertexAttribL4d
;
1064 vfmt
->VertexAttribL1dv
= vbo_VertexAttribL1dv
;
1065 vfmt
->VertexAttribL2dv
= vbo_VertexAttribL2dv
;
1066 vfmt
->VertexAttribL3dv
= vbo_VertexAttribL3dv
;
1067 vfmt
->VertexAttribL4dv
= vbo_VertexAttribL4dv
;
1072 * Tell the VBO module to use a real OpenGL vertex buffer object to
1073 * store accumulated immediate-mode vertex data.
1074 * This replaces the malloced buffer which was created in
1075 * vb_exec_vtx_init() below.
1077 void vbo_use_buffer_objects(struct gl_context
*ctx
)
1079 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1080 /* Any buffer name but 0 can be used here since this bufferobj won't
1081 * go into the bufferobj hashtable.
1083 GLuint bufName
= IMM_BUFFER_NAME
;
1084 GLenum target
= GL_ARRAY_BUFFER_ARB
;
1085 GLenum usage
= GL_STREAM_DRAW_ARB
;
1086 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
1088 /* Make sure this func is only used once */
1089 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
1091 _mesa_align_free(exec
->vtx
.buffer_map
);
1092 exec
->vtx
.buffer_map
= NULL
;
1093 exec
->vtx
.buffer_ptr
= NULL
;
1095 /* Allocate a real buffer object now */
1096 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
1097 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
);
1098 if (!ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
,
1100 GL_DYNAMIC_STORAGE_BIT
|
1101 GL_CLIENT_STORAGE_BIT
,
1102 exec
->vtx
.bufferobj
)) {
1103 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "VBO allocation");
1109 * If this function is called, all VBO buffers will be unmapped when
1111 * Otherwise, if a simple command like glColor3f() is called and we flush,
1112 * the current VBO may be left mapped.
1115 vbo_always_unmap_buffers(struct gl_context
*ctx
)
1117 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1118 exec
->begin_vertices_flags
|= FLUSH_STORED_VERTICES
;
1122 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
1124 struct gl_context
*ctx
= exec
->ctx
;
1125 struct vbo_context
*vbo
= vbo_context(ctx
);
1128 /* Allocate a buffer object. Will just reuse this object
1129 * continuously, unless vbo_use_buffer_objects() is called to enable
1132 _mesa_reference_buffer_object(ctx
,
1133 &exec
->vtx
.bufferobj
,
1134 ctx
->Shared
->NullBufferObj
);
1136 assert(!exec
->vtx
.buffer_map
);
1137 exec
->vtx
.buffer_map
= _mesa_align_malloc(VBO_VERT_BUFFER_SIZE
, 64);
1138 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
1140 vbo_exec_vtxfmt_init( exec
);
1141 _mesa_noop_vtxfmt_init(&exec
->vtxfmt_noop
);
1143 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
1144 assert(i
< ARRAY_SIZE(exec
->vtx
.attrsz
));
1145 exec
->vtx
.attrsz
[i
] = 0;
1146 assert(i
< ARRAY_SIZE(exec
->vtx
.attrtype
));
1147 exec
->vtx
.attrtype
[i
] = GL_FLOAT
;
1148 assert(i
< ARRAY_SIZE(exec
->vtx
.active_sz
));
1149 exec
->vtx
.active_sz
[i
] = 0;
1151 for (i
= 0 ; i
< VERT_ATTRIB_MAX
; i
++) {
1152 assert(i
< ARRAY_SIZE(exec
->vtx
.inputs
));
1153 assert(i
< ARRAY_SIZE(exec
->vtx
.arrays
));
1154 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
1158 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
1161 memcpy(arrays
, &vbo
->currval
[VBO_ATTRIB_POS
],
1162 VERT_ATTRIB_FF_MAX
* sizeof(arrays
[0]));
1163 for (i
= 0; i
< VERT_ATTRIB_FF_MAX
; ++i
) {
1164 struct gl_client_array
*array
;
1165 array
= &arrays
[VERT_ATTRIB_FF(i
)];
1166 array
->BufferObj
= NULL
;
1167 _mesa_reference_buffer_object(ctx
, &array
->BufferObj
,
1168 vbo
->currval
[VBO_ATTRIB_POS
+i
].BufferObj
);
1171 memcpy(arrays
+ VERT_ATTRIB_GENERIC(0),
1172 &vbo
->currval
[VBO_ATTRIB_GENERIC0
],
1173 VERT_ATTRIB_GENERIC_MAX
* sizeof(arrays
[0]));
1175 for (i
= 0; i
< VERT_ATTRIB_GENERIC_MAX
; ++i
) {
1176 struct gl_client_array
*array
;
1177 array
= &arrays
[VERT_ATTRIB_GENERIC(i
)];
1178 array
->BufferObj
= NULL
;
1179 _mesa_reference_buffer_object(ctx
, &array
->BufferObj
,
1180 vbo
->currval
[VBO_ATTRIB_GENERIC0
+i
].BufferObj
);
1184 exec
->vtx
.vertex_size
= 0;
1186 exec
->begin_vertices_flags
= FLUSH_UPDATE_CURRENT
;
1190 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
1192 /* using a real VBO for vertex data */
1193 struct gl_context
*ctx
= exec
->ctx
;
1196 /* True VBOs should already be unmapped
1198 if (exec
->vtx
.buffer_map
) {
1199 assert(exec
->vtx
.bufferobj
->Name
== 0 ||
1200 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
1201 if (exec
->vtx
.bufferobj
->Name
== 0) {
1202 _mesa_align_free(exec
->vtx
.buffer_map
);
1203 exec
->vtx
.buffer_map
= NULL
;
1204 exec
->vtx
.buffer_ptr
= NULL
;
1208 /* Drop any outstanding reference to the vertex buffer
1210 for (i
= 0; i
< ARRAY_SIZE(exec
->vtx
.arrays
); i
++) {
1211 _mesa_reference_buffer_object(ctx
,
1212 &exec
->vtx
.arrays
[i
].BufferObj
,
1216 /* Free the vertex buffer. Unmap first if needed.
1218 if (_mesa_bufferobj_mapped(exec
->vtx
.bufferobj
, MAP_INTERNAL
)) {
1219 ctx
->Driver
.UnmapBuffer(ctx
, exec
->vtx
.bufferobj
, MAP_INTERNAL
);
1221 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
1226 * If inside glBegin()/glEnd(), it should assert(0). Otherwise, if
1227 * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1228 * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1229 * __struct gl_contextRec::Current and gl_light_attrib::Material
1231 * Note that the default T&L engine never clears the
1232 * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1234 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1236 void vbo_exec_FlushVertices( struct gl_context
*ctx
, GLuint flags
)
1238 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1241 /* debug check: make sure we don't get called recursively */
1242 exec
->flush_call_depth
++;
1243 assert(exec
->flush_call_depth
== 1);
1246 if (_mesa_inside_begin_end(ctx
)) {
1247 /* We've had glBegin but not glEnd! */
1249 exec
->flush_call_depth
--;
1250 assert(exec
->flush_call_depth
== 0);
1255 /* Flush (draw), and make sure VBO is left unmapped when done */
1256 vbo_exec_FlushVertices_internal(exec
, GL_TRUE
);
1258 /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1260 ctx
->Driver
.NeedFlush
&= ~(FLUSH_UPDATE_CURRENT
| flags
);
1263 exec
->flush_call_depth
--;
1264 assert(exec
->flush_call_depth
== 0);
1269 static void reset_attrfv( struct vbo_exec_context
*exec
)
1273 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
1274 exec
->vtx
.attrsz
[i
] = 0;
1275 exec
->vtx
.attrtype
[i
] = GL_FLOAT
;
1276 exec
->vtx
.active_sz
[i
] = 0;
1279 exec
->vtx
.vertex_size
= 0;
1284 _es_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
1286 vbo_Color4f(r
, g
, b
, a
);
1291 _es_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
1293 vbo_Normal3f(x
, y
, z
);
1298 _es_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
1300 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
1305 _es_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
1307 vbo_Materialfv(face
, pname
, params
);
1312 _es_Materialf(GLenum face
, GLenum pname
, GLfloat param
)
1316 p
[1] = p
[2] = p
[3] = 0.0F
;
1317 vbo_Materialfv(face
, pname
, p
);
1322 * A special version of glVertexAttrib4f that does not treat index 0 as
1326 VertexAttrib4f_nopos(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1328 GET_CURRENT_CONTEXT(ctx
);
1329 if (index
< MAX_VERTEX_GENERIC_ATTRIBS
)
1330 ATTRF(VBO_ATTRIB_GENERIC0
+ index
, 4, x
, y
, z
, w
);
1332 ERROR(GL_INVALID_VALUE
);
1336 _es_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1338 VertexAttrib4f_nopos(index
, x
, y
, z
, w
);
1343 _es_VertexAttrib1f(GLuint indx
, GLfloat x
)
1345 VertexAttrib4f_nopos(indx
, x
, 0.0f
, 0.0f
, 1.0f
);
1350 _es_VertexAttrib1fv(GLuint indx
, const GLfloat
* values
)
1352 VertexAttrib4f_nopos(indx
, values
[0], 0.0f
, 0.0f
, 1.0f
);
1357 _es_VertexAttrib2f(GLuint indx
, GLfloat x
, GLfloat y
)
1359 VertexAttrib4f_nopos(indx
, x
, y
, 0.0f
, 1.0f
);
1364 _es_VertexAttrib2fv(GLuint indx
, const GLfloat
* values
)
1366 VertexAttrib4f_nopos(indx
, values
[0], values
[1], 0.0f
, 1.0f
);
1371 _es_VertexAttrib3f(GLuint indx
, GLfloat x
, GLfloat y
, GLfloat z
)
1373 VertexAttrib4f_nopos(indx
, x
, y
, z
, 1.0f
);
1378 _es_VertexAttrib3fv(GLuint indx
, const GLfloat
* values
)
1380 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], 1.0f
);
1385 _es_VertexAttrib4fv(GLuint indx
, const GLfloat
* values
)
1387 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], values
[3]);