[MESA]
[reactos.git] / reactos / dll / opengl / 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 /* Copy stored stored vertices to start of new list.
128 */
129 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
130
131 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
132 memcpy( exec->vtx.buffer_ptr, data,
133 exec->vtx.vertex_size * sizeof(GLfloat));
134 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
135 data += exec->vtx.vertex_size;
136 exec->vtx.vert_count++;
137 }
138
139 exec->vtx.copied.nr = 0;
140 }
141
142
143 /**
144 * Copy the active vertex's values to the ctx->Current fields.
145 */
146 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
147 {
148 struct gl_context *ctx = exec->ctx;
149 struct vbo_context *vbo = vbo_context(ctx);
150 GLuint i;
151
152 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
153 if (exec->vtx.attrsz[i]) {
154 /* Note: the exec->vtx.current[i] pointers point into the
155 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
156 */
157 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
158 GLfloat tmp[4];
159
160 COPY_CLEAN_4V(tmp,
161 exec->vtx.attrsz[i],
162 exec->vtx.attrptr[i]);
163
164 if (memcmp(current, tmp, sizeof(tmp)) != 0) {
165 memcpy(current, tmp, sizeof(tmp));
166
167 /* Given that we explicitly state size here, there is no need
168 * for the COPY_CLEAN above, could just copy 16 bytes and be
169 * done. The only problem is when Mesa accesses ctx->Current
170 * directly.
171 */
172 vbo->currval[i].Size = exec->vtx.attrsz[i];
173 assert(vbo->currval[i].Type == GL_FLOAT);
174 vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
175
176 /* This triggers rather too much recalculation of Mesa state
177 * that doesn't get used (eg light positions).
178 */
179 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && i <= VBO_ATTRIB_MAT_BACK_INDEXES)
180 ctx->NewState |= _NEW_LIGHT;
181
182 ctx->NewState |= _NEW_CURRENT_ATTRIB;
183 }
184 }
185 }
186
187 /* Colormaterial -- this kindof sucks.
188 */
189 if (ctx->Light.ColorMaterialEnabled &&
190 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
191 _mesa_update_color_material(ctx,
192 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
193 }
194 }
195
196
197 /**
198 * Copy current vertex attribute values into the current vertex.
199 */
200 static void
201 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
202 {
203 struct gl_context *ctx = exec->ctx;
204 struct vbo_context *vbo = vbo_context(ctx);
205 GLint i;
206
207 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
208 const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
209 switch (exec->vtx.attrsz[i]) {
210 case 4: exec->vtx.attrptr[i][3] = current[3];
211 case 3: exec->vtx.attrptr[i][2] = current[2];
212 case 2: exec->vtx.attrptr[i][1] = current[1];
213 case 1: exec->vtx.attrptr[i][0] = current[0];
214 break;
215 }
216 }
217 }
218
219
220 /**
221 * Flush existing data, set new attrib size, replay copied vertices.
222 * This is called when we transition from a small vertex attribute size
223 * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
224 * We need to go back over the previous 2-component texcoords and insert
225 * zero and one values.
226 */
227 static void
228 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
229 GLuint attr, GLuint newSize )
230 {
231 struct gl_context *ctx = exec->ctx;
232 struct vbo_context *vbo = vbo_context(ctx);
233 const GLint lastcount = exec->vtx.vert_count;
234 GLfloat *old_attrptr[VBO_ATTRIB_MAX];
235 const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
236 const GLuint oldSize = exec->vtx.attrsz[attr];
237 GLuint i;
238
239 /* Run pipeline on current vertices, copy wrapped vertices
240 * to exec->vtx.copied.
241 */
242 vbo_exec_wrap_buffers( exec );
243
244 if (unlikely(exec->vtx.copied.nr)) {
245 /* We're in the middle of a primitive, keep the old vertex
246 * format around to be able to translate the copied vertices to
247 * the new format.
248 */
249 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
250 }
251
252 if (unlikely(oldSize)) {
253 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
254 * case when the attribute already exists in the vertex and is
255 * having its size increased.
256 */
257 vbo_exec_copy_to_current( exec );
258 }
259
260 /* Heuristic: Attempt to isolate attributes received outside
261 * begin/end so that they don't bloat the vertices.
262 */
263 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
264 !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
265 vbo_exec_copy_to_current( exec );
266 reset_attrfv( exec );
267 }
268
269 /* Fix up sizes:
270 */
271 exec->vtx.attrsz[attr] = newSize;
272 exec->vtx.vertex_size += newSize - oldSize;
273 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
274 (exec->vtx.vertex_size * sizeof(GLfloat)));
275 exec->vtx.vert_count = 0;
276 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
277
278 if (unlikely(oldSize)) {
279 /* Size changed, recalculate all the attrptr[] values
280 */
281 GLfloat *tmp = exec->vtx.vertex;
282
283 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
284 if (exec->vtx.attrsz[i]) {
285 exec->vtx.attrptr[i] = tmp;
286 tmp += exec->vtx.attrsz[i];
287 }
288 else
289 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
290 }
291
292 /* Copy from current to repopulate the vertex with correct
293 * values.
294 */
295 vbo_exec_copy_from_current( exec );
296 }
297 else {
298 /* Just have to append the new attribute at the end */
299 exec->vtx.attrptr[attr] = exec->vtx.vertex +
300 exec->vtx.vertex_size - newSize;
301 }
302
303 /* Replay stored vertices to translate them
304 * to new format here.
305 *
306 * -- No need to replay - just copy piecewise
307 */
308 if (unlikely(exec->vtx.copied.nr)) {
309 GLfloat *data = exec->vtx.copied.buffer;
310 GLfloat *dest = exec->vtx.buffer_ptr;
311 GLuint j;
312
313 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
314
315 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
316 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
317 GLuint sz = exec->vtx.attrsz[j];
318
319 if (sz) {
320 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
321 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
322
323 if (j == attr) {
324 if (oldSize) {
325 GLfloat tmp[4];
326 COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
327 COPY_SZ_4V(dest + new_offset, newSize, tmp);
328 } else {
329 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
330 COPY_SZ_4V(dest + new_offset, sz, current);
331 }
332 }
333 else {
334 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
335 }
336 }
337 }
338
339 data += old_vtx_size;
340 dest += exec->vtx.vertex_size;
341 }
342
343 exec->vtx.buffer_ptr = dest;
344 exec->vtx.vert_count += exec->vtx.copied.nr;
345 exec->vtx.copied.nr = 0;
346 }
347 }
348
349
350 /**
351 * This is when a vertex attribute transitions to a different size.
352 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
353 * glTexCoord4f() call. We promote the array from size=2 to size=4.
354 */
355 static void
356 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
357 {
358 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
359
360 if (newSize > exec->vtx.attrsz[attr]) {
361 /* New size is larger. Need to flush existing vertices and get
362 * an enlarged vertex format.
363 */
364 vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
365 }
366 else if (newSize < exec->vtx.active_sz[attr]) {
367 static const GLfloat id[4] = { 0, 0, 0, 1 };
368 GLuint i;
369
370 /* New size is smaller - just need to fill in some
371 * zeros. Don't need to flush or wrap.
372 */
373 for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
374 exec->vtx.attrptr[attr][i-1] = id[i-1];
375 }
376
377 exec->vtx.active_sz[attr] = newSize;
378
379 /* Does setting NeedFlush belong here? Necessitates resetting
380 * vtxfmt on each flush (otherwise flags won't get reset
381 * afterwards).
382 */
383 if (attr == 0)
384 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
385 }
386
387
388 /**
389 * This macro is used to implement all the glVertex, glColor, glTexCoord,
390 * glVertexAttrib, etc functions.
391 */
392 #define ATTR( A, N, V0, V1, V2, V3 ) \
393 do { \
394 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
395 \
396 if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
397 ctx->Driver.BeginVertices( ctx ); \
398 \
399 if (unlikely(exec->vtx.active_sz[A] != N)) \
400 vbo_exec_fixup_vertex(ctx, A, N); \
401 \
402 { \
403 GLfloat *dest = exec->vtx.attrptr[A]; \
404 if (N>0) dest[0] = V0; \
405 if (N>1) dest[1] = V1; \
406 if (N>2) dest[2] = V2; \
407 if (N>3) dest[3] = V3; \
408 } \
409 \
410 if ((A) == 0) { \
411 /* This is a glVertex call */ \
412 GLuint i; \
413 \
414 for (i = 0; i < exec->vtx.vertex_size; i++) \
415 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
416 \
417 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
418 \
419 /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
420 /* something to draw (not just updating a color or texcoord).*/ \
421 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
422 \
423 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
424 vbo_exec_vtx_wrap( exec ); \
425 } \
426 } while (0)
427
428
429 #define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
430 #define TAG(x) vbo_##x
431
432 #include "vbo_attrib_tmp.h"
433
434
435
436 /**
437 * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
438 * this may be a (partial) no-op.
439 */
440 static void GLAPIENTRY
441 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
442 {
443 GLbitfield updateMats;
444 GET_CURRENT_CONTEXT(ctx);
445
446 /* This function should be a no-op when it tries to update material
447 * attributes which are currently tracking glColor via glColorMaterial.
448 * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
449 * indicating which material attributes can actually be updated below.
450 */
451 if (ctx->Light.ColorMaterialEnabled) {
452 updateMats = ~ctx->Light.ColorMaterialBitmask;
453 }
454 else {
455 /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
456 updateMats = ALL_MATERIAL_BITS;
457 }
458
459 if (face == GL_FRONT) {
460 updateMats &= FRONT_MATERIAL_BITS;
461 }
462 else if (face == GL_BACK) {
463 updateMats &= BACK_MATERIAL_BITS;
464 }
465 else if (face != GL_FRONT_AND_BACK) {
466 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
467 return;
468 }
469
470 switch (pname) {
471 case GL_EMISSION:
472 if (updateMats & MAT_BIT_FRONT_EMISSION)
473 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
474 if (updateMats & MAT_BIT_BACK_EMISSION)
475 MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
476 break;
477 case GL_AMBIENT:
478 if (updateMats & MAT_BIT_FRONT_AMBIENT)
479 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
480 if (updateMats & MAT_BIT_BACK_AMBIENT)
481 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
482 break;
483 case GL_DIFFUSE:
484 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
485 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
486 if (updateMats & MAT_BIT_BACK_DIFFUSE)
487 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
488 break;
489 case GL_SPECULAR:
490 if (updateMats & MAT_BIT_FRONT_SPECULAR)
491 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
492 if (updateMats & MAT_BIT_BACK_SPECULAR)
493 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
494 break;
495 case GL_SHININESS:
496 if (*params < 0 || *params > ctx->Const.MaxShininess) {
497 _mesa_error(ctx, GL_INVALID_VALUE,
498 "glMaterial(invalid shininess: %f out range [0, %f])",
499 *params, ctx->Const.MaxShininess);
500 return;
501 }
502 if (updateMats & MAT_BIT_FRONT_SHININESS)
503 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
504 if (updateMats & MAT_BIT_BACK_SHININESS)
505 MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
506 break;
507 case GL_COLOR_INDEXES:
508 if (updateMats & MAT_BIT_FRONT_INDEXES)
509 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
510 if (updateMats & MAT_BIT_BACK_INDEXES)
511 MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
512 break;
513 case GL_AMBIENT_AND_DIFFUSE:
514 if (updateMats & MAT_BIT_FRONT_AMBIENT)
515 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
516 if (updateMats & MAT_BIT_FRONT_DIFFUSE)
517 MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
518 if (updateMats & MAT_BIT_BACK_AMBIENT)
519 MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
520 if (updateMats & MAT_BIT_BACK_DIFFUSE)
521 MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
522 break;
523 default:
524 _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
525 return;
526 }
527 }
528
529
530 /**
531 * Flush (draw) vertices.
532 * \param unmap - leave VBO unmapped after flushing?
533 */
534 static void
535 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
536 {
537 if (exec->vtx.vert_count || unmap) {
538 vbo_exec_vtx_flush( exec, unmap );
539 }
540
541 if (exec->vtx.vertex_size) {
542 vbo_exec_copy_to_current( exec );
543 reset_attrfv( exec );
544 }
545 }
546
547
548 #if FEATURE_beginend
549
550
551 #if FEATURE_evaluators
552
553 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
554 {
555 GET_CURRENT_CONTEXT( ctx );
556 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
557
558 {
559 GLint i;
560 if (exec->eval.recalculate_maps)
561 vbo_exec_eval_update( exec );
562
563 for (i = 0; i <= VBO_ATTRIB_TEX; i++) {
564 if (exec->eval.map1[i].map)
565 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
566 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
567 }
568 }
569
570
571 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
572 exec->vtx.vertex_size * sizeof(GLfloat));
573
574 vbo_exec_do_EvalCoord1f( exec, u );
575
576 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
577 exec->vtx.vertex_size * sizeof(GLfloat));
578 }
579
580 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
581 {
582 GET_CURRENT_CONTEXT( ctx );
583 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
584
585 {
586 GLint i;
587 if (exec->eval.recalculate_maps)
588 vbo_exec_eval_update( exec );
589
590 for (i = 0; i <= VBO_ATTRIB_TEX; i++) {
591 if (exec->eval.map2[i].map)
592 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
593 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
594 }
595
596 if (ctx->Eval.AutoNormal)
597 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
598 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
599 }
600
601 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
602 exec->vtx.vertex_size * sizeof(GLfloat));
603
604 vbo_exec_do_EvalCoord2f( exec, u, v );
605
606 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
607 exec->vtx.vertex_size * sizeof(GLfloat));
608 }
609
610 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
611 {
612 vbo_exec_EvalCoord1f( u[0] );
613 }
614
615 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
616 {
617 vbo_exec_EvalCoord2f( u[0], u[1] );
618 }
619
620 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
621 {
622 GET_CURRENT_CONTEXT( ctx );
623 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
624 (GLfloat) ctx->Eval.MapGrid1un);
625 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
626
627 vbo_exec_EvalCoord1f( u );
628 }
629
630
631 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
632 {
633 GET_CURRENT_CONTEXT( ctx );
634 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
635 (GLfloat) ctx->Eval.MapGrid2un);
636 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
637 (GLfloat) ctx->Eval.MapGrid2vn);
638 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
639 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
640
641 vbo_exec_EvalCoord2f( u, v );
642 }
643
644
645 static void GLAPIENTRY
646 vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
647 {
648 GET_CURRENT_CONTEXT(ctx);
649 GLint i;
650 GLfloat u, du;
651 GLenum prim;
652
653 ASSERT_OUTSIDE_BEGIN_END(ctx);
654
655 switch (mode) {
656 case GL_POINT:
657 prim = GL_POINTS;
658 break;
659 case GL_LINE:
660 prim = GL_LINE_STRIP;
661 break;
662 default:
663 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
664 return;
665 }
666
667 /* No effect if vertex maps disabled.
668 */
669 if (!ctx->Eval.Map1Vertex4 &&
670 !ctx->Eval.Map1Vertex3)
671 return;
672
673 du = ctx->Eval.MapGrid1du;
674 u = ctx->Eval.MapGrid1u1 + i1 * du;
675
676 CALL_Begin(GET_DISPATCH(), (prim));
677 for (i=i1;i<=i2;i++,u+=du) {
678 CALL_EvalCoord1f(GET_DISPATCH(), (u));
679 }
680 CALL_End(GET_DISPATCH(), ());
681 }
682
683
684 static void GLAPIENTRY
685 vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
686 {
687 GET_CURRENT_CONTEXT(ctx);
688 GLfloat u, du, v, dv, v1, u1;
689 GLint i, j;
690
691 ASSERT_OUTSIDE_BEGIN_END(ctx);
692
693 switch (mode) {
694 case GL_POINT:
695 case GL_LINE:
696 case GL_FILL:
697 break;
698 default:
699 _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
700 return;
701 }
702
703 /* No effect if vertex maps disabled.
704 */
705 if (!ctx->Eval.Map2Vertex4 &&
706 !ctx->Eval.Map2Vertex3)
707 return;
708
709 du = ctx->Eval.MapGrid2du;
710 dv = ctx->Eval.MapGrid2dv;
711 v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
712 u1 = ctx->Eval.MapGrid2u1 + i1 * du;
713
714 switch (mode) {
715 case GL_POINT:
716 CALL_Begin(GET_DISPATCH(), (GL_POINTS));
717 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
718 for (u=u1,i=i1;i<=i2;i++,u+=du) {
719 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
720 }
721 }
722 CALL_End(GET_DISPATCH(), ());
723 break;
724 case GL_LINE:
725 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
726 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
727 for (u=u1,i=i1;i<=i2;i++,u+=du) {
728 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
729 }
730 CALL_End(GET_DISPATCH(), ());
731 }
732 for (u=u1,i=i1;i<=i2;i++,u+=du) {
733 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
734 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
735 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
736 }
737 CALL_End(GET_DISPATCH(), ());
738 }
739 break;
740 case GL_FILL:
741 for (v=v1,j=j1;j<j2;j++,v+=dv) {
742 CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
743 for (u=u1,i=i1;i<=i2;i++,u+=du) {
744 CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
745 CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
746 }
747 CALL_End(GET_DISPATCH(), ());
748 }
749 break;
750 }
751 }
752
753 #endif /* FEATURE_evaluators */
754
755
756 /**
757 * Execute a glRectf() function. This is not suitable for GL_COMPILE
758 * modes (as the test for outside begin/end is not compiled),
759 * but may be useful for drivers in circumstances which exclude
760 * display list interactions.
761 *
762 * (None of the functions in this file are suitable for GL_COMPILE
763 * modes).
764 */
765 static void GLAPIENTRY
766 vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
767 {
768 GET_CURRENT_CONTEXT(ctx);
769 ASSERT_OUTSIDE_BEGIN_END(ctx);
770
771 CALL_Begin(GET_DISPATCH(), (GL_QUADS));
772 CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
773 CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
774 CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
775 CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
776 CALL_End(GET_DISPATCH(), ());
777 }
778
779
780 /**
781 * Called via glBegin.
782 */
783 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
784 {
785 GET_CURRENT_CONTEXT( ctx );
786
787 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
788 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
789 int i;
790
791 if (!_mesa_valid_prim_mode(ctx, mode)) {
792 _mesa_error(ctx, GL_INVALID_ENUM, "glBegin");
793 return;
794 }
795
796 vbo_draw_method(exec, DRAW_BEGIN_END);
797
798 if (ctx->Driver.PrepareExecBegin)
799 ctx->Driver.PrepareExecBegin(ctx);
800
801 if (ctx->NewState) {
802 _mesa_update_state( ctx );
803
804 CALL_Begin(ctx->Exec, (mode));
805 return;
806 }
807
808 if (!_mesa_valid_to_render(ctx, "glBegin")) {
809 return;
810 }
811
812 /* Heuristic: attempt to isolate attributes occuring outside
813 * begin/end pairs.
814 */
815 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
816 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
817
818 i = exec->vtx.prim_count++;
819 exec->vtx.prim[i].mode = mode;
820 exec->vtx.prim[i].begin = 1;
821 exec->vtx.prim[i].end = 0;
822 exec->vtx.prim[i].indexed = 0;
823 exec->vtx.prim[i].weak = 0;
824 exec->vtx.prim[i].pad = 0;
825 exec->vtx.prim[i].start = exec->vtx.vert_count;
826 exec->vtx.prim[i].count = 0;
827 exec->vtx.prim[i].num_instances = 1;
828
829 ctx->Driver.CurrentExecPrimitive = mode;
830 }
831 else
832 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
833
834 }
835
836
837 /**
838 * Called via glEnd.
839 */
840 static void GLAPIENTRY vbo_exec_End( void )
841 {
842 GET_CURRENT_CONTEXT( ctx );
843
844 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
845 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
846
847 if (exec->vtx.prim_count > 0) {
848 /* close off current primitive */
849 int idx = exec->vtx.vert_count;
850 int i = exec->vtx.prim_count - 1;
851
852 exec->vtx.prim[i].end = 1;
853 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
854 }
855
856 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
857
858 if (exec->vtx.prim_count == VBO_MAX_PRIM)
859 vbo_exec_vtx_flush( exec, GL_FALSE );
860 }
861 else
862 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
863 }
864
865
866 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
867 {
868 GLvertexformat *vfmt = &exec->vtxfmt;
869
870 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
871
872 vfmt->Begin = vbo_exec_Begin;
873 vfmt->End = vbo_exec_End;
874
875 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
876 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
877
878 vfmt->Rectf = vbo_exec_Rectf;
879
880 /* from attrib_tmp.h:
881 */
882 vfmt->Color3f = vbo_Color3f;
883 vfmt->Color3fv = vbo_Color3fv;
884 vfmt->Color4f = vbo_Color4f;
885 vfmt->Color4fv = vbo_Color4fv;
886 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
887 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
888 vfmt->Normal3f = vbo_Normal3f;
889 vfmt->Normal3fv = vbo_Normal3fv;
890 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
891 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
892 vfmt->TexCoord1f = vbo_TexCoord1f;
893 vfmt->TexCoord1fv = vbo_TexCoord1fv;
894 vfmt->TexCoord2f = vbo_TexCoord2f;
895 vfmt->TexCoord2fv = vbo_TexCoord2fv;
896 vfmt->TexCoord3f = vbo_TexCoord3f;
897 vfmt->TexCoord3fv = vbo_TexCoord3fv;
898 vfmt->TexCoord4f = vbo_TexCoord4f;
899 vfmt->TexCoord4fv = vbo_TexCoord4fv;
900 vfmt->Vertex2f = vbo_Vertex2f;
901 vfmt->Vertex2fv = vbo_Vertex2fv;
902 vfmt->Vertex3f = vbo_Vertex3f;
903 vfmt->Vertex3fv = vbo_Vertex3fv;
904 vfmt->Vertex4f = vbo_Vertex4f;
905 vfmt->Vertex4fv = vbo_Vertex4fv;
906
907 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
908 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
909 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
910 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
911 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
912 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
913 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
914 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
915
916 vfmt->Materialfv = vbo_Materialfv;
917
918 vfmt->EdgeFlag = vbo_EdgeFlag;
919 vfmt->Indexf = vbo_Indexf;
920 vfmt->Indexfv = vbo_Indexfv;
921 }
922
923
924 #else /* FEATURE_beginend */
925
926
927 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
928 {
929 /* silence warnings */
930 (void) vbo_Color3f;
931 (void) vbo_Color3fv;
932 (void) vbo_Color4f;
933 (void) vbo_Color4fv;
934 (void) vbo_FogCoordfEXT;
935 (void) vbo_FogCoordfvEXT;
936 (void) vbo_MultiTexCoord1f;
937 (void) vbo_MultiTexCoord1fv;
938 (void) vbo_MultiTexCoord2f;
939 (void) vbo_MultiTexCoord2fv;
940 (void) vbo_MultiTexCoord3f;
941 (void) vbo_MultiTexCoord3fv;
942 (void) vbo_MultiTexCoord4f;
943 (void) vbo_MultiTexCoord4fv;
944 (void) vbo_Normal3f;
945 (void) vbo_Normal3fv;
946 (void) vbo_SecondaryColor3fEXT;
947 (void) vbo_SecondaryColor3fvEXT;
948 (void) vbo_TexCoord1f;
949 (void) vbo_TexCoord1fv;
950 (void) vbo_TexCoord2f;
951 (void) vbo_TexCoord2fv;
952 (void) vbo_TexCoord3f;
953 (void) vbo_TexCoord3fv;
954 (void) vbo_TexCoord4f;
955 (void) vbo_TexCoord4fv;
956 (void) vbo_Vertex2f;
957 (void) vbo_Vertex2fv;
958 (void) vbo_Vertex3f;
959 (void) vbo_Vertex3fv;
960 (void) vbo_Vertex4f;
961 (void) vbo_Vertex4fv;
962
963 (void) vbo_VertexAttrib1fNV;
964 (void) vbo_VertexAttrib1fvNV;
965 (void) vbo_VertexAttrib2fNV;
966 (void) vbo_VertexAttrib2fvNV;
967 (void) vbo_VertexAttrib3fNV;
968 (void) vbo_VertexAttrib3fvNV;
969 (void) vbo_VertexAttrib4fNV;
970 (void) vbo_VertexAttrib4fvNV;
971
972 (void) vbo_Materialfv;
973
974 (void) vbo_EdgeFlag;
975 (void) vbo_Indexf;
976 (void) vbo_Indexfv;
977 }
978
979
980 #endif /* FEATURE_beginend */
981
982
983 /**
984 * Tell the VBO module to use a real OpenGL vertex buffer object to
985 * store accumulated immediate-mode vertex data.
986 * This replaces the malloced buffer which was created in
987 * vb_exec_vtx_init() below.
988 */
989 void vbo_use_buffer_objects(struct gl_context *ctx)
990 {
991 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
992 /* Any buffer name but 0 can be used here since this bufferobj won't
993 * go into the bufferobj hashtable.
994 */
995 GLuint bufName = IMM_BUFFER_NAME;
996 GLenum target = GL_ARRAY_BUFFER_ARB;
997 GLenum usage = GL_STREAM_DRAW_ARB;
998 GLsizei size = VBO_VERT_BUFFER_SIZE;
999
1000 /* Make sure this func is only used once */
1001 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
1002 if (exec->vtx.buffer_map) {
1003 _mesa_align_free(exec->vtx.buffer_map);
1004 exec->vtx.buffer_map = NULL;
1005 exec->vtx.buffer_ptr = NULL;
1006 }
1007
1008 /* Allocate a real buffer object now */
1009 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1010 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
1011 if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj)) {
1012 _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
1013 }
1014 }
1015
1016
1017 /**
1018 * If this function is called, all VBO buffers will be unmapped when
1019 * we flush.
1020 * Otherwise, if a simple command like glColor3f() is called and we flush,
1021 * the current VBO may be left mapped.
1022 */
1023 void
1024 vbo_always_unmap_buffers(struct gl_context *ctx)
1025 {
1026 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1027 exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
1028 }
1029
1030
1031 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
1032 {
1033 struct gl_context *ctx = exec->ctx;
1034 struct vbo_context *vbo = vbo_context(ctx);
1035 GLuint i;
1036
1037 /* Allocate a buffer object. Will just reuse this object
1038 * continuously, unless vbo_use_buffer_objects() is called to enable
1039 * use of real VBOs.
1040 */
1041 _mesa_reference_buffer_object(ctx,
1042 &exec->vtx.bufferobj,
1043 ctx->Shared->NullBufferObj);
1044
1045 ASSERT(!exec->vtx.buffer_map);
1046 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
1047 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1048
1049 vbo_exec_vtxfmt_init( exec );
1050 _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
1051
1052 /* Hook our functions into the dispatch table.
1053 */
1054 _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
1055
1056 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1057 ASSERT(i < Elements(exec->vtx.attrsz));
1058 exec->vtx.attrsz[i] = 0;
1059 ASSERT(i < Elements(exec->vtx.active_sz));
1060 exec->vtx.active_sz[i] = 0;
1061 }
1062 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
1063 ASSERT(i < Elements(exec->vtx.inputs));
1064 ASSERT(i < Elements(exec->vtx.arrays));
1065 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
1066 }
1067
1068 {
1069 struct gl_client_array *arrays = exec->vtx.arrays;
1070 unsigned i;
1071
1072 memcpy(arrays, vbo->legacy_currval,
1073 VERT_ATTRIB_MAX * sizeof(arrays[0]));
1074 for (i = 0; i < VERT_ATTRIB_MAX; ++i) {
1075 struct gl_client_array *array;
1076 array = &arrays[VERT_ATTRIB(i)];
1077 array->BufferObj = NULL;
1078 _mesa_reference_buffer_object(ctx, &arrays->BufferObj,
1079 vbo->legacy_currval[i].BufferObj);
1080 }
1081 }
1082
1083 exec->vtx.vertex_size = 0;
1084
1085 exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
1086 }
1087
1088
1089 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
1090 {
1091 /* using a real VBO for vertex data */
1092 struct gl_context *ctx = exec->ctx;
1093 unsigned i;
1094
1095 /* True VBOs should already be unmapped
1096 */
1097 if (exec->vtx.buffer_map) {
1098 ASSERT(exec->vtx.bufferobj->Name == 0 ||
1099 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1100 if (exec->vtx.bufferobj->Name == 0) {
1101 _mesa_align_free(exec->vtx.buffer_map);
1102 exec->vtx.buffer_map = NULL;
1103 exec->vtx.buffer_ptr = NULL;
1104 }
1105 }
1106
1107 /* Drop any outstanding reference to the vertex buffer
1108 */
1109 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
1110 _mesa_reference_buffer_object(ctx,
1111 &exec->vtx.arrays[i].BufferObj,
1112 NULL);
1113 }
1114
1115 /* Free the vertex buffer. Unmap first if needed.
1116 */
1117 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
1118 ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj);
1119 }
1120 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1121 }
1122
1123
1124 /**
1125 * Called upon first glVertex, glColor, glTexCoord, etc.
1126 */
1127 void vbo_exec_BeginVertices( struct gl_context *ctx )
1128 {
1129 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1130
1131 vbo_exec_vtx_map( exec );
1132
1133 assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
1134 assert(exec->begin_vertices_flags);
1135
1136 ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
1137 }
1138
1139
1140 /**
1141 * Called via ctx->Driver.FlushVertices()
1142 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1143 */
1144 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
1145 {
1146 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1147
1148 #ifdef DEBUG
1149 /* debug check: make sure we don't get called recursively */
1150 exec->flush_call_depth++;
1151 assert(exec->flush_call_depth == 1);
1152 #endif
1153
1154 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
1155 /* We've had glBegin but not glEnd! */
1156 #ifdef DEBUG
1157 exec->flush_call_depth--;
1158 assert(exec->flush_call_depth == 0);
1159 #endif
1160 return;
1161 }
1162
1163 /* Flush (draw), and make sure VBO is left unmapped when done */
1164 vbo_exec_FlushVertices_internal(exec, GL_TRUE);
1165
1166 /* Need to do this to ensure BeginVertices gets called again:
1167 */
1168 ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1169
1170 #ifdef DEBUG
1171 exec->flush_call_depth--;
1172 assert(exec->flush_call_depth == 0);
1173 #endif
1174 }
1175
1176
1177 static void reset_attrfv( struct vbo_exec_context *exec )
1178 {
1179 GLuint i;
1180
1181 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1182 exec->vtx.attrsz[i] = 0;
1183 exec->vtx.active_sz[i] = 0;
1184 }
1185
1186 exec->vtx.vertex_size = 0;
1187 }