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