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