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