mesa: remove per-format memcpy codepaths from texstore functions
[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_validate.h"
45 #include "main/dispatch.h"
46
47 #include "vbo_context.h"
48 #include "vbo_noop.h"
49
50
51 #ifdef ERROR
52 #undef ERROR
53 #endif
54
55
56 /** ID/name for immediate-mode VBO */
57 #define IMM_BUFFER_NAME 0xaabbccdd
58
59
60 static void reset_attrfv( struct vbo_exec_context *exec );
61
62
63 /**
64 * Close off the last primitive, execute the buffer, restart the
65 * primitive.
66 */
67 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
68 {
69 if (exec->vtx.prim_count == 0) {
70 exec->vtx.copied.nr = 0;
71 exec->vtx.vert_count = 0;
72 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
73 }
74 else {
75 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
76 GLuint last_count;
77
78 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
79 GLint i = exec->vtx.prim_count - 1;
80 assert(i >= 0);
81 exec->vtx.prim[i].count = (exec->vtx.vert_count -
82 exec->vtx.prim[i].start);
83 }
84
85 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
86
87 /* Execute the buffer and save copied vertices.
88 */
89 if (exec->vtx.vert_count)
90 vbo_exec_vtx_flush( exec, GL_FALSE );
91 else {
92 exec->vtx.prim_count = 0;
93 exec->vtx.copied.nr = 0;
94 }
95
96 /* Emit a glBegin to start the new list.
97 */
98 assert(exec->vtx.prim_count == 0);
99
100 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
101 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
102 exec->vtx.prim[0].start = 0;
103 exec->vtx.prim[0].count = 0;
104 exec->vtx.prim_count++;
105
106 if (exec->vtx.copied.nr == last_count)
107 exec->vtx.prim[0].begin = last_begin;
108 }
109 }
110 }
111
112
113 /**
114 * Deal with buffer wrapping where provoked by the vertex buffer
115 * filling up, as opposed to upgrade_vertex().
116 */
117 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
118 {
119 GLfloat *data = exec->vtx.copied.buffer;
120 GLuint i;
121
122 /* Run pipeline on current vertices, copy wrapped vertices
123 * to exec->vtx.copied.
124 */
125 vbo_exec_wrap_buffers( exec );
126
127 if (!exec->vtx.buffer_ptr) {
128 /* probably ran out of memory earlier when allocating the VBO */
129 return;
130 }
131
132 /* Copy stored stored vertices to start of new list.
133 */
134 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
135
136 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
137 memcpy( exec->vtx.buffer_ptr, data,
138 exec->vtx.vertex_size * sizeof(GLfloat));
139 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
140 data += exec->vtx.vertex_size;
141 exec->vtx.vert_count++;
142 }
143
144 exec->vtx.copied.nr = 0;
145 }
146
147
148 /**
149 * Copy the active vertex's values to the ctx->Current fields.
150 */
151 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
152 {
153 struct gl_context *ctx = exec->ctx;
154 struct vbo_context *vbo = vbo_context(ctx);
155 GLuint i;
156
157 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
158 if (exec->vtx.attrsz[i]) {
159 /* Note: the exec->vtx.current[i] pointers point into the
160 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
161 */
162 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
163 GLfloat tmp[4];
164
165 COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp,
166 exec->vtx.attrsz[i],
167 exec->vtx.attrptr[i],
168 exec->vtx.attrtype[i]);
169
170 if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
171 memcmp(current, tmp, sizeof(tmp)) != 0) {
172 memcpy(current, tmp, sizeof(tmp));
173
174 /* Given that we explicitly state size here, there is no need
175 * for the COPY_CLEAN above, could just copy 16 bytes and be
176 * done. The only problem is when Mesa accesses ctx->Current
177 * directly.
178 */
179 vbo->currval[i].Size = exec->vtx.attrsz[i];
180 vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
181 vbo->currval[i].Type = exec->vtx.attrtype[i];
182 vbo->currval[i].Integer =
183 vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
184
185 /* This triggers rather too much recalculation of Mesa state
186 * that doesn't get used (eg light positions).
187 */
188 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
189 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
190 ctx->NewState |= _NEW_LIGHT;
191
192 ctx->NewState |= _NEW_CURRENT_ATTRIB;
193 }
194 }
195 }
196
197 /* Colormaterial -- this kindof sucks.
198 */
199 if (ctx->Light.ColorMaterialEnabled &&
200 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
201 _mesa_update_color_material(ctx,
202 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
203 }
204 }
205
206
207 /**
208 * Copy current vertex attribute values into the current vertex.
209 */
210 static void
211 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
212 {
213 struct gl_context *ctx = exec->ctx;
214 struct vbo_context *vbo = vbo_context(ctx);
215 GLint i;
216
217 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
218 const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
219 switch (exec->vtx.attrsz[i]) {
220 case 4: exec->vtx.attrptr[i][3] = current[3];
221 case 3: exec->vtx.attrptr[i][2] = current[2];
222 case 2: exec->vtx.attrptr[i][1] = current[1];
223 case 1: exec->vtx.attrptr[i][0] = current[0];
224 break;
225 }
226 }
227 }
228
229
230 /**
231 * Flush existing data, set new attrib size, replay copied vertices.
232 * This is called when we transition from a small vertex attribute size
233 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
234 * We need to go back over the previous 2-component texcoords and insert
235 * zero and one values.
236 */
237 static void
238 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
239 GLuint attr, GLuint newSize )
240 {
241 struct gl_context *ctx = exec->ctx;
242 struct vbo_context *vbo = vbo_context(ctx);
243 const GLint lastcount = exec->vtx.vert_count;
244 GLfloat *old_attrptr[VBO_ATTRIB_MAX];
245 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
246 const GLuint oldSize = exec->vtx.attrsz[attr];
247 GLuint i;
248
249 /* Run pipeline on current vertices, copy wrapped vertices
250 * to exec->vtx.copied.
251 */
252 vbo_exec_wrap_buffers( exec );
253
254 if (unlikely(exec->vtx.copied.nr)) {
255 /* We're in the middle of a primitive, keep the old vertex
256 * format around to be able to translate the copied vertices to
257 * the new format.
258 */
259 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
260 }
261
262 if (unlikely(oldSize)) {
263 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
264 * case when the attribute already exists in the vertex and is
265 * having its size increased.
266 */
267 vbo_exec_copy_to_current( exec );
268 }
269
270 /* Heuristic: Attempt to isolate attributes received outside
271 * begin/end so that they don't bloat the vertices.
272 */
273 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
274 !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
275 vbo_exec_copy_to_current( exec );
276 reset_attrfv( exec );
277 }
278
279 /* Fix up sizes:
280 */
281 exec->vtx.attrsz[attr] = newSize;
282 exec->vtx.vertex_size += newSize - oldSize;
283 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
284 (exec->vtx.vertex_size * sizeof(GLfloat)));
285 exec->vtx.vert_count = 0;
286 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
287
288 if (unlikely(oldSize)) {
289 /* Size changed, recalculate all the attrptr[] values
290 */
291 GLfloat *tmp = exec->vtx.vertex;
292
293 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
294 if (exec->vtx.attrsz[i]) {
295 exec->vtx.attrptr[i] = tmp;
296 tmp += exec->vtx.attrsz[i];
297 }
298 else
299 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
300 }
301
302 /* Copy from current to repopulate the vertex with correct
303 * values.
304 */
305 vbo_exec_copy_from_current( exec );
306 }
307 else {
308 /* Just have to append the new attribute at the end */
309 exec->vtx.attrptr[attr] = exec->vtx.vertex +
310 exec->vtx.vertex_size - newSize;
311 }
312
313 /* Replay stored vertices to translate them
314 * to new format here.
315 *
316 * -- No need to replay - just copy piecewise
317 */
318 if (unlikely(exec->vtx.copied.nr)) {
319 GLfloat *data = exec->vtx.copied.buffer;
320 GLfloat *dest = exec->vtx.buffer_ptr;
321 GLuint j;
322
323 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
324
325 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
326 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
327 GLuint sz = exec->vtx.attrsz[j];
328
329 if (sz) {
330 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
331 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
332
333 if (j == attr) {
334 if (oldSize) {
335 GLfloat tmp[4];
336 COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, oldSize,
337 data + old_offset,
338 exec->vtx.attrtype[j]);
339 COPY_SZ_4V(dest + new_offset, newSize, tmp);
340 } else {
341 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
342 COPY_SZ_4V(dest + new_offset, sz, current);
343 }
344 }
345 else {
346 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
347 }
348 }
349 }
350
351 data += old_vtx_size;
352 dest += exec->vtx.vertex_size;
353 }
354
355 exec->vtx.buffer_ptr = dest;
356 exec->vtx.vert_count += exec->vtx.copied.nr;
357 exec->vtx.copied.nr = 0;
358 }
359 }
360
361
362 /**
363 * This is when a vertex attribute transitions to a different size.
364 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
365 * glTexCoord4f() call. We promote the array from size=2 to size=4.
366 */
367 static void
368 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
369 {
370 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
371
372 if (newSize > exec->vtx.attrsz[attr]) {
373 /* New size is larger. Need to flush existing vertices and get
374 * an enlarged vertex format.
375 */
376 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
377 }
378 else if (newSize < exec->vtx.active_sz[attr]) {
379 GLuint i;
380 const GLfloat *id =
381 vbo_get_default_vals_as_float(exec->vtx.attrtype[attr]);
382
383 /* New size is smaller - just need to fill in some
384 * zeros. Don't need to flush or wrap.
385 */
386 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
387 exec->vtx.attrptr[attr][i-1] = id[i-1];
388 }
389
390 exec->vtx.active_sz[attr] = newSize;
391
392 /* Does setting NeedFlush belong here? Necessitates resetting
393 * vtxfmt on each flush (otherwise flags won't get reset
394 * afterwards).
395 */
396 if (attr == 0)
397 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
398 }
399
400
401 /**
402 * This macro is used to implement all the glVertex, glColor, glTexCoord,
403 * glVertexAttrib, etc functions.
404 */
405 #define ATTR( A, N, T, V0, V1, V2, V3 ) \
406 do { \
407 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
408 \
409 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
410 ctx->Driver.BeginVertices( ctx ); \
411 \
412 if (unlikely(exec->vtx.active_sz[A] != N)) \
413 vbo_exec_fixup_vertex(ctx, A, N); \
414 \
415 { \
416 GLfloat *dest = exec->vtx.attrptr[A]; \
417 if (N>0) dest[0] = V0; \
418 if (N>1) dest[1] = V1; \
419 if (N>2) dest[2] = V2; \
420 if (N>3) dest[3] = V3; \
421 exec->vtx.attrtype[A] = T; \
422 } \
423 \
424 if ((A) == 0) { \
425 /* This is a glVertex call */ \
426 GLuint i; \
427 \
428 for (i = 0; i < exec->vtx.vertex_size; i++) \
429 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
430 \
431 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
432 \
433 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
434 /* something to draw (not just updating a color or texcoord).*/ \
435 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
436 \
437 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
438 vbo_exec_vtx_wrap( exec ); \
439 } \
440 } while (0)
441
442
443 #define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
444 #define TAG(x) vbo_##x
445
446 #include "vbo_attrib_tmp.h"
447
448
449
450 /**
451 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
452 * this may be a (partial) no-op.
453 */
454 static void GLAPIENTRY
455 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
456 {
457 GLbitfield updateMats;
458 GET_CURRENT_CONTEXT(ctx);
459
460 /* This function should be a no-op when it tries to update material
461 * attributes which are currently tracking glColor via glColorMaterial.
462 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
463 * indicating which material attributes can actually be updated below.
464 */
465 if (ctx->Light.ColorMaterialEnabled) {
466 updateMats = ~ctx->Light._ColorMaterialBitmask;
467 }
468 else {
469 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
470 updateMats = ALL_MATERIAL_BITS;
471 }
472
473 if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
474 updateMats &= FRONT_MATERIAL_BITS;
475 }
476 else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
477 updateMats &= BACK_MATERIAL_BITS;
478 }
479 else if (face != GL_FRONT_AND_BACK) {
480 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
481 return;
482 }
483
484 switch (pname) {
485 case GL_EMISSION:
486 if (updateMats & MAT_BIT_FRONT_EMISSION)
487 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
488 if (updateMats & MAT_BIT_BACK_EMISSION)
489 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
490 break;
491 case GL_AMBIENT:
492 if (updateMats & MAT_BIT_FRONT_AMBIENT)
493 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
494 if (updateMats & MAT_BIT_BACK_AMBIENT)
495 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
496 break;
497 case GL_DIFFUSE:
498 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
499 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
500 if (updateMats & MAT_BIT_BACK_DIFFUSE)
501 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
502 break;
503 case GL_SPECULAR:
504 if (updateMats & MAT_BIT_FRONT_SPECULAR)
505 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
506 if (updateMats & MAT_BIT_BACK_SPECULAR)
507 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
508 break;
509 case GL_SHININESS:
510 if (*params < 0 || *params > ctx->Const.MaxShininess) {
511 _mesa_error(ctx, GL_INVALID_VALUE,
512 "glMaterial(invalid shininess: %f out range [0, %f])",
513 *params, ctx->Const.MaxShininess);
514 return;
515 }
516 if (updateMats & MAT_BIT_FRONT_SHININESS)
517 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
518 if (updateMats & MAT_BIT_BACK_SHININESS)
519 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
520 break;
521 case GL_COLOR_INDEXES:
522 if (ctx->API != API_OPENGL_COMPAT) {
523 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
524 return;
525 }
526 if (updateMats & MAT_BIT_FRONT_INDEXES)
527 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
528 if (updateMats & MAT_BIT_BACK_INDEXES)
529 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
530 break;
531 case GL_AMBIENT_AND_DIFFUSE:
532 if (updateMats & MAT_BIT_FRONT_AMBIENT)
533 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
534 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
535 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
536 if (updateMats & MAT_BIT_BACK_AMBIENT)
537 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
538 if (updateMats & MAT_BIT_BACK_DIFFUSE)
539 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
540 break;
541 default:
542 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
543 return;
544 }
545 }
546
547
548 /**
549 * Flush (draw) vertices.
550 * \param unmap - leave VBO unmapped after flushing?
551 */
552 static void
553 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
554 {
555 if (exec->vtx.vert_count || unmap) {
556 vbo_exec_vtx_flush( exec, unmap );
557 }
558
559 if (exec->vtx.vertex_size) {
560 vbo_exec_copy_to_current( exec );
561 reset_attrfv( exec );
562 }
563 }
564
565
566 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
567 {
568 GET_CURRENT_CONTEXT( ctx );
569 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
570
571 {
572 GLint i;
573 if (exec->eval.recalculate_maps)
574 vbo_exec_eval_update( exec );
575
576 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
577 if (exec->eval.map1[i].map)
578 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
579 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
580 }
581 }
582
583
584 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
585 exec->vtx.vertex_size * sizeof(GLfloat));
586
587 vbo_exec_do_EvalCoord1f( exec, u );
588
589 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
590 exec->vtx.vertex_size * sizeof(GLfloat));
591 }
592
593 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
594 {
595 GET_CURRENT_CONTEXT( ctx );
596 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
597
598 {
599 GLint i;
600 if (exec->eval.recalculate_maps)
601 vbo_exec_eval_update( exec );
602
603 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
604 if (exec->eval.map2[i].map)
605 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
606 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
607 }
608
609 if (ctx->Eval.AutoNormal)
610 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
611 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
612 }
613
614 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
615 exec->vtx.vertex_size * sizeof(GLfloat));
616
617 vbo_exec_do_EvalCoord2f( exec, u, v );
618
619 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
620 exec->vtx.vertex_size * sizeof(GLfloat));
621 }
622
623 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
624 {
625 vbo_exec_EvalCoord1f( u[0] );
626 }
627
628 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
629 {
630 vbo_exec_EvalCoord2f( u[0], u[1] );
631 }
632
633 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
634 {
635 GET_CURRENT_CONTEXT( ctx );
636 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
637 (GLfloat) ctx->Eval.MapGrid1un);
638 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
639
640 vbo_exec_EvalCoord1f( u );
641 }
642
643
644 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
645 {
646 GET_CURRENT_CONTEXT( ctx );
647 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
648 (GLfloat) ctx->Eval.MapGrid2un);
649 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
650 (GLfloat) ctx->Eval.MapGrid2vn);
651 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
652 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
653
654 vbo_exec_EvalCoord2f( u, v );
655 }
656
657
658 static void GLAPIENTRY
659 vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
660 {
661 GET_CURRENT_CONTEXT(ctx);
662 GLint i;
663 GLfloat u, du;
664 GLenum prim;
665
666 switch (mode) {
667 case GL_POINT:
668 prim = GL_POINTS;
669 break;
670 case GL_LINE:
671 prim = GL_LINE_STRIP;
672 break;
673 default:
674 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
675 return;
676 }
677
678 /* No effect if vertex maps disabled.
679 */
680 if (!ctx->Eval.Map1Vertex4 &&
681 !ctx->Eval.Map1Vertex3)
682 return;
683
684 du = ctx->Eval.MapGrid1du;
685 u = ctx->Eval.MapGrid1u1 + i1 * du;
686
687 CALL_Begin(GET_DISPATCH(), (prim));
688 for (i=i1;i<=i2;i++,u+=du) {
689 CALL_EvalCoord1f(GET_DISPATCH(), (u));
690 }
691 CALL_End(GET_DISPATCH(), ());
692 }
693
694
695 static void GLAPIENTRY
696 vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
697 {
698 GET_CURRENT_CONTEXT(ctx);
699 GLfloat u, du, v, dv, v1, u1;
700 GLint i, j;
701
702 switch (mode) {
703 case GL_POINT:
704 case GL_LINE:
705 case GL_FILL:
706 break;
707 default:
708 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
709 return;
710 }
711
712 /* No effect if vertex maps disabled.
713 */
714 if (!ctx->Eval.Map2Vertex4 &&
715 !ctx->Eval.Map2Vertex3)
716 return;
717
718 du = ctx->Eval.MapGrid2du;
719 dv = ctx->Eval.MapGrid2dv;
720 v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
721 u1 = ctx->Eval.MapGrid2u1 + i1 * du;
722
723 switch (mode) {
724 case GL_POINT:
725 CALL_Begin(GET_DISPATCH(), (GL_POINTS));
726 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
727 for (u=u1,i=i1;i<=i2;i++,u+=du) {
728 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
729 }
730 }
731 CALL_End(GET_DISPATCH(), ());
732 break;
733 case GL_LINE:
734 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
735 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
736 for (u=u1,i=i1;i<=i2;i++,u+=du) {
737 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
738 }
739 CALL_End(GET_DISPATCH(), ());
740 }
741 for (u=u1,i=i1;i<=i2;i++,u+=du) {
742 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
743 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
744 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
745 }
746 CALL_End(GET_DISPATCH(), ());
747 }
748 break;
749 case GL_FILL:
750 for (v=v1,j=j1;j<j2;j++,v+=dv) {
751 CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
752 for (u=u1,i=i1;i<=i2;i++,u+=du) {
753 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
754 CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
755 }
756 CALL_End(GET_DISPATCH(), ());
757 }
758 break;
759 }
760 }
761
762
763 /**
764 * Execute a glRectf() function. This is not suitable for GL_COMPILE
765 * modes (as the test for outside begin/end is not compiled),
766 * but may be useful for drivers in circumstances which exclude
767 * display list interactions.
768 *
769 * (None of the functions in this file are suitable for GL_COMPILE
770 * modes).
771 */
772 static void GLAPIENTRY
773 vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
774 {
775 CALL_Begin(GET_DISPATCH(), (GL_QUADS));
776 CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
777 CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
778 CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
779 CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
780 CALL_End(GET_DISPATCH(), ());
781 }
782
783
784 /**
785 * Called via glBegin.
786 */
787 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
788 {
789 GET_CURRENT_CONTEXT( ctx );
790 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
791 int i;
792
793 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
794 _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
795 return;
796 }
797
798 if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
799 return;
800 }
801
802 vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
803
804 if (ctx->NewState) {
805 _mesa_update_state( ctx );
806
807 CALL_Begin(ctx->Exec, (mode));
808 return;
809 }
810
811 if (!_mesa_valid_to_render(ctx, "glBegin")) {
812 return;
813 }
814
815 /* Heuristic: attempt to isolate attributes occuring outside
816 * begin/end pairs.
817 */
818 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
819 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
820
821 i = exec->vtx.prim_count++;
822 exec->vtx.prim[i].mode = mode;
823 exec->vtx.prim[i].begin = 1;
824 exec->vtx.prim[i].end = 0;
825 exec->vtx.prim[i].indexed = 0;
826 exec->vtx.prim[i].weak = 0;
827 exec->vtx.prim[i].pad = 0;
828 exec->vtx.prim[i].start = exec->vtx.vert_count;
829 exec->vtx.prim[i].count = 0;
830 exec->vtx.prim[i].num_instances = 1;
831 exec->vtx.prim[i].base_instance = 0;
832
833 ctx->Driver.CurrentExecPrimitive = mode;
834
835 ctx->Exec = ctx->BeginEnd;
836 /* We may have been called from a display list, in which case we should
837 * leave dlist.c's dispatch table in place.
838 */
839 if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
840 ctx->CurrentDispatch = ctx->BeginEnd;
841 _glapi_set_dispatch(ctx->CurrentDispatch);
842 } else {
843 assert(ctx->CurrentDispatch == ctx->Save);
844 }
845 }
846
847
848 /**
849 * Called via glEnd.
850 */
851 static void GLAPIENTRY vbo_exec_End( void )
852 {
853 GET_CURRENT_CONTEXT( ctx );
854 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
855
856 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
857 _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
858 return;
859 }
860
861 ctx->Exec = ctx->OutsideBeginEnd;
862 if (ctx->CurrentDispatch == ctx->BeginEnd) {
863 ctx->CurrentDispatch = ctx->OutsideBeginEnd;
864 _glapi_set_dispatch(ctx->CurrentDispatch);
865 }
866
867 if (exec->vtx.prim_count > 0) {
868 /* close off current primitive */
869 int idx = exec->vtx.vert_count;
870 int i = exec->vtx.prim_count - 1;
871
872 exec->vtx.prim[i].end = 1;
873 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
874 }
875
876 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
877
878 if (exec->vtx.prim_count == VBO_MAX_PRIM)
879 vbo_exec_vtx_flush( exec, GL_FALSE );
880
881 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
882 _mesa_flush(ctx);
883 }
884 }
885
886
887 /**
888 * Called via glPrimitiveRestartNV()
889 */
890 static void GLAPIENTRY
891 vbo_exec_PrimitiveRestartNV(void)
892 {
893 GLenum curPrim;
894 GET_CURRENT_CONTEXT( ctx );
895
896 curPrim = ctx->Driver.CurrentExecPrimitive;
897
898 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
899 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
900 }
901 else {
902 vbo_exec_End();
903 vbo_exec_Begin(curPrim);
904 }
905 }
906
907
908
909 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
910 {
911 struct gl_context *ctx = exec->ctx;
912 GLvertexformat *vfmt = &exec->vtxfmt;
913
914 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
915
916 vfmt->Begin = vbo_exec_Begin;
917 vfmt->End = vbo_exec_End;
918 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
919
920 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
921 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
922
923 vfmt->Rectf = vbo_exec_Rectf;
924
925 /* from attrib_tmp.h:
926 */
927 vfmt->Color3f = vbo_Color3f;
928 vfmt->Color3fv = vbo_Color3fv;
929 vfmt->Color4f = vbo_Color4f;
930 vfmt->Color4fv = vbo_Color4fv;
931 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
932 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
933 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
934 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
935 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
936 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
937 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
938 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
939 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
940 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
941 vfmt->Normal3f = vbo_Normal3f;
942 vfmt->Normal3fv = vbo_Normal3fv;
943 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
944 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
945 vfmt->TexCoord1f = vbo_TexCoord1f;
946 vfmt->TexCoord1fv = vbo_TexCoord1fv;
947 vfmt->TexCoord2f = vbo_TexCoord2f;
948 vfmt->TexCoord2fv = vbo_TexCoord2fv;
949 vfmt->TexCoord3f = vbo_TexCoord3f;
950 vfmt->TexCoord3fv = vbo_TexCoord3fv;
951 vfmt->TexCoord4f = vbo_TexCoord4f;
952 vfmt->TexCoord4fv = vbo_TexCoord4fv;
953 vfmt->Vertex2f = vbo_Vertex2f;
954 vfmt->Vertex2fv = vbo_Vertex2fv;
955 vfmt->Vertex3f = vbo_Vertex3f;
956 vfmt->Vertex3fv = vbo_Vertex3fv;
957 vfmt->Vertex4f = vbo_Vertex4f;
958 vfmt->Vertex4fv = vbo_Vertex4fv;
959
960 if (ctx->API == API_OPENGLES2) {
961 vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
962 vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
963 vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
964 vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
965 vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
966 vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
967 vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
968 vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
969 } else {
970 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
971 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
972 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
973 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
974 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
975 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
976 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
977 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
978 }
979
980 /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
981 * they can have a single entrypoint for updating any of the legacy
982 * attribs.
983 */
984 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
985 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
986 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
987 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
988 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
989 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
990 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
991 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
992
993 /* integer-valued */
994 vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
995 vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
996 vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
997 vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
998 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
999 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
1000 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
1001
1002 /* unsigned integer-valued */
1003 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
1004 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
1005 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
1006 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
1007 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
1008 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
1009 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
1010
1011 vfmt->Materialfv = vbo_Materialfv;
1012
1013 vfmt->EdgeFlag = vbo_EdgeFlag;
1014 vfmt->Indexf = vbo_Indexf;
1015 vfmt->Indexfv = vbo_Indexfv;
1016
1017 /* ARB_vertex_type_2_10_10_10_rev */
1018 vfmt->VertexP2ui = vbo_VertexP2ui;
1019 vfmt->VertexP2uiv = vbo_VertexP2uiv;
1020 vfmt->VertexP3ui = vbo_VertexP3ui;
1021 vfmt->VertexP3uiv = vbo_VertexP3uiv;
1022 vfmt->VertexP4ui = vbo_VertexP4ui;
1023 vfmt->VertexP4uiv = vbo_VertexP4uiv;
1024
1025 vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
1026 vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
1027 vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
1028 vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
1029 vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
1030 vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
1031 vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
1032 vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
1033
1034 vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
1035 vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
1036 vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
1037 vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
1038 vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
1039 vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
1040 vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
1041 vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
1042
1043 vfmt->NormalP3ui = vbo_NormalP3ui;
1044 vfmt->NormalP3uiv = vbo_NormalP3uiv;
1045
1046 vfmt->ColorP3ui = vbo_ColorP3ui;
1047 vfmt->ColorP3uiv = vbo_ColorP3uiv;
1048 vfmt->ColorP4ui = vbo_ColorP4ui;
1049 vfmt->ColorP4uiv = vbo_ColorP4uiv;
1050
1051 vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
1052 vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
1053
1054 vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
1055 vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
1056 vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
1057 vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
1058 vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
1059 vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
1060 vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
1061 vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
1062 }
1063
1064
1065 /**
1066 * Tell the VBO module to use a real OpenGL vertex buffer object to
1067 * store accumulated immediate-mode vertex data.
1068 * This replaces the malloced buffer which was created in
1069 * vb_exec_vtx_init() below.
1070 */
1071 void vbo_use_buffer_objects(struct gl_context *ctx)
1072 {
1073 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1074 /* Any buffer name but 0 can be used here since this bufferobj won't
1075 * go into the bufferobj hashtable.
1076 */
1077 GLuint bufName = IMM_BUFFER_NAME;
1078 GLenum target = GL_ARRAY_BUFFER_ARB;
1079 GLenum usage = GL_STREAM_DRAW_ARB;
1080 GLsizei size = VBO_VERT_BUFFER_SIZE;
1081
1082 /* Make sure this func is only used once */
1083 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1084 if (exec->vtx.buffer_map) {
1085 _mesa_align_free(exec->vtx.buffer_map);
1086 exec->vtx.buffer_map = NULL;
1087 exec->vtx.buffer_ptr = NULL;
1088 }
1089
1090 /* Allocate a real buffer object now */
1091 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1092 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
1093 if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj)) {
1094 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1095 }
1096 }
1097
1098
1099 /**
1100 * If this function is called, all VBO buffers will be unmapped when
1101 * we flush.
1102 * Otherwise, if a simple command like glColor3f() is called and we flush,
1103 * the current VBO may be left mapped.
1104 */
1105 void
1106 vbo_always_unmap_buffers(struct gl_context *ctx)
1107 {
1108 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1109 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1110 }
1111
1112
1113 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
1114 {
1115 struct gl_context *ctx = exec->ctx;
1116 struct vbo_context *vbo = vbo_context(ctx);
1117 GLuint i;
1118
1119 /* Allocate a buffer object. Will just reuse this object
1120 * continuously, unless vbo_use_buffer_objects() is called to enable
1121 * use of real VBOs.
1122 */
1123 _mesa_reference_buffer_object(ctx,
1124 &exec->vtx.bufferobj,
1125 ctx->Shared->NullBufferObj);
1126
1127 ASSERT(!exec->vtx.buffer_map);
1128 exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
1129 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1130
1131 vbo_exec_vtxfmt_init( exec );
1132 _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1133
1134 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1135 ASSERT(i < Elements(exec->vtx.attrsz));
1136 exec->vtx.attrsz[i] = 0;
1137 ASSERT(i < Elements(exec->vtx.attrtype));
1138 exec->vtx.attrtype[i] = GL_FLOAT;
1139 ASSERT(i < Elements(exec->vtx.active_sz));
1140 exec->vtx.active_sz[i] = 0;
1141 }
1142 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
1143 ASSERT(i < Elements(exec->vtx.inputs));
1144 ASSERT(i < Elements(exec->vtx.arrays));
1145 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
1146 }
1147
1148 {
1149 struct gl_client_array *arrays = exec->vtx.arrays;
1150 unsigned i;
1151
1152 memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
1153 VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
1154 for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
1155 struct gl_client_array *array;
1156 array = &arrays[VERT_ATTRIB_FF(i)];
1157 array->BufferObj = NULL;
1158 _mesa_reference_buffer_object(ctx, &arrays->BufferObj,
1159 vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
1160 }
1161
1162 memcpy(arrays + VERT_ATTRIB_GENERIC(0),
1163 &vbo->currval[VBO_ATTRIB_GENERIC0],
1164 VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
1165
1166 for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
1167 struct gl_client_array *array;
1168 array = &arrays[VERT_ATTRIB_GENERIC(i)];
1169 array->BufferObj = NULL;
1170 _mesa_reference_buffer_object(ctx, &array->BufferObj,
1171 vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
1172 }
1173 }
1174
1175 exec->vtx.vertex_size = 0;
1176
1177 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1178 }
1179
1180
1181 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
1182 {
1183 /* using a real VBO for vertex data */
1184 struct gl_context *ctx = exec->ctx;
1185 unsigned i;
1186
1187 /* True VBOs should already be unmapped
1188 */
1189 if (exec->vtx.buffer_map) {
1190 ASSERT(exec->vtx.bufferobj->Name == 0 ||
1191 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1192 if (exec->vtx.bufferobj->Name == 0) {
1193 _mesa_align_free(exec->vtx.buffer_map);
1194 exec->vtx.buffer_map = NULL;
1195 exec->vtx.buffer_ptr = NULL;
1196 }
1197 }
1198
1199 /* Drop any outstanding reference to the vertex buffer
1200 */
1201 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
1202 _mesa_reference_buffer_object(ctx,
1203 &exec->vtx.arrays[i].BufferObj,
1204 NULL);
1205 }
1206
1207 /* Free the vertex buffer. Unmap first if needed.
1208 */
1209 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
1210 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj);
1211 }
1212 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1213 }
1214
1215
1216 /**
1217 * Called upon first glVertex, glColor, glTexCoord, etc.
1218 */
1219 void vbo_exec_BeginVertices( struct gl_context *ctx )
1220 {
1221 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1222
1223 vbo_exec_vtx_map( exec );
1224
1225 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
1226 assert(exec->begin_vertices_flags);
1227
1228 ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
1229 }
1230
1231
1232 /**
1233 * Called via ctx->Driver.FlushVertices()
1234 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1235 */
1236 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
1237 {
1238 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1239
1240 #ifdef DEBUG
1241 /* debug check: make sure we don't get called recursively */
1242 exec->flush_call_depth++;
1243 assert(exec->flush_call_depth == 1);
1244 #endif
1245
1246 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
1247 /* We've had glBegin but not glEnd! */
1248 #ifdef DEBUG
1249 exec->flush_call_depth--;
1250 assert(exec->flush_call_depth == 0);
1251 #endif
1252 return;
1253 }
1254
1255 /* Flush (draw), and make sure VBO is left unmapped when done */
1256 vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1257
1258 /* Need to do this to ensure BeginVertices gets called again:
1259 */
1260 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1261
1262 #ifdef DEBUG
1263 exec->flush_call_depth--;
1264 assert(exec->flush_call_depth == 0);
1265 #endif
1266 }
1267
1268
1269 static void reset_attrfv( struct vbo_exec_context *exec )
1270 {
1271 GLuint i;
1272
1273 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1274 exec->vtx.attrsz[i] = 0;
1275 exec->vtx.attrtype[i] = GL_FLOAT;
1276 exec->vtx.active_sz[i] = 0;
1277 }
1278
1279 exec->vtx.vertex_size = 0;
1280 }
1281
1282
1283 void GLAPIENTRY
1284 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1285 {
1286 vbo_Color4f(r, g, b, a);
1287 }
1288
1289
1290 void GLAPIENTRY
1291 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1292 {
1293 vbo_Normal3f(x, y, z);
1294 }
1295
1296
1297 void GLAPIENTRY
1298 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1299 {
1300 vbo_MultiTexCoord4f(target, s, t, r, q);
1301 }
1302
1303
1304 void GLAPIENTRY
1305 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1306 {
1307 vbo_Materialfv(face, pname, params);
1308 }
1309
1310
1311 void GLAPIENTRY
1312 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1313 {
1314 GLfloat p[4];
1315 p[0] = param;
1316 p[1] = p[2] = p[3] = 0.0F;
1317 vbo_Materialfv(face, pname, p);
1318 }
1319
1320
1321 /**
1322 * A special version of glVertexAttrib4f that does not treat index 0 as
1323 * VBO_ATTRIB_POS.
1324 */
1325 static void
1326 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1327 {
1328 GET_CURRENT_CONTEXT(ctx);
1329 if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1330 ATTR(VBO_ATTRIB_GENERIC0 + index, 4, GL_FLOAT, x, y, z, w);
1331 else
1332 ERROR(GL_INVALID_VALUE);
1333 }
1334
1335 void GLAPIENTRY
1336 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1337 {
1338 VertexAttrib4f_nopos(index, x, y, z, w);
1339 }
1340
1341
1342 void GLAPIENTRY
1343 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1344 {
1345 VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1346 }
1347
1348
1349 void GLAPIENTRY
1350 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1351 {
1352 VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1353 }
1354
1355
1356 void GLAPIENTRY
1357 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1358 {
1359 VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1360 }
1361
1362
1363 void GLAPIENTRY
1364 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1365 {
1366 VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1367 }
1368
1369
1370 void GLAPIENTRY
1371 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1372 {
1373 VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1374 }
1375
1376
1377 void GLAPIENTRY
1378 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1379 {
1380 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1381 }
1382
1383
1384 void GLAPIENTRY
1385 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1386 {
1387 VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1388 }