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