vbo: fix another GL_LINE_LOOP bug
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 VMware, Inc.
4
5 All Rights Reserved.
6
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:
13
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
16 Software.
17
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.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keithw@vmware.com>
31 */
32
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"
45
46 #include "vbo_context.h"
47 #include "vbo_noop.h"
48
49
50 #ifdef ERROR
51 #undef ERROR
52 #endif
53
54
55 /** ID/name for immediate-mode VBO */
56 #define IMM_BUFFER_NAME 0xaabbccdd
57
58
59 static void reset_attrfv( struct vbo_exec_context *exec );
60
61
62 /**
63 * Close off the last primitive, execute the buffer, restart the
64 * primitive. This is called when we fill a vertex buffer before
65 * hitting glEnd.
66 */
67 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
68 {
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;
73 }
74 else {
75 struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
76 const GLuint last_begin = last_prim->begin;
77 GLuint last_count;
78
79 if (_mesa_inside_begin_end(exec->ctx)) {
80 last_prim->count = exec->vtx.vert_count - last_prim->start;
81 }
82
83 last_count = last_prim->count;
84
85 /* Special handling for wrapping GL_LINE_LOOP */
86 if (last_prim->mode == GL_LINE_LOOP &&
87 last_count > 0 &&
88 !last_prim->end) {
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.
95 */
96 last_prim->start++;
97 last_prim->count--;
98 }
99 }
100
101 /* Execute the buffer and save copied vertices.
102 */
103 if (exec->vtx.vert_count)
104 vbo_exec_vtx_flush( exec, GL_FALSE );
105 else {
106 exec->vtx.prim_count = 0;
107 exec->vtx.copied.nr = 0;
108 }
109
110 /* Emit a glBegin to start the new list.
111 */
112 assert(exec->vtx.prim_count == 0);
113
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++;
121
122 if (exec->vtx.copied.nr == last_count)
123 exec->vtx.prim[0].begin = last_begin;
124 }
125 }
126 }
127
128
129 /**
130 * Deal with buffer wrapping where provoked by the vertex buffer
131 * filling up, as opposed to upgrade_vertex().
132 */
133 static void
134 vbo_exec_vtx_wrap(struct vbo_exec_context *exec)
135 {
136 unsigned numComponents;
137
138 /* Run pipeline on current vertices, copy wrapped vertices
139 * to exec->vtx.copied.
140 */
141 vbo_exec_wrap_buffers( exec );
142
143 if (!exec->vtx.buffer_ptr) {
144 /* probably ran out of memory earlier when allocating the VBO */
145 return;
146 }
147
148 /* Copy stored stored vertices to start of new list.
149 */
150 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
151
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;
158
159 exec->vtx.copied.nr = 0;
160 }
161
162
163 /**
164 * Copy the active vertex's values to the ctx->Current fields.
165 */
166 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
167 {
168 struct gl_context *ctx = exec->ctx;
169 struct vbo_context *vbo = vbo_context(ctx);
170 GLuint i;
171
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.
176 */
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;
180
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));
184 } else {
185 COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
186 exec->vtx.attrsz[i],
187 exec->vtx.attrptr[i],
188 exec->vtx.attrtype[i]);
189 }
190
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);
194
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
198 * directly.
199 */
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]);
208
209 /* This triggers rather too much recalculation of Mesa state
210 * that doesn't get used (eg light positions).
211 */
212 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
213 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
214 ctx->NewState |= _NEW_LIGHT;
215
216 ctx->NewState |= _NEW_CURRENT_ATTRIB;
217 }
218 }
219 }
220
221 /* Colormaterial -- this kindof sucks.
222 */
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]);
227 }
228 }
229
230
231 /**
232 * Copy current vertex attribute values into the current vertex.
233 */
234 static void
235 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
236 {
237 struct gl_context *ctx = exec->ctx;
238 struct vbo_context *vbo = vbo_context(ctx);
239 GLint i;
240
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));
244 } else {
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];
251 break;
252 }
253 }
254 }
255 }
256
257
258 /**
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.
264 */
265 static void
266 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
267 GLuint attr, GLuint newSize )
268 {
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];
275 GLuint i;
276
277 /* Run pipeline on current vertices, copy wrapped vertices
278 * to exec->vtx.copied.
279 */
280 vbo_exec_wrap_buffers( exec );
281
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
285 * the new format.
286 */
287 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
288 }
289
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.
294 */
295 vbo_exec_copy_to_current( exec );
296 }
297
298 /* Heuristic: Attempt to isolate attributes received outside
299 * begin/end so that they don't bloat the vertices.
300 */
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 );
305 }
306
307 /* Fix up sizes:
308 */
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;
314
315 if (unlikely(oldSize)) {
316 /* Size changed, recalculate all the attrptr[] values
317 */
318 fi_type *tmp = exec->vtx.vertex;
319
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];
324 }
325 else
326 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
327 }
328
329 /* Copy from current to repopulate the vertex with correct
330 * values.
331 */
332 vbo_exec_copy_from_current( exec );
333 }
334 else {
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;
338 }
339
340 /* Replay stored vertices to translate them
341 * to new format here.
342 *
343 * -- No need to replay - just copy piecewise
344 */
345 if (unlikely(exec->vtx.copied.nr)) {
346 fi_type *data = exec->vtx.copied.buffer;
347 fi_type *dest = exec->vtx.buffer_ptr;
348 GLuint j;
349
350 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
351
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];
355
356 if (sz) {
357 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
358 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
359
360 if (j == attr) {
361 if (oldSize) {
362 fi_type tmp[4];
363 COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
364 data + old_offset,
365 exec->vtx.attrtype[j]);
366 COPY_SZ_4V(dest + new_offset, newSize, tmp);
367 } else {
368 fi_type *current = (fi_type *)vbo->currval[j].Ptr;
369 COPY_SZ_4V(dest + new_offset, sz, current);
370 }
371 }
372 else {
373 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
374 }
375 }
376 }
377
378 data += old_vtx_size;
379 dest += exec->vtx.vertex_size;
380 }
381
382 exec->vtx.buffer_ptr = dest;
383 exec->vtx.vert_count += exec->vtx.copied.nr;
384 exec->vtx.copied.nr = 0;
385 }
386 }
387
388
389 /**
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).
394 */
395 static void
396 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
397 GLuint newSize, GLenum newType)
398 {
399 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
400
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.
405 */
406 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
407 }
408 else if (newSize < exec->vtx.active_sz[attr]) {
409 GLuint i;
410 const fi_type *id =
411 vbo_get_default_vals_as_union(exec->vtx.attrtype[attr]);
412
413 /* New size is smaller - just need to fill in some
414 * zeros. Don't need to flush or wrap.
415 */
416 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
417 exec->vtx.attrptr[attr][i-1] = id[i-1];
418 }
419
420 exec->vtx.active_sz[attr] = newSize;
421
422 /* Does setting NeedFlush belong here? Necessitates resetting
423 * vtxfmt on each flush (otherwise flags won't get reset
424 * afterwards).
425 */
426 if (attr == 0)
427 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
428 }
429
430
431 /**
432 * Called upon first glVertex, glColor, glTexCoord, etc.
433 */
434 static void
435 vbo_exec_begin_vertices(struct gl_context *ctx)
436 {
437 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
438
439 vbo_exec_vtx_map( exec );
440
441 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
442 assert(exec->begin_vertices_flags);
443
444 ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
445 }
446
447
448 /**
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
456 */
457 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 ) \
458 do { \
459 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
460 int sz = (sizeof(C) / sizeof(GLfloat)); \
461 \
462 assert(sz == 1 || sz == 2); \
463 \
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); \
468 } \
469 \
470 /* store vertex attribute in vertex buffer */ \
471 { \
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; \
478 } \
479 \
480 if ((A) == 0) { \
481 /* This is a glVertex call */ \
482 GLuint i; \
483 \
484 if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
485 vbo_exec_begin_vertices(ctx); \
486 } \
487 \
488 if (unlikely(!exec->vtx.buffer_ptr)) { \
489 vbo_exec_vtx_map(exec); \
490 } \
491 assert(exec->vtx.buffer_ptr); \
492 \
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]; \
496 \
497 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
498 \
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; \
502 \
503 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
504 vbo_exec_vtx_wrap( exec ); \
505 } else { \
506 /* we now have accumulated per-vertex attributes */ \
507 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
508 } \
509 } while (0)
510
511 #define ERROR(err) _mesa_error( ctx, err, __func__ )
512 #define TAG(x) vbo_##x
513
514 #include "vbo_attrib_tmp.h"
515
516
517
518 /**
519 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
520 * this may be a (partial) no-op.
521 */
522 static void GLAPIENTRY
523 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
524 {
525 GLbitfield updateMats;
526 GET_CURRENT_CONTEXT(ctx);
527
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.
532 */
533 if (ctx->Light.ColorMaterialEnabled) {
534 updateMats = ~ctx->Light._ColorMaterialBitmask;
535 }
536 else {
537 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
538 updateMats = ALL_MATERIAL_BITS;
539 }
540
541 if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
542 updateMats &= FRONT_MATERIAL_BITS;
543 }
544 else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
545 updateMats &= BACK_MATERIAL_BITS;
546 }
547 else if (face != GL_FRONT_AND_BACK) {
548 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
549 return;
550 }
551
552 switch (pname) {
553 case GL_EMISSION:
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);
558 break;
559 case GL_AMBIENT:
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);
564 break;
565 case GL_DIFFUSE:
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);
570 break;
571 case GL_SPECULAR:
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);
576 break;
577 case GL_SHININESS:
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);
582 return;
583 }
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);
588 break;
589 case GL_COLOR_INDEXES:
590 if (ctx->API != API_OPENGL_COMPAT) {
591 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
592 return;
593 }
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);
598 break;
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);
608 break;
609 default:
610 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
611 return;
612 }
613 }
614
615
616 /**
617 * Flush (draw) vertices.
618 * \param unmap - leave VBO unmapped after flushing?
619 */
620 static void
621 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
622 {
623 if (exec->vtx.vert_count || unmap) {
624 vbo_exec_vtx_flush( exec, unmap );
625 }
626
627 if (exec->vtx.vertex_size) {
628 vbo_exec_copy_to_current( exec );
629 reset_attrfv( exec );
630 }
631 }
632
633
634 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
635 {
636 GET_CURRENT_CONTEXT( ctx );
637 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
638
639 {
640 GLint i;
641 if (exec->eval.recalculate_maps)
642 vbo_exec_eval_update( exec );
643
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 );
648 }
649 }
650
651
652 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
653 exec->vtx.vertex_size * sizeof(GLfloat));
654
655 vbo_exec_do_EvalCoord1f( exec, u );
656
657 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
658 exec->vtx.vertex_size * sizeof(GLfloat));
659 }
660
661 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
662 {
663 GET_CURRENT_CONTEXT( ctx );
664 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
665
666 {
667 GLint i;
668 if (exec->eval.recalculate_maps)
669 vbo_exec_eval_update( exec );
670
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 );
675 }
676
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 );
680 }
681
682 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
683 exec->vtx.vertex_size * sizeof(GLfloat));
684
685 vbo_exec_do_EvalCoord2f( exec, u, v );
686
687 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
688 exec->vtx.vertex_size * sizeof(GLfloat));
689 }
690
691 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
692 {
693 vbo_exec_EvalCoord1f( u[0] );
694 }
695
696 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
697 {
698 vbo_exec_EvalCoord2f( u[0], u[1] );
699 }
700
701 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
702 {
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;
707
708 vbo_exec_EvalCoord1f( u );
709 }
710
711
712 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
713 {
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;
721
722 vbo_exec_EvalCoord2f( u, v );
723 }
724
725
726 /**
727 * Called via glBegin.
728 */
729 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
730 {
731 GET_CURRENT_CONTEXT( ctx );
732 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
733 int i;
734
735 if (_mesa_inside_begin_end(ctx)) {
736 _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
737 return;
738 }
739
740 if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
741 return;
742 }
743
744 vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
745
746 if (ctx->NewState) {
747 _mesa_update_state( ctx );
748
749 CALL_Begin(ctx->Exec, (mode));
750 return;
751 }
752
753 if (!_mesa_valid_to_render(ctx, "glBegin")) {
754 return;
755 }
756
757 /* Heuristic: attempt to isolate attributes occurring outside
758 * begin/end pairs.
759 */
760 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
761 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
762
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;
775
776 ctx->Driver.CurrentExecPrimitive = mode;
777
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.
781 */
782 if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
783 ctx->CurrentDispatch = ctx->BeginEnd;
784 _glapi_set_dispatch(ctx->CurrentDispatch);
785 } else {
786 assert(ctx->CurrentDispatch == ctx->Save);
787 }
788 }
789
790
791 /**
792 * Try to merge / concatenate the two most recent VBO primitives.
793 */
794 static void
795 try_vbo_merge(struct vbo_exec_context *exec)
796 {
797 struct _mesa_prim *cur = &exec->vtx.prim[exec->vtx.prim_count - 1];
798
799 assert(exec->vtx.prim_count >= 1);
800
801 vbo_try_prim_conversion(cur);
802
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);
806
807 if (vbo_can_merge_prims(prev, cur)) {
808 assert(cur->begin);
809 assert(cur->end);
810 assert(prev->begin);
811 assert(prev->end);
812 vbo_merge_prims(prev, cur);
813 exec->vtx.prim_count--; /* drop the last primitive */
814 }
815 }
816 }
817
818
819 /**
820 * Called via glEnd.
821 */
822 static void GLAPIENTRY vbo_exec_End( void )
823 {
824 GET_CURRENT_CONTEXT( ctx );
825 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
826
827 if (!_mesa_inside_begin_end(ctx)) {
828 _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
829 return;
830 }
831
832 ctx->Exec = ctx->OutsideBeginEnd;
833 if (ctx->CurrentDispatch == ctx->BeginEnd) {
834 ctx->CurrentDispatch = ctx->OutsideBeginEnd;
835 _glapi_set_dispatch(ctx->CurrentDispatch);
836 }
837
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];
841
842 last_prim->end = 1;
843 last_prim->count = exec->vtx.vert_count - last_prim->start;
844
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.
849 */
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;
854
855 /* copy 0th vertex to end of buffer */
856 memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
857
858 last_prim->start++; /* skip vertex0 */
859 /* note that last_prim->count stays unchanged */
860 last_prim->mode = GL_LINE_STRIP;
861
862 /* Increment the vertex count so the next primitive doesn't
863 * overwrite the last vertex which we just added.
864 */
865 exec->vtx.vert_count++;
866 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
867 }
868
869 try_vbo_merge(exec);
870 }
871
872 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
873
874 if (exec->vtx.prim_count == VBO_MAX_PRIM)
875 vbo_exec_vtx_flush( exec, GL_FALSE );
876
877 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
878 _mesa_flush(ctx);
879 }
880 }
881
882
883 /**
884 * Called via glPrimitiveRestartNV()
885 */
886 static void GLAPIENTRY
887 vbo_exec_PrimitiveRestartNV(void)
888 {
889 GLenum curPrim;
890 GET_CURRENT_CONTEXT( ctx );
891
892 curPrim = ctx->Driver.CurrentExecPrimitive;
893
894 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
895 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
896 }
897 else {
898 vbo_exec_End();
899 vbo_exec_Begin(curPrim);
900 }
901 }
902
903
904
905 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
906 {
907 struct gl_context *ctx = exec->ctx;
908 GLvertexformat *vfmt = &exec->vtxfmt;
909
910 vfmt->ArrayElement = _ae_ArrayElement;
911
912 vfmt->Begin = vbo_exec_Begin;
913 vfmt->End = vbo_exec_End;
914 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
915
916 vfmt->CallList = _mesa_CallList;
917 vfmt->CallLists = _mesa_CallLists;
918
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;
925
926 /* from attrib_tmp.h:
927 */
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;
960
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;
970 } else {
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;
979 }
980
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
983 * attribs.
984 */
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;
993
994 /* integer-valued */
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;
1002
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;
1011
1012 vfmt->Materialfv = vbo_Materialfv;
1013
1014 vfmt->EdgeFlag = vbo_EdgeFlag;
1015 vfmt->Indexf = vbo_Indexf;
1016 vfmt->Indexfv = vbo_Indexfv;
1017
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;
1025
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;
1034
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;
1043
1044 vfmt->NormalP3ui = vbo_NormalP3ui;
1045 vfmt->NormalP3uiv = vbo_NormalP3uiv;
1046
1047 vfmt->ColorP3ui = vbo_ColorP3ui;
1048 vfmt->ColorP3uiv = vbo_ColorP3uiv;
1049 vfmt->ColorP4ui = vbo_ColorP4ui;
1050 vfmt->ColorP4uiv = vbo_ColorP4uiv;
1051
1052 vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
1053 vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
1054
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;
1063
1064 vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
1065 vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
1066 vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
1067 vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
1068
1069 vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
1070 vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
1071 vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
1072 vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
1073 }
1074
1075
1076 /**
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.
1081 */
1082 void vbo_use_buffer_objects(struct gl_context *ctx)
1083 {
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.
1087 */
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;
1092
1093 /* Make sure this func is only used once */
1094 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1095
1096 _mesa_align_free(exec->vtx.buffer_map);
1097 exec->vtx.buffer_map = NULL;
1098 exec->vtx.buffer_ptr = NULL;
1099
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,
1104 GL_MAP_WRITE_BIT |
1105 GL_DYNAMIC_STORAGE_BIT |
1106 GL_CLIENT_STORAGE_BIT,
1107 exec->vtx.bufferobj)) {
1108 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1109 }
1110 }
1111
1112
1113 /**
1114 * If this function is called, all VBO buffers will be unmapped when
1115 * we flush.
1116 * Otherwise, if a simple command like glColor3f() is called and we flush,
1117 * the current VBO may be left mapped.
1118 */
1119 void
1120 vbo_always_unmap_buffers(struct gl_context *ctx)
1121 {
1122 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1123 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1124 }
1125
1126
1127 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
1128 {
1129 struct gl_context *ctx = exec->ctx;
1130 struct vbo_context *vbo = vbo_context(ctx);
1131 GLuint i;
1132
1133 /* Allocate a buffer object. Will just reuse this object
1134 * continuously, unless vbo_use_buffer_objects() is called to enable
1135 * use of real VBOs.
1136 */
1137 _mesa_reference_buffer_object(ctx,
1138 &exec->vtx.bufferobj,
1139 ctx->Shared->NullBufferObj);
1140
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;
1144
1145 vbo_exec_vtxfmt_init( exec );
1146 _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1147
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;
1155 }
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];
1160 }
1161
1162 {
1163 struct gl_client_array *arrays = exec->vtx.arrays;
1164 unsigned i;
1165
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);
1174 }
1175
1176 memcpy(arrays + VERT_ATTRIB_GENERIC(0),
1177 &vbo->currval[VBO_ATTRIB_GENERIC0],
1178 VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
1179
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);
1186 }
1187 }
1188
1189 exec->vtx.vertex_size = 0;
1190
1191 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1192 }
1193
1194
1195 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
1196 {
1197 /* using a real VBO for vertex data */
1198 struct gl_context *ctx = exec->ctx;
1199 unsigned i;
1200
1201 /* True VBOs should already be unmapped
1202 */
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;
1210 }
1211 }
1212
1213 /* Drop any outstanding reference to the vertex buffer
1214 */
1215 for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) {
1216 _mesa_reference_buffer_object(ctx,
1217 &exec->vtx.arrays[i].BufferObj,
1218 NULL);
1219 }
1220
1221 /* Free the vertex buffer. Unmap first if needed.
1222 */
1223 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1224 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
1225 }
1226 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1227 }
1228
1229
1230 /**
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
1235 *
1236 * Note that the default T&L engine never clears the
1237 * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1238 *
1239 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1240 */
1241 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
1242 {
1243 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1244
1245 #ifdef DEBUG
1246 /* debug check: make sure we don't get called recursively */
1247 exec->flush_call_depth++;
1248 assert(exec->flush_call_depth == 1);
1249 #endif
1250
1251 if (_mesa_inside_begin_end(ctx)) {
1252 /* We've had glBegin but not glEnd! */
1253 #ifdef DEBUG
1254 exec->flush_call_depth--;
1255 assert(exec->flush_call_depth == 0);
1256 #endif
1257 return;
1258 }
1259
1260 /* Flush (draw), and make sure VBO is left unmapped when done */
1261 vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1262
1263 /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1264 */
1265 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1266
1267 #ifdef DEBUG
1268 exec->flush_call_depth--;
1269 assert(exec->flush_call_depth == 0);
1270 #endif
1271 }
1272
1273
1274 static void reset_attrfv( struct vbo_exec_context *exec )
1275 {
1276 GLuint i;
1277
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;
1282 }
1283
1284 exec->vtx.vertex_size = 0;
1285 }
1286
1287
1288 void GLAPIENTRY
1289 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1290 {
1291 vbo_Color4f(r, g, b, a);
1292 }
1293
1294
1295 void GLAPIENTRY
1296 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1297 {
1298 vbo_Normal3f(x, y, z);
1299 }
1300
1301
1302 void GLAPIENTRY
1303 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1304 {
1305 vbo_MultiTexCoord4f(target, s, t, r, q);
1306 }
1307
1308
1309 void GLAPIENTRY
1310 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1311 {
1312 vbo_Materialfv(face, pname, params);
1313 }
1314
1315
1316 void GLAPIENTRY
1317 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1318 {
1319 GLfloat p[4];
1320 p[0] = param;
1321 p[1] = p[2] = p[3] = 0.0F;
1322 vbo_Materialfv(face, pname, p);
1323 }
1324
1325
1326 /**
1327 * A special version of glVertexAttrib4f that does not treat index 0 as
1328 * VBO_ATTRIB_POS.
1329 */
1330 static void
1331 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1332 {
1333 GET_CURRENT_CONTEXT(ctx);
1334 if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1335 ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1336 else
1337 ERROR(GL_INVALID_VALUE);
1338 }
1339
1340 void GLAPIENTRY
1341 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1342 {
1343 VertexAttrib4f_nopos(index, x, y, z, w);
1344 }
1345
1346
1347 void GLAPIENTRY
1348 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1349 {
1350 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1351 }
1352
1353
1354 void GLAPIENTRY
1355 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1356 {
1357 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1358 }
1359
1360
1361 void GLAPIENTRY
1362 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1363 {
1364 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1365 }
1366
1367
1368 void GLAPIENTRY
1369 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1370 {
1371 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1372 }
1373
1374
1375 void GLAPIENTRY
1376 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1377 {
1378 VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1379 }
1380
1381
1382 void GLAPIENTRY
1383 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1384 {
1385 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1386 }
1387
1388
1389 void GLAPIENTRY
1390 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1391 {
1392 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1393 }