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