Merge branch 'mesa_7_6_branch' into mesa_7_7_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 #include "main/dlist.h"
39 #include "main/eval.h"
40 #include "main/state.h"
41 #include "main/light.h"
42 #include "main/api_arrayelt.h"
43 #include "main/api_noop.h"
44 #include "glapi/dispatch.h"
45
46 #include "vbo_context.h"
47
48 #ifdef ERROR
49 #undef ERROR
50 #endif
51
52
53 /** ID/name for immediate-mode VBO */
54 #define IMM_BUFFER_NAME 0xaabbccdd
55
56
57 static void reset_attrfv( struct vbo_exec_context *exec );
58
59
60 /**
61 * Close off the last primitive, execute the buffer, restart the
62 * primitive.
63 */
64 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
65 {
66 if (exec->vtx.prim_count == 0) {
67 exec->vtx.copied.nr = 0;
68 exec->vtx.vert_count = 0;
69 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
70 }
71 else {
72 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
73 GLuint last_count;
74
75 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
76 GLint i = exec->vtx.prim_count - 1;
77 assert(i >= 0);
78 exec->vtx.prim[i].count = (exec->vtx.vert_count -
79 exec->vtx.prim[i].start);
80 }
81
82 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
83
84 /* Execute the buffer and save copied vertices.
85 */
86 if (exec->vtx.vert_count)
87 vbo_exec_vtx_flush( exec, GL_FALSE );
88 else {
89 exec->vtx.prim_count = 0;
90 exec->vtx.copied.nr = 0;
91 }
92
93 /* Emit a glBegin to start the new list.
94 */
95 assert(exec->vtx.prim_count == 0);
96
97 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
98 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
99 exec->vtx.prim[0].start = 0;
100 exec->vtx.prim[0].count = 0;
101 exec->vtx.prim_count++;
102
103 if (exec->vtx.copied.nr == last_count)
104 exec->vtx.prim[0].begin = last_begin;
105 }
106 }
107 }
108
109
110 /**
111 * Deal with buffer wrapping where provoked by the vertex buffer
112 * filling up, as opposed to upgrade_vertex().
113 */
114 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
115 {
116 GLfloat *data = exec->vtx.copied.buffer;
117 GLuint i;
118
119 /* Run pipeline on current vertices, copy wrapped vertices
120 * to exec->vtx.copied.
121 */
122 vbo_exec_wrap_buffers( exec );
123
124 /* Copy stored stored vertices to start of new list.
125 */
126 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
127
128 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
129 _mesa_memcpy( exec->vtx.buffer_ptr, data,
130 exec->vtx.vertex_size * sizeof(GLfloat));
131 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
132 data += exec->vtx.vertex_size;
133 exec->vtx.vert_count++;
134 }
135
136 exec->vtx.copied.nr = 0;
137 }
138
139
140 /**
141 * Copy the active vertex's values to the ctx->Current fields.
142 */
143 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
144 {
145 GLcontext *ctx = exec->ctx;
146 struct vbo_context *vbo = vbo_context(ctx);
147 GLuint i;
148
149 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
150 if (exec->vtx.attrsz[i]) {
151 /* Note: the exec->vtx.current[i] pointers point into the
152 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
153 */
154 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
155 GLfloat tmp[4];
156
157 COPY_CLEAN_4V(tmp,
158 exec->vtx.attrsz[i],
159 exec->vtx.attrptr[i]);
160
161 if (memcmp(current, tmp, sizeof(tmp)) != 0)
162 {
163 memcpy(current, tmp, sizeof(tmp));
164
165 /* Given that we explicitly state size here, there is no need
166 * for the COPY_CLEAN above, could just copy 16 bytes and be
167 * done. The only problem is when Mesa accesses ctx->Current
168 * directly.
169 */
170 vbo->currval[i].Size = exec->vtx.attrsz[i];
171
172 /* This triggers rather too much recalculation of Mesa state
173 * that doesn't get used (eg light positions).
174 */
175 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
176 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
177 ctx->NewState |= _NEW_LIGHT;
178
179 ctx->NewState |= _NEW_CURRENT_ATTRIB;
180 }
181 }
182 }
183
184 /* Colormaterial -- this kindof sucks.
185 */
186 if (ctx->Light.ColorMaterialEnabled &&
187 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
188 _mesa_update_color_material(ctx,
189 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
190 }
191 }
192
193
194 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
195 {
196 GLcontext *ctx = exec->ctx;
197 struct vbo_context *vbo = vbo_context(ctx);
198 GLint i;
199
200 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
201 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
202 switch (exec->vtx.attrsz[i]) {
203 case 4: exec->vtx.attrptr[i][3] = current[3];
204 case 3: exec->vtx.attrptr[i][2] = current[2];
205 case 2: exec->vtx.attrptr[i][1] = current[1];
206 case 1: exec->vtx.attrptr[i][0] = current[0];
207 break;
208 }
209 }
210 }
211
212
213 /**
214 * Flush existing data, set new attrib size, replay copied vertices.
215 */
216 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
217 GLuint attr,
218 GLuint newsz )
219 {
220 GLcontext *ctx = exec->ctx;
221 struct vbo_context *vbo = vbo_context(ctx);
222 GLint lastcount = exec->vtx.vert_count;
223 GLfloat *tmp;
224 GLuint oldsz;
225 GLuint i;
226
227 /* Run pipeline on current vertices, copy wrapped vertices
228 * to exec->vtx.copied.
229 */
230 vbo_exec_wrap_buffers( exec );
231
232
233 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
234 * when the attribute already exists in the vertex and is having
235 * its size increased.
236 */
237 vbo_exec_copy_to_current( exec );
238
239
240 /* Heuristic: Attempt to isolate attributes received outside
241 * begin/end so that they don't bloat the vertices.
242 */
243 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
244 exec->vtx.attrsz[attr] == 0 &&
245 lastcount > 8 &&
246 exec->vtx.vertex_size) {
247 reset_attrfv( exec );
248 }
249
250 /* Fix up sizes:
251 */
252 oldsz = exec->vtx.attrsz[attr];
253 exec->vtx.attrsz[attr] = newsz;
254
255 exec->vtx.vertex_size += newsz - oldsz;
256 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
257 (exec->vtx.vertex_size * sizeof(GLfloat)));
258 exec->vtx.vert_count = 0;
259 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
260
261
262 /* Recalculate all the attrptr[] values
263 */
264 for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
265 if (exec->vtx.attrsz[i]) {
266 exec->vtx.attrptr[i] = tmp;
267 tmp += exec->vtx.attrsz[i];
268 }
269 else
270 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
271 }
272
273 /* Copy from current to repopulate the vertex with correct values.
274 */
275 vbo_exec_copy_from_current( exec );
276
277 /* Replay stored vertices to translate them
278 * to new format here.
279 *
280 * -- No need to replay - just copy piecewise
281 */
282 if (exec->vtx.copied.nr)
283 {
284 GLfloat *data = exec->vtx.copied.buffer;
285 GLfloat *dest = exec->vtx.buffer_ptr;
286 GLuint j;
287
288 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
289
290 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
291 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
292 if (exec->vtx.attrsz[j]) {
293 if (j == attr) {
294 if (oldsz) {
295 COPY_CLEAN_4V( dest, oldsz, data );
296 data += oldsz;
297 dest += newsz;
298 } else {
299 const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
300 COPY_SZ_4V( dest, newsz, current );
301 dest += newsz;
302 }
303 }
304 else {
305 GLuint sz = exec->vtx.attrsz[j];
306 COPY_SZ_4V( dest, sz, data );
307 dest += sz;
308 data += sz;
309 }
310 }
311 }
312 }
313
314 exec->vtx.buffer_ptr = dest;
315 exec->vtx.vert_count += exec->vtx.copied.nr;
316 exec->vtx.copied.nr = 0;
317 }
318 }
319
320
321 static void vbo_exec_fixup_vertex( GLcontext *ctx,
322 GLuint attr, GLuint sz )
323 {
324 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
325 int i;
326
327 if (sz > exec->vtx.attrsz[attr]) {
328 /* New size is larger. Need to flush existing vertices and get
329 * an enlarged vertex format.
330 */
331 vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
332 }
333 else if (sz < exec->vtx.active_sz[attr]) {
334 static const GLfloat id[4] = { 0, 0, 0, 1 };
335
336 /* New size is smaller - just need to fill in some
337 * zeros. Don't need to flush or wrap.
338 */
339 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
340 exec->vtx.attrptr[attr][i-1] = id[i-1];
341 }
342
343 exec->vtx.active_sz[attr] = sz;
344
345 /* Does setting NeedFlush belong here? Necessitates resetting
346 * vtxfmt on each flush (otherwise flags won't get reset
347 * afterwards).
348 */
349 if (attr == 0)
350 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
351 }
352
353
354 #if FEATURE_beginend
355
356 /*
357 */
358 #define ATTR( A, N, V0, V1, V2, V3 ) \
359 do { \
360 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
361 \
362 if (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 #if FEATURE_evaluators
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 /* use noop eval mesh */
491 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
492 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
493
494 #endif /* FEATURE_evaluators */
495
496
497 /**
498 * Called via glBegin.
499 */
500 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
501 {
502 GET_CURRENT_CONTEXT( ctx );
503
504 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
505 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
506 int i;
507
508 if (ctx->NewState) {
509 _mesa_update_state( ctx );
510
511 CALL_Begin(ctx->Exec, (mode));
512 return;
513 }
514
515 if (!_mesa_valid_to_render(ctx, "glBegin")) {
516 return;
517 }
518
519 /* Heuristic: attempt to isolate attributes occuring outside
520 * begin/end pairs.
521 */
522 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
523 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
524
525 i = exec->vtx.prim_count++;
526 exec->vtx.prim[i].mode = mode;
527 exec->vtx.prim[i].begin = 1;
528 exec->vtx.prim[i].end = 0;
529 exec->vtx.prim[i].indexed = 0;
530 exec->vtx.prim[i].weak = 0;
531 exec->vtx.prim[i].pad = 0;
532 exec->vtx.prim[i].start = exec->vtx.vert_count;
533 exec->vtx.prim[i].count = 0;
534
535 ctx->Driver.CurrentExecPrimitive = mode;
536 }
537 else
538 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
539
540 }
541
542
543 /**
544 * Called via glEnd.
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, GL_FALSE );
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 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
573
574 vfmt->Begin = vbo_exec_Begin;
575 vfmt->End = vbo_exec_End;
576
577 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
578 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
579
580 vfmt->Rectf = _mesa_noop_Rectf;
581
582 /* from attrib_tmp.h:
583 */
584 vfmt->Color3f = vbo_Color3f;
585 vfmt->Color3fv = vbo_Color3fv;
586 vfmt->Color4f = vbo_Color4f;
587 vfmt->Color4fv = vbo_Color4fv;
588 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
589 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
590 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
591 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
592 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
593 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
594 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
595 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
596 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
597 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
598 vfmt->Normal3f = vbo_Normal3f;
599 vfmt->Normal3fv = vbo_Normal3fv;
600 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
601 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
602 vfmt->TexCoord1f = vbo_TexCoord1f;
603 vfmt->TexCoord1fv = vbo_TexCoord1fv;
604 vfmt->TexCoord2f = vbo_TexCoord2f;
605 vfmt->TexCoord2fv = vbo_TexCoord2fv;
606 vfmt->TexCoord3f = vbo_TexCoord3f;
607 vfmt->TexCoord3fv = vbo_TexCoord3fv;
608 vfmt->TexCoord4f = vbo_TexCoord4f;
609 vfmt->TexCoord4fv = vbo_TexCoord4fv;
610 vfmt->Vertex2f = vbo_Vertex2f;
611 vfmt->Vertex2fv = vbo_Vertex2fv;
612 vfmt->Vertex3f = vbo_Vertex3f;
613 vfmt->Vertex3fv = vbo_Vertex3fv;
614 vfmt->Vertex4f = vbo_Vertex4f;
615 vfmt->Vertex4fv = vbo_Vertex4fv;
616
617 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
618 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
619 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
620 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
621 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
622 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
623 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
624 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
625
626 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
627 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
628 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
629 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
630 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
631 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
632 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
633 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
634
635 vfmt->Materialfv = vbo_Materialfv;
636
637 vfmt->EdgeFlag = vbo_EdgeFlag;
638 vfmt->Indexf = vbo_Indexf;
639 vfmt->Indexfv = vbo_Indexfv;
640
641 }
642
643
644 #else /* FEATURE_beginend */
645
646
647 #define ATTR( A, N, V0, V1, V2, V3 ) \
648 do { \
649 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
650 \
651 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
652 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
653 \
654 if (exec->vtx.active_sz[A] != N) \
655 vbo_exec_fixup_vertex(ctx, A, N); \
656 \
657 { \
658 GLfloat *dest = exec->vtx.attrptr[A]; \
659 if (N>0) dest[0] = V0; \
660 if (N>1) dest[1] = V1; \
661 if (N>2) dest[2] = V2; \
662 if (N>3) dest[3] = V3; \
663 } \
664 } while (0)
665
666 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
667 #define TAG(x) vbo_##x
668
669 #include "vbo_attrib_tmp.h"
670
671 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
672 {
673 /* silence warnings */
674 (void) vbo_Color3f;
675 (void) vbo_Color3fv;
676 (void) vbo_Color4f;
677 (void) vbo_Color4fv;
678 (void) vbo_FogCoordfEXT;
679 (void) vbo_FogCoordfvEXT;
680 (void) vbo_MultiTexCoord1f;
681 (void) vbo_MultiTexCoord1fv;
682 (void) vbo_MultiTexCoord2f;
683 (void) vbo_MultiTexCoord2fv;
684 (void) vbo_MultiTexCoord3f;
685 (void) vbo_MultiTexCoord3fv;
686 (void) vbo_MultiTexCoord4f;
687 (void) vbo_MultiTexCoord4fv;
688 (void) vbo_Normal3f;
689 (void) vbo_Normal3fv;
690 (void) vbo_SecondaryColor3fEXT;
691 (void) vbo_SecondaryColor3fvEXT;
692 (void) vbo_TexCoord1f;
693 (void) vbo_TexCoord1fv;
694 (void) vbo_TexCoord2f;
695 (void) vbo_TexCoord2fv;
696 (void) vbo_TexCoord3f;
697 (void) vbo_TexCoord3fv;
698 (void) vbo_TexCoord4f;
699 (void) vbo_TexCoord4fv;
700 (void) vbo_Vertex2f;
701 (void) vbo_Vertex2fv;
702 (void) vbo_Vertex3f;
703 (void) vbo_Vertex3fv;
704 (void) vbo_Vertex4f;
705 (void) vbo_Vertex4fv;
706
707 (void) vbo_VertexAttrib1fARB;
708 (void) vbo_VertexAttrib1fvARB;
709 (void) vbo_VertexAttrib2fARB;
710 (void) vbo_VertexAttrib2fvARB;
711 (void) vbo_VertexAttrib3fARB;
712 (void) vbo_VertexAttrib3fvARB;
713 (void) vbo_VertexAttrib4fARB;
714 (void) vbo_VertexAttrib4fvARB;
715
716 (void) vbo_VertexAttrib1fNV;
717 (void) vbo_VertexAttrib1fvNV;
718 (void) vbo_VertexAttrib2fNV;
719 (void) vbo_VertexAttrib2fvNV;
720 (void) vbo_VertexAttrib3fNV;
721 (void) vbo_VertexAttrib3fvNV;
722 (void) vbo_VertexAttrib4fNV;
723 (void) vbo_VertexAttrib4fvNV;
724
725 (void) vbo_Materialfv;
726
727 (void) vbo_EdgeFlag;
728 (void) vbo_Indexf;
729 (void) vbo_Indexfv;
730 }
731
732
733 #endif /* FEATURE_beginend */
734
735
736 /**
737 * Tell the VBO module to use a real OpenGL vertex buffer object to
738 * store accumulated immediate-mode vertex data.
739 * This replaces the malloced buffer which was created in
740 * vb_exec_vtx_init() below.
741 */
742 void vbo_use_buffer_objects(GLcontext *ctx)
743 {
744 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
745 /* Any buffer name but 0 can be used here since this bufferobj won't
746 * go into the bufferobj hashtable.
747 */
748 GLuint bufName = IMM_BUFFER_NAME;
749 GLenum target = GL_ARRAY_BUFFER_ARB;
750 GLenum usage = GL_STREAM_DRAW_ARB;
751 GLsizei size = VBO_VERT_BUFFER_SIZE;
752
753 /* Make sure this func is only used once */
754 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
755 if (exec->vtx.buffer_map) {
756 _mesa_align_free(exec->vtx.buffer_map);
757 exec->vtx.buffer_map = NULL;
758 exec->vtx.buffer_ptr = NULL;
759 }
760
761 /* Allocate a real buffer object now */
762 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
763 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
764 }
765
766
767
768 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
769 {
770 GLcontext *ctx = exec->ctx;
771 struct vbo_context *vbo = vbo_context(ctx);
772 GLuint i;
773
774 /* Allocate a buffer object. Will just reuse this object
775 * continuously, unless vbo_use_buffer_objects() is called to enable
776 * use of real VBOs.
777 */
778 _mesa_reference_buffer_object(ctx,
779 &exec->vtx.bufferobj,
780 ctx->Shared->NullBufferObj);
781
782 ASSERT(!exec->vtx.buffer_map);
783 exec->vtx.buffer_map = (GLfloat *)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE, 64);
784 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
785
786 vbo_exec_vtxfmt_init( exec );
787
788 /* Hook our functions into the dispatch table.
789 */
790 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
791
792 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
793 ASSERT(i < Elements(exec->vtx.attrsz));
794 exec->vtx.attrsz[i] = 0;
795 ASSERT(i < Elements(exec->vtx.active_sz));
796 exec->vtx.active_sz[i] = 0;
797 }
798 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
799 ASSERT(i < Elements(exec->vtx.inputs));
800 ASSERT(i < Elements(exec->vtx.arrays));
801 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
802 }
803
804 {
805 struct gl_client_array *arrays = exec->vtx.arrays;
806 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
807 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
808 }
809
810 exec->vtx.vertex_size = 0;
811 }
812
813
814 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
815 {
816 /* using a real VBO for vertex data */
817 GLcontext *ctx = exec->ctx;
818 unsigned i;
819
820 /* True VBOs should already be unmapped
821 */
822 if (exec->vtx.buffer_map) {
823 ASSERT(exec->vtx.bufferobj->Name == 0 ||
824 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
825 if (exec->vtx.bufferobj->Name == 0) {
826 ALIGN_FREE(exec->vtx.buffer_map);
827 exec->vtx.buffer_map = NULL;
828 exec->vtx.buffer_ptr = NULL;
829 }
830 }
831
832 /* Drop any outstanding reference to the vertex buffer
833 */
834 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
835 _mesa_reference_buffer_object(ctx,
836 &exec->vtx.arrays[i].BufferObj,
837 NULL);
838 }
839
840 /* Free the vertex buffer:
841 */
842 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
843 }
844
845 void vbo_exec_BeginVertices( GLcontext *ctx )
846 {
847 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
848 if (0) _mesa_printf("%s\n", __FUNCTION__);
849 vbo_exec_vtx_map( exec );
850
851 assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
852 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
853 }
854
855 void vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap )
856 {
857 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
858
859 if (exec->vtx.vert_count || unmap) {
860 vbo_exec_vtx_flush( exec, unmap );
861 }
862
863 if (exec->vtx.vertex_size) {
864 vbo_exec_copy_to_current( exec );
865 reset_attrfv( exec );
866 }
867 }
868
869
870 /**
871 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
872 */
873 void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
874 {
875 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
876
877 #ifdef DEBUG
878 /* debug check: make sure we don't get called recursively */
879 exec->flush_call_depth++;
880 assert(exec->flush_call_depth == 1);
881 #endif
882
883 if (0) _mesa_printf("%s\n", __FUNCTION__);
884
885 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
886 if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__);
887 #ifdef DEBUG
888 exec->flush_call_depth--;
889 assert(exec->flush_call_depth == 0);
890 #endif
891 return;
892 }
893
894 vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
895
896 /* Need to do this to ensure BeginVertices gets called again:
897 */
898 if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) {
899 _mesa_restore_exec_vtxfmt( ctx );
900 exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
901 }
902
903 exec->ctx->Driver.NeedFlush &= ~flags;
904
905 #ifdef DEBUG
906 exec->flush_call_depth--;
907 assert(exec->flush_call_depth == 0);
908 #endif
909 }
910
911
912 static void reset_attrfv( struct vbo_exec_context *exec )
913 {
914 GLuint i;
915
916 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
917 exec->vtx.attrsz[i] = 0;
918 exec->vtx.active_sz[i] = 0;
919 }
920
921 exec->vtx.vertex_size = 0;
922 }
923
924
925 void GLAPIENTRY
926 _vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
927 {
928 vbo_Color4f(r, g, b, a);
929 }
930
931
932 void GLAPIENTRY
933 _vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
934 {
935 vbo_Normal3f(x, y, z);
936 }
937
938
939 void GLAPIENTRY
940 _vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
941 {
942 vbo_MultiTexCoord4f(target, s, t, r, q);
943 }
944
945 void GLAPIENTRY
946 _vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
947 {
948 vbo_Materialfv(face, pname, params);
949 }
950
951
952 void GLAPIENTRY
953 _vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
954 {
955 vbo_VertexAttrib4fARB(index, x, y, z, w);
956 }