st/mesa: support for 1D/2D texture arrays
[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/mfeatures.h"
38 #include "main/vtxfmt.h"
39 #include "main/dlist.h"
40 #include "main/eval.h"
41 #include "main/state.h"
42 #include "main/light.h"
43 #include "main/api_arrayelt.h"
44 #include "main/api_noop.h"
45 #include "main/dispatch.h"
46
47 #include "vbo_context.h"
48
49 #ifdef ERROR
50 #undef ERROR
51 #endif
52
53
54 /** ID/name for immediate-mode VBO */
55 #define IMM_BUFFER_NAME 0xaabbccdd
56
57
58 static void reset_attrfv( struct vbo_exec_context *exec );
59
60
61 /**
62 * Close off the last primitive, execute the buffer, restart the
63 * primitive.
64 */
65 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
66 {
67 if (exec->vtx.prim_count == 0) {
68 exec->vtx.copied.nr = 0;
69 exec->vtx.vert_count = 0;
70 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
71 }
72 else {
73 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
74 GLuint last_count;
75
76 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
77 GLint i = exec->vtx.prim_count - 1;
78 assert(i >= 0);
79 exec->vtx.prim[i].count = (exec->vtx.vert_count -
80 exec->vtx.prim[i].start);
81 }
82
83 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
84
85 /* Execute the buffer and save copied vertices.
86 */
87 if (exec->vtx.vert_count)
88 vbo_exec_vtx_flush( exec, GL_FALSE );
89 else {
90 exec->vtx.prim_count = 0;
91 exec->vtx.copied.nr = 0;
92 }
93
94 /* Emit a glBegin to start the new list.
95 */
96 assert(exec->vtx.prim_count == 0);
97
98 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
99 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
100 exec->vtx.prim[0].start = 0;
101 exec->vtx.prim[0].count = 0;
102 exec->vtx.prim_count++;
103
104 if (exec->vtx.copied.nr == last_count)
105 exec->vtx.prim[0].begin = last_begin;
106 }
107 }
108 }
109
110
111 /**
112 * Deal with buffer wrapping where provoked by the vertex buffer
113 * filling up, as opposed to upgrade_vertex().
114 */
115 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
116 {
117 GLfloat *data = exec->vtx.copied.buffer;
118 GLuint i;
119
120 /* Run pipeline on current vertices, copy wrapped vertices
121 * to exec->vtx.copied.
122 */
123 vbo_exec_wrap_buffers( exec );
124
125 /* Copy stored stored vertices to start of new list.
126 */
127 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
128
129 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
130 memcpy( exec->vtx.buffer_ptr, data,
131 exec->vtx.vertex_size * sizeof(GLfloat));
132 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
133 data += exec->vtx.vertex_size;
134 exec->vtx.vert_count++;
135 }
136
137 exec->vtx.copied.nr = 0;
138 }
139
140
141 /**
142 * Copy the active vertex's values to the ctx->Current fields.
143 */
144 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
145 {
146 struct gl_context *ctx = exec->ctx;
147 struct vbo_context *vbo = vbo_context(ctx);
148 GLuint i;
149
150 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
151 if (exec->vtx.attrsz[i]) {
152 /* Note: the exec->vtx.current[i] pointers point into the
153 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
154 */
155 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
156 GLfloat tmp[4];
157
158 COPY_CLEAN_4V(tmp,
159 exec->vtx.attrsz[i],
160 exec->vtx.attrptr[i]);
161
162 if (memcmp(current, tmp, sizeof(tmp)) != 0)
163 {
164 memcpy(current, tmp, sizeof(tmp));
165
166 /* Given that we explicitly state size here, there is no need
167 * for the COPY_CLEAN above, could just copy 16 bytes and be
168 * done. The only problem is when Mesa accesses ctx->Current
169 * directly.
170 */
171 vbo->currval[i].Size = exec->vtx.attrsz[i];
172
173 /* This triggers rather too much recalculation of Mesa state
174 * that doesn't get used (eg light positions).
175 */
176 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
177 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
178 ctx->NewState |= _NEW_LIGHT;
179
180 ctx->NewState |= _NEW_CURRENT_ATTRIB;
181 }
182 }
183 }
184
185 /* Colormaterial -- this kindof sucks.
186 */
187 if (ctx->Light.ColorMaterialEnabled &&
188 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
189 _mesa_update_color_material(ctx,
190 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
191 }
192 }
193
194
195 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
196 {
197 struct gl_context *ctx = exec->ctx;
198 struct vbo_context *vbo = vbo_context(ctx);
199 GLint i;
200
201 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
202 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
203 switch (exec->vtx.attrsz[i]) {
204 case 4: exec->vtx.attrptr[i][3] = current[3];
205 case 3: exec->vtx.attrptr[i][2] = current[2];
206 case 2: exec->vtx.attrptr[i][1] = current[1];
207 case 1: exec->vtx.attrptr[i][0] = current[0];
208 break;
209 }
210 }
211 }
212
213
214 /**
215 * Flush existing data, set new attrib size, replay copied vertices.
216 */
217 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
218 GLuint attr,
219 GLuint newsz )
220 {
221 struct gl_context *ctx = exec->ctx;
222 struct vbo_context *vbo = vbo_context(ctx);
223 GLint lastcount = exec->vtx.vert_count;
224 GLfloat *old_attrptr[VBO_ATTRIB_MAX];
225 GLuint old_vtx_size = exec->vtx.vertex_size;
226 GLuint oldsz = exec->vtx.attrsz[attr];
227 GLuint i;
228
229 /* Run pipeline on current vertices, copy wrapped vertices
230 * to exec->vtx.copied.
231 */
232 vbo_exec_wrap_buffers( exec );
233
234 if (unlikely(exec->vtx.copied.nr)) {
235 /* We're in the middle of a primitive, keep the old vertex
236 * format around to be able to translate the copied vertices to
237 * the new format.
238 */
239 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
240 }
241
242 if (unlikely(oldsz)) {
243 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
244 * case when the attribute already exists in the vertex and is
245 * having its size increased.
246 */
247 vbo_exec_copy_to_current( exec );
248 }
249
250 /* Heuristic: Attempt to isolate attributes received outside
251 * begin/end so that they don't bloat the vertices.
252 */
253 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
254 !oldsz && lastcount > 8 && exec->vtx.vertex_size) {
255 vbo_exec_copy_to_current( exec );
256 reset_attrfv( exec );
257 }
258
259 /* Fix up sizes:
260 */
261 exec->vtx.attrsz[attr] = newsz;
262 exec->vtx.vertex_size += newsz - oldsz;
263 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
264 (exec->vtx.vertex_size * sizeof(GLfloat)));
265 exec->vtx.vert_count = 0;
266 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
267
268 if (unlikely(oldsz)) {
269 /* Size changed, recalculate all the attrptr[] values
270 */
271 GLfloat *tmp = exec->vtx.vertex;
272
273 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
274 if (exec->vtx.attrsz[i]) {
275 exec->vtx.attrptr[i] = tmp;
276 tmp += exec->vtx.attrsz[i];
277 }
278 else
279 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
280 }
281
282 /* Copy from current to repopulate the vertex with correct
283 * values.
284 */
285 vbo_exec_copy_from_current( exec );
286
287 } else {
288 /* Just have to append the new attribute at the end */
289 exec->vtx.attrptr[attr] = exec->vtx.vertex +
290 exec->vtx.vertex_size - newsz;
291 }
292
293 /* Replay stored vertices to translate them
294 * to new format here.
295 *
296 * -- No need to replay - just copy piecewise
297 */
298 if (unlikely(exec->vtx.copied.nr)) {
299 GLfloat *data = exec->vtx.copied.buffer;
300 GLfloat *dest = exec->vtx.buffer_ptr;
301 GLuint j;
302
303 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
304
305 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
306 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
307 GLuint sz = exec->vtx.attrsz[j];
308
309 if (sz) {
310 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
311 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
312
313 if (j == attr) {
314 if (oldsz) {
315 GLfloat tmp[4];
316 COPY_CLEAN_4V(tmp, oldsz, data + old_offset);
317 COPY_SZ_4V(dest + new_offset, newsz, tmp);
318 } else {
319 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
320 COPY_SZ_4V(dest + new_offset, sz, current);
321 }
322 }
323 else {
324 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
325 }
326 }
327 }
328
329 data += old_vtx_size;
330 dest += exec->vtx.vertex_size;
331 }
332
333 exec->vtx.buffer_ptr = dest;
334 exec->vtx.vert_count += exec->vtx.copied.nr;
335 exec->vtx.copied.nr = 0;
336 }
337 }
338
339
340 static void vbo_exec_fixup_vertex( struct gl_context *ctx,
341 GLuint attr, GLuint sz )
342 {
343 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
344 int i;
345
346 if (sz > exec->vtx.attrsz[attr]) {
347 /* New size is larger. Need to flush existing vertices and get
348 * an enlarged vertex format.
349 */
350 vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
351 }
352 else if (sz < exec->vtx.active_sz[attr]) {
353 static const GLfloat id[4] = { 0, 0, 0, 1 };
354
355 /* New size is smaller - just need to fill in some
356 * zeros. Don't need to flush or wrap.
357 */
358 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
359 exec->vtx.attrptr[attr][i-1] = id[i-1];
360 }
361
362 exec->vtx.active_sz[attr] = sz;
363
364 /* Does setting NeedFlush belong here? Necessitates resetting
365 * vtxfmt on each flush (otherwise flags won't get reset
366 * afterwards).
367 */
368 if (attr == 0)
369 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
370 }
371
372
373 /*
374 */
375 #define ATTR( A, N, V0, V1, V2, V3 ) \
376 do { \
377 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
378 \
379 if (unlikely(!(exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
380 ctx->Driver.BeginVertices( ctx ); \
381 if (unlikely(exec->vtx.active_sz[A] != N)) \
382 vbo_exec_fixup_vertex(ctx, A, N); \
383 \
384 { \
385 GLfloat *dest = exec->vtx.attrptr[A]; \
386 if (N>0) dest[0] = V0; \
387 if (N>1) dest[1] = V1; \
388 if (N>2) dest[2] = V2; \
389 if (N>3) dest[3] = V3; \
390 } \
391 \
392 if ((A) == 0) { \
393 GLuint i; \
394 \
395 for (i = 0; i < exec->vtx.vertex_size; i++) \
396 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
397 \
398 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
399 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
400 \
401 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
402 vbo_exec_vtx_wrap( exec ); \
403 } \
404 } while (0)
405
406
407 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
408 #define TAG(x) vbo_##x
409
410 #include "vbo_attrib_tmp.h"
411
412
413 #if FEATURE_beginend
414
415
416 #if FEATURE_evaluators
417
418 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
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.map1[i].map)
430 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
431 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
432 }
433 }
434
435
436 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
437 exec->vtx.vertex_size * sizeof(GLfloat));
438
439 vbo_exec_do_EvalCoord1f( exec, u );
440
441 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
442 exec->vtx.vertex_size * sizeof(GLfloat));
443 }
444
445 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
446 {
447 GET_CURRENT_CONTEXT( ctx );
448 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
449
450 {
451 GLint i;
452 if (exec->eval.recalculate_maps)
453 vbo_exec_eval_update( exec );
454
455 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
456 if (exec->eval.map2[i].map)
457 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
458 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
459 }
460
461 if (ctx->Eval.AutoNormal)
462 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
463 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
464 }
465
466 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
467 exec->vtx.vertex_size * sizeof(GLfloat));
468
469 vbo_exec_do_EvalCoord2f( exec, u, v );
470
471 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
472 exec->vtx.vertex_size * sizeof(GLfloat));
473 }
474
475 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
476 {
477 vbo_exec_EvalCoord1f( u[0] );
478 }
479
480 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
481 {
482 vbo_exec_EvalCoord2f( u[0], u[1] );
483 }
484
485 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
486 {
487 GET_CURRENT_CONTEXT( ctx );
488 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
489 (GLfloat) ctx->Eval.MapGrid1un);
490 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
491
492 vbo_exec_EvalCoord1f( u );
493 }
494
495
496 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
497 {
498 GET_CURRENT_CONTEXT( ctx );
499 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
500 (GLfloat) ctx->Eval.MapGrid2un);
501 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
502 (GLfloat) ctx->Eval.MapGrid2vn);
503 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
504 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
505
506 vbo_exec_EvalCoord2f( u, v );
507 }
508
509 /* use noop eval mesh */
510 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
511 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
512
513 #endif /* FEATURE_evaluators */
514
515
516 /**
517 * Called via glBegin.
518 */
519 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
520 {
521 GET_CURRENT_CONTEXT( ctx );
522
523 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
524 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
525 int i;
526
527 if (ctx->NewState) {
528 _mesa_update_state( ctx );
529
530 CALL_Begin(ctx->Exec, (mode));
531 return;
532 }
533
534 if (!_mesa_valid_to_render(ctx, "glBegin")) {
535 return;
536 }
537
538 /* Heuristic: attempt to isolate attributes occuring outside
539 * begin/end pairs.
540 */
541 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
542 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
543
544 i = exec->vtx.prim_count++;
545 exec->vtx.prim[i].mode = mode;
546 exec->vtx.prim[i].begin = 1;
547 exec->vtx.prim[i].end = 0;
548 exec->vtx.prim[i].indexed = 0;
549 exec->vtx.prim[i].weak = 0;
550 exec->vtx.prim[i].pad = 0;
551 exec->vtx.prim[i].start = exec->vtx.vert_count;
552 exec->vtx.prim[i].count = 0;
553 exec->vtx.prim[i].num_instances = 1;
554
555 ctx->Driver.CurrentExecPrimitive = mode;
556 }
557 else
558 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
559
560 }
561
562
563 /**
564 * Called via glEnd.
565 */
566 static void GLAPIENTRY vbo_exec_End( void )
567 {
568 GET_CURRENT_CONTEXT( ctx );
569
570 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
571 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
572 int idx = exec->vtx.vert_count;
573 int i = exec->vtx.prim_count - 1;
574
575 exec->vtx.prim[i].end = 1;
576 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
577
578 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
579
580 if (exec->vtx.prim_count == VBO_MAX_PRIM)
581 vbo_exec_vtx_flush( exec, GL_FALSE );
582 }
583 else
584 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
585 }
586
587
588 /**
589 * Called via glPrimitiveRestartNV()
590 */
591 static void GLAPIENTRY
592 vbo_exec_PrimitiveRestartNV(void)
593 {
594 GLenum curPrim;
595 GET_CURRENT_CONTEXT( ctx );
596
597 curPrim = ctx->Driver.CurrentExecPrimitive;
598
599 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
600 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
601 }
602 else {
603 vbo_exec_End();
604 vbo_exec_Begin(curPrim);
605 }
606 }
607
608
609
610 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
611 {
612 GLvertexformat *vfmt = &exec->vtxfmt;
613
614 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
615
616 vfmt->Begin = vbo_exec_Begin;
617 vfmt->End = vbo_exec_End;
618 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
619
620 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
621 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
622
623 vfmt->Rectf = _mesa_noop_Rectf;
624
625 /* from attrib_tmp.h:
626 */
627 vfmt->Color3f = vbo_Color3f;
628 vfmt->Color3fv = vbo_Color3fv;
629 vfmt->Color4f = vbo_Color4f;
630 vfmt->Color4fv = vbo_Color4fv;
631 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
632 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
633 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
634 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
635 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
636 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
637 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
638 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
639 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
640 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
641 vfmt->Normal3f = vbo_Normal3f;
642 vfmt->Normal3fv = vbo_Normal3fv;
643 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
644 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
645 vfmt->TexCoord1f = vbo_TexCoord1f;
646 vfmt->TexCoord1fv = vbo_TexCoord1fv;
647 vfmt->TexCoord2f = vbo_TexCoord2f;
648 vfmt->TexCoord2fv = vbo_TexCoord2fv;
649 vfmt->TexCoord3f = vbo_TexCoord3f;
650 vfmt->TexCoord3fv = vbo_TexCoord3fv;
651 vfmt->TexCoord4f = vbo_TexCoord4f;
652 vfmt->TexCoord4fv = vbo_TexCoord4fv;
653 vfmt->Vertex2f = vbo_Vertex2f;
654 vfmt->Vertex2fv = vbo_Vertex2fv;
655 vfmt->Vertex3f = vbo_Vertex3f;
656 vfmt->Vertex3fv = vbo_Vertex3fv;
657 vfmt->Vertex4f = vbo_Vertex4f;
658 vfmt->Vertex4fv = vbo_Vertex4fv;
659
660 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
661 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
662 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
663 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
664 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
665 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
666 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
667 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
668
669 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
670 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
671 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
672 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
673 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
674 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
675 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
676 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
677
678 /* integer-valued */
679 vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
680 vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
681 vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
682 vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
683 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
684 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
685 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
686
687 /* unsigned integer-valued */
688 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
689 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
690 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
691 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
692 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
693 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
694 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
695
696 vfmt->Materialfv = vbo_Materialfv;
697
698 vfmt->EdgeFlag = vbo_EdgeFlag;
699 vfmt->Indexf = vbo_Indexf;
700 vfmt->Indexfv = vbo_Indexfv;
701
702 }
703
704
705 #else /* FEATURE_beginend */
706
707
708 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
709 {
710 /* silence warnings */
711 (void) vbo_Color3f;
712 (void) vbo_Color3fv;
713 (void) vbo_Color4f;
714 (void) vbo_Color4fv;
715 (void) vbo_FogCoordfEXT;
716 (void) vbo_FogCoordfvEXT;
717 (void) vbo_MultiTexCoord1f;
718 (void) vbo_MultiTexCoord1fv;
719 (void) vbo_MultiTexCoord2f;
720 (void) vbo_MultiTexCoord2fv;
721 (void) vbo_MultiTexCoord3f;
722 (void) vbo_MultiTexCoord3fv;
723 (void) vbo_MultiTexCoord4f;
724 (void) vbo_MultiTexCoord4fv;
725 (void) vbo_Normal3f;
726 (void) vbo_Normal3fv;
727 (void) vbo_SecondaryColor3fEXT;
728 (void) vbo_SecondaryColor3fvEXT;
729 (void) vbo_TexCoord1f;
730 (void) vbo_TexCoord1fv;
731 (void) vbo_TexCoord2f;
732 (void) vbo_TexCoord2fv;
733 (void) vbo_TexCoord3f;
734 (void) vbo_TexCoord3fv;
735 (void) vbo_TexCoord4f;
736 (void) vbo_TexCoord4fv;
737 (void) vbo_Vertex2f;
738 (void) vbo_Vertex2fv;
739 (void) vbo_Vertex3f;
740 (void) vbo_Vertex3fv;
741 (void) vbo_Vertex4f;
742 (void) vbo_Vertex4fv;
743
744 (void) vbo_VertexAttrib1fARB;
745 (void) vbo_VertexAttrib1fvARB;
746 (void) vbo_VertexAttrib2fARB;
747 (void) vbo_VertexAttrib2fvARB;
748 (void) vbo_VertexAttrib3fARB;
749 (void) vbo_VertexAttrib3fvARB;
750 (void) vbo_VertexAttrib4fARB;
751 (void) vbo_VertexAttrib4fvARB;
752
753 (void) vbo_VertexAttrib1fNV;
754 (void) vbo_VertexAttrib1fvNV;
755 (void) vbo_VertexAttrib2fNV;
756 (void) vbo_VertexAttrib2fvNV;
757 (void) vbo_VertexAttrib3fNV;
758 (void) vbo_VertexAttrib3fvNV;
759 (void) vbo_VertexAttrib4fNV;
760 (void) vbo_VertexAttrib4fvNV;
761
762 (void) vbo_Materialfv;
763
764 (void) vbo_EdgeFlag;
765 (void) vbo_Indexf;
766 (void) vbo_Indexfv;
767 }
768
769
770 #endif /* FEATURE_beginend */
771
772
773 /**
774 * Tell the VBO module to use a real OpenGL vertex buffer object to
775 * store accumulated immediate-mode vertex data.
776 * This replaces the malloced buffer which was created in
777 * vb_exec_vtx_init() below.
778 */
779 void vbo_use_buffer_objects(struct gl_context *ctx)
780 {
781 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
782 /* Any buffer name but 0 can be used here since this bufferobj won't
783 * go into the bufferobj hashtable.
784 */
785 GLuint bufName = IMM_BUFFER_NAME;
786 GLenum target = GL_ARRAY_BUFFER_ARB;
787 GLenum usage = GL_STREAM_DRAW_ARB;
788 GLsizei size = VBO_VERT_BUFFER_SIZE;
789
790 /* Make sure this func is only used once */
791 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
792 if (exec->vtx.buffer_map) {
793 _mesa_align_free(exec->vtx.buffer_map);
794 exec->vtx.buffer_map = NULL;
795 exec->vtx.buffer_ptr = NULL;
796 }
797
798 /* Allocate a real buffer object now */
799 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
800 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
801 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
802 }
803
804
805
806 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
807 {
808 struct gl_context *ctx = exec->ctx;
809 struct vbo_context *vbo = vbo_context(ctx);
810 GLuint i;
811
812 /* Allocate a buffer object. Will just reuse this object
813 * continuously, unless vbo_use_buffer_objects() is called to enable
814 * use of real VBOs.
815 */
816 _mesa_reference_buffer_object(ctx,
817 &exec->vtx.bufferobj,
818 ctx->Shared->NullBufferObj);
819
820 ASSERT(!exec->vtx.buffer_map);
821 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
822 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
823
824 vbo_exec_vtxfmt_init( exec );
825
826 /* Hook our functions into the dispatch table.
827 */
828 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
829
830 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
831 ASSERT(i < Elements(exec->vtx.attrsz));
832 exec->vtx.attrsz[i] = 0;
833 ASSERT(i < Elements(exec->vtx.active_sz));
834 exec->vtx.active_sz[i] = 0;
835 }
836 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
837 ASSERT(i < Elements(exec->vtx.inputs));
838 ASSERT(i < Elements(exec->vtx.arrays));
839 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
840 }
841
842 {
843 struct gl_client_array *arrays = exec->vtx.arrays;
844 unsigned i;
845
846 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
847 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
848
849 for (i = 0; i < 16; ++i) {
850 arrays[i ].BufferObj = NULL;
851 arrays[i + 16].BufferObj = NULL;
852 _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
853 vbo->legacy_currval[i].BufferObj);
854 _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
855 vbo->generic_currval[i].BufferObj);
856 }
857 }
858
859 exec->vtx.vertex_size = 0;
860 }
861
862
863 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
864 {
865 /* using a real VBO for vertex data */
866 struct gl_context *ctx = exec->ctx;
867 unsigned i;
868
869 /* True VBOs should already be unmapped
870 */
871 if (exec->vtx.buffer_map) {
872 ASSERT(exec->vtx.bufferobj->Name == 0 ||
873 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
874 if (exec->vtx.bufferobj->Name == 0) {
875 _mesa_align_free(exec->vtx.buffer_map);
876 exec->vtx.buffer_map = NULL;
877 exec->vtx.buffer_ptr = NULL;
878 }
879 }
880
881 /* Drop any outstanding reference to the vertex buffer
882 */
883 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
884 _mesa_reference_buffer_object(ctx,
885 &exec->vtx.arrays[i].BufferObj,
886 NULL);
887 }
888
889 /* Free the vertex buffer. Unmap first if needed.
890 */
891 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
892 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
893 }
894 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
895 }
896
897 void vbo_exec_BeginVertices( struct gl_context *ctx )
898 {
899 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
900 if (0) printf("%s\n", __FUNCTION__);
901 vbo_exec_vtx_map( exec );
902
903 assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
904 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
905 }
906
907 void vbo_exec_FlushVertices_internal( struct gl_context *ctx, GLboolean unmap )
908 {
909 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
910
911 if (exec->vtx.vert_count || unmap) {
912 vbo_exec_vtx_flush( exec, unmap );
913 }
914
915 if (exec->vtx.vertex_size) {
916 vbo_exec_copy_to_current( exec );
917 reset_attrfv( exec );
918 }
919 }
920
921
922 /**
923 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
924 */
925 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
926 {
927 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
928
929 #ifdef DEBUG
930 /* debug check: make sure we don't get called recursively */
931 exec->flush_call_depth++;
932 assert(exec->flush_call_depth == 1);
933 #endif
934
935 if (0) printf("%s\n", __FUNCTION__);
936
937 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
938 if (0) printf("%s - inside begin/end\n", __FUNCTION__);
939 #ifdef DEBUG
940 exec->flush_call_depth--;
941 assert(exec->flush_call_depth == 0);
942 #endif
943 return;
944 }
945
946 vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
947
948 /* Need to do this to ensure BeginVertices gets called again:
949 */
950 if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
951 exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
952
953 exec->ctx->Driver.NeedFlush &= ~flags;
954
955 #ifdef DEBUG
956 exec->flush_call_depth--;
957 assert(exec->flush_call_depth == 0);
958 #endif
959 }
960
961
962 static void reset_attrfv( struct vbo_exec_context *exec )
963 {
964 GLuint i;
965
966 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
967 exec->vtx.attrsz[i] = 0;
968 exec->vtx.active_sz[i] = 0;
969 }
970
971 exec->vtx.vertex_size = 0;
972 }
973
974
975 void GLAPIENTRY
976 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
977 {
978 vbo_Color4f(r, g, b, a);
979 }
980
981
982 void GLAPIENTRY
983 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
984 {
985 vbo_Normal3f(x, y, z);
986 }
987
988
989 void GLAPIENTRY
990 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
991 {
992 vbo_MultiTexCoord4f(target, s, t, r, q);
993 }
994
995
996 void GLAPIENTRY
997 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
998 {
999 vbo_Materialfv(face, pname, params);
1000 }
1001
1002
1003 void GLAPIENTRY
1004 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1005 {
1006 GLfloat p[4];
1007 p[0] = param;
1008 p[1] = p[2] = p[3] = 0.0F;
1009 vbo_Materialfv(face, pname, p);
1010 }
1011
1012
1013 /**
1014 * A special version of glVertexAttrib4f that does not treat index 0 as
1015 * VBO_ATTRIB_POS.
1016 */
1017 static void
1018 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1019 {
1020 GET_CURRENT_CONTEXT(ctx);
1021 if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1022 ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1023 else
1024 ERROR();
1025 }
1026
1027 void GLAPIENTRY
1028 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1029 {
1030 VertexAttrib4f_nopos(index, x, y, z, w);
1031 }
1032
1033
1034 void GLAPIENTRY
1035 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1036 {
1037 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1038 }
1039
1040
1041 void GLAPIENTRY
1042 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1043 {
1044 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1045 }
1046
1047
1048 void GLAPIENTRY
1049 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1050 {
1051 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1052 }
1053
1054
1055 void GLAPIENTRY
1056 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1057 {
1058 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1059 }
1060
1061
1062 void GLAPIENTRY
1063 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1064 {
1065 VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1066 }
1067
1068
1069 void GLAPIENTRY
1070 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1071 {
1072 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1073 }
1074
1075
1076 void GLAPIENTRY
1077 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1078 {
1079 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1080 }