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