vbo: minor clean-up in vbo_exec_api.c
[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 #include "util/bitscan.h"
46
47 #include "vbo_context.h"
48 #include "vbo_noop.h"
49
50
51 /** ID/name for immediate-mode VBO */
52 #define IMM_BUFFER_NAME 0xaabbccdd
53
54
55 static void
56 vbo_reset_all_attr(struct vbo_exec_context *exec);
57
58
59 /**
60 * Close off the last primitive, execute the buffer, restart the
61 * primitive. This is called when we fill a vertex buffer before
62 * hitting glEnd.
63 */
64 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
65 {
66 if (exec->vtx.prim_count == 0) {
67 exec->vtx.copied.nr = 0;
68 exec->vtx.vert_count = 0;
69 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
70 }
71 else {
72 struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
73 const GLuint last_begin = last_prim->begin;
74 GLuint last_count;
75
76 if (_mesa_inside_begin_end(exec->ctx)) {
77 last_prim->count = exec->vtx.vert_count - last_prim->start;
78 }
79
80 last_count = last_prim->count;
81
82 /* Special handling for wrapping GL_LINE_LOOP */
83 if (last_prim->mode == GL_LINE_LOOP &&
84 last_count > 0 &&
85 !last_prim->end) {
86 /* draw this section of the incomplete line loop as a line strip */
87 last_prim->mode = GL_LINE_STRIP;
88 if (!last_prim->begin) {
89 /* This is not the first section of the line loop, so don't
90 * draw the 0th vertex. We're saving it until we draw the
91 * very last section of the loop.
92 */
93 last_prim->start++;
94 last_prim->count--;
95 }
96 }
97
98 /* Execute the buffer and save copied vertices.
99 */
100 if (exec->vtx.vert_count)
101 vbo_exec_vtx_flush( exec, GL_FALSE );
102 else {
103 exec->vtx.prim_count = 0;
104 exec->vtx.copied.nr = 0;
105 }
106
107 /* Emit a glBegin to start the new list.
108 */
109 assert(exec->vtx.prim_count == 0);
110
111 if (_mesa_inside_begin_end(exec->ctx)) {
112 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
113 exec->vtx.prim[0].begin = 0;
114 exec->vtx.prim[0].end = 0;
115 exec->vtx.prim[0].start = 0;
116 exec->vtx.prim[0].count = 0;
117 exec->vtx.prim_count++;
118
119 if (exec->vtx.copied.nr == last_count)
120 exec->vtx.prim[0].begin = last_begin;
121 }
122 }
123 }
124
125
126 /**
127 * Deal with buffer wrapping where provoked by the vertex buffer
128 * filling up, as opposed to upgrade_vertex().
129 */
130 static void
131 vbo_exec_vtx_wrap(struct vbo_exec_context *exec)
132 {
133 unsigned numComponents;
134
135 /* Run pipeline on current vertices, copy wrapped vertices
136 * to exec->vtx.copied.
137 */
138 vbo_exec_wrap_buffers( exec );
139
140 if (!exec->vtx.buffer_ptr) {
141 /* probably ran out of memory earlier when allocating the VBO */
142 return;
143 }
144
145 /* Copy stored stored vertices to start of new list.
146 */
147 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
148
149 numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
150 memcpy(exec->vtx.buffer_ptr,
151 exec->vtx.copied.buffer,
152 numComponents * sizeof(fi_type));
153 exec->vtx.buffer_ptr += numComponents;
154 exec->vtx.vert_count += exec->vtx.copied.nr;
155
156 exec->vtx.copied.nr = 0;
157 }
158
159
160 /**
161 * Copy the active vertex's values to the ctx->Current fields.
162 */
163 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
164 {
165 struct gl_context *ctx = exec->ctx;
166 struct vbo_context *vbo = vbo_context(ctx);
167 GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
168
169 while (enabled) {
170 const int i = u_bit_scan64(&enabled);
171
172 /* Note: the exec->vtx.current[i] pointers point into the
173 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
174 */
175 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
176 fi_type tmp[8]; /* space for doubles */
177 int dmul = exec->vtx.attrtype[i] == GL_DOUBLE ? 2 : 1;
178
179 assert(exec->vtx.attrsz[i]);
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 /* Colormaterial -- this kindof sucks.
221 */
222 if (ctx->Light.ColorMaterialEnabled &&
223 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
224 _mesa_update_color_material(ctx,
225 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
226 }
227 }
228
229
230 /**
231 * Copy current vertex attribute values into the current vertex.
232 */
233 static void
234 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
235 {
236 struct gl_context *ctx = exec->ctx;
237 struct vbo_context *vbo = vbo_context(ctx);
238 GLint i;
239
240 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
241 if (exec->vtx.attrtype[i] == GL_DOUBLE) {
242 memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr, exec->vtx.attrsz[i] * sizeof(GLfloat));
243 } else {
244 const fi_type *current = (fi_type *) vbo->currval[i].Ptr;
245 switch (exec->vtx.attrsz[i]) {
246 case 4: exec->vtx.attrptr[i][3] = current[3];
247 case 3: exec->vtx.attrptr[i][2] = current[2];
248 case 2: exec->vtx.attrptr[i][1] = current[1];
249 case 1: exec->vtx.attrptr[i][0] = current[0];
250 break;
251 }
252 }
253 }
254 }
255
256
257 /**
258 * Flush existing data, set new attrib size, replay copied vertices.
259 * This is called when we transition from a small vertex attribute size
260 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
261 * We need to go back over the previous 2-component texcoords and insert
262 * zero and one values.
263 */
264 static void
265 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
266 GLuint attr, GLuint newSize )
267 {
268 struct gl_context *ctx = exec->ctx;
269 struct vbo_context *vbo = vbo_context(ctx);
270 const GLint lastcount = exec->vtx.vert_count;
271 fi_type *old_attrptr[VBO_ATTRIB_MAX];
272 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
273 const GLuint oldSize = exec->vtx.attrsz[attr];
274 GLuint i;
275
276 /* Run pipeline on current vertices, copy wrapped vertices
277 * to exec->vtx.copied.
278 */
279 vbo_exec_wrap_buffers( exec );
280
281 if (unlikely(exec->vtx.copied.nr)) {
282 /* We're in the middle of a primitive, keep the old vertex
283 * format around to be able to translate the copied vertices to
284 * the new format.
285 */
286 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
287 }
288
289 if (unlikely(oldSize)) {
290 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
291 * case when the attribute already exists in the vertex and is
292 * having its size increased.
293 */
294 vbo_exec_copy_to_current( exec );
295 }
296
297 /* Heuristic: Attempt to isolate attributes received outside
298 * begin/end so that they don't bloat the vertices.
299 */
300 if (!_mesa_inside_begin_end(ctx) &&
301 !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
302 vbo_exec_copy_to_current( exec );
303 vbo_reset_all_attr(exec);
304 }
305
306 /* Fix up sizes:
307 */
308 exec->vtx.attrsz[attr] = newSize;
309 exec->vtx.vertex_size += newSize - oldSize;
310 exec->vtx.max_vert = vbo_compute_max_verts(exec);
311 exec->vtx.vert_count = 0;
312 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
313 exec->vtx.enabled |= BITFIELD64_BIT(attr);
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
349 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
350
351 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
352 GLbitfield64 enabled = exec->vtx.enabled;
353 while (enabled) {
354 const int j = u_bit_scan64(&enabled);
355 GLuint sz = exec->vtx.attrsz[j];
356 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
357 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
358
359 assert(sz);
360
361 if (j == attr) {
362 if (oldSize) {
363 fi_type tmp[4];
364 COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
365 data + old_offset,
366 exec->vtx.attrtype[j]);
367 COPY_SZ_4V(dest + new_offset, newSize, tmp);
368 } else {
369 fi_type *current = (fi_type *)vbo->currval[j].Ptr;
370 COPY_SZ_4V(dest + new_offset, sz, current);
371 }
372 }
373 else {
374 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
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 exec->vtx.attrtype[attr] = newType;
422
423 /* Does setting NeedFlush belong here? Necessitates resetting
424 * vtxfmt on each flush (otherwise flags won't get reset
425 * afterwards).
426 */
427 if (attr == 0)
428 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
429 }
430
431
432 /**
433 * Called upon first glVertex, glColor, glTexCoord, etc.
434 */
435 static void
436 vbo_exec_begin_vertices(struct gl_context *ctx)
437 {
438 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
439
440 vbo_exec_vtx_map( exec );
441
442 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
443 assert(exec->begin_vertices_flags);
444
445 ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
446 }
447
448
449 /**
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
457 */
458 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 ) \
459 do { \
460 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
461 int sz = (sizeof(C) / sizeof(GLfloat)); \
462 \
463 assert(sz == 1 || sz == 2); \
464 \
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); \
469 } \
470 \
471 /* store vertex attribute in vertex buffer */ \
472 { \
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 assert(exec->vtx.attrtype[A] == T); \
479 } \
480 \
481 if ((A) == 0) { \
482 /* This is a glVertex call */ \
483 GLuint i; \
484 \
485 if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
486 vbo_exec_begin_vertices(ctx); \
487 } \
488 \
489 if (unlikely(!exec->vtx.buffer_ptr)) { \
490 vbo_exec_vtx_map(exec); \
491 } \
492 assert(exec->vtx.buffer_ptr); \
493 \
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]; \
497 \
498 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
499 \
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; \
503 \
504 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
505 vbo_exec_vtx_wrap( exec ); \
506 } else { \
507 /* we now have accumulated per-vertex attributes */ \
508 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
509 } \
510 } while (0)
511
512
513 #undef ERROR
514 #define ERROR(err) _mesa_error( ctx, err, __func__ )
515 #define TAG(x) vbo_##x
516
517 #include "vbo_attrib_tmp.h"
518
519
520
521 /**
522 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
523 * this may be a (partial) no-op.
524 */
525 static void GLAPIENTRY
526 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
527 {
528 GLbitfield updateMats;
529 GET_CURRENT_CONTEXT(ctx);
530
531 /* This function should be a no-op when it tries to update material
532 * attributes which are currently tracking glColor via glColorMaterial.
533 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
534 * indicating which material attributes can actually be updated below.
535 */
536 if (ctx->Light.ColorMaterialEnabled) {
537 updateMats = ~ctx->Light._ColorMaterialBitmask;
538 }
539 else {
540 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
541 updateMats = ALL_MATERIAL_BITS;
542 }
543
544 if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
545 updateMats &= FRONT_MATERIAL_BITS;
546 }
547 else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
548 updateMats &= BACK_MATERIAL_BITS;
549 }
550 else if (face != GL_FRONT_AND_BACK) {
551 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
552 return;
553 }
554
555 switch (pname) {
556 case GL_EMISSION:
557 if (updateMats & MAT_BIT_FRONT_EMISSION)
558 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
559 if (updateMats & MAT_BIT_BACK_EMISSION)
560 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
561 break;
562 case GL_AMBIENT:
563 if (updateMats & MAT_BIT_FRONT_AMBIENT)
564 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
565 if (updateMats & MAT_BIT_BACK_AMBIENT)
566 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
567 break;
568 case GL_DIFFUSE:
569 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
570 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
571 if (updateMats & MAT_BIT_BACK_DIFFUSE)
572 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
573 break;
574 case GL_SPECULAR:
575 if (updateMats & MAT_BIT_FRONT_SPECULAR)
576 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
577 if (updateMats & MAT_BIT_BACK_SPECULAR)
578 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
579 break;
580 case GL_SHININESS:
581 if (*params < 0 || *params > ctx->Const.MaxShininess) {
582 _mesa_error(ctx, GL_INVALID_VALUE,
583 "glMaterial(invalid shininess: %f out range [0, %f])",
584 *params, ctx->Const.MaxShininess);
585 return;
586 }
587 if (updateMats & MAT_BIT_FRONT_SHININESS)
588 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
589 if (updateMats & MAT_BIT_BACK_SHININESS)
590 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
591 break;
592 case GL_COLOR_INDEXES:
593 if (ctx->API != API_OPENGL_COMPAT) {
594 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
595 return;
596 }
597 if (updateMats & MAT_BIT_FRONT_INDEXES)
598 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
599 if (updateMats & MAT_BIT_BACK_INDEXES)
600 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
601 break;
602 case GL_AMBIENT_AND_DIFFUSE:
603 if (updateMats & MAT_BIT_FRONT_AMBIENT)
604 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
605 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
606 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
607 if (updateMats & MAT_BIT_BACK_AMBIENT)
608 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
609 if (updateMats & MAT_BIT_BACK_DIFFUSE)
610 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
611 break;
612 default:
613 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
614 return;
615 }
616 }
617
618
619 /**
620 * Flush (draw) vertices.
621 * \param unmap - leave VBO unmapped after flushing?
622 */
623 static void
624 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
625 {
626 if (exec->vtx.vert_count || unmap) {
627 vbo_exec_vtx_flush( exec, unmap );
628 }
629
630 if (exec->vtx.vertex_size) {
631 vbo_exec_copy_to_current( exec );
632 vbo_reset_all_attr(exec);
633 }
634 }
635
636
637 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
638 {
639 GET_CURRENT_CONTEXT( ctx );
640 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
641
642 {
643 GLint i;
644 if (exec->eval.recalculate_maps)
645 vbo_exec_eval_update( exec );
646
647 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
648 if (exec->eval.map1[i].map)
649 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
650 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz, GL_FLOAT );
651 }
652 }
653
654
655 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
656 exec->vtx.vertex_size * sizeof(GLfloat));
657
658 vbo_exec_do_EvalCoord1f( exec, u );
659
660 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
661 exec->vtx.vertex_size * sizeof(GLfloat));
662 }
663
664 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
665 {
666 GET_CURRENT_CONTEXT( ctx );
667 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
668
669 {
670 GLint i;
671 if (exec->eval.recalculate_maps)
672 vbo_exec_eval_update( exec );
673
674 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
675 if (exec->eval.map2[i].map)
676 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
677 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz, GL_FLOAT );
678 }
679
680 if (ctx->Eval.AutoNormal)
681 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
682 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT );
683 }
684
685 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
686 exec->vtx.vertex_size * sizeof(GLfloat));
687
688 vbo_exec_do_EvalCoord2f( exec, u, v );
689
690 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
691 exec->vtx.vertex_size * sizeof(GLfloat));
692 }
693
694 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
695 {
696 vbo_exec_EvalCoord1f( u[0] );
697 }
698
699 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
700 {
701 vbo_exec_EvalCoord2f( u[0], u[1] );
702 }
703
704 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
705 {
706 GET_CURRENT_CONTEXT( ctx );
707 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
708 (GLfloat) ctx->Eval.MapGrid1un);
709 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
710
711 vbo_exec_EvalCoord1f( u );
712 }
713
714
715 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
716 {
717 GET_CURRENT_CONTEXT( ctx );
718 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
719 (GLfloat) ctx->Eval.MapGrid2un);
720 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
721 (GLfloat) ctx->Eval.MapGrid2vn);
722 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
723 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
724
725 vbo_exec_EvalCoord2f( u, v );
726 }
727
728
729 /**
730 * Called via glBegin.
731 */
732 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
733 {
734 GET_CURRENT_CONTEXT( ctx );
735 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
736 int i;
737
738 if (_mesa_inside_begin_end(ctx)) {
739 _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
740 return;
741 }
742
743 if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
744 return;
745 }
746
747 vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
748
749 if (ctx->NewState) {
750 _mesa_update_state( ctx );
751
752 CALL_Begin(ctx->Exec, (mode));
753 return;
754 }
755
756 if (!_mesa_valid_to_render(ctx, "glBegin")) {
757 return;
758 }
759
760 /* Heuristic: attempt to isolate attributes occurring outside
761 * begin/end pairs.
762 */
763 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
764 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
765
766 i = exec->vtx.prim_count++;
767 exec->vtx.prim[i].mode = mode;
768 exec->vtx.prim[i].begin = 1;
769 exec->vtx.prim[i].end = 0;
770 exec->vtx.prim[i].indexed = 0;
771 exec->vtx.prim[i].weak = 0;
772 exec->vtx.prim[i].pad = 0;
773 exec->vtx.prim[i].start = exec->vtx.vert_count;
774 exec->vtx.prim[i].count = 0;
775 exec->vtx.prim[i].num_instances = 1;
776 exec->vtx.prim[i].base_instance = 0;
777 exec->vtx.prim[i].is_indirect = 0;
778
779 ctx->Driver.CurrentExecPrimitive = mode;
780
781 ctx->Exec = ctx->BeginEnd;
782 /* We may have been called from a display list, in which case we should
783 * leave dlist.c's dispatch table in place.
784 */
785 if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
786 ctx->CurrentDispatch = ctx->BeginEnd;
787 _glapi_set_dispatch(ctx->CurrentDispatch);
788 } else {
789 assert(ctx->CurrentDispatch == ctx->Save);
790 }
791 }
792
793
794 /**
795 * Try to merge / concatenate the two most recent VBO primitives.
796 */
797 static void
798 try_vbo_merge(struct vbo_exec_context *exec)
799 {
800 struct _mesa_prim *cur = &exec->vtx.prim[exec->vtx.prim_count - 1];
801
802 assert(exec->vtx.prim_count >= 1);
803
804 vbo_try_prim_conversion(cur);
805
806 if (exec->vtx.prim_count >= 2) {
807 struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
808 assert(prev == cur - 1);
809
810 if (vbo_can_merge_prims(prev, cur)) {
811 assert(cur->begin);
812 assert(cur->end);
813 assert(prev->begin);
814 assert(prev->end);
815 vbo_merge_prims(prev, cur);
816 exec->vtx.prim_count--; /* drop the last primitive */
817 }
818 }
819 }
820
821
822 /**
823 * Called via glEnd.
824 */
825 static void GLAPIENTRY vbo_exec_End( void )
826 {
827 GET_CURRENT_CONTEXT( ctx );
828 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
829
830 if (!_mesa_inside_begin_end(ctx)) {
831 _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
832 return;
833 }
834
835 ctx->Exec = ctx->OutsideBeginEnd;
836 if (ctx->CurrentDispatch == ctx->BeginEnd) {
837 ctx->CurrentDispatch = ctx->OutsideBeginEnd;
838 _glapi_set_dispatch(ctx->CurrentDispatch);
839 }
840
841 if (exec->vtx.prim_count > 0) {
842 /* close off current primitive */
843 struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
844
845 last_prim->end = 1;
846 last_prim->count = exec->vtx.vert_count - last_prim->start;
847
848 /* Special handling for GL_LINE_LOOP */
849 if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
850 /* We're finishing drawing a line loop. Append 0th vertex onto
851 * end of vertex buffer so we can draw it as a line strip.
852 */
853 const fi_type *src = exec->vtx.buffer_map +
854 last_prim->start * exec->vtx.vertex_size;
855 fi_type *dst = exec->vtx.buffer_map +
856 exec->vtx.vert_count * exec->vtx.vertex_size;
857
858 /* copy 0th vertex to end of buffer */
859 memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
860
861 last_prim->start++; /* skip vertex0 */
862 /* note that last_prim->count stays unchanged */
863 last_prim->mode = GL_LINE_STRIP;
864
865 /* Increment the vertex count so the next primitive doesn't
866 * overwrite the last vertex which we just added.
867 */
868 exec->vtx.vert_count++;
869 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
870 }
871
872 try_vbo_merge(exec);
873 }
874
875 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
876
877 if (exec->vtx.prim_count == VBO_MAX_PRIM)
878 vbo_exec_vtx_flush( exec, GL_FALSE );
879
880 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
881 _mesa_flush(ctx);
882 }
883 }
884
885
886 /**
887 * Called via glPrimitiveRestartNV()
888 */
889 static void GLAPIENTRY
890 vbo_exec_PrimitiveRestartNV(void)
891 {
892 GLenum curPrim;
893 GET_CURRENT_CONTEXT( ctx );
894
895 curPrim = ctx->Driver.CurrentExecPrimitive;
896
897 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
898 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
899 }
900 else {
901 vbo_exec_End();
902 vbo_exec_Begin(curPrim);
903 }
904 }
905
906
907
908 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
909 {
910 struct gl_context *ctx = exec->ctx;
911 GLvertexformat *vfmt = &exec->vtxfmt;
912
913 vfmt->ArrayElement = _ae_ArrayElement;
914
915 vfmt->Begin = vbo_exec_Begin;
916 vfmt->End = vbo_exec_End;
917 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
918
919 vfmt->CallList = _mesa_CallList;
920 vfmt->CallLists = _mesa_CallLists;
921
922 vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
923 vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
924 vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
925 vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
926 vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
927 vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
928
929 /* from attrib_tmp.h:
930 */
931 vfmt->Color3f = vbo_Color3f;
932 vfmt->Color3fv = vbo_Color3fv;
933 vfmt->Color4f = vbo_Color4f;
934 vfmt->Color4fv = vbo_Color4fv;
935 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
936 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
937 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
938 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
939 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
940 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
941 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
942 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
943 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
944 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
945 vfmt->Normal3f = vbo_Normal3f;
946 vfmt->Normal3fv = vbo_Normal3fv;
947 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
948 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
949 vfmt->TexCoord1f = vbo_TexCoord1f;
950 vfmt->TexCoord1fv = vbo_TexCoord1fv;
951 vfmt->TexCoord2f = vbo_TexCoord2f;
952 vfmt->TexCoord2fv = vbo_TexCoord2fv;
953 vfmt->TexCoord3f = vbo_TexCoord3f;
954 vfmt->TexCoord3fv = vbo_TexCoord3fv;
955 vfmt->TexCoord4f = vbo_TexCoord4f;
956 vfmt->TexCoord4fv = vbo_TexCoord4fv;
957 vfmt->Vertex2f = vbo_Vertex2f;
958 vfmt->Vertex2fv = vbo_Vertex2fv;
959 vfmt->Vertex3f = vbo_Vertex3f;
960 vfmt->Vertex3fv = vbo_Vertex3fv;
961 vfmt->Vertex4f = vbo_Vertex4f;
962 vfmt->Vertex4fv = vbo_Vertex4fv;
963
964 if (ctx->API == API_OPENGLES2) {
965 vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
966 vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
967 vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
968 vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
969 vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
970 vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
971 vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
972 vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
973 } else {
974 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
975 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
976 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
977 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
978 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
979 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
980 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
981 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
982 }
983
984 /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
985 * they can have a single entrypoint for updating any of the legacy
986 * attribs.
987 */
988 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
989 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
990 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
991 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
992 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
993 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
994 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
995 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
996
997 /* integer-valued */
998 vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
999 vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
1000 vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
1001 vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
1002 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
1003 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
1004 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
1005
1006 /* unsigned integer-valued */
1007 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
1008 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
1009 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
1010 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
1011 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
1012 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
1013 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
1014
1015 vfmt->Materialfv = vbo_Materialfv;
1016
1017 vfmt->EdgeFlag = vbo_EdgeFlag;
1018 vfmt->Indexf = vbo_Indexf;
1019 vfmt->Indexfv = vbo_Indexfv;
1020
1021 /* ARB_vertex_type_2_10_10_10_rev */
1022 vfmt->VertexP2ui = vbo_VertexP2ui;
1023 vfmt->VertexP2uiv = vbo_VertexP2uiv;
1024 vfmt->VertexP3ui = vbo_VertexP3ui;
1025 vfmt->VertexP3uiv = vbo_VertexP3uiv;
1026 vfmt->VertexP4ui = vbo_VertexP4ui;
1027 vfmt->VertexP4uiv = vbo_VertexP4uiv;
1028
1029 vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
1030 vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
1031 vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
1032 vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
1033 vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
1034 vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
1035 vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
1036 vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
1037
1038 vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
1039 vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
1040 vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
1041 vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
1042 vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
1043 vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
1044 vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
1045 vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
1046
1047 vfmt->NormalP3ui = vbo_NormalP3ui;
1048 vfmt->NormalP3uiv = vbo_NormalP3uiv;
1049
1050 vfmt->ColorP3ui = vbo_ColorP3ui;
1051 vfmt->ColorP3uiv = vbo_ColorP3uiv;
1052 vfmt->ColorP4ui = vbo_ColorP4ui;
1053 vfmt->ColorP4uiv = vbo_ColorP4uiv;
1054
1055 vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
1056 vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
1057
1058 vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
1059 vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
1060 vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
1061 vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
1062 vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
1063 vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
1064 vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
1065 vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
1066
1067 vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
1068 vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
1069 vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
1070 vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
1071
1072 vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
1073 vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
1074 vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
1075 vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
1076 }
1077
1078
1079 /**
1080 * Tell the VBO module to use a real OpenGL vertex buffer object to
1081 * store accumulated immediate-mode vertex data.
1082 * This replaces the malloced buffer which was created in
1083 * vb_exec_vtx_init() below.
1084 */
1085 void vbo_use_buffer_objects(struct gl_context *ctx)
1086 {
1087 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1088 /* Any buffer name but 0 can be used here since this bufferobj won't
1089 * go into the bufferobj hashtable.
1090 */
1091 GLuint bufName = IMM_BUFFER_NAME;
1092 GLenum target = GL_ARRAY_BUFFER_ARB;
1093 GLenum usage = GL_STREAM_DRAW_ARB;
1094 GLsizei size = VBO_VERT_BUFFER_SIZE;
1095
1096 /* Make sure this func is only used once */
1097 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1098
1099 _mesa_align_free(exec->vtx.buffer_map);
1100 exec->vtx.buffer_map = NULL;
1101 exec->vtx.buffer_ptr = NULL;
1102
1103 /* Allocate a real buffer object now */
1104 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1105 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName);
1106 if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage,
1107 GL_MAP_WRITE_BIT |
1108 GL_DYNAMIC_STORAGE_BIT |
1109 GL_CLIENT_STORAGE_BIT,
1110 exec->vtx.bufferobj)) {
1111 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1112 }
1113 }
1114
1115
1116 /**
1117 * If this function is called, all VBO buffers will be unmapped when
1118 * we flush.
1119 * Otherwise, if a simple command like glColor3f() is called and we flush,
1120 * the current VBO may be left mapped.
1121 */
1122 void
1123 vbo_always_unmap_buffers(struct gl_context *ctx)
1124 {
1125 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1126 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1127 }
1128
1129
1130 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
1131 {
1132 struct gl_context *ctx = exec->ctx;
1133 struct vbo_context *vbo = vbo_context(ctx);
1134 GLuint i;
1135
1136 /* Allocate a buffer object. Will just reuse this object
1137 * continuously, unless vbo_use_buffer_objects() is called to enable
1138 * use of real VBOs.
1139 */
1140 _mesa_reference_buffer_object(ctx,
1141 &exec->vtx.bufferobj,
1142 ctx->Shared->NullBufferObj);
1143
1144 assert(!exec->vtx.buffer_map);
1145 exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
1146 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1147
1148 vbo_exec_vtxfmt_init( exec );
1149 _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1150
1151 exec->vtx.enabled = 0;
1152 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1153 assert(i < ARRAY_SIZE(exec->vtx.attrsz));
1154 exec->vtx.attrsz[i] = 0;
1155 assert(i < ARRAY_SIZE(exec->vtx.attrtype));
1156 exec->vtx.attrtype[i] = GL_FLOAT;
1157 assert(i < ARRAY_SIZE(exec->vtx.active_sz));
1158 exec->vtx.active_sz[i] = 0;
1159 }
1160 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
1161 assert(i < ARRAY_SIZE(exec->vtx.inputs));
1162 assert(i < ARRAY_SIZE(exec->vtx.arrays));
1163 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
1164 }
1165
1166 {
1167 struct gl_client_array *arrays = exec->vtx.arrays;
1168 unsigned i;
1169
1170 memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
1171 VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
1172 for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
1173 struct gl_client_array *array;
1174 array = &arrays[VERT_ATTRIB_FF(i)];
1175 array->BufferObj = NULL;
1176 _mesa_reference_buffer_object(ctx, &array->BufferObj,
1177 vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
1178 }
1179
1180 memcpy(arrays + VERT_ATTRIB_GENERIC(0),
1181 &vbo->currval[VBO_ATTRIB_GENERIC0],
1182 VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
1183
1184 for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
1185 struct gl_client_array *array;
1186 array = &arrays[VERT_ATTRIB_GENERIC(i)];
1187 array->BufferObj = NULL;
1188 _mesa_reference_buffer_object(ctx, &array->BufferObj,
1189 vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
1190 }
1191 }
1192
1193 exec->vtx.vertex_size = 0;
1194
1195 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1196 }
1197
1198
1199 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
1200 {
1201 /* using a real VBO for vertex data */
1202 struct gl_context *ctx = exec->ctx;
1203 unsigned i;
1204
1205 /* True VBOs should already be unmapped
1206 */
1207 if (exec->vtx.buffer_map) {
1208 assert(exec->vtx.bufferobj->Name == 0 ||
1209 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1210 if (exec->vtx.bufferobj->Name == 0) {
1211 _mesa_align_free(exec->vtx.buffer_map);
1212 exec->vtx.buffer_map = NULL;
1213 exec->vtx.buffer_ptr = NULL;
1214 }
1215 }
1216
1217 /* Drop any outstanding reference to the vertex buffer
1218 */
1219 for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) {
1220 _mesa_reference_buffer_object(ctx,
1221 &exec->vtx.arrays[i].BufferObj,
1222 NULL);
1223 }
1224
1225 /* Free the vertex buffer. Unmap first if needed.
1226 */
1227 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1228 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
1229 }
1230 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1231 }
1232
1233
1234 /**
1235 * If inside glBegin()/glEnd(), it should assert(0). Otherwise, if
1236 * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1237 * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1238 * __struct gl_contextRec::Current and gl_light_attrib::Material
1239 *
1240 * Note that the default T&L engine never clears the
1241 * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1242 *
1243 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1244 */
1245 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
1246 {
1247 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1248
1249 #ifdef DEBUG
1250 /* debug check: make sure we don't get called recursively */
1251 exec->flush_call_depth++;
1252 assert(exec->flush_call_depth == 1);
1253 #endif
1254
1255 if (_mesa_inside_begin_end(ctx)) {
1256 /* We've had glBegin but not glEnd! */
1257 #ifdef DEBUG
1258 exec->flush_call_depth--;
1259 assert(exec->flush_call_depth == 0);
1260 #endif
1261 return;
1262 }
1263
1264 /* Flush (draw), and make sure VBO is left unmapped when done */
1265 vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1266
1267 /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
1268 */
1269 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1270
1271 #ifdef DEBUG
1272 exec->flush_call_depth--;
1273 assert(exec->flush_call_depth == 0);
1274 #endif
1275 }
1276
1277 /**
1278 * Reset the vertex attribute by setting its size to zero.
1279 */
1280 static void
1281 vbo_reset_attr(struct vbo_exec_context *exec, GLuint attr)
1282 {
1283 exec->vtx.attrsz[attr] = 0;
1284 exec->vtx.attrtype[attr] = GL_FLOAT;
1285 exec->vtx.active_sz[attr] = 0;
1286 }
1287
1288 static void
1289 vbo_reset_all_attr(struct vbo_exec_context *exec)
1290 {
1291 while (exec->vtx.enabled) {
1292 const int i = u_bit_scan64(&exec->vtx.enabled);
1293 vbo_reset_attr(exec, i);
1294 }
1295
1296 exec->vtx.vertex_size = 0;
1297 }
1298
1299
1300 void GLAPIENTRY
1301 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1302 {
1303 vbo_Color4f(r, g, b, a);
1304 }
1305
1306
1307 void GLAPIENTRY
1308 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1309 {
1310 vbo_Normal3f(x, y, z);
1311 }
1312
1313
1314 void GLAPIENTRY
1315 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1316 {
1317 vbo_MultiTexCoord4f(target, s, t, r, q);
1318 }
1319
1320
1321 void GLAPIENTRY
1322 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1323 {
1324 vbo_Materialfv(face, pname, params);
1325 }
1326
1327
1328 void GLAPIENTRY
1329 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1330 {
1331 GLfloat p[4];
1332 p[0] = param;
1333 p[1] = p[2] = p[3] = 0.0F;
1334 vbo_Materialfv(face, pname, p);
1335 }
1336
1337
1338 /**
1339 * A special version of glVertexAttrib4f that does not treat index 0 as
1340 * VBO_ATTRIB_POS.
1341 */
1342 static void
1343 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1344 {
1345 GET_CURRENT_CONTEXT(ctx);
1346 if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1347 ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1348 else
1349 ERROR(GL_INVALID_VALUE);
1350 }
1351
1352 void GLAPIENTRY
1353 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1354 {
1355 VertexAttrib4f_nopos(index, x, y, z, w);
1356 }
1357
1358
1359 void GLAPIENTRY
1360 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1361 {
1362 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1363 }
1364
1365
1366 void GLAPIENTRY
1367 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1368 {
1369 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1370 }
1371
1372
1373 void GLAPIENTRY
1374 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1375 {
1376 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1377 }
1378
1379
1380 void GLAPIENTRY
1381 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1382 {
1383 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1384 }
1385
1386
1387 void GLAPIENTRY
1388 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1389 {
1390 VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1391 }
1392
1393
1394 void GLAPIENTRY
1395 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1396 {
1397 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1398 }
1399
1400
1401 void GLAPIENTRY
1402 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1403 {
1404 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1405 }