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