Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 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 
31
 */
32
 
33
 
34
 
35
/* Display list compiler attempts to store lists of vertices with the
36
 * same vertex layout.  Additionally it attempts to minimize the need
37
 * for execute-time fixup of these vertex lists, allowing them to be
38
 * cached on hardware.
39
 *
40
 * There are still some circumstances where this can be thwarted, for
41
 * example by building a list that consists of one very long primitive
42
 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43
 * from inside a different begin/end object (Begin(Lines), CallList,
44
 * End).
45
 *
46
 * In that case the code will have to replay the list as individual
47
 * commands through the Exec dispatch table, or fix up the copied
48
 * vertices at execute-time.
49
 *
50
 * The other case where fixup is required is when a vertex attribute
51
 * is introduced in the middle of a primitive.  Eg:
52
 *  Begin(Lines)
53
 *  TexCoord1f()           Vertex2f()
54
 *  TexCoord1f() Color3f() Vertex2f()
55
 *  End()
56
 *
57
 *  If the current value of Color isn't known at compile-time, this
58
 *  primitive will require fixup.
59
 *
60
 *
61
 * The list compiler currently doesn't attempt to compile lists
62
 * containing EvalCoord or EvalPoint commands.  On encountering one of
63
 * these, compilation falls back to opcodes.
64
 *
65
 * This could be improved to fallback only when a mix of EvalCoord and
66
 * Vertex commands are issued within a single primitive.
67
 */
68
 
69
 
70
#include "main/glheader.h"
71
#include "main/bufferobj.h"
72
#include "main/context.h"
73
#include "main/dlist.h"
74
#include "main/enums.h"
75
#include "main/eval.h"
76
#include "main/macros.h"
77
#include "main/api_noop.h"
78
#include "main/api_validate.h"
79
#include "main/api_arrayelt.h"
80
#include "main/vtxfmt.h"
81
#include "main/dispatch.h"
82
 
83
#include "vbo_context.h"
84
 
85
 
86
#if FEATURE_dlist
87
 
88
 
89
#ifdef ERROR
90
#undef ERROR
91
#endif
92
 
93
 
94
/* An interesting VBO number/name to help with debugging */
95
#define VBO_BUF_ID  12345
96
 
97
 
98
/*
99
 * NOTE: Old 'parity' issue is gone, but copying can still be
100
 * wrong-footed on replay.
101
 */
102
static GLuint _save_copy_vertices( struct gl_context *ctx,
103
				   const struct vbo_save_vertex_list *node,
104
				   const GLfloat *src_buffer)
105
{
106
   struct vbo_save_context *save = &vbo_context( ctx )->save;
107
   const struct _mesa_prim *prim = &node->prim[node->prim_count-1];
108
   GLuint nr = prim->count;
109
   GLuint sz = save->vertex_size;
110
   const GLfloat *src = src_buffer + prim->start * sz;
111
   GLfloat *dst = save->copied.buffer;
112
   GLuint ovf, i;
113
 
114
   if (prim->end)
115
      return 0;
116
 
117
   switch( prim->mode )
118
   {
119
   case GL_POINTS:
120
      return 0;
121
   case GL_LINES:
122
      ovf = nr&1;
123
      for (i = 0 ; i < ovf ; i++)
124
	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
125
      return i;
126
   case GL_TRIANGLES:
127
      ovf = nr%3;
128
      for (i = 0 ; i < ovf ; i++)
129
	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
130
      return i;
131
   case GL_QUADS:
132
      ovf = nr&3;
133
      for (i = 0 ; i < ovf ; i++)
134
	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
135
      return i;
136
   case GL_LINE_STRIP:
137
      if (nr == 0)
138
	 return 0;
139
      else {
140
	 memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
141
	 return 1;
142
      }
143
   case GL_LINE_LOOP:
144
   case GL_TRIANGLE_FAN:
145
   case GL_POLYGON:
146
      if (nr == 0)
147
	 return 0;
148
      else if (nr == 1) {
149
	 memcpy( dst, src+0, sz*sizeof(GLfloat) );
150
	 return 1;
151
      } else {
152
	 memcpy( dst, src+0, sz*sizeof(GLfloat) );
153
	 memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
154
	 return 2;
155
      }
156
   case GL_TRIANGLE_STRIP:
157
   case GL_QUAD_STRIP:
158
      switch (nr) {
159
      case 0: ovf = 0; break;
160
      case 1: ovf = 1; break;
161
      default: ovf = 2 + (nr&1); break;
162
      }
163
      for (i = 0 ; i < ovf ; i++)
164
	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
165
      return i;
166
   default:
167
      assert(0);
168
      return 0;
169
   }
170
}
171
 
172
 
173
static struct vbo_save_vertex_store *alloc_vertex_store( struct gl_context *ctx )
174
{
175
   struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
176
 
177
   /* obj->Name needs to be non-zero, but won't ever be examined more
178
    * closely than that.  In particular these buffers won't be entered
179
    * into the hash and can never be confused with ones visible to the
180
    * user.  Perhaps there could be a special number for internal
181
    * buffers:
182
    */
183
   vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
184
                                                         VBO_BUF_ID,
185
                                                         GL_ARRAY_BUFFER_ARB);
186
 
187
   ctx->Driver.BufferData( ctx,
188
			   GL_ARRAY_BUFFER_ARB,
189
			   VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
190
			   NULL,
191
			   GL_STATIC_DRAW_ARB,
192
			   vertex_store->bufferobj);
193
 
194
   vertex_store->buffer = NULL;
195
   vertex_store->used = 0;
196
   vertex_store->refcount = 1;
197
 
198
   return vertex_store;
199
}
200
 
201
static void free_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
202
{
203
   assert(!vertex_store->buffer);
204
 
205
   if (vertex_store->bufferobj) {
206
      _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
207
   }
208
 
209
   FREE( vertex_store );
210
}
211
 
212
static GLfloat *map_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
213
{
214
   assert(vertex_store->bufferobj);
215
   assert(!vertex_store->buffer);
216
   vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx,
217
							   GL_ARRAY_BUFFER_ARB,	/* not used */
218
							   GL_WRITE_ONLY, /* not used */
219
							   vertex_store->bufferobj);
220
 
221
   assert(vertex_store->buffer);
222
   return vertex_store->buffer + vertex_store->used;
223
}
224
 
225
static void unmap_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
226
{
227
   ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
228
   vertex_store->buffer = NULL;
229
}
230
 
231
 
232
static struct vbo_save_primitive_store *alloc_prim_store( struct gl_context *ctx )
233
{
234
   struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store);
235
   (void) ctx;
236
   store->used = 0;
237
   store->refcount = 1;
238
   return store;
239
}
240
 
241
static void _save_reset_counters( struct gl_context *ctx )
242
{
243
   struct vbo_save_context *save = &vbo_context(ctx)->save;
244
 
245
   save->prim = save->prim_store->buffer + save->prim_store->used;
246
   save->buffer = (save->vertex_store->buffer +
247
		   save->vertex_store->used);
248
 
249
   assert(save->buffer == save->buffer_ptr);
250
 
251
   if (save->vertex_size)
252
      save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
253
			 save->vertex_size);
254
   else
255
      save->max_vert = 0;
256
 
257
   save->vert_count = 0;
258
   save->prim_count = 0;
259
   save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
260
   save->dangling_attr_ref = 0;
261
}
262
 
263
 
264
/* Insert the active immediate struct onto the display list currently
265
 * being built.
266
 */
267
static void _save_compile_vertex_list( struct gl_context *ctx )
268
{
269
   struct vbo_save_context *save = &vbo_context(ctx)->save;
270
   struct vbo_save_vertex_list *node;
271
 
272
   /* Allocate space for this structure in the display list currently
273
    * being compiled.
274
    */
275
   node = (struct vbo_save_vertex_list *)
276
      _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
277
 
278
   if (!node)
279
      return;
280
 
281
   /* Duplicate our template, increment refcounts to the storage structs:
282
    */
283
   memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
284
   node->vertex_size = save->vertex_size;
285
   node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
286
   node->count = save->vert_count;
287
   node->wrap_count = save->copied.nr;
288
   node->dangling_attr_ref = save->dangling_attr_ref;
289
   node->prim = save->prim;
290
   node->prim_count = save->prim_count;
291
   node->vertex_store = save->vertex_store;
292
   node->prim_store = save->prim_store;
293
 
294
   node->vertex_store->refcount++;
295
   node->prim_store->refcount++;
296
 
297
 
298
   node->current_size = node->vertex_size - node->attrsz[0];
299
   node->current_data = NULL;
300
 
301
   if (node->current_size) {
302
      /* If the malloc fails, we just pull the data out of the VBO
303
       * later instead.
304
       */
305
      node->current_data = MALLOC( node->current_size * sizeof(GLfloat) );
306
      if (node->current_data) {
307
         const char *buffer = (const char *)save->vertex_store->buffer;
308
         unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
309
         unsigned vertex_offset = 0;
310
 
311
         if (node->count)
312
            vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat);
313
 
314
         memcpy( node->current_data,
315
                 buffer + node->buffer_offset + vertex_offset + attr_offset,
316
                 node->current_size * sizeof(GLfloat) );
317
      }
318
   }
319
 
320
 
321
 
322
   assert(node->attrsz[VBO_ATTRIB_POS] != 0 ||
323
	  node->count == 0);
324
 
325
   if (save->dangling_attr_ref)
326
      ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
327
 
328
   save->vertex_store->used += save->vertex_size * node->count;
329
   save->prim_store->used += node->prim_count;
330
 
331
 
332
   /* Copy duplicated vertices
333
    */
334
   save->copied.nr = _save_copy_vertices( ctx, node, save->buffer );
335
 
336
 
337
   /* Deal with GL_COMPILE_AND_EXECUTE:
338
    */
339
   if (ctx->ExecuteFlag) {
340
      struct _glapi_table *dispatch = GET_DISPATCH();
341
 
342
      _glapi_set_dispatch(ctx->Exec);
343
 
344
      vbo_loopback_vertex_list( ctx,
345
				(const GLfloat *)((const char *)save->vertex_store->buffer +
346
						  node->buffer_offset),
347
				node->attrsz,
348
				node->prim,
349
				node->prim_count,
350
				node->wrap_count,
351
				node->vertex_size);
352
 
353
      _glapi_set_dispatch(dispatch);
354
   }
355
 
356
 
357
   /* Decide whether the storage structs are full, or can be used for
358
    * the next vertex lists as well.
359
    */
360
   if (save->vertex_store->used >
361
       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
362
 
363
      /* Unmap old store:
364
       */
365
      unmap_vertex_store( ctx, save->vertex_store );
366
 
367
      /* Release old reference:
368
       */
369
      save->vertex_store->refcount--;
370
      assert(save->vertex_store->refcount != 0);
371
      save->vertex_store = NULL;
372
 
373
      /* Allocate and map new store:
374
       */
375
      save->vertex_store = alloc_vertex_store( ctx );
376
      save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
377
   }
378
 
379
   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
380
      save->prim_store->refcount--;
381
      assert(save->prim_store->refcount != 0);
382
      save->prim_store = alloc_prim_store( ctx );
383
   }
384
 
385
   /* Reset our structures for the next run of vertices:
386
    */
387
   _save_reset_counters( ctx );
388
}
389
 
390
 
391
/* TODO -- If no new vertices have been stored, don't bother saving
392
 * it.
393
 */
394
static void _save_wrap_buffers( struct gl_context *ctx )
395
{
396
   struct vbo_save_context *save = &vbo_context(ctx)->save;
397
   GLint i = save->prim_count - 1;
398
   GLenum mode;
399
   GLboolean weak;
400
 
401
   assert(i < (GLint) save->prim_max);
402
   assert(i >= 0);
403
 
404
   /* Close off in-progress primitive.
405
    */
406
   save->prim[i].count = (save->vert_count -
407
			  save->prim[i].start);
408
   mode = save->prim[i].mode;
409
   weak = save->prim[i].weak;
410
 
411
   /* store the copied vertices, and allocate a new list.
412
    */
413
   _save_compile_vertex_list( ctx );
414
 
415
   /* Restart interrupted primitive
416
    */
417
   save->prim[0].mode = mode;
418
   save->prim[0].weak = weak;
419
   save->prim[0].begin = 0;
420
   save->prim[0].end = 0;
421
   save->prim[0].pad = 0;
422
   save->prim[0].start = 0;
423
   save->prim[0].count = 0;
424
   save->prim[0].num_instances = 1;
425
   save->prim_count = 1;
426
}
427
 
428
 
429
 
430
/* Called only when buffers are wrapped as the result of filling the
431
 * vertex_store struct.
432
 */
433
static void _save_wrap_filled_vertex( struct gl_context *ctx )
434
{
435
   struct vbo_save_context *save = &vbo_context(ctx)->save;
436
   GLfloat *data = save->copied.buffer;
437
   GLuint i;
438
 
439
   /* Emit a glEnd to close off the last vertex list.
440
    */
441
   _save_wrap_buffers( ctx );
442
 
443
    /* Copy stored stored vertices to start of new list.
444
    */
445
   assert(save->max_vert - save->vert_count > save->copied.nr);
446
 
447
   for (i = 0 ; i < save->copied.nr ; i++) {
448
      memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
449
      data += save->vertex_size;
450
      save->buffer_ptr += save->vertex_size;
451
      save->vert_count++;
452
   }
453
}
454
 
455
 
456
static void _save_copy_to_current( struct gl_context *ctx )
457
{
458
   struct vbo_save_context *save = &vbo_context(ctx)->save;
459
   GLuint i;
460
 
461
   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
462
      if (save->attrsz[i]) {
463
	 save->currentsz[i][0] = save->attrsz[i];
464
	 COPY_CLEAN_4V(save->current[i],
465
		       save->attrsz[i],
466
		       save->attrptr[i]);
467
      }
468
   }
469
}
470
 
471
 
472
static void _save_copy_from_current( struct gl_context *ctx )
473
{
474
   struct vbo_save_context *save = &vbo_context(ctx)->save;
475
   GLint i;
476
 
477
   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
478
      switch (save->attrsz[i]) {
479
      case 4: save->attrptr[i][3] = save->current[i][3];
480
      case 3: save->attrptr[i][2] = save->current[i][2];
481
      case 2: save->attrptr[i][1] = save->current[i][1];
482
      case 1: save->attrptr[i][0] = save->current[i][0];
483
      case 0: break;
484
      }
485
   }
486
}
487
 
488
 
489
 
490
 
491
/* Flush existing data, set new attrib size, replay copied vertices.
492
 */
493
static void _save_upgrade_vertex( struct gl_context *ctx,
494
				 GLuint attr,
495
				 GLuint newsz )
496
{
497
   struct vbo_save_context *save = &vbo_context(ctx)->save;
498
   GLuint oldsz;
499
   GLuint i;
500
   GLfloat *tmp;
501
 
502
   /* Store the current run of vertices, and emit a GL_END.  Emit a
503
    * BEGIN in the new buffer.
504
    */
505
   if (save->vert_count)
506
      _save_wrap_buffers( ctx );
507
   else
508
      assert( save->copied.nr == 0 );
509
 
510
   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
511
    * when the attribute already exists in the vertex and is having
512
    * its size increased.
513
    */
514
   _save_copy_to_current( ctx );
515
 
516
   /* Fix up sizes:
517
    */
518
   oldsz = save->attrsz[attr];
519
   save->attrsz[attr] = newsz;
520
 
521
   save->vertex_size += newsz - oldsz;
522
   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
523
		      save->vertex_size);
524
   save->vert_count = 0;
525
 
526
   /* Recalculate all the attrptr[] values:
527
    */
528
   for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
529
      if (save->attrsz[i]) {
530
	 save->attrptr[i] = tmp;
531
	 tmp += save->attrsz[i];
532
      }
533
      else
534
	 save->attrptr[i] = NULL; /* will not be dereferenced. */
535
   }
536
 
537
   /* Copy from current to repopulate the vertex with correct values.
538
    */
539
   _save_copy_from_current( ctx );
540
 
541
   /* Replay stored vertices to translate them to new format here.
542
    *
543
    * If there are copied vertices and the new (upgraded) attribute
544
    * has not been defined before, this list is somewhat degenerate,
545
    * and will need fixup at runtime.
546
    */
547
   if (save->copied.nr)
548
   {
549
      GLfloat *data = save->copied.buffer;
550
      GLfloat *dest = save->buffer;
551
      GLuint j;
552
 
553
      /* Need to note this and fix up at runtime (or loopback):
554
       */
555
      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
556
	 assert(oldsz == 0);
557
	 save->dangling_attr_ref = GL_TRUE;
558
      }
559
 
560
      for (i = 0 ; i < save->copied.nr ; i++) {
561
	 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
562
	    if (save->attrsz[j]) {
563
	       if (j == attr) {
564
		  if (oldsz) {
565
		     COPY_CLEAN_4V( dest, oldsz, data );
566
		     data += oldsz;
567
		     dest += newsz;
568
		  }
569
		  else {
570
		     COPY_SZ_4V( dest, newsz, save->current[attr] );
571
		     dest += newsz;
572
		  }
573
	       }
574
	       else {
575
		  GLint sz = save->attrsz[j];
576
		  COPY_SZ_4V( dest, sz, data );
577
		  data += sz;
578
		  dest += sz;
579
	       }
580
	    }
581
	 }
582
      }
583
 
584
      save->buffer_ptr = dest;
585
      save->vert_count += save->copied.nr;
586
   }
587
}
588
 
589
static void save_fixup_vertex( struct gl_context *ctx, GLuint attr, GLuint sz )
590
{
591
   struct vbo_save_context *save = &vbo_context(ctx)->save;
592
 
593
   if (sz > save->attrsz[attr]) {
594
      /* New size is larger.  Need to flush existing vertices and get
595
       * an enlarged vertex format.
596
       */
597
      _save_upgrade_vertex( ctx, attr, sz );
598
   }
599
   else if (sz < save->active_sz[attr]) {
600
      static GLfloat id[4] = { 0, 0, 0, 1 };
601
      GLuint i;
602
 
603
      /* New size is equal or smaller - just need to fill in some
604
       * zeros.
605
       */
606
      for (i = sz ; i <= save->attrsz[attr] ; i++)
607
	 save->attrptr[attr][i-1] = id[i-1];
608
   }
609
 
610
   save->active_sz[attr] = sz;
611
}
612
 
613
static void _save_reset_vertex( struct gl_context *ctx )
614
{
615
   struct vbo_save_context *save = &vbo_context(ctx)->save;
616
   GLuint i;
617
 
618
   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
619
      save->attrsz[i] = 0;
620
      save->active_sz[i] = 0;
621
   }
622
 
623
   save->vertex_size = 0;
624
}
625
 
626
 
627
 
628
#define ERROR()   _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
629
 
630
 
631
/* Only one size for each attribute may be active at once.  Eg. if
632
 * Color3f is installed/active, then Color4f may not be, even if the
633
 * vertex actually contains 4 color coordinates.  This is because the
634
 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
635
 * of the chooser function when switching between Color4f and Color3f.
636
 */
637
#define ATTR( A, N, V0, V1, V2, V3 )				\
638
do {								\
639
   struct vbo_save_context *save = &vbo_context(ctx)->save;	\
640
								\
641
   if (save->active_sz[A] != N)				\
642
      save_fixup_vertex(ctx, A, N);				\
643
								\
644
   {								\
645
      GLfloat *dest = save->attrptr[A];			\
646
      if (N>0) dest[0] = V0;					\
647
      if (N>1) dest[1] = V1;					\
648
      if (N>2) dest[2] = V2;					\
649
      if (N>3) dest[3] = V3;					\
650
   }								\
651
								\
652
   if ((A) == 0) {						\
653
      GLuint i;							\
654
								\
655
      for (i = 0; i < save->vertex_size; i++)			\
656
	 save->buffer_ptr[i] = save->vertex[i];			\
657
								\
658
      save->buffer_ptr += save->vertex_size;				\
659
								\
660
      if (++save->vert_count >= save->max_vert)			\
661
	 _save_wrap_filled_vertex( ctx );			\
662
   }								\
663
} while (0)
664
 
665
#define TAG(x) _save_##x
666
 
667
#include "vbo_attrib_tmp.h"
668
 
669
 
670
 
671
 
672
/* Cope with EvalCoord/CallList called within a begin/end object:
673
 *     -- Flush current buffer
674
 *     -- Fallback to opcodes for the rest of the begin/end object.
675
 */
676
static void DO_FALLBACK( struct gl_context *ctx )
677
{
678
   struct vbo_save_context *save = &vbo_context(ctx)->save;
679
 
680
   if (save->vert_count || save->prim_count) {
681
      GLint i = save->prim_count - 1;
682
 
683
      /* Close off in-progress primitive.
684
       */
685
      save->prim[i].count = (save->vert_count -
686
                             save->prim[i].start);
687
 
688
      /* Need to replay this display list with loopback,
689
       * unfortunately, otherwise this primitive won't be handled
690
       * properly:
691
       */
692
      save->dangling_attr_ref = 1;
693
 
694
      _save_compile_vertex_list( ctx );
695
   }
696
 
697
   _save_copy_to_current( ctx );
698
   _save_reset_vertex( ctx );
699
   _save_reset_counters( ctx );
700
   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
701
   ctx->Driver.SaveNeedFlush = 0;
702
}
703
 
704
static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
705
{
706
   GET_CURRENT_CONTEXT(ctx);
707
   DO_FALLBACK(ctx);
708
   CALL_EvalCoord1f(ctx->Save, (u));
709
}
710
 
711
static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
712
{
713
   GET_CURRENT_CONTEXT(ctx);
714
   DO_FALLBACK(ctx);
715
   CALL_EvalCoord1fv(ctx->Save, (v));
716
}
717
 
718
static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
719
{
720
   GET_CURRENT_CONTEXT(ctx);
721
   DO_FALLBACK(ctx);
722
   CALL_EvalCoord2f(ctx->Save, (u, v));
723
}
724
 
725
static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
726
{
727
   GET_CURRENT_CONTEXT(ctx);
728
   DO_FALLBACK(ctx);
729
   CALL_EvalCoord2fv(ctx->Save, (v));
730
}
731
 
732
static void GLAPIENTRY _save_EvalPoint1( GLint i )
733
{
734
   GET_CURRENT_CONTEXT(ctx);
735
   DO_FALLBACK(ctx);
736
   CALL_EvalPoint1(ctx->Save, (i));
737
}
738
 
739
static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
740
{
741
   GET_CURRENT_CONTEXT(ctx);
742
   DO_FALLBACK(ctx);
743
   CALL_EvalPoint2(ctx->Save, (i, j));
744
}
745
 
746
static void GLAPIENTRY _save_CallList( GLuint l )
747
{
748
   GET_CURRENT_CONTEXT(ctx);
749
   DO_FALLBACK(ctx);
750
   CALL_CallList(ctx->Save, (l));
751
}
752
 
753
static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
754
{
755
   GET_CURRENT_CONTEXT(ctx);
756
   DO_FALLBACK(ctx);
757
   CALL_CallLists(ctx->Save, (n, type, v));
758
}
759
 
760
 
761
 
762
 
763
/* This begin is hooked into ...  Updating of
764
 * ctx->Driver.CurrentSavePrimitive is already taken care of.
765
 */
766
GLboolean vbo_save_NotifyBegin( struct gl_context *ctx, GLenum mode )
767
{
768
   struct vbo_save_context *save = &vbo_context(ctx)->save;
769
 
770
   GLuint i = save->prim_count++;
771
 
772
   assert(i < save->prim_max);
773
   save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK;
774
   save->prim[i].begin = 1;
775
   save->prim[i].end = 0;
776
   save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
777
   save->prim[i].pad = 0;
778
   save->prim[i].start = save->vert_count;
779
   save->prim[i].count = 0;
780
   save->prim[i].num_instances = 1;
781
 
782
   _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );
783
   ctx->Driver.SaveNeedFlush = 1;
784
   return GL_TRUE;
785
}
786
 
787
 
788
 
789
static void GLAPIENTRY _save_End( void )
790
{
791
   GET_CURRENT_CONTEXT( ctx );
792
   struct vbo_save_context *save = &vbo_context(ctx)->save;
793
   GLint i = save->prim_count - 1;
794
 
795
   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
796
   save->prim[i].end = 1;
797
   save->prim[i].count = (save->vert_count -
798
			  save->prim[i].start);
799
 
800
   if (i == (GLint) save->prim_max - 1) {
801
      _save_compile_vertex_list( ctx );
802
      assert(save->copied.nr == 0);
803
   }
804
 
805
   /* Swap out this vertex format while outside begin/end.  Any color,
806
    * etc. received between here and the next begin will be compiled
807
    * as opcodes.
808
    */
809
   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
810
}
811
 
812
 
813
/* These are all errors as this vtxfmt is only installed inside
814
 * begin/end pairs.
815
 */
816
static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
817
			       const GLvoid *indices)
818
{
819
   GET_CURRENT_CONTEXT(ctx);
820
   (void) mode; (void) count; (void) type; (void) indices;
821
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
822
}
823
 
824
 
825
static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
826
				    GLuint start, GLuint end,
827
				    GLsizei count, GLenum type,
828
				    const GLvoid *indices)
829
{
830
   GET_CURRENT_CONTEXT(ctx);
831
   (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
832
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
833
}
834
 
835
static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode,
836
						    GLsizei count,
837
						    GLenum type,
838
						    const GLvoid *indices,
839
						    GLint basevertex)
840
{
841
   GET_CURRENT_CONTEXT(ctx);
842
   (void) mode; (void) count; (void) type; (void) indices; (void)basevertex;
843
 
844
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
845
}
846
 
847
static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode,
848
							 GLuint start,
849
							 GLuint end,
850
							 GLsizei count,
851
							 GLenum type,
852
							 const GLvoid *indices,
853
							 GLint basevertex)
854
{
855
   GET_CURRENT_CONTEXT(ctx);
856
   (void) mode; (void) start; (void) end; (void) count; (void) type;
857
   (void) indices; (void)basevertex;
858
 
859
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
860
}
861
 
862
static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
863
{
864
   GET_CURRENT_CONTEXT(ctx);
865
   (void) mode; (void) start; (void) count;
866
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
867
}
868
 
869
static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
870
{
871
   GET_CURRENT_CONTEXT(ctx);
872
   (void) x1; (void) y1; (void) x2; (void) y2;
873
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
874
}
875
 
876
static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
877
{
878
   GET_CURRENT_CONTEXT(ctx);
879
   (void) mode; (void) i1; (void) i2;
880
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
881
}
882
 
883
static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
884
				  GLint j1, GLint j2 )
885
{
886
   GET_CURRENT_CONTEXT(ctx);
887
   (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
888
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
889
}
890
 
891
static void GLAPIENTRY _save_Begin( GLenum mode )
892
{
893
   GET_CURRENT_CONTEXT( ctx );
894
   (void) mode;
895
   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
896
}
897
 
898
 
899
static void GLAPIENTRY _save_PrimitiveRestartNV( void )
900
{
901
   GLenum curPrim;
902
   GET_CURRENT_CONTEXT( ctx );
903
 
904
   curPrim = ctx->Driver.CurrentSavePrimitive;
905
 
906
   _save_End();
907
   _save_Begin(curPrim);
908
}
909
 
910
 
911
/* Unlike the functions above, these are to be hooked into the vtxfmt
912
 * maintained in ctx->ListState, active when the list is known or
913
 * suspected to be outside any begin/end primitive.
914
 */
915
static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
916
{
917
   GET_CURRENT_CONTEXT(ctx);
918
   vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
919
   CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
920
   CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
921
   CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
922
   CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
923
   CALL_End(GET_DISPATCH(), ());
924
}
925
 
926
 
927
static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
928
{
929
   GET_CURRENT_CONTEXT(ctx);
930
   GLint i;
931
 
932
   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
933
      return;
934
 
935
   _ae_map_vbos( ctx );
936
 
937
   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
938
 
939
   for (i = 0; i < count; i++)
940
       CALL_ArrayElement(GET_DISPATCH(), (start + i));
941
   CALL_End(GET_DISPATCH(), ());
942
 
943
   _ae_unmap_vbos( ctx );
944
}
945
 
946
/* Could do better by copying the arrays and element list intact and
947
 * then emitting an indexed prim at runtime.
948
 */
949
static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
950
				   const GLvoid *indices)
951
{
952
   GET_CURRENT_CONTEXT(ctx);
953
   GLint i;
954
 
955
   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
956
      return;
957
 
958
   _ae_map_vbos( ctx );
959
 
960
   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
961
      indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
962
 
963
   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
964
 
965
   switch (type) {
966
   case GL_UNSIGNED_BYTE:
967
      for (i = 0 ; i < count ; i++)
968
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
969
      break;
970
   case GL_UNSIGNED_SHORT:
971
      for (i = 0 ; i < count ; i++)
972
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
973
      break;
974
   case GL_UNSIGNED_INT:
975
      for (i = 0 ; i < count ; i++)
976
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
977
      break;
978
   default:
979
      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
980
      break;
981
   }
982
 
983
   CALL_End(GET_DISPATCH(), ());
984
 
985
   _ae_unmap_vbos( ctx );
986
}
987
 
988
static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
989
					GLuint start, GLuint end,
990
					GLsizei count, GLenum type,
991
					const GLvoid *indices)
992
{
993
   GET_CURRENT_CONTEXT(ctx);
994
   if (_mesa_validate_DrawRangeElements( ctx, mode,
995
					 start, end,
996
					 count, type, indices, 0 ))
997
      _save_OBE_DrawElements( mode, count, type, indices );
998
}
999
 
1000
 
1001
 
1002
 
1003
 
1004
static void _save_vtxfmt_init( struct gl_context *ctx )
1005
{
1006
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1007
   GLvertexformat *vfmt = &save->vtxfmt;
1008
 
1009
   _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
1010
 
1011
   vfmt->Begin = _save_Begin;
1012
   vfmt->Color3f = _save_Color3f;
1013
   vfmt->Color3fv = _save_Color3fv;
1014
   vfmt->Color4f = _save_Color4f;
1015
   vfmt->Color4fv = _save_Color4fv;
1016
   vfmt->EdgeFlag = _save_EdgeFlag;
1017
   vfmt->End = _save_End;
1018
   vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1019
   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1020
   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1021
   vfmt->Indexf = _save_Indexf;
1022
   vfmt->Indexfv = _save_Indexfv;
1023
   vfmt->Materialfv = _save_Materialfv;
1024
   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1025
   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1026
   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1027
   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1028
   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1029
   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1030
   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1031
   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1032
   vfmt->Normal3f = _save_Normal3f;
1033
   vfmt->Normal3fv = _save_Normal3fv;
1034
   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1035
   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1036
   vfmt->TexCoord1f = _save_TexCoord1f;
1037
   vfmt->TexCoord1fv = _save_TexCoord1fv;
1038
   vfmt->TexCoord2f = _save_TexCoord2f;
1039
   vfmt->TexCoord2fv = _save_TexCoord2fv;
1040
   vfmt->TexCoord3f = _save_TexCoord3f;
1041
   vfmt->TexCoord3fv = _save_TexCoord3fv;
1042
   vfmt->TexCoord4f = _save_TexCoord4f;
1043
   vfmt->TexCoord4fv = _save_TexCoord4fv;
1044
   vfmt->Vertex2f = _save_Vertex2f;
1045
   vfmt->Vertex2fv = _save_Vertex2fv;
1046
   vfmt->Vertex3f = _save_Vertex3f;
1047
   vfmt->Vertex3fv = _save_Vertex3fv;
1048
   vfmt->Vertex4f = _save_Vertex4f;
1049
   vfmt->Vertex4fv = _save_Vertex4fv;
1050
   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1051
   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1052
   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1053
   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1054
   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1055
   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1056
   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1057
   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1058
 
1059
   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1060
   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1061
   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1062
   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1063
   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1064
   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1065
   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1066
   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1067
 
1068
   /* integer-valued */
1069
   vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1070
   vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1071
   vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1072
   vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1073
   vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1074
   vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1075
   vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1076
 
1077
   /* unsigned integer-valued */
1078
   vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1079
   vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1080
   vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1081
   vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1082
   vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1083
   vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1084
   vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1085
 
1086
   /* This will all require us to fallback to saving the list as opcodes:
1087
    */
1088
   _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */
1089
 
1090
   _MESA_INIT_EVAL_VTXFMT(vfmt, _save_);
1091
 
1092
   /* These are all errors as we at least know we are in some sort of
1093
    * begin/end pair:
1094
    */
1095
   vfmt->Begin = _save_Begin;
1096
   vfmt->Rectf = _save_Rectf;
1097
   vfmt->DrawArrays = _save_DrawArrays;
1098
   vfmt->DrawElements = _save_DrawElements;
1099
   vfmt->DrawRangeElements = _save_DrawRangeElements;
1100
   vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
1101
   vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
1102
   /* Loops back into vfmt->DrawElements */
1103
   vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1104
   vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1105
}
1106
 
1107
 
1108
void vbo_save_SaveFlushVertices( struct gl_context *ctx )
1109
{
1110
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1111
 
1112
   /* Noop when we are actually active:
1113
    */
1114
   if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1115
       ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1116
      return;
1117
 
1118
   if (save->vert_count ||
1119
       save->prim_count)
1120
      _save_compile_vertex_list( ctx );
1121
 
1122
   _save_copy_to_current( ctx );
1123
   _save_reset_vertex( ctx );
1124
   _save_reset_counters( ctx );
1125
   ctx->Driver.SaveNeedFlush = 0;
1126
}
1127
 
1128
void vbo_save_NewList( struct gl_context *ctx, GLuint list, GLenum mode )
1129
{
1130
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1131
 
1132
   (void) list; (void) mode;
1133
 
1134
   if (!save->prim_store)
1135
      save->prim_store = alloc_prim_store( ctx );
1136
 
1137
   if (!save->vertex_store)
1138
      save->vertex_store = alloc_vertex_store( ctx );
1139
 
1140
   save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
1141
 
1142
   _save_reset_vertex( ctx );
1143
   _save_reset_counters( ctx );
1144
   ctx->Driver.SaveNeedFlush = 0;
1145
}
1146
 
1147
void vbo_save_EndList( struct gl_context *ctx )
1148
{
1149
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1150
 
1151
   /* EndList called inside a (saved) Begin/End pair?
1152
    */
1153
   if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) {
1154
 
1155
      if (save->prim_count > 0) {
1156
         GLint i = save->prim_count - 1;
1157
         ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1158
         save->prim[i].end = 0;
1159
         save->prim[i].count = (save->vert_count -
1160
                                save->prim[i].start);
1161
      }
1162
 
1163
      /* Make sure this vertex list gets replayed by the "loopback"
1164
       * mechanism:
1165
       */
1166
      save->dangling_attr_ref = 1;
1167
      vbo_save_SaveFlushVertices( ctx );
1168
 
1169
      /* Swap out this vertex format while outside begin/end.  Any color,
1170
       * etc. received between here and the next begin will be compiled
1171
       * as opcodes.
1172
       */
1173
      _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1174
   }
1175
 
1176
   unmap_vertex_store( ctx, save->vertex_store );
1177
 
1178
   assert(save->vertex_size == 0);
1179
}
1180
 
1181
void vbo_save_BeginCallList( struct gl_context *ctx, struct gl_display_list *dlist )
1182
{
1183
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1184
   save->replay_flags |= dlist->Flags;
1185
}
1186
 
1187
void vbo_save_EndCallList( struct gl_context *ctx )
1188
{
1189
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1190
 
1191
   if (ctx->ListState.CallDepth == 1) {
1192
      /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1193
       * flag, if it is set:
1194
       */
1195
      save->replay_flags &= VBO_SAVE_FALLBACK;
1196
   }
1197
}
1198
 
1199
 
1200
static void vbo_destroy_vertex_list( struct gl_context *ctx, void *data )
1201
{
1202
   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1203
   (void) ctx;
1204
 
1205
   if ( --node->vertex_store->refcount == 0 )
1206
      free_vertex_store( ctx, node->vertex_store );
1207
 
1208
   if ( --node->prim_store->refcount == 0 )
1209
      FREE( node->prim_store );
1210
 
1211
   if (node->current_data) {
1212
      FREE(node->current_data);
1213
      node->current_data = NULL;
1214
   }
1215
}
1216
 
1217
 
1218
static void vbo_print_vertex_list( struct gl_context *ctx, void *data )
1219
{
1220
   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1221
   GLuint i;
1222
   (void) ctx;
1223
 
1224
   printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1225
	  node->count,
1226
	  node->prim_count,
1227
	  node->vertex_size);
1228
 
1229
   for (i = 0 ; i < node->prim_count ; i++) {
1230
      struct _mesa_prim *prim = &node->prim[i];
1231
      _mesa_debug(NULL, "   prim %d: %s%s %d..%d %s %s\n",
1232
		  i,
1233
		  _mesa_lookup_prim_by_nr(prim->mode),
1234
		  prim->weak ? " (weak)" : "",
1235
		  prim->start,
1236
		  prim->start + prim->count,
1237
		  (prim->begin) ? "BEGIN" : "(wrap)",
1238
		  (prim->end) ? "END" : "(wrap)");
1239
   }
1240
}
1241
 
1242
 
1243
static void _save_current_init( struct gl_context *ctx )
1244
{
1245
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1246
   GLint i;
1247
 
1248
   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1249
      const GLuint j = i - VBO_ATTRIB_POS;
1250
      ASSERT(j < VERT_ATTRIB_MAX);
1251
      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1252
      save->current[i] = ctx->ListState.CurrentAttrib[j];
1253
   }
1254
 
1255
   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1256
      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1257
      ASSERT(j < MAT_ATTRIB_MAX);
1258
      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1259
      save->current[i] = ctx->ListState.CurrentMaterial[j];
1260
   }
1261
}
1262
 
1263
/**
1264
 * Initialize the display list compiler
1265
 */
1266
void vbo_save_api_init( struct vbo_save_context *save )
1267
{
1268
   struct gl_context *ctx = save->ctx;
1269
   GLuint i;
1270
 
1271
   save->opcode_vertex_list =
1272
      _mesa_dlist_alloc_opcode( ctx,
1273
                                sizeof(struct vbo_save_vertex_list),
1274
                                vbo_save_playback_vertex_list,
1275
                                vbo_destroy_vertex_list,
1276
                                vbo_print_vertex_list );
1277
 
1278
   ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1279
 
1280
   _save_vtxfmt_init( ctx );
1281
   _save_current_init( ctx );
1282
 
1283
   /* These will actually get set again when binding/drawing */
1284
   for (i = 0; i < VBO_ATTRIB_MAX; i++)
1285
      save->inputs[i] = &save->arrays[i];
1286
 
1287
   /* Hook our array functions into the outside-begin-end vtxfmt in
1288
    * ctx->ListState.
1289
    */
1290
   ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1291
   ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1292
   ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1293
   ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1294
   /* loops back into _save_OBE_DrawElements */
1295
   ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1296
   ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1297
   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1298
}
1299
 
1300
 
1301
#endif /* FEATURE_dlist */