Merge branch 'mesa_7_5_branch'
[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 #if FEATURE_dlist
39 #include "main/dlist.h"
40 #endif
41 #include "main/state.h"
42 #include "main/light.h"
43 #include "main/api_arrayelt.h"
44 #include "main/api_noop.h"
45 #include "glapi/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 /* 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 /* Deal with buffer wrapping where provoked by the vertex buffer
111 * filling up, as opposed to upgrade_vertex().
112 */
113 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
114 {
115 GLfloat *data = exec->vtx.copied.buffer;
116 GLuint i;
117
118 /* Run pipeline on current vertices, copy wrapped vertices
119 * to exec->vtx.copied.
120 */
121 vbo_exec_wrap_buffers( exec );
122
123 /* Copy stored stored vertices to start of new list.
124 */
125 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
126
127 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
128 _mesa_memcpy( exec->vtx.buffer_ptr, data,
129 exec->vtx.vertex_size * sizeof(GLfloat));
130 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
131 data += exec->vtx.vertex_size;
132 exec->vtx.vert_count++;
133 }
134
135 exec->vtx.copied.nr = 0;
136 }
137
138
139 /*
140 * Copy the active vertex's values to the ctx->Current fields.
141 */
142 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
143 {
144 GLcontext *ctx = exec->ctx;
145 struct vbo_context *vbo = vbo_context(ctx);
146 GLuint i;
147
148 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
149 if (exec->vtx.attrsz[i]) {
150 /* Note: the exec->vtx.current[i] pointers point into the
151 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
152 */
153 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
154 GLfloat tmp[4];
155
156 COPY_CLEAN_4V(tmp,
157 exec->vtx.attrsz[i],
158 exec->vtx.attrptr[i]);
159
160 if (memcmp(current, tmp, sizeof(tmp)) != 0)
161 {
162 memcpy(current, tmp, sizeof(tmp));
163
164 /* Given that we explicitly state size here, there is no need
165 * for the COPY_CLEAN above, could just copy 16 bytes and be
166 * done. The only problem is when Mesa accesses ctx->Current
167 * directly.
168 */
169 vbo->currval[i].Size = exec->vtx.attrsz[i];
170
171 /* This triggers rather too much recalculation of Mesa state
172 * that doesn't get used (eg light positions).
173 */
174 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
175 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
176 ctx->NewState |= _NEW_LIGHT;
177
178 ctx->NewState |= _NEW_CURRENT_ATTRIB;
179 }
180 }
181 }
182
183 /* Colormaterial -- this kindof sucks.
184 */
185 if (ctx->Light.ColorMaterialEnabled &&
186 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
187 _mesa_update_color_material(ctx,
188 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
189 }
190 }
191
192
193 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
194 {
195 GLcontext *ctx = exec->ctx;
196 struct vbo_context *vbo = vbo_context(ctx);
197 GLint i;
198
199 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
200 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
201 switch (exec->vtx.attrsz[i]) {
202 case 4: exec->vtx.attrptr[i][3] = current[3];
203 case 3: exec->vtx.attrptr[i][2] = current[2];
204 case 2: exec->vtx.attrptr[i][1] = current[1];
205 case 1: exec->vtx.attrptr[i][0] = current[0];
206 break;
207 }
208 }
209 }
210
211
212 /* Flush existing data, set new attrib size, replay copied vertices.
213 */
214 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
215 GLuint attr,
216 GLuint newsz )
217 {
218 GLcontext *ctx = exec->ctx;
219 struct vbo_context *vbo = vbo_context(ctx);
220 GLint lastcount = exec->vtx.vert_count;
221 GLfloat *tmp;
222 GLuint oldsz;
223 GLuint i;
224
225 /* Run pipeline on current vertices, copy wrapped vertices
226 * to exec->vtx.copied.
227 */
228 vbo_exec_wrap_buffers( exec );
229
230
231 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
232 * when the attribute already exists in the vertex and is having
233 * its size increased.
234 */
235 vbo_exec_copy_to_current( exec );
236
237
238 /* Heuristic: Attempt to isolate attributes received outside
239 * begin/end so that they don't bloat the vertices.
240 */
241 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
242 exec->vtx.attrsz[attr] == 0 &&
243 lastcount > 8 &&
244 exec->vtx.vertex_size) {
245 reset_attrfv( exec );
246 }
247
248 /* Fix up sizes:
249 */
250 oldsz = exec->vtx.attrsz[attr];
251 exec->vtx.attrsz[attr] = newsz;
252
253 exec->vtx.vertex_size += newsz - oldsz;
254 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
255 (exec->vtx.vertex_size * sizeof(GLfloat)));
256 exec->vtx.vert_count = 0;
257 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
258
259
260 /* Recalculate all the attrptr[] values
261 */
262 for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
263 if (exec->vtx.attrsz[i]) {
264 exec->vtx.attrptr[i] = tmp;
265 tmp += exec->vtx.attrsz[i];
266 }
267 else
268 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
269 }
270
271 /* Copy from current to repopulate the vertex with correct values.
272 */
273 vbo_exec_copy_from_current( exec );
274
275 /* Replay stored vertices to translate them
276 * to new format here.
277 *
278 * -- No need to replay - just copy piecewise
279 */
280 if (exec->vtx.copied.nr)
281 {
282 GLfloat *data = exec->vtx.copied.buffer;
283 GLfloat *dest = exec->vtx.buffer_ptr;
284 GLuint j;
285
286 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
287
288 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
289 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
290 if (exec->vtx.attrsz[j]) {
291 if (j == attr) {
292 if (oldsz) {
293 COPY_CLEAN_4V( dest, oldsz, data );
294 data += oldsz;
295 dest += newsz;
296 } else {
297 const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
298 COPY_SZ_4V( dest, newsz, current );
299 dest += newsz;
300 }
301 }
302 else {
303 GLuint sz = exec->vtx.attrsz[j];
304 COPY_SZ_4V( dest, sz, data );
305 dest += sz;
306 data += sz;
307 }
308 }
309 }
310 }
311
312 exec->vtx.buffer_ptr = dest;
313 exec->vtx.vert_count += exec->vtx.copied.nr;
314 exec->vtx.copied.nr = 0;
315 }
316 }
317
318
319 static void vbo_exec_fixup_vertex( GLcontext *ctx,
320 GLuint attr, GLuint sz )
321 {
322 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
323 int i;
324
325 if (sz > exec->vtx.attrsz[attr]) {
326 /* New size is larger. Need to flush existing vertices and get
327 * an enlarged vertex format.
328 */
329 vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
330 }
331 else if (sz < exec->vtx.active_sz[attr]) {
332 static const GLfloat id[4] = { 0, 0, 0, 1 };
333
334 /* New size is smaller - just need to fill in some
335 * zeros. Don't need to flush or wrap.
336 */
337 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
338 exec->vtx.attrptr[attr][i-1] = id[i-1];
339 }
340
341 exec->vtx.active_sz[attr] = sz;
342
343 /* Does setting NeedFlush belong here? Necessitates resetting
344 * vtxfmt on each flush (otherwise flags won't get reset
345 * afterwards).
346 */
347 if (attr == 0)
348 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
349 }
350
351
352
353
354 /*
355 */
356 #define ATTR( A, N, V0, V1, V2, V3 ) \
357 do { \
358 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
359 \
360 if (exec->vtx.active_sz[A] != N) \
361 vbo_exec_fixup_vertex(ctx, A, N); \
362 \
363 { \
364 GLfloat *dest = exec->vtx.attrptr[A]; \
365 if (N>0) dest[0] = V0; \
366 if (N>1) dest[1] = V1; \
367 if (N>2) dest[2] = V2; \
368 if (N>3) dest[3] = V3; \
369 } \
370 \
371 if ((A) == 0) { \
372 GLuint i; \
373 \
374 for (i = 0; i < exec->vtx.vertex_size; i++) \
375 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
376 \
377 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
378 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
379 \
380 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
381 vbo_exec_vtx_wrap( exec ); \
382 } \
383 } while (0)
384
385
386 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
387 #define TAG(x) vbo_##x
388
389 #include "vbo_attrib_tmp.h"
390
391
392
393
394
395 /* Eval
396 */
397 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
398 {
399 GET_CURRENT_CONTEXT( ctx );
400 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
401
402 {
403 GLint i;
404 if (exec->eval.recalculate_maps)
405 vbo_exec_eval_update( exec );
406
407 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
408 if (exec->eval.map1[i].map)
409 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
410 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
411 }
412 }
413
414
415 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
416 exec->vtx.vertex_size * sizeof(GLfloat));
417
418 vbo_exec_do_EvalCoord1f( exec, u );
419
420 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
421 exec->vtx.vertex_size * sizeof(GLfloat));
422 }
423
424 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
425 {
426 GET_CURRENT_CONTEXT( ctx );
427 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
428
429 {
430 GLint i;
431 if (exec->eval.recalculate_maps)
432 vbo_exec_eval_update( exec );
433
434 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
435 if (exec->eval.map2[i].map)
436 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
437 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
438 }
439
440 if (ctx->Eval.AutoNormal)
441 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
442 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
443 }
444
445 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
446 exec->vtx.vertex_size * sizeof(GLfloat));
447
448 vbo_exec_do_EvalCoord2f( exec, u, v );
449
450 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
451 exec->vtx.vertex_size * sizeof(GLfloat));
452 }
453
454 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
455 {
456 vbo_exec_EvalCoord1f( u[0] );
457 }
458
459 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
460 {
461 vbo_exec_EvalCoord2f( u[0], u[1] );
462 }
463
464 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
465 {
466 GET_CURRENT_CONTEXT( ctx );
467 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
468 (GLfloat) ctx->Eval.MapGrid1un);
469 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
470
471 vbo_exec_EvalCoord1f( u );
472 }
473
474
475 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
476 {
477 GET_CURRENT_CONTEXT( ctx );
478 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
479 (GLfloat) ctx->Eval.MapGrid2un);
480 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
481 (GLfloat) ctx->Eval.MapGrid2vn);
482 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
483 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
484
485 vbo_exec_EvalCoord2f( u, v );
486 }
487
488
489 /**
490 * Check if programs/shaders are enabled and valid at glBegin time.
491 */
492 GLboolean
493 vbo_validate_shaders(GLcontext *ctx)
494 {
495 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
496 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
497 return GL_FALSE;
498 }
499 if (ctx->Shader.CurrentProgram && !ctx->Shader.CurrentProgram->LinkStatus) {
500 return GL_FALSE;
501 }
502 return GL_TRUE;
503 }
504
505
506 /* Build a list of primitives on the fly. Keep
507 * ctx->Driver.CurrentExecPrimitive uptodate as well.
508 */
509 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
510 {
511 GET_CURRENT_CONTEXT( ctx );
512
513 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
514 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
515 int i;
516
517 if (ctx->NewState) {
518 _mesa_update_state( ctx );
519
520 CALL_Begin(ctx->Exec, (mode));
521 return;
522 }
523
524 if (!vbo_validate_shaders(ctx)) {
525 _mesa_error(ctx, GL_INVALID_OPERATION,
526 "glBegin (invalid vertex/fragment program)");
527 return;
528 }
529
530 /* Heuristic: attempt to isolate attributes occuring outside
531 * begin/end pairs.
532 */
533 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
534 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
535
536 i = exec->vtx.prim_count++;
537 exec->vtx.prim[i].mode = mode;
538 exec->vtx.prim[i].begin = 1;
539 exec->vtx.prim[i].end = 0;
540 exec->vtx.prim[i].indexed = 0;
541 exec->vtx.prim[i].weak = 0;
542 exec->vtx.prim[i].pad = 0;
543 exec->vtx.prim[i].start = exec->vtx.vert_count;
544 exec->vtx.prim[i].count = 0;
545
546 ctx->Driver.CurrentExecPrimitive = mode;
547 }
548 else
549 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
550
551 }
552
553 static void GLAPIENTRY vbo_exec_End( void )
554 {
555 GET_CURRENT_CONTEXT( ctx );
556
557 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
558 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
559 int idx = exec->vtx.vert_count;
560 int i = exec->vtx.prim_count - 1;
561
562 exec->vtx.prim[i].end = 1;
563 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
564
565 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
566
567 if (exec->vtx.prim_count == VBO_MAX_PRIM)
568 vbo_exec_vtx_flush( exec, GL_FALSE );
569 }
570 else
571 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
572 }
573
574
575 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
576 {
577 GLvertexformat *vfmt = &exec->vtxfmt;
578
579 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
580 vfmt->Begin = vbo_exec_Begin;
581 #if FEATURE_dlist
582 vfmt->CallList = _mesa_CallList;
583 vfmt->CallLists = _mesa_CallLists;
584 #endif
585 vfmt->End = vbo_exec_End;
586 vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
587 vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
588 vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
589 vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
590 vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
591 vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
592
593 vfmt->Rectf = _mesa_noop_Rectf;
594 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
595 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
596
597
598 /* from attrib_tmp.h:
599 */
600 vfmt->Color3f = vbo_Color3f;
601 vfmt->Color3fv = vbo_Color3fv;
602 vfmt->Color4f = vbo_Color4f;
603 vfmt->Color4fv = vbo_Color4fv;
604 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
605 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
606 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
607 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
608 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
609 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
610 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
611 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
612 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
613 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
614 vfmt->Normal3f = vbo_Normal3f;
615 vfmt->Normal3fv = vbo_Normal3fv;
616 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
617 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
618 vfmt->TexCoord1f = vbo_TexCoord1f;
619 vfmt->TexCoord1fv = vbo_TexCoord1fv;
620 vfmt->TexCoord2f = vbo_TexCoord2f;
621 vfmt->TexCoord2fv = vbo_TexCoord2fv;
622 vfmt->TexCoord3f = vbo_TexCoord3f;
623 vfmt->TexCoord3fv = vbo_TexCoord3fv;
624 vfmt->TexCoord4f = vbo_TexCoord4f;
625 vfmt->TexCoord4fv = vbo_TexCoord4fv;
626 vfmt->Vertex2f = vbo_Vertex2f;
627 vfmt->Vertex2fv = vbo_Vertex2fv;
628 vfmt->Vertex3f = vbo_Vertex3f;
629 vfmt->Vertex3fv = vbo_Vertex3fv;
630 vfmt->Vertex4f = vbo_Vertex4f;
631 vfmt->Vertex4fv = vbo_Vertex4fv;
632
633 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
634 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
635 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
636 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
637 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
638 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
639 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
640 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
641
642 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
643 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
644 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
645 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
646 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
647 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
648 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
649 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
650
651 vfmt->Materialfv = vbo_Materialfv;
652
653 vfmt->EdgeFlag = vbo_EdgeFlag;
654 vfmt->Indexf = vbo_Indexf;
655 vfmt->Indexfv = vbo_Indexfv;
656
657 }
658
659
660 /**
661 * Tell the VBO module to use a real OpenGL vertex buffer object to
662 * store accumulated immediate-mode vertex data.
663 * This replaces the malloced buffer which was created in
664 * vb_exec_vtx_init() below.
665 */
666 void vbo_use_buffer_objects(GLcontext *ctx)
667 {
668 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
669 /* Any buffer name but 0 can be used here since this bufferobj won't
670 * go into the bufferobj hashtable.
671 */
672 GLuint bufName = IMM_BUFFER_NAME;
673 GLenum target = GL_ARRAY_BUFFER_ARB;
674 GLenum usage = GL_STREAM_DRAW_ARB;
675 GLsizei size = VBO_VERT_BUFFER_SIZE;
676
677 /* Make sure this func is only used once */
678 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
679 if (exec->vtx.buffer_map) {
680 _mesa_align_free(exec->vtx.buffer_map);
681 exec->vtx.buffer_map = NULL;
682 exec->vtx.buffer_ptr = NULL;
683 }
684
685 /* Allocate a real buffer object now */
686 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
687 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
688 }
689
690
691
692 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
693 {
694 GLcontext *ctx = exec->ctx;
695 struct vbo_context *vbo = vbo_context(ctx);
696 GLuint i;
697
698 /* Allocate a buffer object. Will just reuse this object
699 * continuously, unless vbo_use_buffer_objects() is called to enable
700 * use of real VBOs.
701 */
702 _mesa_reference_buffer_object(ctx,
703 &exec->vtx.bufferobj,
704 ctx->Shared->NullBufferObj);
705
706 ASSERT(!exec->vtx.buffer_map);
707 exec->vtx.buffer_map = (GLfloat *)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE, 64);
708 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
709
710 vbo_exec_vtxfmt_init( exec );
711
712 /* Hook our functions into the dispatch table.
713 */
714 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
715
716 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
717 exec->vtx.attrsz[i] = 0;
718 exec->vtx.active_sz[i] = 0;
719 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
720 }
721
722 {
723 struct gl_client_array *arrays = exec->vtx.arrays;
724 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
725 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
726 }
727
728 exec->vtx.vertex_size = 0;
729 }
730
731
732 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
733 {
734 /* using a real VBO for vertex data */
735 GLcontext *ctx = exec->ctx;
736 unsigned i;
737
738 /* True VBOs should already be unmapped
739 */
740 if (exec->vtx.buffer_map) {
741 ASSERT(exec->vtx.bufferobj->Name == 0 ||
742 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
743 if (exec->vtx.bufferobj->Name == 0) {
744 ALIGN_FREE(exec->vtx.buffer_map);
745 exec->vtx.buffer_map = NULL;
746 exec->vtx.buffer_ptr = NULL;
747 }
748 }
749
750 /* Drop any outstanding reference to the vertex buffer
751 */
752 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
753 _mesa_reference_buffer_object(ctx,
754 &exec->vtx.arrays[i].BufferObj,
755 NULL);
756 }
757
758 /* Free the vertex buffer:
759 */
760 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
761 }
762
763 void vbo_exec_BeginVertices( GLcontext *ctx )
764 {
765 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
766 if (0) _mesa_printf("%s\n", __FUNCTION__);
767 vbo_exec_vtx_map( exec );
768
769 assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
770 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
771 }
772
773 void vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap )
774 {
775 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
776
777 if (exec->vtx.vert_count || unmap) {
778 vbo_exec_vtx_flush( exec, unmap );
779 }
780
781 if (exec->vtx.vertex_size) {
782 vbo_exec_copy_to_current( exec );
783 reset_attrfv( exec );
784 }
785 }
786
787
788
789 void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
790 {
791 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
792
793 if (0) _mesa_printf("%s\n", __FUNCTION__);
794
795 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
796 if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__);
797 return;
798 }
799
800 vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
801
802 /* Need to do this to ensure BeginVertices gets called again:
803 */
804 if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) {
805 _mesa_restore_exec_vtxfmt( ctx );
806 exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
807 }
808
809 exec->ctx->Driver.NeedFlush &= ~flags;
810 }
811
812
813 static void reset_attrfv( struct vbo_exec_context *exec )
814 {
815 GLuint i;
816
817 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
818 exec->vtx.attrsz[i] = 0;
819 exec->vtx.active_sz[i] = 0;
820 }
821
822 exec->vtx.vertex_size = 0;
823 }
824
825
826 void GLAPIENTRY
827 _vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
828 {
829 vbo_Color4f(r, g, b, a);
830 }
831
832
833 void GLAPIENTRY
834 _vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
835 {
836 vbo_Normal3f(x, y, z);
837 }
838
839
840 void GLAPIENTRY
841 _vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
842 {
843 vbo_MultiTexCoord4f(target, s, t, r, q);
844 }
845
846 void GLAPIENTRY
847 _vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
848 {
849 vbo_Materialfv(face, pname, params);
850 }
851
852
853 void GLAPIENTRY
854 _vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
855 {
856 vbo_VertexAttrib4fARB(index, x, y, z, w);
857 }