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].end
= 0;
118 exec
->vtx
.prim
[0].start
= 0;
119 exec
->vtx
.prim
[0].count
= 0;
120 exec
->vtx
.prim_count
++;
122 if (exec
->vtx
.copied
.nr
== last_count
)
123 exec
->vtx
.prim
[0].begin
= last_begin
;
130 * Deal with buffer wrapping where provoked by the vertex buffer
131 * filling up, as opposed to upgrade_vertex().
134 vbo_exec_vtx_wrap(struct vbo_exec_context
*exec
)
136 unsigned numComponents
;
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 numComponents
= exec
->vtx
.copied
.nr
* exec
->vtx
.vertex_size
;
153 memcpy(exec
->vtx
.buffer_ptr
,
154 exec
->vtx
.copied
.buffer
,
155 numComponents
* sizeof(fi_type
));
156 exec
->vtx
.buffer_ptr
+= numComponents
;
157 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
159 exec
->vtx
.copied
.nr
= 0;
164 * Copy the active vertex's values to the ctx->Current fields.
166 static void vbo_exec_copy_to_current( struct vbo_exec_context
*exec
)
168 struct gl_context
*ctx
= exec
->ctx
;
169 struct vbo_context
*vbo
= vbo_context(ctx
);
172 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
173 if (exec
->vtx
.attrsz
[i
]) {
174 /* Note: the exec->vtx.current[i] pointers point into the
175 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
177 GLfloat
*current
= (GLfloat
*)vbo
->currval
[i
].Ptr
;
178 fi_type tmp
[8]; /* space for doubles */
179 int dmul
= exec
->vtx
.attrtype
[i
] == GL_DOUBLE
? 2 : 1;
181 if (exec
->vtx
.attrtype
[i
] == GL_DOUBLE
) {
182 memset(tmp
, 0, sizeof(tmp
));
183 memcpy(tmp
, exec
->vtx
.attrptr
[i
], exec
->vtx
.attrsz
[i
] * sizeof(GLfloat
));
185 COPY_CLEAN_4V_TYPE_AS_UNION(tmp
,
187 exec
->vtx
.attrptr
[i
],
188 exec
->vtx
.attrtype
[i
]);
191 if (exec
->vtx
.attrtype
[i
] != vbo
->currval
[i
].Type
||
192 memcmp(current
, tmp
, 4 * sizeof(GLfloat
) * dmul
) != 0) {
193 memcpy(current
, tmp
, 4 * sizeof(GLfloat
) * dmul
);
195 /* Given that we explicitly state size here, there is no need
196 * for the COPY_CLEAN above, could just copy 16 bytes and be
197 * done. The only problem is when Mesa accesses ctx->Current
200 /* Size here is in components - not bytes */
201 vbo
->currval
[i
].Size
= exec
->vtx
.attrsz
[i
] / dmul
;
202 vbo
->currval
[i
]._ElementSize
= vbo
->currval
[i
].Size
* sizeof(GLfloat
) * dmul
;
203 vbo
->currval
[i
].Type
= exec
->vtx
.attrtype
[i
];
204 vbo
->currval
[i
].Integer
=
205 vbo_attrtype_to_integer_flag(exec
->vtx
.attrtype
[i
]);
206 vbo
->currval
[i
].Doubles
=
207 vbo_attrtype_to_double_flag(exec
->vtx
.attrtype
[i
]);
209 /* This triggers rather too much recalculation of Mesa state
210 * that doesn't get used (eg light positions).
212 if (i
>= VBO_ATTRIB_MAT_FRONT_AMBIENT
&&
213 i
<= VBO_ATTRIB_MAT_BACK_INDEXES
)
214 ctx
->NewState
|= _NEW_LIGHT
;
216 ctx
->NewState
|= _NEW_CURRENT_ATTRIB
;
221 /* Colormaterial -- this kindof sucks.
223 if (ctx
->Light
.ColorMaterialEnabled
&&
224 exec
->vtx
.attrsz
[VBO_ATTRIB_COLOR0
]) {
225 _mesa_update_color_material(ctx
,
226 ctx
->Current
.Attrib
[VBO_ATTRIB_COLOR0
]);
232 * Copy current vertex attribute values into the current vertex.
235 vbo_exec_copy_from_current(struct vbo_exec_context
*exec
)
237 struct gl_context
*ctx
= exec
->ctx
;
238 struct vbo_context
*vbo
= vbo_context(ctx
);
241 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
242 if (exec
->vtx
.attrtype
[i
] == GL_DOUBLE
) {
243 memcpy(exec
->vtx
.attrptr
[i
], vbo
->currval
[i
].Ptr
, exec
->vtx
.attrsz
[i
] * sizeof(GLfloat
));
245 const fi_type
*current
= (fi_type
*) vbo
->currval
[i
].Ptr
;
246 switch (exec
->vtx
.attrsz
[i
]) {
247 case 4: exec
->vtx
.attrptr
[i
][3] = current
[3];
248 case 3: exec
->vtx
.attrptr
[i
][2] = current
[2];
249 case 2: exec
->vtx
.attrptr
[i
][1] = current
[1];
250 case 1: exec
->vtx
.attrptr
[i
][0] = current
[0];
259 * Flush existing data, set new attrib size, replay copied vertices.
260 * This is called when we transition from a small vertex attribute size
261 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
262 * We need to go back over the previous 2-component texcoords and insert
263 * zero and one values.
266 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context
*exec
,
267 GLuint attr
, GLuint newSize
)
269 struct gl_context
*ctx
= exec
->ctx
;
270 struct vbo_context
*vbo
= vbo_context(ctx
);
271 const GLint lastcount
= exec
->vtx
.vert_count
;
272 fi_type
*old_attrptr
[VBO_ATTRIB_MAX
];
273 const GLuint old_vtx_size
= exec
->vtx
.vertex_size
; /* floats per vertex */
274 const GLuint oldSize
= exec
->vtx
.attrsz
[attr
];
277 /* Run pipeline on current vertices, copy wrapped vertices
278 * to exec->vtx.copied.
280 vbo_exec_wrap_buffers( exec
);
282 if (unlikely(exec
->vtx
.copied
.nr
)) {
283 /* We're in the middle of a primitive, keep the old vertex
284 * format around to be able to translate the copied vertices to
287 memcpy(old_attrptr
, exec
->vtx
.attrptr
, sizeof(old_attrptr
));
290 if (unlikely(oldSize
)) {
291 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
292 * case when the attribute already exists in the vertex and is
293 * having its size increased.
295 vbo_exec_copy_to_current( exec
);
298 /* Heuristic: Attempt to isolate attributes received outside
299 * begin/end so that they don't bloat the vertices.
301 if (!_mesa_inside_begin_end(ctx
) &&
302 !oldSize
&& lastcount
> 8 && exec
->vtx
.vertex_size
) {
303 vbo_exec_copy_to_current( exec
);
304 reset_attrfv( exec
);
309 exec
->vtx
.attrsz
[attr
] = newSize
;
310 exec
->vtx
.vertex_size
+= newSize
- oldSize
;
311 exec
->vtx
.max_vert
= vbo_compute_max_verts(exec
);
312 exec
->vtx
.vert_count
= 0;
313 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
315 if (unlikely(oldSize
)) {
316 /* Size changed, recalculate all the attrptr[] values
318 fi_type
*tmp
= exec
->vtx
.vertex
;
320 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
321 if (exec
->vtx
.attrsz
[i
]) {
322 exec
->vtx
.attrptr
[i
] = tmp
;
323 tmp
+= exec
->vtx
.attrsz
[i
];
326 exec
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
329 /* Copy from current to repopulate the vertex with correct
332 vbo_exec_copy_from_current( exec
);
335 /* Just have to append the new attribute at the end */
336 exec
->vtx
.attrptr
[attr
] = exec
->vtx
.vertex
+
337 exec
->vtx
.vertex_size
- newSize
;
340 /* Replay stored vertices to translate them
341 * to new format here.
343 * -- No need to replay - just copy piecewise
345 if (unlikely(exec
->vtx
.copied
.nr
)) {
346 fi_type
*data
= exec
->vtx
.copied
.buffer
;
347 fi_type
*dest
= exec
->vtx
.buffer_ptr
;
350 assert(exec
->vtx
.buffer_ptr
== exec
->vtx
.buffer_map
);
352 for (i
= 0 ; i
< exec
->vtx
.copied
.nr
; i
++) {
353 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
354 GLuint sz
= exec
->vtx
.attrsz
[j
];
357 GLint old_offset
= old_attrptr
[j
] - exec
->vtx
.vertex
;
358 GLint new_offset
= exec
->vtx
.attrptr
[j
] - exec
->vtx
.vertex
;
363 COPY_CLEAN_4V_TYPE_AS_UNION(tmp
, oldSize
,
365 exec
->vtx
.attrtype
[j
]);
366 COPY_SZ_4V(dest
+ new_offset
, newSize
, tmp
);
368 fi_type
*current
= (fi_type
*)vbo
->currval
[j
].Ptr
;
369 COPY_SZ_4V(dest
+ new_offset
, sz
, current
);
373 COPY_SZ_4V(dest
+ new_offset
, sz
, data
+ old_offset
);
378 data
+= old_vtx_size
;
379 dest
+= exec
->vtx
.vertex_size
;
382 exec
->vtx
.buffer_ptr
= dest
;
383 exec
->vtx
.vert_count
+= exec
->vtx
.copied
.nr
;
384 exec
->vtx
.copied
.nr
= 0;
390 * This is when a vertex attribute transitions to a different size.
391 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
392 * glTexCoord4f() call. We promote the array from size=2 to size=4.
393 * \param newSize size of new vertex (number of 32-bit words).
396 vbo_exec_fixup_vertex(struct gl_context
*ctx
, GLuint attr
,
397 GLuint newSize
, GLenum newType
)
399 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
401 if (newSize
> exec
->vtx
.attrsz
[attr
] ||
402 newType
!= exec
->vtx
.attrtype
[attr
]) {
403 /* New size is larger. Need to flush existing vertices and get
404 * an enlarged vertex format.
406 vbo_exec_wrap_upgrade_vertex( exec
, attr
, newSize
);
408 else if (newSize
< exec
->vtx
.active_sz
[attr
]) {
411 vbo_get_default_vals_as_union(exec
->vtx
.attrtype
[attr
]);
413 /* New size is smaller - just need to fill in some
414 * zeros. Don't need to flush or wrap.
416 for (i
= newSize
; i
<= exec
->vtx
.attrsz
[attr
]; i
++)
417 exec
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
420 exec
->vtx
.active_sz
[attr
] = newSize
;
422 /* Does setting NeedFlush belong here? Necessitates resetting
423 * vtxfmt on each flush (otherwise flags won't get reset
427 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
432 * Called upon first glVertex, glColor, glTexCoord, etc.
435 vbo_exec_begin_vertices(struct gl_context
*ctx
)
437 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
439 vbo_exec_vtx_map( exec
);
441 assert((ctx
->Driver
.NeedFlush
& FLUSH_UPDATE_CURRENT
) == 0);
442 assert(exec
->begin_vertices_flags
);
444 ctx
->Driver
.NeedFlush
|= exec
->begin_vertices_flags
;
449 * This macro is used to implement all the glVertex, glColor, glTexCoord,
450 * glVertexAttrib, etc functions.
451 * \param A attribute index
452 * \param N attribute size (1..4)
453 * \param T type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
454 * \param C cast type (fi_type or double)
455 * \param V0, V1, v2, V3 attribute value
457 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 ) \
459 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
460 int sz = (sizeof(C) / sizeof(GLfloat)); \
462 assert(sz == 1 || sz == 2); \
464 /* check if attribute size or type is changing */ \
465 if (unlikely(exec->vtx.active_sz[A] != N * sz) || \
466 unlikely(exec->vtx.attrtype[A] != T)) { \
467 vbo_exec_fixup_vertex(ctx, A, N * sz, T); \
470 /* store vertex attribute in vertex buffer */ \
472 C *dest = (C *)exec->vtx.attrptr[A]; \
473 if (N>0) dest[0] = V0; \
474 if (N>1) dest[1] = V1; \
475 if (N>2) dest[2] = V2; \
476 if (N>3) dest[3] = V3; \
477 exec->vtx.attrtype[A] = T; \
481 /* This is a glVertex call */ \
484 if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
485 vbo_exec_begin_vertices(ctx); \
488 if (unlikely(!exec->vtx.buffer_ptr)) { \
489 vbo_exec_vtx_map(exec); \
491 assert(exec->vtx.buffer_ptr); \
493 /* copy 32-bit words */ \
494 for (i = 0; i < exec->vtx.vertex_size; i++) \
495 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
497 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
499 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
500 /* something to draw (not just updating a color or texcoord).*/ \
501 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
503 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
504 vbo_exec_vtx_wrap( exec ); \
506 /* we now have accumulated per-vertex attributes */ \
507 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
511 #define ERROR(err) _mesa_error( ctx, err, __func__ )
512 #define TAG(x) vbo_##x
514 #include "vbo_attrib_tmp.h"
519 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
520 * this may be a (partial) no-op.
522 static void GLAPIENTRY
523 vbo_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
525 GLbitfield updateMats
;
526 GET_CURRENT_CONTEXT(ctx
);
528 /* This function should be a no-op when it tries to update material
529 * attributes which are currently tracking glColor via glColorMaterial.
530 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
531 * indicating which material attributes can actually be updated below.
533 if (ctx
->Light
.ColorMaterialEnabled
) {
534 updateMats
= ~ctx
->Light
._ColorMaterialBitmask
;
537 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
538 updateMats
= ALL_MATERIAL_BITS
;
541 if (ctx
->API
== API_OPENGL_COMPAT
&& face
== GL_FRONT
) {
542 updateMats
&= FRONT_MATERIAL_BITS
;
544 else if (ctx
->API
== API_OPENGL_COMPAT
&& face
== GL_BACK
) {
545 updateMats
&= BACK_MATERIAL_BITS
;
547 else if (face
!= GL_FRONT_AND_BACK
) {
548 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterial(invalid face)");
554 if (updateMats
& MAT_BIT_FRONT_EMISSION
)
555 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, params
);
556 if (updateMats
& MAT_BIT_BACK_EMISSION
)
557 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION
, 4, params
);
560 if (updateMats
& MAT_BIT_FRONT_AMBIENT
)
561 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, params
);
562 if (updateMats
& MAT_BIT_BACK_AMBIENT
)
563 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT
, 4, params
);
566 if (updateMats
& MAT_BIT_FRONT_DIFFUSE
)
567 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, params
);
568 if (updateMats
& MAT_BIT_BACK_DIFFUSE
)
569 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE
, 4, params
);
572 if (updateMats
& MAT_BIT_FRONT_SPECULAR
)
573 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, params
);
574 if (updateMats
& MAT_BIT_BACK_SPECULAR
)
575 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR
, 4, params
);
578 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
579 _mesa_error(ctx
, GL_INVALID_VALUE
,
580 "glMaterial(invalid shininess: %f out range [0, %f])",
581 *params
, ctx
->Const
.MaxShininess
);
584 if (updateMats
& MAT_BIT_FRONT_SHININESS
)
585 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, params
);
586 if (updateMats
& MAT_BIT_BACK_SHININESS
)
587 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS
, 1, params
);
589 case GL_COLOR_INDEXES
:
590 if (ctx
->API
!= API_OPENGL_COMPAT
) {
591 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterialfv(pname)");
594 if (updateMats
& MAT_BIT_FRONT_INDEXES
)
595 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, params
);
596 if (updateMats
& MAT_BIT_BACK_INDEXES
)
597 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES
, 3, params
);
599 case GL_AMBIENT_AND_DIFFUSE
:
600 if (updateMats
& MAT_BIT_FRONT_AMBIENT
)
601 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, params
);
602 if (updateMats
& MAT_BIT_FRONT_DIFFUSE
)
603 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, params
);
604 if (updateMats
& MAT_BIT_BACK_AMBIENT
)
605 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT
, 4, params
);
606 if (updateMats
& MAT_BIT_BACK_DIFFUSE
)
607 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE
, 4, params
);
610 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMaterialfv(pname)");
617 * Flush (draw) vertices.
618 * \param unmap - leave VBO unmapped after flushing?
621 vbo_exec_FlushVertices_internal(struct vbo_exec_context
*exec
, GLboolean unmap
)
623 if (exec
->vtx
.vert_count
|| unmap
) {
624 vbo_exec_vtx_flush( exec
, unmap
);
627 if (exec
->vtx
.vertex_size
) {
628 vbo_exec_copy_to_current( exec
);
629 reset_attrfv( exec
);
634 static void GLAPIENTRY
vbo_exec_EvalCoord1f( GLfloat u
)
636 GET_CURRENT_CONTEXT( ctx
);
637 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
641 if (exec
->eval
.recalculate_maps
)
642 vbo_exec_eval_update( exec
);
644 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
645 if (exec
->eval
.map1
[i
].map
)
646 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map1
[i
].sz
)
647 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map1
[i
].sz
, GL_FLOAT
);
652 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
653 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
655 vbo_exec_do_EvalCoord1f( exec
, u
);
657 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
658 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
661 static void GLAPIENTRY
vbo_exec_EvalCoord2f( GLfloat u
, GLfloat v
)
663 GET_CURRENT_CONTEXT( ctx
);
664 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
668 if (exec
->eval
.recalculate_maps
)
669 vbo_exec_eval_update( exec
);
671 for (i
= 0; i
<= VBO_ATTRIB_TEX7
; i
++) {
672 if (exec
->eval
.map2
[i
].map
)
673 if (exec
->vtx
.active_sz
[i
] != exec
->eval
.map2
[i
].sz
)
674 vbo_exec_fixup_vertex( ctx
, i
, exec
->eval
.map2
[i
].sz
, GL_FLOAT
);
677 if (ctx
->Eval
.AutoNormal
)
678 if (exec
->vtx
.active_sz
[VBO_ATTRIB_NORMAL
] != 3)
679 vbo_exec_fixup_vertex( ctx
, VBO_ATTRIB_NORMAL
, 3, GL_FLOAT
);
682 memcpy( exec
->vtx
.copied
.buffer
, exec
->vtx
.vertex
,
683 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
685 vbo_exec_do_EvalCoord2f( exec
, u
, v
);
687 memcpy( exec
->vtx
.vertex
, exec
->vtx
.copied
.buffer
,
688 exec
->vtx
.vertex_size
* sizeof(GLfloat
));
691 static void GLAPIENTRY
vbo_exec_EvalCoord1fv( const GLfloat
*u
)
693 vbo_exec_EvalCoord1f( u
[0] );
696 static void GLAPIENTRY
vbo_exec_EvalCoord2fv( const GLfloat
*u
)
698 vbo_exec_EvalCoord2f( u
[0], u
[1] );
701 static void GLAPIENTRY
vbo_exec_EvalPoint1( GLint i
)
703 GET_CURRENT_CONTEXT( ctx
);
704 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
705 (GLfloat
) ctx
->Eval
.MapGrid1un
);
706 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
708 vbo_exec_EvalCoord1f( u
);
712 static void GLAPIENTRY
vbo_exec_EvalPoint2( GLint i
, GLint j
)
714 GET_CURRENT_CONTEXT( ctx
);
715 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
716 (GLfloat
) ctx
->Eval
.MapGrid2un
);
717 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
718 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
719 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
720 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
722 vbo_exec_EvalCoord2f( u
, v
);
727 * Called via glBegin.
729 static void GLAPIENTRY
vbo_exec_Begin( GLenum mode
)
731 GET_CURRENT_CONTEXT( ctx
);
732 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
735 if (_mesa_inside_begin_end(ctx
)) {
736 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBegin");
740 if (!_mesa_valid_prim_mode(ctx
, mode
, "glBegin")) {
744 vbo_draw_method(vbo_context(ctx
), DRAW_BEGIN_END
);
747 _mesa_update_state( ctx
);
749 CALL_Begin(ctx
->Exec
, (mode
));
753 if (!_mesa_valid_to_render(ctx
, "glBegin")) {
757 /* Heuristic: attempt to isolate attributes occurring outside
760 if (exec
->vtx
.vertex_size
&& !exec
->vtx
.attrsz
[0])
761 vbo_exec_FlushVertices_internal(exec
, GL_FALSE
);
763 i
= exec
->vtx
.prim_count
++;
764 exec
->vtx
.prim
[i
].mode
= mode
;
765 exec
->vtx
.prim
[i
].begin
= 1;
766 exec
->vtx
.prim
[i
].end
= 0;
767 exec
->vtx
.prim
[i
].indexed
= 0;
768 exec
->vtx
.prim
[i
].weak
= 0;
769 exec
->vtx
.prim
[i
].pad
= 0;
770 exec
->vtx
.prim
[i
].start
= exec
->vtx
.vert_count
;
771 exec
->vtx
.prim
[i
].count
= 0;
772 exec
->vtx
.prim
[i
].num_instances
= 1;
773 exec
->vtx
.prim
[i
].base_instance
= 0;
774 exec
->vtx
.prim
[i
].is_indirect
= 0;
776 ctx
->Driver
.CurrentExecPrimitive
= mode
;
778 ctx
->Exec
= ctx
->BeginEnd
;
779 /* We may have been called from a display list, in which case we should
780 * leave dlist.c's dispatch table in place.
782 if (ctx
->CurrentDispatch
== ctx
->OutsideBeginEnd
) {
783 ctx
->CurrentDispatch
= ctx
->BeginEnd
;
784 _glapi_set_dispatch(ctx
->CurrentDispatch
);
786 assert(ctx
->CurrentDispatch
== ctx
->Save
);
792 * Try to merge / concatenate the two most recent VBO primitives.
795 try_vbo_merge(struct vbo_exec_context
*exec
)
797 struct _mesa_prim
*cur
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 1];
799 assert(exec
->vtx
.prim_count
>= 1);
801 vbo_try_prim_conversion(cur
);
803 if (exec
->vtx
.prim_count
>= 2) {
804 struct _mesa_prim
*prev
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 2];
805 assert(prev
== cur
- 1);
807 if (vbo_can_merge_prims(prev
, cur
)) {
812 vbo_merge_prims(prev
, cur
);
813 exec
->vtx
.prim_count
--; /* drop the last primitive */
822 static void GLAPIENTRY
vbo_exec_End( void )
824 GET_CURRENT_CONTEXT( ctx
);
825 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
827 if (!_mesa_inside_begin_end(ctx
)) {
828 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEnd");
832 ctx
->Exec
= ctx
->OutsideBeginEnd
;
833 if (ctx
->CurrentDispatch
== ctx
->BeginEnd
) {
834 ctx
->CurrentDispatch
= ctx
->OutsideBeginEnd
;
835 _glapi_set_dispatch(ctx
->CurrentDispatch
);
838 if (exec
->vtx
.prim_count
> 0) {
839 /* close off current primitive */
840 struct _mesa_prim
*last_prim
= &exec
->vtx
.prim
[exec
->vtx
.prim_count
- 1];
843 last_prim
->count
= exec
->vtx
.vert_count
- last_prim
->start
;
845 /* Special handling for GL_LINE_LOOP */
846 if (last_prim
->mode
== GL_LINE_LOOP
&& last_prim
->begin
== 0) {
847 /* We're finishing drawing a line loop. Append 0th vertex onto
848 * end of vertex buffer so we can draw it as a line strip.
850 const fi_type
*src
= exec
->vtx
.buffer_map
+
851 last_prim
->start
* exec
->vtx
.vertex_size
;
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 last_prim
->start
++; /* skip vertex0 */
859 /* note that last_prim->count stays unchanged */
860 last_prim
->mode
= GL_LINE_STRIP
;
862 /* Increment the vertex count so the next primitive doesn't
863 * overwrite the last vertex which we just added.
865 exec
->vtx
.vert_count
++;
866 exec
->vtx
.buffer_ptr
+= exec
->vtx
.vertex_size
;
872 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
874 if (exec
->vtx
.prim_count
== VBO_MAX_PRIM
)
875 vbo_exec_vtx_flush( exec
, GL_FALSE
);
877 if (MESA_DEBUG_FLAGS
& DEBUG_ALWAYS_FLUSH
) {
884 * Called via glPrimitiveRestartNV()
886 static void GLAPIENTRY
887 vbo_exec_PrimitiveRestartNV(void)
890 GET_CURRENT_CONTEXT( ctx
);
892 curPrim
= ctx
->Driver
.CurrentExecPrimitive
;
894 if (curPrim
== PRIM_OUTSIDE_BEGIN_END
) {
895 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glPrimitiveRestartNV" );
899 vbo_exec_Begin(curPrim
);
905 static void vbo_exec_vtxfmt_init( struct vbo_exec_context
*exec
)
907 struct gl_context
*ctx
= exec
->ctx
;
908 GLvertexformat
*vfmt
= &exec
->vtxfmt
;
910 vfmt
->ArrayElement
= _ae_ArrayElement
;
912 vfmt
->Begin
= vbo_exec_Begin
;
913 vfmt
->End
= vbo_exec_End
;
914 vfmt
->PrimitiveRestartNV
= vbo_exec_PrimitiveRestartNV
;
916 vfmt
->CallList
= _mesa_CallList
;
917 vfmt
->CallLists
= _mesa_CallLists
;
919 vfmt
->EvalCoord1f
= vbo_exec_EvalCoord1f
;
920 vfmt
->EvalCoord1fv
= vbo_exec_EvalCoord1fv
;
921 vfmt
->EvalCoord2f
= vbo_exec_EvalCoord2f
;
922 vfmt
->EvalCoord2fv
= vbo_exec_EvalCoord2fv
;
923 vfmt
->EvalPoint1
= vbo_exec_EvalPoint1
;
924 vfmt
->EvalPoint2
= vbo_exec_EvalPoint2
;
926 /* from attrib_tmp.h:
928 vfmt
->Color3f
= vbo_Color3f
;
929 vfmt
->Color3fv
= vbo_Color3fv
;
930 vfmt
->Color4f
= vbo_Color4f
;
931 vfmt
->Color4fv
= vbo_Color4fv
;
932 vfmt
->FogCoordfEXT
= vbo_FogCoordfEXT
;
933 vfmt
->FogCoordfvEXT
= vbo_FogCoordfvEXT
;
934 vfmt
->MultiTexCoord1fARB
= vbo_MultiTexCoord1f
;
935 vfmt
->MultiTexCoord1fvARB
= vbo_MultiTexCoord1fv
;
936 vfmt
->MultiTexCoord2fARB
= vbo_MultiTexCoord2f
;
937 vfmt
->MultiTexCoord2fvARB
= vbo_MultiTexCoord2fv
;
938 vfmt
->MultiTexCoord3fARB
= vbo_MultiTexCoord3f
;
939 vfmt
->MultiTexCoord3fvARB
= vbo_MultiTexCoord3fv
;
940 vfmt
->MultiTexCoord4fARB
= vbo_MultiTexCoord4f
;
941 vfmt
->MultiTexCoord4fvARB
= vbo_MultiTexCoord4fv
;
942 vfmt
->Normal3f
= vbo_Normal3f
;
943 vfmt
->Normal3fv
= vbo_Normal3fv
;
944 vfmt
->SecondaryColor3fEXT
= vbo_SecondaryColor3fEXT
;
945 vfmt
->SecondaryColor3fvEXT
= vbo_SecondaryColor3fvEXT
;
946 vfmt
->TexCoord1f
= vbo_TexCoord1f
;
947 vfmt
->TexCoord1fv
= vbo_TexCoord1fv
;
948 vfmt
->TexCoord2f
= vbo_TexCoord2f
;
949 vfmt
->TexCoord2fv
= vbo_TexCoord2fv
;
950 vfmt
->TexCoord3f
= vbo_TexCoord3f
;
951 vfmt
->TexCoord3fv
= vbo_TexCoord3fv
;
952 vfmt
->TexCoord4f
= vbo_TexCoord4f
;
953 vfmt
->TexCoord4fv
= vbo_TexCoord4fv
;
954 vfmt
->Vertex2f
= vbo_Vertex2f
;
955 vfmt
->Vertex2fv
= vbo_Vertex2fv
;
956 vfmt
->Vertex3f
= vbo_Vertex3f
;
957 vfmt
->Vertex3fv
= vbo_Vertex3fv
;
958 vfmt
->Vertex4f
= vbo_Vertex4f
;
959 vfmt
->Vertex4fv
= vbo_Vertex4fv
;
961 if (ctx
->API
== API_OPENGLES2
) {
962 vfmt
->VertexAttrib1fARB
= _es_VertexAttrib1f
;
963 vfmt
->VertexAttrib1fvARB
= _es_VertexAttrib1fv
;
964 vfmt
->VertexAttrib2fARB
= _es_VertexAttrib2f
;
965 vfmt
->VertexAttrib2fvARB
= _es_VertexAttrib2fv
;
966 vfmt
->VertexAttrib3fARB
= _es_VertexAttrib3f
;
967 vfmt
->VertexAttrib3fvARB
= _es_VertexAttrib3fv
;
968 vfmt
->VertexAttrib4fARB
= _es_VertexAttrib4f
;
969 vfmt
->VertexAttrib4fvARB
= _es_VertexAttrib4fv
;
971 vfmt
->VertexAttrib1fARB
= vbo_VertexAttrib1fARB
;
972 vfmt
->VertexAttrib1fvARB
= vbo_VertexAttrib1fvARB
;
973 vfmt
->VertexAttrib2fARB
= vbo_VertexAttrib2fARB
;
974 vfmt
->VertexAttrib2fvARB
= vbo_VertexAttrib2fvARB
;
975 vfmt
->VertexAttrib3fARB
= vbo_VertexAttrib3fARB
;
976 vfmt
->VertexAttrib3fvARB
= vbo_VertexAttrib3fvARB
;
977 vfmt
->VertexAttrib4fARB
= vbo_VertexAttrib4fARB
;
978 vfmt
->VertexAttrib4fvARB
= vbo_VertexAttrib4fvARB
;
981 /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
982 * they can have a single entrypoint for updating any of the legacy
985 vfmt
->VertexAttrib1fNV
= vbo_VertexAttrib1fNV
;
986 vfmt
->VertexAttrib1fvNV
= vbo_VertexAttrib1fvNV
;
987 vfmt
->VertexAttrib2fNV
= vbo_VertexAttrib2fNV
;
988 vfmt
->VertexAttrib2fvNV
= vbo_VertexAttrib2fvNV
;
989 vfmt
->VertexAttrib3fNV
= vbo_VertexAttrib3fNV
;
990 vfmt
->VertexAttrib3fvNV
= vbo_VertexAttrib3fvNV
;
991 vfmt
->VertexAttrib4fNV
= vbo_VertexAttrib4fNV
;
992 vfmt
->VertexAttrib4fvNV
= vbo_VertexAttrib4fvNV
;
995 vfmt
->VertexAttribI1i
= vbo_VertexAttribI1i
;
996 vfmt
->VertexAttribI2i
= vbo_VertexAttribI2i
;
997 vfmt
->VertexAttribI3i
= vbo_VertexAttribI3i
;
998 vfmt
->VertexAttribI4i
= vbo_VertexAttribI4i
;
999 vfmt
->VertexAttribI2iv
= vbo_VertexAttribI2iv
;
1000 vfmt
->VertexAttribI3iv
= vbo_VertexAttribI3iv
;
1001 vfmt
->VertexAttribI4iv
= vbo_VertexAttribI4iv
;
1003 /* unsigned integer-valued */
1004 vfmt
->VertexAttribI1ui
= vbo_VertexAttribI1ui
;
1005 vfmt
->VertexAttribI2ui
= vbo_VertexAttribI2ui
;
1006 vfmt
->VertexAttribI3ui
= vbo_VertexAttribI3ui
;
1007 vfmt
->VertexAttribI4ui
= vbo_VertexAttribI4ui
;
1008 vfmt
->VertexAttribI2uiv
= vbo_VertexAttribI2uiv
;
1009 vfmt
->VertexAttribI3uiv
= vbo_VertexAttribI3uiv
;
1010 vfmt
->VertexAttribI4uiv
= vbo_VertexAttribI4uiv
;
1012 vfmt
->Materialfv
= vbo_Materialfv
;
1014 vfmt
->EdgeFlag
= vbo_EdgeFlag
;
1015 vfmt
->Indexf
= vbo_Indexf
;
1016 vfmt
->Indexfv
= vbo_Indexfv
;
1018 /* ARB_vertex_type_2_10_10_10_rev */
1019 vfmt
->VertexP2ui
= vbo_VertexP2ui
;
1020 vfmt
->VertexP2uiv
= vbo_VertexP2uiv
;
1021 vfmt
->VertexP3ui
= vbo_VertexP3ui
;
1022 vfmt
->VertexP3uiv
= vbo_VertexP3uiv
;
1023 vfmt
->VertexP4ui
= vbo_VertexP4ui
;
1024 vfmt
->VertexP4uiv
= vbo_VertexP4uiv
;
1026 vfmt
->TexCoordP1ui
= vbo_TexCoordP1ui
;
1027 vfmt
->TexCoordP1uiv
= vbo_TexCoordP1uiv
;
1028 vfmt
->TexCoordP2ui
= vbo_TexCoordP2ui
;
1029 vfmt
->TexCoordP2uiv
= vbo_TexCoordP2uiv
;
1030 vfmt
->TexCoordP3ui
= vbo_TexCoordP3ui
;
1031 vfmt
->TexCoordP3uiv
= vbo_TexCoordP3uiv
;
1032 vfmt
->TexCoordP4ui
= vbo_TexCoordP4ui
;
1033 vfmt
->TexCoordP4uiv
= vbo_TexCoordP4uiv
;
1035 vfmt
->MultiTexCoordP1ui
= vbo_MultiTexCoordP1ui
;
1036 vfmt
->MultiTexCoordP1uiv
= vbo_MultiTexCoordP1uiv
;
1037 vfmt
->MultiTexCoordP2ui
= vbo_MultiTexCoordP2ui
;
1038 vfmt
->MultiTexCoordP2uiv
= vbo_MultiTexCoordP2uiv
;
1039 vfmt
->MultiTexCoordP3ui
= vbo_MultiTexCoordP3ui
;
1040 vfmt
->MultiTexCoordP3uiv
= vbo_MultiTexCoordP3uiv
;
1041 vfmt
->MultiTexCoordP4ui
= vbo_MultiTexCoordP4ui
;
1042 vfmt
->MultiTexCoordP4uiv
= vbo_MultiTexCoordP4uiv
;
1044 vfmt
->NormalP3ui
= vbo_NormalP3ui
;
1045 vfmt
->NormalP3uiv
= vbo_NormalP3uiv
;
1047 vfmt
->ColorP3ui
= vbo_ColorP3ui
;
1048 vfmt
->ColorP3uiv
= vbo_ColorP3uiv
;
1049 vfmt
->ColorP4ui
= vbo_ColorP4ui
;
1050 vfmt
->ColorP4uiv
= vbo_ColorP4uiv
;
1052 vfmt
->SecondaryColorP3ui
= vbo_SecondaryColorP3ui
;
1053 vfmt
->SecondaryColorP3uiv
= vbo_SecondaryColorP3uiv
;
1055 vfmt
->VertexAttribP1ui
= vbo_VertexAttribP1ui
;
1056 vfmt
->VertexAttribP1uiv
= vbo_VertexAttribP1uiv
;
1057 vfmt
->VertexAttribP2ui
= vbo_VertexAttribP2ui
;
1058 vfmt
->VertexAttribP2uiv
= vbo_VertexAttribP2uiv
;
1059 vfmt
->VertexAttribP3ui
= vbo_VertexAttribP3ui
;
1060 vfmt
->VertexAttribP3uiv
= vbo_VertexAttribP3uiv
;
1061 vfmt
->VertexAttribP4ui
= vbo_VertexAttribP4ui
;
1062 vfmt
->VertexAttribP4uiv
= vbo_VertexAttribP4uiv
;
1064 vfmt
->VertexAttribL1d
= vbo_VertexAttribL1d
;
1065 vfmt
->VertexAttribL2d
= vbo_VertexAttribL2d
;
1066 vfmt
->VertexAttribL3d
= vbo_VertexAttribL3d
;
1067 vfmt
->VertexAttribL4d
= vbo_VertexAttribL4d
;
1069 vfmt
->VertexAttribL1dv
= vbo_VertexAttribL1dv
;
1070 vfmt
->VertexAttribL2dv
= vbo_VertexAttribL2dv
;
1071 vfmt
->VertexAttribL3dv
= vbo_VertexAttribL3dv
;
1072 vfmt
->VertexAttribL4dv
= vbo_VertexAttribL4dv
;
1077 * Tell the VBO module to use a real OpenGL vertex buffer object to
1078 * store accumulated immediate-mode vertex data.
1079 * This replaces the malloced buffer which was created in
1080 * vb_exec_vtx_init() below.
1082 void vbo_use_buffer_objects(struct gl_context
*ctx
)
1084 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1085 /* Any buffer name but 0 can be used here since this bufferobj won't
1086 * go into the bufferobj hashtable.
1088 GLuint bufName
= IMM_BUFFER_NAME
;
1089 GLenum target
= GL_ARRAY_BUFFER_ARB
;
1090 GLenum usage
= GL_STREAM_DRAW_ARB
;
1091 GLsizei size
= VBO_VERT_BUFFER_SIZE
;
1093 /* Make sure this func is only used once */
1094 assert(exec
->vtx
.bufferobj
== ctx
->Shared
->NullBufferObj
);
1096 _mesa_align_free(exec
->vtx
.buffer_map
);
1097 exec
->vtx
.buffer_map
= NULL
;
1098 exec
->vtx
.buffer_ptr
= NULL
;
1100 /* Allocate a real buffer object now */
1101 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
1102 exec
->vtx
.bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, bufName
);
1103 if (!ctx
->Driver
.BufferData(ctx
, target
, size
, NULL
, usage
,
1105 GL_DYNAMIC_STORAGE_BIT
|
1106 GL_CLIENT_STORAGE_BIT
,
1107 exec
->vtx
.bufferobj
)) {
1108 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "VBO allocation");
1114 * If this function is called, all VBO buffers will be unmapped when
1116 * Otherwise, if a simple command like glColor3f() is called and we flush,
1117 * the current VBO may be left mapped.
1120 vbo_always_unmap_buffers(struct gl_context
*ctx
)
1122 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1123 exec
->begin_vertices_flags
|= FLUSH_STORED_VERTICES
;
1127 void vbo_exec_vtx_init( struct vbo_exec_context
*exec
)
1129 struct gl_context
*ctx
= exec
->ctx
;
1130 struct vbo_context
*vbo
= vbo_context(ctx
);
1133 /* Allocate a buffer object. Will just reuse this object
1134 * continuously, unless vbo_use_buffer_objects() is called to enable
1137 _mesa_reference_buffer_object(ctx
,
1138 &exec
->vtx
.bufferobj
,
1139 ctx
->Shared
->NullBufferObj
);
1141 assert(!exec
->vtx
.buffer_map
);
1142 exec
->vtx
.buffer_map
= _mesa_align_malloc(VBO_VERT_BUFFER_SIZE
, 64);
1143 exec
->vtx
.buffer_ptr
= exec
->vtx
.buffer_map
;
1145 vbo_exec_vtxfmt_init( exec
);
1146 _mesa_noop_vtxfmt_init(&exec
->vtxfmt_noop
);
1148 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
1149 assert(i
< ARRAY_SIZE(exec
->vtx
.attrsz
));
1150 exec
->vtx
.attrsz
[i
] = 0;
1151 assert(i
< ARRAY_SIZE(exec
->vtx
.attrtype
));
1152 exec
->vtx
.attrtype
[i
] = GL_FLOAT
;
1153 assert(i
< ARRAY_SIZE(exec
->vtx
.active_sz
));
1154 exec
->vtx
.active_sz
[i
] = 0;
1156 for (i
= 0 ; i
< VERT_ATTRIB_MAX
; i
++) {
1157 assert(i
< ARRAY_SIZE(exec
->vtx
.inputs
));
1158 assert(i
< ARRAY_SIZE(exec
->vtx
.arrays
));
1159 exec
->vtx
.inputs
[i
] = &exec
->vtx
.arrays
[i
];
1163 struct gl_client_array
*arrays
= exec
->vtx
.arrays
;
1166 memcpy(arrays
, &vbo
->currval
[VBO_ATTRIB_POS
],
1167 VERT_ATTRIB_FF_MAX
* sizeof(arrays
[0]));
1168 for (i
= 0; i
< VERT_ATTRIB_FF_MAX
; ++i
) {
1169 struct gl_client_array
*array
;
1170 array
= &arrays
[VERT_ATTRIB_FF(i
)];
1171 array
->BufferObj
= NULL
;
1172 _mesa_reference_buffer_object(ctx
, &array
->BufferObj
,
1173 vbo
->currval
[VBO_ATTRIB_POS
+i
].BufferObj
);
1176 memcpy(arrays
+ VERT_ATTRIB_GENERIC(0),
1177 &vbo
->currval
[VBO_ATTRIB_GENERIC0
],
1178 VERT_ATTRIB_GENERIC_MAX
* sizeof(arrays
[0]));
1180 for (i
= 0; i
< VERT_ATTRIB_GENERIC_MAX
; ++i
) {
1181 struct gl_client_array
*array
;
1182 array
= &arrays
[VERT_ATTRIB_GENERIC(i
)];
1183 array
->BufferObj
= NULL
;
1184 _mesa_reference_buffer_object(ctx
, &array
->BufferObj
,
1185 vbo
->currval
[VBO_ATTRIB_GENERIC0
+i
].BufferObj
);
1189 exec
->vtx
.vertex_size
= 0;
1191 exec
->begin_vertices_flags
= FLUSH_UPDATE_CURRENT
;
1195 void vbo_exec_vtx_destroy( struct vbo_exec_context
*exec
)
1197 /* using a real VBO for vertex data */
1198 struct gl_context
*ctx
= exec
->ctx
;
1201 /* True VBOs should already be unmapped
1203 if (exec
->vtx
.buffer_map
) {
1204 assert(exec
->vtx
.bufferobj
->Name
== 0 ||
1205 exec
->vtx
.bufferobj
->Name
== IMM_BUFFER_NAME
);
1206 if (exec
->vtx
.bufferobj
->Name
== 0) {
1207 _mesa_align_free(exec
->vtx
.buffer_map
);
1208 exec
->vtx
.buffer_map
= NULL
;
1209 exec
->vtx
.buffer_ptr
= NULL
;
1213 /* Drop any outstanding reference to the vertex buffer
1215 for (i
= 0; i
< ARRAY_SIZE(exec
->vtx
.arrays
); i
++) {
1216 _mesa_reference_buffer_object(ctx
,
1217 &exec
->vtx
.arrays
[i
].BufferObj
,
1221 /* Free the vertex buffer. Unmap first if needed.
1223 if (_mesa_bufferobj_mapped(exec
->vtx
.bufferobj
, MAP_INTERNAL
)) {
1224 ctx
->Driver
.UnmapBuffer(ctx
, exec
->vtx
.bufferobj
, MAP_INTERNAL
);
1226 _mesa_reference_buffer_object(ctx
, &exec
->vtx
.bufferobj
, NULL
);
1231 * If inside glBegin()/glEnd(), it should assert(0). Otherwise, if
1232 * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1233 * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1234 * __struct gl_contextRec::Current and gl_light_attrib::Material
1236 * Note that the default T&L engine never clears the
1237 * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1239 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1241 void vbo_exec_FlushVertices( struct gl_context
*ctx
, GLuint flags
)
1243 struct vbo_exec_context
*exec
= &vbo_context(ctx
)->exec
;
1246 /* debug check: make sure we don't get called recursively */
1247 exec
->flush_call_depth
++;
1248 assert(exec
->flush_call_depth
== 1);
1251 if (_mesa_inside_begin_end(ctx
)) {
1252 /* We've had glBegin but not glEnd! */
1254 exec
->flush_call_depth
--;
1255 assert(exec
->flush_call_depth
== 0);
1260 /* Flush (draw), and make sure VBO is left unmapped when done */
1261 vbo_exec_FlushVertices_internal(exec
, GL_TRUE
);
1263 /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1265 ctx
->Driver
.NeedFlush
&= ~(FLUSH_UPDATE_CURRENT
| flags
);
1268 exec
->flush_call_depth
--;
1269 assert(exec
->flush_call_depth
== 0);
1274 static void reset_attrfv( struct vbo_exec_context
*exec
)
1278 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
1279 exec
->vtx
.attrsz
[i
] = 0;
1280 exec
->vtx
.attrtype
[i
] = GL_FLOAT
;
1281 exec
->vtx
.active_sz
[i
] = 0;
1284 exec
->vtx
.vertex_size
= 0;
1289 _es_Color4f(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
)
1291 vbo_Color4f(r
, g
, b
, a
);
1296 _es_Normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
1298 vbo_Normal3f(x
, y
, z
);
1303 _es_MultiTexCoord4f(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
1305 vbo_MultiTexCoord4f(target
, s
, t
, r
, q
);
1310 _es_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
1312 vbo_Materialfv(face
, pname
, params
);
1317 _es_Materialf(GLenum face
, GLenum pname
, GLfloat param
)
1321 p
[1] = p
[2] = p
[3] = 0.0F
;
1322 vbo_Materialfv(face
, pname
, p
);
1327 * A special version of glVertexAttrib4f that does not treat index 0 as
1331 VertexAttrib4f_nopos(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1333 GET_CURRENT_CONTEXT(ctx
);
1334 if (index
< MAX_VERTEX_GENERIC_ATTRIBS
)
1335 ATTRF(VBO_ATTRIB_GENERIC0
+ index
, 4, x
, y
, z
, w
);
1337 ERROR(GL_INVALID_VALUE
);
1341 _es_VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1343 VertexAttrib4f_nopos(index
, x
, y
, z
, w
);
1348 _es_VertexAttrib1f(GLuint indx
, GLfloat x
)
1350 VertexAttrib4f_nopos(indx
, x
, 0.0f
, 0.0f
, 1.0f
);
1355 _es_VertexAttrib1fv(GLuint indx
, const GLfloat
* values
)
1357 VertexAttrib4f_nopos(indx
, values
[0], 0.0f
, 0.0f
, 1.0f
);
1362 _es_VertexAttrib2f(GLuint indx
, GLfloat x
, GLfloat y
)
1364 VertexAttrib4f_nopos(indx
, x
, y
, 0.0f
, 1.0f
);
1369 _es_VertexAttrib2fv(GLuint indx
, const GLfloat
* values
)
1371 VertexAttrib4f_nopos(indx
, values
[0], values
[1], 0.0f
, 1.0f
);
1376 _es_VertexAttrib3f(GLuint indx
, GLfloat x
, GLfloat y
, GLfloat z
)
1378 VertexAttrib4f_nopos(indx
, x
, y
, z
, 1.0f
);
1383 _es_VertexAttrib3fv(GLuint indx
, const GLfloat
* values
)
1385 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], 1.0f
);
1390 _es_VertexAttrib4fv(GLuint indx
, const GLfloat
* values
)
1392 VertexAttrib4f_nopos(indx
, values
[0], values
[1], values
[2], values
[3]);