vbo: add vbo_always_unmap_buffers()
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.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/mfeatures.h"
38 #include "main/vtxfmt.h"
39 #include "main/dlist.h"
40 #include "main/eval.h"
41 #include "main/state.h"
42 #include "main/light.h"
43 #include "main/api_arrayelt.h"
44 #include "main/api_noop.h"
45 #include "main/dispatch.h"
46
47 #include "vbo_context.h"
48
49 #ifdef ERROR
50 #undef ERROR
51 #endif
52
53
54 /** ID/name for immediate-mode VBO */
55 #define IMM_BUFFER_NAME 0xaabbccdd
56
57
58 static void reset_attrfv( struct vbo_exec_context *exec );
59
60
61 /**
62 * Close off the last primitive, execute the buffer, restart the
63 * primitive.
64 */
65 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
66 {
67 if (exec->vtx.prim_count == 0) {
68 exec->vtx.copied.nr = 0;
69 exec->vtx.vert_count = 0;
70 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
71 }
72 else {
73 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
74 GLuint last_count;
75
76 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
77 GLint i = exec->vtx.prim_count - 1;
78 assert(i >= 0);
79 exec->vtx.prim[i].count = (exec->vtx.vert_count -
80 exec->vtx.prim[i].start);
81 }
82
83 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
84
85 /* Execute the buffer and save copied vertices.
86 */
87 if (exec->vtx.vert_count)
88 vbo_exec_vtx_flush( exec, GL_FALSE );
89 else {
90 exec->vtx.prim_count = 0;
91 exec->vtx.copied.nr = 0;
92 }
93
94 /* Emit a glBegin to start the new list.
95 */
96 assert(exec->vtx.prim_count == 0);
97
98 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
99 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
100 exec->vtx.prim[0].start = 0;
101 exec->vtx.prim[0].count = 0;
102 exec->vtx.prim_count++;
103
104 if (exec->vtx.copied.nr == last_count)
105 exec->vtx.prim[0].begin = last_begin;
106 }
107 }
108 }
109
110
111 /**
112 * Deal with buffer wrapping where provoked by the vertex buffer
113 * filling up, as opposed to upgrade_vertex().
114 */
115 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
116 {
117 GLfloat *data = exec->vtx.copied.buffer;
118 GLuint i;
119
120 /* Run pipeline on current vertices, copy wrapped vertices
121 * to exec->vtx.copied.
122 */
123 vbo_exec_wrap_buffers( exec );
124
125 /* Copy stored stored vertices to start of new list.
126 */
127 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
128
129 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
130 memcpy( exec->vtx.buffer_ptr, data,
131 exec->vtx.vertex_size * sizeof(GLfloat));
132 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
133 data += exec->vtx.vertex_size;
134 exec->vtx.vert_count++;
135 }
136
137 exec->vtx.copied.nr = 0;
138 }
139
140
141 /**
142 * Copy the active vertex's values to the ctx->Current fields.
143 */
144 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
145 {
146 struct gl_context *ctx = exec->ctx;
147 struct vbo_context *vbo = vbo_context(ctx);
148 GLuint i;
149
150 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
151 if (exec->vtx.attrsz[i]) {
152 /* Note: the exec->vtx.current[i] pointers point into the
153 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
154 */
155 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
156 GLfloat tmp[4];
157
158 COPY_CLEAN_4V(tmp,
159 exec->vtx.attrsz[i],
160 exec->vtx.attrptr[i]);
161
162 if (memcmp(current, tmp, sizeof(tmp)) != 0) {
163 memcpy(current, tmp, sizeof(tmp));
164
165 /* Given that we explicitly state size here, there is no need
166 * for the COPY_CLEAN above, could just copy 16 bytes and be
167 * done. The only problem is when Mesa accesses ctx->Current
168 * directly.
169 */
170 vbo->currval[i].Size = exec->vtx.attrsz[i];
171
172 /* This triggers rather too much recalculation of Mesa state
173 * that doesn't get used (eg light positions).
174 */
175 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
176 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
177 ctx->NewState |= _NEW_LIGHT;
178
179 ctx->NewState |= _NEW_CURRENT_ATTRIB;
180 }
181 }
182 }
183
184 /* Colormaterial -- this kindof sucks.
185 */
186 if (ctx->Light.ColorMaterialEnabled &&
187 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
188 _mesa_update_color_material(ctx,
189 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
190 }
191 }
192
193
194 /**
195 * Copy current vertex attribute values into the current vertex.
196 */
197 static void
198 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
199 {
200 struct gl_context *ctx = exec->ctx;
201 struct vbo_context *vbo = vbo_context(ctx);
202 GLint i;
203
204 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
205 const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
206 switch (exec->vtx.attrsz[i]) {
207 case 4: exec->vtx.attrptr[i][3] = current[3];
208 case 3: exec->vtx.attrptr[i][2] = current[2];
209 case 2: exec->vtx.attrptr[i][1] = current[1];
210 case 1: exec->vtx.attrptr[i][0] = current[0];
211 break;
212 }
213 }
214 }
215
216
217 /**
218 * Flush existing data, set new attrib size, replay copied vertices.
219 * This is called when we transition from a small vertex attribute size
220 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
221 * We need to go back over the previous 2-component texcoords and insert
222 * zero and one values.
223 */
224 static void
225 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
226 GLuint attr, GLuint newSize )
227 {
228 struct gl_context *ctx = exec->ctx;
229 struct vbo_context *vbo = vbo_context(ctx);
230 const GLint lastcount = exec->vtx.vert_count;
231 GLfloat *old_attrptr[VBO_ATTRIB_MAX];
232 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
233 const GLuint oldSize = exec->vtx.attrsz[attr];
234 GLuint i;
235
236 /* Run pipeline on current vertices, copy wrapped vertices
237 * to exec->vtx.copied.
238 */
239 vbo_exec_wrap_buffers( exec );
240
241 if (unlikely(exec->vtx.copied.nr)) {
242 /* We're in the middle of a primitive, keep the old vertex
243 * format around to be able to translate the copied vertices to
244 * the new format.
245 */
246 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
247 }
248
249 if (unlikely(oldSize)) {
250 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
251 * case when the attribute already exists in the vertex and is
252 * having its size increased.
253 */
254 vbo_exec_copy_to_current( exec );
255 }
256
257 /* Heuristic: Attempt to isolate attributes received outside
258 * begin/end so that they don't bloat the vertices.
259 */
260 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
261 !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
262 vbo_exec_copy_to_current( exec );
263 reset_attrfv( exec );
264 }
265
266 /* Fix up sizes:
267 */
268 exec->vtx.attrsz[attr] = newSize;
269 exec->vtx.vertex_size += newSize - oldSize;
270 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
271 (exec->vtx.vertex_size * sizeof(GLfloat)));
272 exec->vtx.vert_count = 0;
273 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
274
275 if (unlikely(oldSize)) {
276 /* Size changed, recalculate all the attrptr[] values
277 */
278 GLfloat *tmp = exec->vtx.vertex;
279
280 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
281 if (exec->vtx.attrsz[i]) {
282 exec->vtx.attrptr[i] = tmp;
283 tmp += exec->vtx.attrsz[i];
284 }
285 else
286 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
287 }
288
289 /* Copy from current to repopulate the vertex with correct
290 * values.
291 */
292 vbo_exec_copy_from_current( exec );
293 }
294 else {
295 /* Just have to append the new attribute at the end */
296 exec->vtx.attrptr[attr] = exec->vtx.vertex +
297 exec->vtx.vertex_size - newSize;
298 }
299
300 /* Replay stored vertices to translate them
301 * to new format here.
302 *
303 * -- No need to replay - just copy piecewise
304 */
305 if (unlikely(exec->vtx.copied.nr)) {
306 GLfloat *data = exec->vtx.copied.buffer;
307 GLfloat *dest = exec->vtx.buffer_ptr;
308 GLuint j;
309
310 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
311
312 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
313 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
314 GLuint sz = exec->vtx.attrsz[j];
315
316 if (sz) {
317 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
318 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
319
320 if (j == attr) {
321 if (oldSize) {
322 GLfloat tmp[4];
323 COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
324 COPY_SZ_4V(dest + new_offset, newSize, tmp);
325 } else {
326 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
327 COPY_SZ_4V(dest + new_offset, sz, current);
328 }
329 }
330 else {
331 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
332 }
333 }
334 }
335
336 data += old_vtx_size;
337 dest += exec->vtx.vertex_size;
338 }
339
340 exec->vtx.buffer_ptr = dest;
341 exec->vtx.vert_count += exec->vtx.copied.nr;
342 exec->vtx.copied.nr = 0;
343 }
344 }
345
346
347 /**
348 * This is when a vertex attribute transitions to a different size.
349 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
350 * glTexCoord4f() call. We promote the array from size=2 to size=4.
351 */
352 static void
353 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
354 {
355 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
356
357 if (newSize > exec->vtx.attrsz[attr]) {
358 /* New size is larger. Need to flush existing vertices and get
359 * an enlarged vertex format.
360 */
361 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
362 }
363 else if (newSize < exec->vtx.active_sz[attr]) {
364 static const GLfloat id[4] = { 0, 0, 0, 1 };
365 GLuint i;
366
367 /* New size is smaller - just need to fill in some
368 * zeros. Don't need to flush or wrap.
369 */
370 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
371 exec->vtx.attrptr[attr][i-1] = id[i-1];
372 }
373
374 exec->vtx.active_sz[attr] = newSize;
375
376 /* Does setting NeedFlush belong here? Necessitates resetting
377 * vtxfmt on each flush (otherwise flags won't get reset
378 * afterwards).
379 */
380 if (attr == 0)
381 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
382 }
383
384
385 /**
386 * This macro is used to implement all the glVertex, glColor, glTexCoord,
387 * glVertexAttrib, etc functions.
388 */
389 #define ATTR( A, N, V0, V1, V2, V3 ) \
390 do { \
391 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
392 \
393 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
394 ctx->Driver.BeginVertices( ctx ); \
395 \
396 if (unlikely(exec->vtx.active_sz[A] != N)) \
397 vbo_exec_fixup_vertex(ctx, A, N); \
398 \
399 { \
400 GLfloat *dest = exec->vtx.attrptr[A]; \
401 if (N>0) dest[0] = V0; \
402 if (N>1) dest[1] = V1; \
403 if (N>2) dest[2] = V2; \
404 if (N>3) dest[3] = V3; \
405 } \
406 \
407 if ((A) == 0) { \
408 /* This is a glVertex call */ \
409 GLuint i; \
410 \
411 for (i = 0; i < exec->vtx.vertex_size; i++) \
412 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
413 \
414 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
415 \
416 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
417 /* something to draw (not just updating a color or texcoord).*/ \
418 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
419 \
420 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
421 vbo_exec_vtx_wrap( exec ); \
422 } \
423 } while (0)
424
425
426 #define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
427 #define TAG(x) vbo_##x
428
429 #include "vbo_attrib_tmp.h"
430
431
432 #if FEATURE_beginend
433
434
435 #if FEATURE_evaluators
436
437 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
438 {
439 GET_CURRENT_CONTEXT( ctx );
440 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
441
442 {
443 GLint i;
444 if (exec->eval.recalculate_maps)
445 vbo_exec_eval_update( exec );
446
447 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
448 if (exec->eval.map1[i].map)
449 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
450 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
451 }
452 }
453
454
455 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
456 exec->vtx.vertex_size * sizeof(GLfloat));
457
458 vbo_exec_do_EvalCoord1f( exec, u );
459
460 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
461 exec->vtx.vertex_size * sizeof(GLfloat));
462 }
463
464 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
465 {
466 GET_CURRENT_CONTEXT( ctx );
467 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
468
469 {
470 GLint i;
471 if (exec->eval.recalculate_maps)
472 vbo_exec_eval_update( exec );
473
474 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
475 if (exec->eval.map2[i].map)
476 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
477 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
478 }
479
480 if (ctx->Eval.AutoNormal)
481 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
482 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
483 }
484
485 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
486 exec->vtx.vertex_size * sizeof(GLfloat));
487
488 vbo_exec_do_EvalCoord2f( exec, u, v );
489
490 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
491 exec->vtx.vertex_size * sizeof(GLfloat));
492 }
493
494 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
495 {
496 vbo_exec_EvalCoord1f( u[0] );
497 }
498
499 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
500 {
501 vbo_exec_EvalCoord2f( u[0], u[1] );
502 }
503
504 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
505 {
506 GET_CURRENT_CONTEXT( ctx );
507 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
508 (GLfloat) ctx->Eval.MapGrid1un);
509 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
510
511 vbo_exec_EvalCoord1f( u );
512 }
513
514
515 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
516 {
517 GET_CURRENT_CONTEXT( ctx );
518 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
519 (GLfloat) ctx->Eval.MapGrid2un);
520 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
521 (GLfloat) ctx->Eval.MapGrid2vn);
522 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
523 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
524
525 vbo_exec_EvalCoord2f( u, v );
526 }
527
528 /* use noop eval mesh */
529 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
530 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
531
532 #endif /* FEATURE_evaluators */
533
534
535 /**
536 * Flush (draw) vertices.
537 * \param unmap - leave VBO unmapped after flushing?
538 */
539 static void
540 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
541 {
542 if (exec->vtx.vert_count || unmap) {
543 vbo_exec_vtx_flush( exec, unmap );
544 }
545
546 if (exec->vtx.vertex_size) {
547 vbo_exec_copy_to_current( exec );
548 reset_attrfv( exec );
549 }
550 }
551
552
553 /**
554 * Called via glBegin.
555 */
556 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
557 {
558 GET_CURRENT_CONTEXT( ctx );
559
560 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
561 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
562 int i;
563
564 if (ctx->NewState) {
565 _mesa_update_state( ctx );
566
567 CALL_Begin(ctx->Exec, (mode));
568 return;
569 }
570
571 if (!_mesa_valid_to_render(ctx, "glBegin")) {
572 return;
573 }
574
575 /* Heuristic: attempt to isolate attributes occuring outside
576 * begin/end pairs.
577 */
578 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
579 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
580
581 i = exec->vtx.prim_count++;
582 exec->vtx.prim[i].mode = mode;
583 exec->vtx.prim[i].begin = 1;
584 exec->vtx.prim[i].end = 0;
585 exec->vtx.prim[i].indexed = 0;
586 exec->vtx.prim[i].weak = 0;
587 exec->vtx.prim[i].pad = 0;
588 exec->vtx.prim[i].start = exec->vtx.vert_count;
589 exec->vtx.prim[i].count = 0;
590 exec->vtx.prim[i].num_instances = 1;
591
592 ctx->Driver.CurrentExecPrimitive = mode;
593 }
594 else
595 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
596
597 }
598
599
600 /**
601 * Called via glEnd.
602 */
603 static void GLAPIENTRY vbo_exec_End( void )
604 {
605 GET_CURRENT_CONTEXT( ctx );
606
607 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
608 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
609 int idx = exec->vtx.vert_count;
610 int i = exec->vtx.prim_count - 1;
611
612 exec->vtx.prim[i].end = 1;
613 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
614
615 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
616
617 if (exec->vtx.prim_count == VBO_MAX_PRIM)
618 vbo_exec_vtx_flush( exec, GL_FALSE );
619 }
620 else
621 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
622 }
623
624
625 /**
626 * Called via glPrimitiveRestartNV()
627 */
628 static void GLAPIENTRY
629 vbo_exec_PrimitiveRestartNV(void)
630 {
631 GLenum curPrim;
632 GET_CURRENT_CONTEXT( ctx );
633
634 curPrim = ctx->Driver.CurrentExecPrimitive;
635
636 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
637 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
638 }
639 else {
640 vbo_exec_End();
641 vbo_exec_Begin(curPrim);
642 }
643 }
644
645
646
647 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
648 {
649 GLvertexformat *vfmt = &exec->vtxfmt;
650
651 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
652
653 vfmt->Begin = vbo_exec_Begin;
654 vfmt->End = vbo_exec_End;
655 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
656
657 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
658 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
659
660 vfmt->Rectf = _mesa_noop_Rectf;
661
662 /* from attrib_tmp.h:
663 */
664 vfmt->Color3f = vbo_Color3f;
665 vfmt->Color3fv = vbo_Color3fv;
666 vfmt->Color4f = vbo_Color4f;
667 vfmt->Color4fv = vbo_Color4fv;
668 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
669 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
670 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
671 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
672 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
673 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
674 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
675 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
676 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
677 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
678 vfmt->Normal3f = vbo_Normal3f;
679 vfmt->Normal3fv = vbo_Normal3fv;
680 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
681 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
682 vfmt->TexCoord1f = vbo_TexCoord1f;
683 vfmt->TexCoord1fv = vbo_TexCoord1fv;
684 vfmt->TexCoord2f = vbo_TexCoord2f;
685 vfmt->TexCoord2fv = vbo_TexCoord2fv;
686 vfmt->TexCoord3f = vbo_TexCoord3f;
687 vfmt->TexCoord3fv = vbo_TexCoord3fv;
688 vfmt->TexCoord4f = vbo_TexCoord4f;
689 vfmt->TexCoord4fv = vbo_TexCoord4fv;
690 vfmt->Vertex2f = vbo_Vertex2f;
691 vfmt->Vertex2fv = vbo_Vertex2fv;
692 vfmt->Vertex3f = vbo_Vertex3f;
693 vfmt->Vertex3fv = vbo_Vertex3fv;
694 vfmt->Vertex4f = vbo_Vertex4f;
695 vfmt->Vertex4fv = vbo_Vertex4fv;
696
697 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
698 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
699 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
700 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
701 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
702 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
703 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
704 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
705
706 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
707 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
708 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
709 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
710 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
711 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
712 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
713 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
714
715 /* integer-valued */
716 vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
717 vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
718 vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
719 vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
720 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
721 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
722 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
723
724 /* unsigned integer-valued */
725 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
726 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
727 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
728 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
729 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
730 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
731 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
732
733 vfmt->Materialfv = vbo_Materialfv;
734
735 vfmt->EdgeFlag = vbo_EdgeFlag;
736 vfmt->Indexf = vbo_Indexf;
737 vfmt->Indexfv = vbo_Indexfv;
738
739 }
740
741
742 #else /* FEATURE_beginend */
743
744
745 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
746 {
747 /* silence warnings */
748 (void) vbo_Color3f;
749 (void) vbo_Color3fv;
750 (void) vbo_Color4f;
751 (void) vbo_Color4fv;
752 (void) vbo_FogCoordfEXT;
753 (void) vbo_FogCoordfvEXT;
754 (void) vbo_MultiTexCoord1f;
755 (void) vbo_MultiTexCoord1fv;
756 (void) vbo_MultiTexCoord2f;
757 (void) vbo_MultiTexCoord2fv;
758 (void) vbo_MultiTexCoord3f;
759 (void) vbo_MultiTexCoord3fv;
760 (void) vbo_MultiTexCoord4f;
761 (void) vbo_MultiTexCoord4fv;
762 (void) vbo_Normal3f;
763 (void) vbo_Normal3fv;
764 (void) vbo_SecondaryColor3fEXT;
765 (void) vbo_SecondaryColor3fvEXT;
766 (void) vbo_TexCoord1f;
767 (void) vbo_TexCoord1fv;
768 (void) vbo_TexCoord2f;
769 (void) vbo_TexCoord2fv;
770 (void) vbo_TexCoord3f;
771 (void) vbo_TexCoord3fv;
772 (void) vbo_TexCoord4f;
773 (void) vbo_TexCoord4fv;
774 (void) vbo_Vertex2f;
775 (void) vbo_Vertex2fv;
776 (void) vbo_Vertex3f;
777 (void) vbo_Vertex3fv;
778 (void) vbo_Vertex4f;
779 (void) vbo_Vertex4fv;
780
781 (void) vbo_VertexAttrib1fARB;
782 (void) vbo_VertexAttrib1fvARB;
783 (void) vbo_VertexAttrib2fARB;
784 (void) vbo_VertexAttrib2fvARB;
785 (void) vbo_VertexAttrib3fARB;
786 (void) vbo_VertexAttrib3fvARB;
787 (void) vbo_VertexAttrib4fARB;
788 (void) vbo_VertexAttrib4fvARB;
789
790 (void) vbo_VertexAttrib1fNV;
791 (void) vbo_VertexAttrib1fvNV;
792 (void) vbo_VertexAttrib2fNV;
793 (void) vbo_VertexAttrib2fvNV;
794 (void) vbo_VertexAttrib3fNV;
795 (void) vbo_VertexAttrib3fvNV;
796 (void) vbo_VertexAttrib4fNV;
797 (void) vbo_VertexAttrib4fvNV;
798
799 (void) vbo_Materialfv;
800
801 (void) vbo_EdgeFlag;
802 (void) vbo_Indexf;
803 (void) vbo_Indexfv;
804 }
805
806
807 #endif /* FEATURE_beginend */
808
809
810 /**
811 * Tell the VBO module to use a real OpenGL vertex buffer object to
812 * store accumulated immediate-mode vertex data.
813 * This replaces the malloced buffer which was created in
814 * vb_exec_vtx_init() below.
815 */
816 void vbo_use_buffer_objects(struct gl_context *ctx)
817 {
818 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
819 /* Any buffer name but 0 can be used here since this bufferobj won't
820 * go into the bufferobj hashtable.
821 */
822 GLuint bufName = IMM_BUFFER_NAME;
823 GLenum target = GL_ARRAY_BUFFER_ARB;
824 GLenum usage = GL_STREAM_DRAW_ARB;
825 GLsizei size = VBO_VERT_BUFFER_SIZE;
826
827 /* Make sure this func is only used once */
828 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
829 if (exec->vtx.buffer_map) {
830 _mesa_align_free(exec->vtx.buffer_map);
831 exec->vtx.buffer_map = NULL;
832 exec->vtx.buffer_ptr = NULL;
833 }
834
835 /* Allocate a real buffer object now */
836 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
837 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
838 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
839 }
840
841
842 /**
843 * If this function is called, all VBO buffers will be unmapped when
844 * we flush.
845 * Otherwise, if a simple command like glColor3f() is called and we flush,
846 * the current VBO may be left mapped.
847 */
848 void
849 vbo_always_unmap_buffers(struct gl_context *ctx)
850 {
851 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
852 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
853 }
854
855
856 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
857 {
858 struct gl_context *ctx = exec->ctx;
859 struct vbo_context *vbo = vbo_context(ctx);
860 GLuint i;
861
862 /* Allocate a buffer object. Will just reuse this object
863 * continuously, unless vbo_use_buffer_objects() is called to enable
864 * use of real VBOs.
865 */
866 _mesa_reference_buffer_object(ctx,
867 &exec->vtx.bufferobj,
868 ctx->Shared->NullBufferObj);
869
870 ASSERT(!exec->vtx.buffer_map);
871 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
872 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
873
874 vbo_exec_vtxfmt_init( exec );
875
876 /* Hook our functions into the dispatch table.
877 */
878 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
879
880 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
881 ASSERT(i < Elements(exec->vtx.attrsz));
882 exec->vtx.attrsz[i] = 0;
883 ASSERT(i < Elements(exec->vtx.active_sz));
884 exec->vtx.active_sz[i] = 0;
885 }
886 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
887 ASSERT(i < Elements(exec->vtx.inputs));
888 ASSERT(i < Elements(exec->vtx.arrays));
889 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
890 }
891
892 {
893 struct gl_client_array *arrays = exec->vtx.arrays;
894 unsigned i;
895
896 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
897 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
898
899 for (i = 0; i < 16; ++i) {
900 arrays[i ].BufferObj = NULL;
901 arrays[i + 16].BufferObj = NULL;
902 _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
903 vbo->legacy_currval[i].BufferObj);
904 _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
905 vbo->generic_currval[i].BufferObj);
906 }
907 }
908
909 exec->vtx.vertex_size = 0;
910
911 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
912 }
913
914
915 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
916 {
917 /* using a real VBO for vertex data */
918 struct gl_context *ctx = exec->ctx;
919 unsigned i;
920
921 /* True VBOs should already be unmapped
922 */
923 if (exec->vtx.buffer_map) {
924 ASSERT(exec->vtx.bufferobj->Name == 0 ||
925 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
926 if (exec->vtx.bufferobj->Name == 0) {
927 _mesa_align_free(exec->vtx.buffer_map);
928 exec->vtx.buffer_map = NULL;
929 exec->vtx.buffer_ptr = NULL;
930 }
931 }
932
933 /* Drop any outstanding reference to the vertex buffer
934 */
935 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
936 _mesa_reference_buffer_object(ctx,
937 &exec->vtx.arrays[i].BufferObj,
938 NULL);
939 }
940
941 /* Free the vertex buffer. Unmap first if needed.
942 */
943 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
944 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
945 }
946 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
947 }
948
949
950 /**
951 * Called upon first glVertex, glColor, glTexCoord, etc.
952 */
953 void vbo_exec_BeginVertices( struct gl_context *ctx )
954 {
955 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
956
957 vbo_exec_vtx_map( exec );
958
959 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
960 assert(exec->begin_vertices_flags);
961
962 ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
963 }
964
965
966 /**
967 * Called via ctx->Driver.FlushVertices()
968 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
969 */
970 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
971 {
972 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
973
974 #ifdef DEBUG
975 /* debug check: make sure we don't get called recursively */
976 exec->flush_call_depth++;
977 assert(exec->flush_call_depth == 1);
978 #endif
979
980 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
981 /* We've had glBegin but not glEnd! */
982 #ifdef DEBUG
983 exec->flush_call_depth--;
984 assert(exec->flush_call_depth == 0);
985 #endif
986 return;
987 }
988
989 /* Flush (draw), and make sure VBO is left unmapped when done */
990 vbo_exec_FlushVertices_internal(exec, GL_TRUE);
991
992 /* Need to do this to ensure BeginVertices gets called again:
993 */
994 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
995
996 #ifdef DEBUG
997 exec->flush_call_depth--;
998 assert(exec->flush_call_depth == 0);
999 #endif
1000 }
1001
1002
1003 static void reset_attrfv( struct vbo_exec_context *exec )
1004 {
1005 GLuint i;
1006
1007 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1008 exec->vtx.attrsz[i] = 0;
1009 exec->vtx.active_sz[i] = 0;
1010 }
1011
1012 exec->vtx.vertex_size = 0;
1013 }
1014
1015
1016 void GLAPIENTRY
1017 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1018 {
1019 vbo_Color4f(r, g, b, a);
1020 }
1021
1022
1023 void GLAPIENTRY
1024 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1025 {
1026 vbo_Normal3f(x, y, z);
1027 }
1028
1029
1030 void GLAPIENTRY
1031 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1032 {
1033 vbo_MultiTexCoord4f(target, s, t, r, q);
1034 }
1035
1036
1037 void GLAPIENTRY
1038 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1039 {
1040 vbo_Materialfv(face, pname, params);
1041 }
1042
1043
1044 void GLAPIENTRY
1045 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1046 {
1047 GLfloat p[4];
1048 p[0] = param;
1049 p[1] = p[2] = p[3] = 0.0F;
1050 vbo_Materialfv(face, pname, p);
1051 }
1052
1053
1054 /**
1055 * A special version of glVertexAttrib4f that does not treat index 0 as
1056 * VBO_ATTRIB_POS.
1057 */
1058 static void
1059 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1060 {
1061 GET_CURRENT_CONTEXT(ctx);
1062 if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1063 ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1064 else
1065 ERROR(GL_INVALID_VALUE);
1066 }
1067
1068 void GLAPIENTRY
1069 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1070 {
1071 VertexAttrib4f_nopos(index, x, y, z, w);
1072 }
1073
1074
1075 void GLAPIENTRY
1076 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1077 {
1078 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1079 }
1080
1081
1082 void GLAPIENTRY
1083 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1084 {
1085 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1086 }
1087
1088
1089 void GLAPIENTRY
1090 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1091 {
1092 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1093 }
1094
1095
1096 void GLAPIENTRY
1097 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1098 {
1099 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1100 }
1101
1102
1103 void GLAPIENTRY
1104 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1105 {
1106 VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1107 }
1108
1109
1110 void GLAPIENTRY
1111 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1112 {
1113 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1114 }
1115
1116
1117 void GLAPIENTRY
1118 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1119 {
1120 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1121 }