Merge commit 'origin/gallium-0.1'
[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.buffer_ptr = 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, GL_FALSE );
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.buffer_ptr, data,
125 exec->vtx.vertex_size * sizeof(GLfloat));
126 exec->vtx.buffer_ptr += 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 /* Note: the exec->vtx.current[i] pointers point into the
147 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
148 */
149 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
150 GLfloat tmp[4];
151
152 COPY_CLEAN_4V(tmp,
153 exec->vtx.attrsz[i],
154 exec->vtx.attrptr[i]);
155
156 if (memcmp(current, tmp, sizeof(tmp)) != 0)
157 {
158 memcpy(current, tmp, sizeof(tmp));
159
160 /* Given that we explicitly state size here, there is no need
161 * for the COPY_CLEAN above, could just copy 16 bytes and be
162 * done. The only problem is when Mesa accesses ctx->Current
163 * directly.
164 */
165 vbo->currval[i].Size = exec->vtx.attrsz[i];
166
167 /* This triggers rather too much recalculation of Mesa state
168 * that doesn't get used (eg light positions).
169 */
170 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
171 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
172 ctx->NewState |= _NEW_LIGHT;
173
174 ctx->NewState |= _NEW_CURRENT_ATTRIB;
175 }
176 }
177 }
178
179 /* Colormaterial -- this kindof sucks.
180 */
181 if (ctx->Light.ColorMaterialEnabled &&
182 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
183 _mesa_update_color_material(ctx,
184 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
185 }
186
187 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
188 }
189
190
191 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
192 {
193 GLcontext *ctx = exec->ctx;
194 struct vbo_context *vbo = vbo_context(ctx);
195 GLint i;
196
197 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
198 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
199 switch (exec->vtx.attrsz[i]) {
200 case 4: exec->vtx.attrptr[i][3] = current[3];
201 case 3: exec->vtx.attrptr[i][2] = current[2];
202 case 2: exec->vtx.attrptr[i][1] = current[1];
203 case 1: exec->vtx.attrptr[i][0] = current[0];
204 break;
205 }
206 }
207
208 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
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 else
350 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
351 }
352
353
354
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 (exec->vtx.active_sz[A] != N) \
363 vbo_exec_fixup_vertex(ctx, A, N); \
364 \
365 { \
366 GLfloat *dest = exec->vtx.attrptr[A]; \
367 if (N>0) dest[0] = V0; \
368 if (N>1) dest[1] = V1; \
369 if (N>2) dest[2] = V2; \
370 if (N>3) dest[3] = V3; \
371 } \
372 \
373 if ((A) == 0) { \
374 GLuint i; \
375 \
376 for (i = 0; i < exec->vtx.vertex_size; i++) \
377 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
378 \
379 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
380 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
381 \
382 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
383 vbo_exec_vtx_wrap( exec ); \
384 } \
385 } while (0)
386
387
388 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
389 #define TAG(x) vbo_##x
390
391 #include "vbo_attrib_tmp.h"
392
393
394
395
396
397 /* Eval
398 */
399 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
400 {
401 GET_CURRENT_CONTEXT( ctx );
402 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
403
404 {
405 GLint i;
406 if (exec->eval.recalculate_maps)
407 vbo_exec_eval_update( exec );
408
409 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
410 if (exec->eval.map1[i].map)
411 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
412 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
413 }
414 }
415
416
417 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
418 exec->vtx.vertex_size * sizeof(GLfloat));
419
420 vbo_exec_do_EvalCoord1f( exec, u );
421
422 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
423 exec->vtx.vertex_size * sizeof(GLfloat));
424 }
425
426 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
427 {
428 GET_CURRENT_CONTEXT( ctx );
429 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
430
431 {
432 GLint i;
433 if (exec->eval.recalculate_maps)
434 vbo_exec_eval_update( exec );
435
436 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
437 if (exec->eval.map2[i].map)
438 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
439 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
440 }
441
442 if (ctx->Eval.AutoNormal)
443 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
444 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
445 }
446
447 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
448 exec->vtx.vertex_size * sizeof(GLfloat));
449
450 vbo_exec_do_EvalCoord2f( exec, u, v );
451
452 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
453 exec->vtx.vertex_size * sizeof(GLfloat));
454 }
455
456 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
457 {
458 vbo_exec_EvalCoord1f( u[0] );
459 }
460
461 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
462 {
463 vbo_exec_EvalCoord2f( u[0], u[1] );
464 }
465
466 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
467 {
468 GET_CURRENT_CONTEXT( ctx );
469 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
470 (GLfloat) ctx->Eval.MapGrid1un);
471 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
472
473 vbo_exec_EvalCoord1f( u );
474 }
475
476
477 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
478 {
479 GET_CURRENT_CONTEXT( ctx );
480 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
481 (GLfloat) ctx->Eval.MapGrid2un);
482 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
483 (GLfloat) ctx->Eval.MapGrid2vn);
484 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
485 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
486
487 vbo_exec_EvalCoord2f( u, v );
488 }
489
490
491 /**
492 * Check if programs/shaders are enabled and valid at glBegin time.
493 */
494 GLboolean
495 vbo_validate_shaders(GLcontext *ctx)
496 {
497 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
498 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
499 return GL_FALSE;
500 }
501 if (ctx->Shader.CurrentProgram && !ctx->Shader.CurrentProgram->LinkStatus) {
502 return GL_FALSE;
503 }
504 return GL_TRUE;
505 }
506
507
508 /* Build a list of primitives on the fly. Keep
509 * ctx->Driver.CurrentExecPrimitive uptodate as well.
510 */
511 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
512 {
513 GET_CURRENT_CONTEXT( ctx );
514
515 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
516 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
517 int i;
518
519 if (ctx->NewState) {
520 _mesa_update_state( ctx );
521
522 CALL_Begin(ctx->Exec, (mode));
523 return;
524 }
525
526 if (!vbo_validate_shaders(ctx)) {
527 _mesa_error(ctx, GL_INVALID_OPERATION,
528 "glBegin (invalid vertex/fragment program)");
529 return;
530 }
531
532 /* Heuristic: attempt to isolate attributes occuring outside
533 * begin/end pairs.
534 */
535 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
536 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
537
538 i = exec->vtx.prim_count++;
539 exec->vtx.prim[i].mode = mode;
540 exec->vtx.prim[i].begin = 1;
541 exec->vtx.prim[i].end = 0;
542 exec->vtx.prim[i].indexed = 0;
543 exec->vtx.prim[i].weak = 0;
544 exec->vtx.prim[i].pad = 0;
545 exec->vtx.prim[i].start = exec->vtx.vert_count;
546 exec->vtx.prim[i].count = 0;
547
548 ctx->Driver.CurrentExecPrimitive = mode;
549 }
550 else
551 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
552
553 }
554
555 static void GLAPIENTRY vbo_exec_End( void )
556 {
557 GET_CURRENT_CONTEXT( ctx );
558
559 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
560 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
561 int idx = exec->vtx.vert_count;
562 int i = exec->vtx.prim_count - 1;
563
564 exec->vtx.prim[i].end = 1;
565 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
566
567 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
568
569 if (exec->vtx.prim_count == VBO_MAX_PRIM)
570 vbo_exec_vtx_flush( exec, GL_FALSE );
571 }
572 else
573 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
574 }
575
576
577 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
578 {
579 GLvertexformat *vfmt = &exec->vtxfmt;
580
581 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
582 vfmt->Begin = vbo_exec_Begin;
583 #if FEATURE_dlist
584 vfmt->CallList = _mesa_CallList;
585 vfmt->CallLists = _mesa_CallLists;
586 #endif
587 vfmt->End = vbo_exec_End;
588 vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
589 vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
590 vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
591 vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
592 vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
593 vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
594
595 vfmt->Rectf = _mesa_noop_Rectf;
596 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
597 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
598
599
600 /* from attrib_tmp.h:
601 */
602 vfmt->Color3f = vbo_Color3f;
603 vfmt->Color3fv = vbo_Color3fv;
604 vfmt->Color4f = vbo_Color4f;
605 vfmt->Color4fv = vbo_Color4fv;
606 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
607 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
608 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
609 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
610 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
611 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
612 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
613 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
614 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
615 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
616 vfmt->Normal3f = vbo_Normal3f;
617 vfmt->Normal3fv = vbo_Normal3fv;
618 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
619 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
620 vfmt->TexCoord1f = vbo_TexCoord1f;
621 vfmt->TexCoord1fv = vbo_TexCoord1fv;
622 vfmt->TexCoord2f = vbo_TexCoord2f;
623 vfmt->TexCoord2fv = vbo_TexCoord2fv;
624 vfmt->TexCoord3f = vbo_TexCoord3f;
625 vfmt->TexCoord3fv = vbo_TexCoord3fv;
626 vfmt->TexCoord4f = vbo_TexCoord4f;
627 vfmt->TexCoord4fv = vbo_TexCoord4fv;
628 vfmt->Vertex2f = vbo_Vertex2f;
629 vfmt->Vertex2fv = vbo_Vertex2fv;
630 vfmt->Vertex3f = vbo_Vertex3f;
631 vfmt->Vertex3fv = vbo_Vertex3fv;
632 vfmt->Vertex4f = vbo_Vertex4f;
633 vfmt->Vertex4fv = vbo_Vertex4fv;
634
635 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
636 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
637 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
638 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
639 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
640 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
641 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
642 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
643
644 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
645 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
646 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
647 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
648 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
649 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
650 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
651 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
652
653 vfmt->Materialfv = vbo_Materialfv;
654
655 vfmt->EdgeFlag = vbo_EdgeFlag;
656 vfmt->Indexf = vbo_Indexf;
657 vfmt->Indexfv = vbo_Indexfv;
658
659 }
660
661
662 /**
663 * Tell the VBO module to use a real OpenGL vertex buffer object to
664 * store accumulated immediate-mode vertex data.
665 * This replaces the malloced buffer which was created in
666 * vb_exec_vtx_init() below.
667 */
668 void vbo_use_buffer_objects(GLcontext *ctx)
669 {
670 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
671 /* Any buffer name but 0 can be used here since this bufferobj won't
672 * go into the bufferobj hashtable.
673 */
674 GLuint bufName = 0xaabbccdd;
675 GLenum target = GL_ARRAY_BUFFER_ARB;
676 GLenum usage = GL_STREAM_DRAW_ARB;
677 GLsizei size = VBO_VERT_BUFFER_SIZE;
678
679 /* Make sure this func is only used once */
680 assert(exec->vtx.bufferobj == ctx->Array.NullBufferObj);
681 if (exec->vtx.buffer_map) {
682 _mesa_align_free(exec->vtx.buffer_map);
683 exec->vtx.buffer_map = NULL;
684 }
685
686 /* Allocate a real buffer object now */
687 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
688 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
689 }
690
691
692
693 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
694 {
695 GLcontext *ctx = exec->ctx;
696 struct vbo_context *vbo = vbo_context(ctx);
697 GLuint i;
698
699 /* Allocate a buffer object. Will just reuse this object
700 * continuously, unless vbo_use_buffer_objects() is called to enable
701 * use of real VBOs.
702 */
703 _mesa_reference_buffer_object(ctx,
704 &exec->vtx.bufferobj,
705 ctx->Array.NullBufferObj);
706
707 ASSERT(!exec->vtx.buffer_map);
708 exec->vtx.buffer_map = (GLfloat *)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE, 64);
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 if (exec->vtx.bufferobj->Name) {
735 /* using a real VBO for vertex data */
736 GLcontext *ctx = exec->ctx;
737 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
738 }
739 else {
740 /* just using malloc'd space for vertex data */
741 if (exec->vtx.buffer_map) {
742 ALIGN_FREE(exec->vtx.buffer_map);
743 exec->vtx.buffer_map = NULL;
744 }
745 }
746 }
747
748 void vbo_exec_BeginVertices( GLcontext *ctx )
749 {
750 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
751 if (0) _mesa_printf("%s\n", __FUNCTION__);
752 vbo_exec_vtx_map( exec );
753 }
754
755 void vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap )
756 {
757 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
758
759 if (exec->vtx.vert_count || unmap) {
760 vbo_exec_vtx_flush( exec, unmap );
761 }
762
763 if (exec->vtx.vertex_size) {
764 vbo_exec_copy_to_current( exec );
765 reset_attrfv( exec );
766 }
767 }
768
769
770
771 void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
772 {
773 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
774
775 if (0) _mesa_printf("%s\n", __FUNCTION__);
776
777 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
778 if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__);
779 return;
780 }
781
782 vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
783
784 /* Need to do this to ensure BeginVertices gets called again:
785 */
786 _mesa_restore_exec_vtxfmt( ctx );
787
788 exec->ctx->Driver.NeedFlush = 0;
789 }
790
791
792 static void reset_attrfv( struct vbo_exec_context *exec )
793 {
794 GLuint i;
795
796 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
797 exec->vtx.attrsz[i] = 0;
798 exec->vtx.active_sz[i] = 0;
799 }
800
801 exec->vtx.vertex_size = 0;
802 }
803
804
805 void GLAPIENTRY
806 _vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
807 {
808 vbo_Color4f(r, g, b, a);
809 }
810
811
812 void GLAPIENTRY
813 _vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
814 {
815 vbo_Normal3f(x, y, z);
816 }
817
818
819 void GLAPIENTRY
820 _vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
821 {
822 vbo_MultiTexCoord4f(target, s, t, r, q);
823 }
824
825 void GLAPIENTRY
826 _vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
827 {
828 vbo_Materialfv(face, pname, params);
829 }
830
831
832 void GLAPIENTRY
833 _vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
834 {
835 vbo_VertexAttrib4fARB(index, x, y, z, w);
836 }