Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4358 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_validate.h"
78
#include "main/api_arrayelt.h"
79
#include "main/vtxfmt.h"
80
#include "main/dispatch.h"
81
 
82
#include "vbo_context.h"
83
#include "vbo_noop.h"
84
 
85
 
86
#ifdef ERROR
87
#undef ERROR
88
#endif
89
 
90
 
91
/* An interesting VBO number/name to help with debugging */
92
#define VBO_BUF_ID  12345
93
 
94
 
95
/*
96
 * NOTE: Old 'parity' issue is gone, but copying can still be
97
 * wrong-footed on replay.
98
 */
99
static GLuint
100
_save_copy_vertices(struct gl_context *ctx,
101
                    const struct vbo_save_vertex_list *node,
102
                    const GLfloat * src_buffer)
103
{
104
   struct vbo_save_context *save = &vbo_context(ctx)->save;
105
   const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
106
   GLuint nr = prim->count;
107
   GLuint sz = save->vertex_size;
108
   const GLfloat *src = src_buffer + prim->start * sz;
109
   GLfloat *dst = save->copied.buffer;
110
   GLuint ovf, i;
111
 
112
   if (prim->end)
113
      return 0;
114
 
115
   switch (prim->mode) {
116
   case GL_POINTS:
117
      return 0;
118
   case GL_LINES:
119
      ovf = nr & 1;
120
      for (i = 0; i < ovf; i++)
121
         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
122
                sz * sizeof(GLfloat));
123
      return i;
124
   case GL_TRIANGLES:
125
      ovf = nr % 3;
126
      for (i = 0; i < ovf; i++)
127
         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
128
                sz * sizeof(GLfloat));
129
      return i;
130
   case GL_QUADS:
131
      ovf = nr & 3;
132
      for (i = 0; i < ovf; i++)
133
         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
134
                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
      }
152
      else {
153
         memcpy(dst, src + 0, sz * sizeof(GLfloat));
154
         memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
155
         return 2;
156
      }
157
   case GL_TRIANGLE_STRIP:
158
   case GL_QUAD_STRIP:
159
      switch (nr) {
160
      case 0:
161
         ovf = 0;
162
         break;
163
      case 1:
164
         ovf = 1;
165
         break;
166
      default:
167
         ovf = 2 + (nr & 1);
168
         break;
169
      }
170
      for (i = 0; i < ovf; i++)
171
         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
172
                sz * sizeof(GLfloat));
173
      return i;
174
   default:
175
      assert(0);
176
      return 0;
177
   }
178
}
179
 
180
 
181
static struct vbo_save_vertex_store *
182
alloc_vertex_store(struct gl_context *ctx)
183
{
184
   struct vbo_save_context *save = &vbo_context(ctx)->save;
185
   struct vbo_save_vertex_store *vertex_store =
186
      CALLOC_STRUCT(vbo_save_vertex_store);
187
 
188
   /* obj->Name needs to be non-zero, but won't ever be examined more
189
    * closely than that.  In particular these buffers won't be entered
190
    * into the hash and can never be confused with ones visible to the
191
    * user.  Perhaps there could be a special number for internal
192
    * buffers:
193
    */
194
   vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
195
                                                         VBO_BUF_ID,
196
                                                         GL_ARRAY_BUFFER_ARB);
197
   if (vertex_store->bufferobj) {
198
      save->out_of_memory =
199
         !ctx->Driver.BufferData(ctx,
200
                                 GL_ARRAY_BUFFER_ARB,
201
                                 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
202
                                 NULL, GL_STATIC_DRAW_ARB,
203
                                 vertex_store->bufferobj);
204
   }
205
   else {
206
      save->out_of_memory = GL_TRUE;
207
   }
208
 
209
   if (save->out_of_memory) {
210
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
211
      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
212
   }
213
 
214
   vertex_store->buffer = NULL;
215
   vertex_store->used = 0;
216
   vertex_store->refcount = 1;
217
 
218
   return vertex_store;
219
}
220
 
221
 
222
static void
223
free_vertex_store(struct gl_context *ctx,
224
                  struct vbo_save_vertex_store *vertex_store)
225
{
226
   assert(!vertex_store->buffer);
227
 
228
   if (vertex_store->bufferobj) {
229
      _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
230
   }
231
 
232
   free(vertex_store);
233
}
234
 
235
 
236
GLfloat *
237
vbo_save_map_vertex_store(struct gl_context *ctx,
238
                          struct vbo_save_vertex_store *vertex_store)
239
{
240
   assert(vertex_store->bufferobj);
241
   assert(!vertex_store->buffer);
242
   if (vertex_store->bufferobj->Size > 0) {
243
      vertex_store->buffer =
244
         (GLfloat *) ctx->Driver.MapBufferRange(ctx, 0,
245
                                                vertex_store->bufferobj->Size,
246
                                                GL_MAP_WRITE_BIT,  /* not used */
247
                                                vertex_store->bufferobj);
248
      assert(vertex_store->buffer);
249
      return vertex_store->buffer + vertex_store->used;
250
   }
251
   else {
252
      /* probably ran out of memory for buffers */
253
      return NULL;
254
   }
255
}
256
 
257
 
258
void
259
vbo_save_unmap_vertex_store(struct gl_context *ctx,
260
                            struct vbo_save_vertex_store *vertex_store)
261
{
262
   if (vertex_store->bufferobj->Size > 0) {
263
      ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj);
264
   }
265
   vertex_store->buffer = NULL;
266
}
267
 
268
 
269
static struct vbo_save_primitive_store *
270
alloc_prim_store(struct gl_context *ctx)
271
{
272
   struct vbo_save_primitive_store *store =
273
      CALLOC_STRUCT(vbo_save_primitive_store);
274
   (void) ctx;
275
   store->used = 0;
276
   store->refcount = 1;
277
   return store;
278
}
279
 
280
 
281
static void
282
_save_reset_counters(struct gl_context *ctx)
283
{
284
   struct vbo_save_context *save = &vbo_context(ctx)->save;
285
 
286
   save->prim = save->prim_store->buffer + save->prim_store->used;
287
   save->buffer = save->vertex_store->buffer + save->vertex_store->used;
288
 
289
   assert(save->buffer == save->buffer_ptr);
290
 
291
   if (save->vertex_size)
292
      save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
293
                        save->vertex_size);
294
   else
295
      save->max_vert = 0;
296
 
297
   save->vert_count = 0;
298
   save->prim_count = 0;
299
   save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
300
   save->dangling_attr_ref = 0;
301
}
302
 
303
/**
304
 * For a list of prims, try merging prims that can just be extensions of the
305
 * previous prim.
306
 */
307
static void
308
merge_prims(struct gl_context *ctx,
309
            struct _mesa_prim *prim_list,
310
            GLuint *prim_count)
311
{
312
   GLuint i;
313
   struct _mesa_prim *prev_prim = prim_list;
314
 
315
   for (i = 1; i < *prim_count; i++) {
316
      struct _mesa_prim *this_prim = prim_list + i;
317
 
318
      vbo_try_prim_conversion(this_prim);
319
 
320
      if (vbo_can_merge_prims(prev_prim, this_prim)) {
321
         /* We've found a prim that just extend the previous one.  Tack it
322
          * onto the previous one, and let this primitive struct get dropped.
323
          */
324
         vbo_merge_prims(prev_prim, this_prim);
325
         continue;
326
      }
327
 
328
      /* If any previous primitives have been dropped, then we need to copy
329
       * this later one into the next available slot.
330
       */
331
      prev_prim++;
332
      if (prev_prim != this_prim)
333
         *prev_prim = *this_prim;
334
   }
335
 
336
   *prim_count = prev_prim - prim_list + 1;
337
}
338
 
339
/**
340
 * Insert the active immediate struct onto the display list currently
341
 * being built.
342
 */
343
static void
344
_save_compile_vertex_list(struct gl_context *ctx)
345
{
346
   struct vbo_save_context *save = &vbo_context(ctx)->save;
347
   struct vbo_save_vertex_list *node;
348
 
349
   /* Allocate space for this structure in the display list currently
350
    * being compiled.
351
    */
352
   node = (struct vbo_save_vertex_list *)
353
      _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
354
 
355
   if (!node)
356
      return;
357
 
358
   /* Duplicate our template, increment refcounts to the storage structs:
359
    */
360
   memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
361
   memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
362
   node->vertex_size = save->vertex_size;
363
   node->buffer_offset =
364
      (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
365
   node->count = save->vert_count;
366
   node->wrap_count = save->copied.nr;
367
   node->dangling_attr_ref = save->dangling_attr_ref;
368
   node->prim = save->prim;
369
   node->prim_count = save->prim_count;
370
   node->vertex_store = save->vertex_store;
371
   node->prim_store = save->prim_store;
372
 
373
   node->vertex_store->refcount++;
374
   node->prim_store->refcount++;
375
 
376
   if (node->prim[0].no_current_update) {
377
      node->current_size = 0;
378
      node->current_data = NULL;
379
   }
380
   else {
381
      node->current_size = node->vertex_size - node->attrsz[0];
382
      node->current_data = NULL;
383
 
384
      if (node->current_size) {
385
         /* If the malloc fails, we just pull the data out of the VBO
386
          * later instead.
387
          */
388
         node->current_data = malloc(node->current_size * sizeof(GLfloat));
389
         if (node->current_data) {
390
            const char *buffer = (const char *) save->vertex_store->buffer;
391
            unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
392
            unsigned vertex_offset = 0;
393
 
394
            if (node->count)
395
               vertex_offset =
396
                  (node->count - 1) * node->vertex_size * sizeof(GLfloat);
397
 
398
            memcpy(node->current_data,
399
                   buffer + node->buffer_offset + vertex_offset + attr_offset,
400
                   node->current_size * sizeof(GLfloat));
401
         }
402
      }
403
   }
404
 
405
   assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
406
 
407
   if (save->dangling_attr_ref)
408
      ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
409
 
410
   save->vertex_store->used += save->vertex_size * node->count;
411
   save->prim_store->used += node->prim_count;
412
 
413
   /* Copy duplicated vertices
414
    */
415
   save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
416
 
417
   merge_prims(ctx, node->prim, &node->prim_count);
418
 
419
   /* Deal with GL_COMPILE_AND_EXECUTE:
420
    */
421
   if (ctx->ExecuteFlag) {
422
      struct _glapi_table *dispatch = GET_DISPATCH();
423
 
424
      _glapi_set_dispatch(ctx->Exec);
425
 
426
      vbo_loopback_vertex_list(ctx,
427
                               (const GLfloat *) ((const char *) save->
428
                                                  vertex_store->buffer +
429
                                                  node->buffer_offset),
430
                               node->attrsz, node->prim, node->prim_count,
431
                               node->wrap_count, node->vertex_size);
432
 
433
      _glapi_set_dispatch(dispatch);
434
   }
435
 
436
   /* Decide whether the storage structs are full, or can be used for
437
    * the next vertex lists as well.
438
    */
439
   if (save->vertex_store->used >
440
       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
441
 
442
      /* Unmap old store:
443
       */
444
      vbo_save_unmap_vertex_store(ctx, save->vertex_store);
445
 
446
      /* Release old reference:
447
       */
448
      save->vertex_store->refcount--;
449
      assert(save->vertex_store->refcount != 0);
450
      save->vertex_store = NULL;
451
 
452
      /* Allocate and map new store:
453
       */
454
      save->vertex_store = alloc_vertex_store(ctx);
455
      save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
456
      save->out_of_memory = save->buffer_ptr == NULL;
457
   }
458
 
459
   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
460
      save->prim_store->refcount--;
461
      assert(save->prim_store->refcount != 0);
462
      save->prim_store = alloc_prim_store(ctx);
463
   }
464
 
465
   /* Reset our structures for the next run of vertices:
466
    */
467
   _save_reset_counters(ctx);
468
}
469
 
470
 
471
/**
472
 * This is called when we fill a vertex buffer before we hit a glEnd().
473
 * We
474
 * TODO -- If no new vertices have been stored, don't bother saving it.
475
 */
476
static void
477
_save_wrap_buffers(struct gl_context *ctx)
478
{
479
   struct vbo_save_context *save = &vbo_context(ctx)->save;
480
   GLint i = save->prim_count - 1;
481
   GLenum mode;
482
   GLboolean weak;
483
   GLboolean no_current_update;
484
 
485
   assert(i < (GLint) save->prim_max);
486
   assert(i >= 0);
487
 
488
   /* Close off in-progress primitive.
489
    */
490
   save->prim[i].count = (save->vert_count - save->prim[i].start);
491
   mode = save->prim[i].mode;
492
   weak = save->prim[i].weak;
493
   no_current_update = save->prim[i].no_current_update;
494
 
495
   /* store the copied vertices, and allocate a new list.
496
    */
497
   _save_compile_vertex_list(ctx);
498
 
499
   /* Restart interrupted primitive
500
    */
501
   save->prim[0].mode = mode;
502
   save->prim[0].weak = weak;
503
   save->prim[0].no_current_update = no_current_update;
504
   save->prim[0].begin = 0;
505
   save->prim[0].end = 0;
506
   save->prim[0].pad = 0;
507
   save->prim[0].start = 0;
508
   save->prim[0].count = 0;
509
   save->prim[0].num_instances = 1;
510
   save->prim[0].base_instance = 0;
511
   save->prim_count = 1;
512
}
513
 
514
 
515
/**
516
 * Called only when buffers are wrapped as the result of filling the
517
 * vertex_store struct.
518
 */
519
static void
520
_save_wrap_filled_vertex(struct gl_context *ctx)
521
{
522
   struct vbo_save_context *save = &vbo_context(ctx)->save;
523
   GLfloat *data = save->copied.buffer;
524
   GLuint i;
525
 
526
   /* Emit a glEnd to close off the last vertex list.
527
    */
528
   _save_wrap_buffers(ctx);
529
 
530
   /* Copy stored stored vertices to start of new list.
531
    */
532
   assert(save->max_vert - save->vert_count > save->copied.nr);
533
 
534
   for (i = 0; i < save->copied.nr; i++) {
535
      memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
536
      data += save->vertex_size;
537
      save->buffer_ptr += save->vertex_size;
538
      save->vert_count++;
539
   }
540
}
541
 
542
 
543
static void
544
_save_copy_to_current(struct gl_context *ctx)
545
{
546
   struct vbo_save_context *save = &vbo_context(ctx)->save;
547
   GLuint i;
548
 
549
   for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
550
      if (save->attrsz[i]) {
551
         save->currentsz[i][0] = save->attrsz[i];
552
         COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i],
553
                                     save->attrptr[i], save->attrtype[i]);
554
      }
555
   }
556
}
557
 
558
 
559
static void
560
_save_copy_from_current(struct gl_context *ctx)
561
{
562
   struct vbo_save_context *save = &vbo_context(ctx)->save;
563
   GLint i;
564
 
565
   for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
566
      switch (save->attrsz[i]) {
567
      case 4:
568
         save->attrptr[i][3] = save->current[i][3];
569
      case 3:
570
         save->attrptr[i][2] = save->current[i][2];
571
      case 2:
572
         save->attrptr[i][1] = save->current[i][1];
573
      case 1:
574
         save->attrptr[i][0] = save->current[i][0];
575
      case 0:
576
         break;
577
      }
578
   }
579
}
580
 
581
 
582
/**
583
 * Called when we increase the size of a vertex attribute.  For example,
584
 * if we've seen one or more glTexCoord2f() calls and now we get a
585
 * glTexCoord3f() call.
586
 * Flush existing data, set new attrib size, replay copied vertices.
587
 */
588
static void
589
_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
590
{
591
   struct vbo_save_context *save = &vbo_context(ctx)->save;
592
   GLuint oldsz;
593
   GLuint i;
594
   GLfloat *tmp;
595
 
596
   /* Store the current run of vertices, and emit a GL_END.  Emit a
597
    * BEGIN in the new buffer.
598
    */
599
   if (save->vert_count)
600
      _save_wrap_buffers(ctx);
601
   else
602
      assert(save->copied.nr == 0);
603
 
604
   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
605
    * when the attribute already exists in the vertex and is having
606
    * its size increased.
607
    */
608
   _save_copy_to_current(ctx);
609
 
610
   /* Fix up sizes:
611
    */
612
   oldsz = save->attrsz[attr];
613
   save->attrsz[attr] = newsz;
614
 
615
   save->vertex_size += newsz - oldsz;
616
   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
617
                     save->vertex_size);
618
   save->vert_count = 0;
619
 
620
   /* Recalculate all the attrptr[] values:
621
    */
622
   for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
623
      if (save->attrsz[i]) {
624
         save->attrptr[i] = tmp;
625
         tmp += save->attrsz[i];
626
      }
627
      else {
628
         save->attrptr[i] = NULL;       /* will not be dereferenced. */
629
      }
630
   }
631
 
632
   /* Copy from current to repopulate the vertex with correct values.
633
    */
634
   _save_copy_from_current(ctx);
635
 
636
   /* Replay stored vertices to translate them to new format here.
637
    *
638
    * If there are copied vertices and the new (upgraded) attribute
639
    * has not been defined before, this list is somewhat degenerate,
640
    * and will need fixup at runtime.
641
    */
642
   if (save->copied.nr) {
643
      const GLfloat *data = save->copied.buffer;
644
      GLfloat *dest = save->buffer;
645
      GLuint j;
646
 
647
      /* Need to note this and fix up at runtime (or loopback):
648
       */
649
      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
650
         assert(oldsz == 0);
651
         save->dangling_attr_ref = GL_TRUE;
652
      }
653
 
654
      for (i = 0; i < save->copied.nr; i++) {
655
         for (j = 0; j < VBO_ATTRIB_MAX; j++) {
656
            if (save->attrsz[j]) {
657
               if (j == attr) {
658
                  if (oldsz) {
659
                     COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data,
660
                                                 save->attrtype[j]);
661
                     data += oldsz;
662
                     dest += newsz;
663
                  }
664
                  else {
665
                     COPY_SZ_4V(dest, newsz, save->current[attr]);
666
                     dest += newsz;
667
                  }
668
               }
669
               else {
670
                  GLint sz = save->attrsz[j];
671
                  COPY_SZ_4V(dest, sz, data);
672
                  data += sz;
673
                  dest += sz;
674
               }
675
            }
676
         }
677
      }
678
 
679
      save->buffer_ptr = dest;
680
      save->vert_count += save->copied.nr;
681
   }
682
}
683
 
684
 
685
/**
686
 * This is called when the size of a vertex attribute changes.
687
 * For example, after seeing one or more glTexCoord2f() calls we
688
 * get a glTexCoord4f() or glTexCoord1f() call.
689
 */
690
static void
691
save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
692
{
693
   struct vbo_save_context *save = &vbo_context(ctx)->save;
694
 
695
   if (sz > save->attrsz[attr]) {
696
      /* New size is larger.  Need to flush existing vertices and get
697
       * an enlarged vertex format.
698
       */
699
      _save_upgrade_vertex(ctx, attr, sz);
700
   }
701
   else if (sz < save->active_sz[attr]) {
702
      GLuint i;
703
      const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]);
704
 
705
      /* New size is equal or smaller - just need to fill in some
706
       * zeros.
707
       */
708
      for (i = sz; i <= save->attrsz[attr]; i++)
709
         save->attrptr[attr][i - 1] = id[i - 1];
710
   }
711
 
712
   save->active_sz[attr] = sz;
713
}
714
 
715
 
716
/**
717
 * Reset the current size of all vertex attributes to the default
718
 * value of 0.  This signals that we haven't yet seen any per-vertex
719
 * commands such as glNormal3f() or glTexCoord2f().
720
 */
721
static void
722
_save_reset_vertex(struct gl_context *ctx)
723
{
724
   struct vbo_save_context *save = &vbo_context(ctx)->save;
725
   GLuint i;
726
 
727
   for (i = 0; i < VBO_ATTRIB_MAX; i++) {
728
      save->attrsz[i] = 0;
729
      save->active_sz[i] = 0;
730
   }
731
 
732
   save->vertex_size = 0;
733
}
734
 
735
 
736
 
737
#define ERROR(err)   _mesa_compile_error(ctx, err, __FUNCTION__);
738
 
739
 
740
/* Only one size for each attribute may be active at once.  Eg. if
741
 * Color3f is installed/active, then Color4f may not be, even if the
742
 * vertex actually contains 4 color coordinates.  This is because the
743
 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
744
 * of the chooser function when switching between Color4f and Color3f.
745
 */
746
#define ATTR(A, N, T, V0, V1, V2, V3)				\
747
do {								\
748
   struct vbo_save_context *save = &vbo_context(ctx)->save;	\
749
								\
750
   if (save->active_sz[A] != N)					\
751
      save_fixup_vertex(ctx, A, N);				\
752
								\
753
   {								\
754
      GLfloat *dest = save->attrptr[A];				\
755
      if (N>0) dest[0] = V0;					\
756
      if (N>1) dest[1] = V1;					\
757
      if (N>2) dest[2] = V2;					\
758
      if (N>3) dest[3] = V3;					\
759
      save->attrtype[A] = T;                                    \
760
   }								\
761
								\
762
   if ((A) == 0) {						\
763
      GLuint i;							\
764
								\
765
      for (i = 0; i < save->vertex_size; i++)			\
766
	 save->buffer_ptr[i] = save->vertex[i];			\
767
								\
768
      save->buffer_ptr += save->vertex_size;			\
769
								\
770
      if (++save->vert_count >= save->max_vert)			\
771
	 _save_wrap_filled_vertex(ctx);				\
772
   }								\
773
} while (0)
774
 
775
#define TAG(x) _save_##x
776
 
777
#include "vbo_attrib_tmp.h"
778
 
779
 
780
 
781
#define MAT( ATTR, N, face, params )			\
782
do {							\
783
   if (face != GL_BACK)					\
784
      MAT_ATTR( ATTR, N, params ); /* front */		\
785
   if (face != GL_FRONT)				\
786
      MAT_ATTR( ATTR + 1, N, params ); /* back */	\
787
} while (0)
788
 
789
 
790
/**
791
 * Save a glMaterial call found between glBegin/End.
792
 * glMaterial calls outside Begin/End are handled in dlist.c.
793
 */
794
static void GLAPIENTRY
795
_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
796
{
797
   GET_CURRENT_CONTEXT(ctx);
798
 
799
   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
800
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
801
      return;
802
   }
803
 
804
   switch (pname) {
805
   case GL_EMISSION:
806
      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
807
      break;
808
   case GL_AMBIENT:
809
      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
810
      break;
811
   case GL_DIFFUSE:
812
      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
813
      break;
814
   case GL_SPECULAR:
815
      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
816
      break;
817
   case GL_SHININESS:
818
      if (*params < 0 || *params > ctx->Const.MaxShininess) {
819
         _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
820
      }
821
      else {
822
         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
823
      }
824
      break;
825
   case GL_COLOR_INDEXES:
826
      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
827
      break;
828
   case GL_AMBIENT_AND_DIFFUSE:
829
      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
830
      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
831
      break;
832
   default:
833
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
834
      return;
835
   }
836
}
837
 
838
 
839
/* Cope with EvalCoord/CallList called within a begin/end object:
840
 *     -- Flush current buffer
841
 *     -- Fallback to opcodes for the rest of the begin/end object.
842
 */
843
static void
844
dlist_fallback(struct gl_context *ctx)
845
{
846
   struct vbo_save_context *save = &vbo_context(ctx)->save;
847
 
848
   if (save->vert_count || save->prim_count) {
849
      if (save->prim_count > 0) {
850
         /* Close off in-progress primitive. */
851
         GLint i = save->prim_count - 1;
852
         save->prim[i].count = save->vert_count - save->prim[i].start;
853
      }
854
 
855
      /* Need to replay this display list with loopback,
856
       * unfortunately, otherwise this primitive won't be handled
857
       * properly:
858
       */
859
      save->dangling_attr_ref = 1;
860
 
861
      _save_compile_vertex_list(ctx);
862
   }
863
 
864
   _save_copy_to_current(ctx);
865
   _save_reset_vertex(ctx);
866
   _save_reset_counters(ctx);
867
   if (save->out_of_memory) {
868
      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
869
   }
870
   else {
871
      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
872
   }
873
   ctx->Driver.SaveNeedFlush = GL_FALSE;
874
}
875
 
876
 
877
static void GLAPIENTRY
878
_save_EvalCoord1f(GLfloat u)
879
{
880
   GET_CURRENT_CONTEXT(ctx);
881
   dlist_fallback(ctx);
882
   CALL_EvalCoord1f(ctx->Save, (u));
883
}
884
 
885
static void GLAPIENTRY
886
_save_EvalCoord1fv(const GLfloat * v)
887
{
888
   GET_CURRENT_CONTEXT(ctx);
889
   dlist_fallback(ctx);
890
   CALL_EvalCoord1fv(ctx->Save, (v));
891
}
892
 
893
static void GLAPIENTRY
894
_save_EvalCoord2f(GLfloat u, GLfloat v)
895
{
896
   GET_CURRENT_CONTEXT(ctx);
897
   dlist_fallback(ctx);
898
   CALL_EvalCoord2f(ctx->Save, (u, v));
899
}
900
 
901
static void GLAPIENTRY
902
_save_EvalCoord2fv(const GLfloat * v)
903
{
904
   GET_CURRENT_CONTEXT(ctx);
905
   dlist_fallback(ctx);
906
   CALL_EvalCoord2fv(ctx->Save, (v));
907
}
908
 
909
static void GLAPIENTRY
910
_save_EvalPoint1(GLint i)
911
{
912
   GET_CURRENT_CONTEXT(ctx);
913
   dlist_fallback(ctx);
914
   CALL_EvalPoint1(ctx->Save, (i));
915
}
916
 
917
static void GLAPIENTRY
918
_save_EvalPoint2(GLint i, GLint j)
919
{
920
   GET_CURRENT_CONTEXT(ctx);
921
   dlist_fallback(ctx);
922
   CALL_EvalPoint2(ctx->Save, (i, j));
923
}
924
 
925
static void GLAPIENTRY
926
_save_CallList(GLuint l)
927
{
928
   GET_CURRENT_CONTEXT(ctx);
929
   dlist_fallback(ctx);
930
   CALL_CallList(ctx->Save, (l));
931
}
932
 
933
static void GLAPIENTRY
934
_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
935
{
936
   GET_CURRENT_CONTEXT(ctx);
937
   dlist_fallback(ctx);
938
   CALL_CallLists(ctx->Save, (n, type, v));
939
}
940
 
941
 
942
 
943
/**
944
 * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
945
 * compiled into a display list.
946
 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
947
 */
948
GLboolean
949
vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
950
{
951
   struct vbo_save_context *save = &vbo_context(ctx)->save;
952
   const GLuint i = save->prim_count++;
953
 
954
   assert(i < save->prim_max);
955
   save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
956
   save->prim[i].begin = 1;
957
   save->prim[i].end = 0;
958
   save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
959
   save->prim[i].no_current_update =
960
      (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
961
   save->prim[i].pad = 0;
962
   save->prim[i].start = save->vert_count;
963
   save->prim[i].count = 0;
964
   save->prim[i].num_instances = 1;
965
   save->prim[i].base_instance = 0;
966
 
967
   if (save->out_of_memory) {
968
      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
969
   }
970
   else {
971
      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
972
   }
973
 
974
   /* We need to call SaveFlushVertices() if there's state change */
975
   ctx->Driver.SaveNeedFlush = GL_TRUE;
976
 
977
   /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
978
    * opcode into the display list.
979
    */
980
   return GL_TRUE;
981
}
982
 
983
 
984
static void GLAPIENTRY
985
_save_End(void)
986
{
987
   GET_CURRENT_CONTEXT(ctx);
988
   struct vbo_save_context *save = &vbo_context(ctx)->save;
989
   const GLint i = save->prim_count - 1;
990
 
991
   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
992
   save->prim[i].end = 1;
993
   save->prim[i].count = (save->vert_count - save->prim[i].start);
994
 
995
   if (i == (GLint) save->prim_max - 1) {
996
      _save_compile_vertex_list(ctx);
997
      assert(save->copied.nr == 0);
998
   }
999
 
1000
   /* Swap out this vertex format while outside begin/end.  Any color,
1001
    * etc. received between here and the next begin will be compiled
1002
    * as opcodes.
1003
    */
1004
   if (save->out_of_memory) {
1005
      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1006
   }
1007
   else {
1008
      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1009
   }
1010
}
1011
 
1012
 
1013
static void GLAPIENTRY
1014
_save_Begin(GLenum mode)
1015
{
1016
   GET_CURRENT_CONTEXT(ctx);
1017
   (void) mode;
1018
   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1019
}
1020
 
1021
 
1022
static void GLAPIENTRY
1023
_save_PrimitiveRestartNV(void)
1024
{
1025
   GLenum curPrim;
1026
   GET_CURRENT_CONTEXT(ctx);
1027
 
1028
   curPrim = ctx->Driver.CurrentSavePrimitive;
1029
 
1030
   _save_End();
1031
   _save_Begin(curPrim);
1032
}
1033
 
1034
 
1035
/* Unlike the functions above, these are to be hooked into the vtxfmt
1036
 * maintained in ctx->ListState, active when the list is known or
1037
 * suspected to be outside any begin/end primitive.
1038
 * Note: OBE = Outside Begin/End
1039
 */
1040
static void GLAPIENTRY
1041
_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1042
{
1043
   GET_CURRENT_CONTEXT(ctx);
1044
   vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1045
   CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1046
   CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1047
   CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1048
   CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1049
   CALL_End(GET_DISPATCH(), ());
1050
}
1051
 
1052
 
1053
static void GLAPIENTRY
1054
_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1055
{
1056
   GET_CURRENT_CONTEXT(ctx);
1057
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1058
   GLint i;
1059
 
1060
   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1061
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1062
      return;
1063
   }
1064
   if (count < 0) {
1065
      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1066
      return;
1067
   }
1068
 
1069
   if (save->out_of_memory)
1070
      return;
1071
 
1072
   _ae_map_vbos(ctx);
1073
 
1074
   vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1075
                              | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1076
 
1077
   for (i = 0; i < count; i++)
1078
      CALL_ArrayElement(GET_DISPATCH(), (start + i));
1079
   CALL_End(GET_DISPATCH(), ());
1080
 
1081
   _ae_unmap_vbos(ctx);
1082
}
1083
 
1084
 
1085
/* Could do better by copying the arrays and element list intact and
1086
 * then emitting an indexed prim at runtime.
1087
 */
1088
static void GLAPIENTRY
1089
_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1090
                       const GLvoid * indices)
1091
{
1092
   GET_CURRENT_CONTEXT(ctx);
1093
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1094
   GLint i;
1095
 
1096
   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1097
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1098
      return;
1099
   }
1100
   if (count < 0) {
1101
      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1102
      return;
1103
   }
1104
   if (type != GL_UNSIGNED_BYTE &&
1105
       type != GL_UNSIGNED_SHORT &&
1106
       type != GL_UNSIGNED_INT) {
1107
      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1108
      return;
1109
   }
1110
 
1111
   if (save->out_of_memory)
1112
      return;
1113
 
1114
   _ae_map_vbos(ctx);
1115
 
1116
   if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
1117
      indices =
1118
         ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices);
1119
 
1120
   vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1121
                              VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1122
 
1123
   switch (type) {
1124
   case GL_UNSIGNED_BYTE:
1125
      for (i = 0; i < count; i++)
1126
         CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
1127
      break;
1128
   case GL_UNSIGNED_SHORT:
1129
      for (i = 0; i < count; i++)
1130
         CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
1131
      break;
1132
   case GL_UNSIGNED_INT:
1133
      for (i = 0; i < count; i++)
1134
         CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
1135
      break;
1136
   default:
1137
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1138
      break;
1139
   }
1140
 
1141
   CALL_End(GET_DISPATCH(), ());
1142
 
1143
   _ae_unmap_vbos(ctx);
1144
}
1145
 
1146
 
1147
static void GLAPIENTRY
1148
_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1149
                            GLsizei count, GLenum type,
1150
                            const GLvoid * indices)
1151
{
1152
   GET_CURRENT_CONTEXT(ctx);
1153
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1154
 
1155
   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1156
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1157
      return;
1158
   }
1159
   if (count < 0) {
1160
      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1161
                          "glDrawRangeElements(count<0)");
1162
      return;
1163
   }
1164
   if (type != GL_UNSIGNED_BYTE &&
1165
       type != GL_UNSIGNED_SHORT &&
1166
       type != GL_UNSIGNED_INT) {
1167
      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1168
      return;
1169
   }
1170
   if (end < start) {
1171
      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1172
                          "glDrawRangeElements(end < start)");
1173
      return;
1174
   }
1175
 
1176
   if (save->out_of_memory)
1177
      return;
1178
 
1179
   _save_OBE_DrawElements(mode, count, type, indices);
1180
}
1181
 
1182
 
1183
static void GLAPIENTRY
1184
_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1185
                            const GLvoid * const *indices, GLsizei primcount)
1186
{
1187
   GLsizei i;
1188
 
1189
   for (i = 0; i < primcount; i++) {
1190
      if (count[i] > 0) {
1191
	 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1192
      }
1193
   }
1194
}
1195
 
1196
 
1197
static void GLAPIENTRY
1198
_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1199
                                      GLenum type,
1200
                                      const GLvoid * const *indices,
1201
                                      GLsizei primcount,
1202
                                      const GLint *basevertex)
1203
{
1204
   GLsizei i;
1205
 
1206
   for (i = 0; i < primcount; i++) {
1207
      if (count[i] > 0) {
1208
	 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1209
						      indices[i],
1210
						      basevertex[i]));
1211
      }
1212
   }
1213
}
1214
 
1215
 
1216
static void
1217
_save_vtxfmt_init(struct gl_context *ctx)
1218
{
1219
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1220
   GLvertexformat *vfmt = &save->vtxfmt;
1221
 
1222
   vfmt->ArrayElement = _ae_ArrayElement;
1223
 
1224
   vfmt->Color3f = _save_Color3f;
1225
   vfmt->Color3fv = _save_Color3fv;
1226
   vfmt->Color4f = _save_Color4f;
1227
   vfmt->Color4fv = _save_Color4fv;
1228
   vfmt->EdgeFlag = _save_EdgeFlag;
1229
   vfmt->End = _save_End;
1230
   vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1231
   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1232
   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1233
   vfmt->Indexf = _save_Indexf;
1234
   vfmt->Indexfv = _save_Indexfv;
1235
   vfmt->Materialfv = _save_Materialfv;
1236
   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1237
   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1238
   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1239
   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1240
   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1241
   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1242
   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1243
   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1244
   vfmt->Normal3f = _save_Normal3f;
1245
   vfmt->Normal3fv = _save_Normal3fv;
1246
   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1247
   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1248
   vfmt->TexCoord1f = _save_TexCoord1f;
1249
   vfmt->TexCoord1fv = _save_TexCoord1fv;
1250
   vfmt->TexCoord2f = _save_TexCoord2f;
1251
   vfmt->TexCoord2fv = _save_TexCoord2fv;
1252
   vfmt->TexCoord3f = _save_TexCoord3f;
1253
   vfmt->TexCoord3fv = _save_TexCoord3fv;
1254
   vfmt->TexCoord4f = _save_TexCoord4f;
1255
   vfmt->TexCoord4fv = _save_TexCoord4fv;
1256
   vfmt->Vertex2f = _save_Vertex2f;
1257
   vfmt->Vertex2fv = _save_Vertex2fv;
1258
   vfmt->Vertex3f = _save_Vertex3f;
1259
   vfmt->Vertex3fv = _save_Vertex3fv;
1260
   vfmt->Vertex4f = _save_Vertex4f;
1261
   vfmt->Vertex4fv = _save_Vertex4fv;
1262
   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1263
   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1264
   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1265
   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1266
   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1267
   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1268
   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1269
   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1270
 
1271
   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1272
   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1273
   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1274
   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1275
   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1276
   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1277
   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1278
   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1279
 
1280
   /* integer-valued */
1281
   vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1282
   vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1283
   vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1284
   vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1285
   vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1286
   vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1287
   vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1288
 
1289
   /* unsigned integer-valued */
1290
   vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1291
   vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1292
   vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1293
   vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1294
   vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1295
   vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1296
   vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1297
 
1298
   vfmt->VertexP2ui = _save_VertexP2ui;
1299
   vfmt->VertexP3ui = _save_VertexP3ui;
1300
   vfmt->VertexP4ui = _save_VertexP4ui;
1301
   vfmt->VertexP2uiv = _save_VertexP2uiv;
1302
   vfmt->VertexP3uiv = _save_VertexP3uiv;
1303
   vfmt->VertexP4uiv = _save_VertexP4uiv;
1304
 
1305
   vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1306
   vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1307
   vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1308
   vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1309
   vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1310
   vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1311
   vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1312
   vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1313
 
1314
   vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1315
   vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1316
   vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1317
   vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1318
   vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1319
   vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1320
   vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1321
   vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1322
 
1323
   vfmt->NormalP3ui = _save_NormalP3ui;
1324
   vfmt->NormalP3uiv = _save_NormalP3uiv;
1325
 
1326
   vfmt->ColorP3ui = _save_ColorP3ui;
1327
   vfmt->ColorP4ui = _save_ColorP4ui;
1328
   vfmt->ColorP3uiv = _save_ColorP3uiv;
1329
   vfmt->ColorP4uiv = _save_ColorP4uiv;
1330
 
1331
   vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1332
   vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1333
 
1334
   vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1335
   vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1336
   vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1337
   vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1338
 
1339
   vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1340
   vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1341
   vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1342
   vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1343
 
1344
   /* This will all require us to fallback to saving the list as opcodes:
1345
    */
1346
   vfmt->CallList = _save_CallList;
1347
   vfmt->CallLists = _save_CallLists;
1348
 
1349
   vfmt->EvalCoord1f = _save_EvalCoord1f;
1350
   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1351
   vfmt->EvalCoord2f = _save_EvalCoord2f;
1352
   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1353
   vfmt->EvalPoint1 = _save_EvalPoint1;
1354
   vfmt->EvalPoint2 = _save_EvalPoint2;
1355
 
1356
   /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1357
    * only used when we're inside a glBegin/End pair.
1358
    */
1359
   vfmt->Begin = _save_Begin;
1360
}
1361
 
1362
 
1363
/**
1364
 * Initialize the dispatch table with the VBO functions for display
1365
 * list compilation.
1366
 */
1367
void
1368
vbo_initialize_save_dispatch(const struct gl_context *ctx,
1369
                             struct _glapi_table *exec)
1370
{
1371
   SET_DrawArrays(exec, _save_OBE_DrawArrays);
1372
   SET_DrawElements(exec, _save_OBE_DrawElements);
1373
   SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1374
   SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1375
   SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1376
   SET_Rectf(exec, _save_OBE_Rectf);
1377
   /* Note: other glDraw functins aren't compiled into display lists */
1378
}
1379
 
1380
 
1381
 
1382
void
1383
vbo_save_SaveFlushVertices(struct gl_context *ctx)
1384
{
1385
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1386
 
1387
   /* Noop when we are actually active:
1388
    */
1389
   if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1390
      return;
1391
 
1392
   if (save->vert_count || save->prim_count)
1393
      _save_compile_vertex_list(ctx);
1394
 
1395
   _save_copy_to_current(ctx);
1396
   _save_reset_vertex(ctx);
1397
   _save_reset_counters(ctx);
1398
   ctx->Driver.SaveNeedFlush = GL_FALSE;
1399
}
1400
 
1401
 
1402
void
1403
vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1404
{
1405
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1406
 
1407
   (void) list;
1408
   (void) mode;
1409
 
1410
   if (!save->prim_store)
1411
      save->prim_store = alloc_prim_store(ctx);
1412
 
1413
   if (!save->vertex_store)
1414
      save->vertex_store = alloc_vertex_store(ctx);
1415
 
1416
   save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1417
 
1418
   _save_reset_vertex(ctx);
1419
   _save_reset_counters(ctx);
1420
   ctx->Driver.SaveNeedFlush = GL_FALSE;
1421
}
1422
 
1423
 
1424
void
1425
vbo_save_EndList(struct gl_context *ctx)
1426
{
1427
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1428
 
1429
   /* EndList called inside a (saved) Begin/End pair?
1430
    */
1431
   if (_mesa_inside_dlist_begin_end(ctx)) {
1432
      if (save->prim_count > 0) {
1433
         GLint i = save->prim_count - 1;
1434
         ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1435
         save->prim[i].end = 0;
1436
         save->prim[i].count = (save->vert_count - save->prim[i].start);
1437
      }
1438
 
1439
      /* Make sure this vertex list gets replayed by the "loopback"
1440
       * mechanism:
1441
       */
1442
      save->dangling_attr_ref = 1;
1443
      vbo_save_SaveFlushVertices(ctx);
1444
 
1445
      /* Swap out this vertex format while outside begin/end.  Any color,
1446
       * etc. received between here and the next begin will be compiled
1447
       * as opcodes.
1448
       */
1449
      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1450
   }
1451
 
1452
   vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1453
 
1454
   assert(save->vertex_size == 0);
1455
}
1456
 
1457
 
1458
void
1459
vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1460
{
1461
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1462
   save->replay_flags |= dlist->Flags;
1463
}
1464
 
1465
 
1466
void
1467
vbo_save_EndCallList(struct gl_context *ctx)
1468
{
1469
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1470
 
1471
   if (ctx->ListState.CallDepth == 1) {
1472
      /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1473
       * flag, if it is set:
1474
       */
1475
      save->replay_flags &= VBO_SAVE_FALLBACK;
1476
   }
1477
}
1478
 
1479
 
1480
static void
1481
vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1482
{
1483
   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1484
   (void) ctx;
1485
 
1486
   if (--node->vertex_store->refcount == 0)
1487
      free_vertex_store(ctx, node->vertex_store);
1488
 
1489
   if (--node->prim_store->refcount == 0)
1490
      free(node->prim_store);
1491
 
1492
   free(node->current_data);
1493
   node->current_data = NULL;
1494
}
1495
 
1496
 
1497
static void
1498
vbo_print_vertex_list(struct gl_context *ctx, void *data)
1499
{
1500
   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1501
   GLuint i;
1502
   (void) ctx;
1503
 
1504
   printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1505
          node->count, node->prim_count, node->vertex_size);
1506
 
1507
   for (i = 0; i < node->prim_count; i++) {
1508
      struct _mesa_prim *prim = &node->prim[i];
1509
      printf("   prim %d: %s%s %d..%d %s %s\n",
1510
             i,
1511
             _mesa_lookup_prim_by_nr(prim->mode),
1512
             prim->weak ? " (weak)" : "",
1513
             prim->start,
1514
             prim->start + prim->count,
1515
             (prim->begin) ? "BEGIN" : "(wrap)",
1516
             (prim->end) ? "END" : "(wrap)");
1517
   }
1518
}
1519
 
1520
 
1521
/**
1522
 * Called during context creation/init.
1523
 */
1524
static void
1525
_save_current_init(struct gl_context *ctx)
1526
{
1527
   struct vbo_save_context *save = &vbo_context(ctx)->save;
1528
   GLint i;
1529
 
1530
   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1531
      const GLuint j = i - VBO_ATTRIB_POS;
1532
      ASSERT(j < VERT_ATTRIB_MAX);
1533
      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1534
      save->current[i] = ctx->ListState.CurrentAttrib[j];
1535
   }
1536
 
1537
   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1538
      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1539
      ASSERT(j < MAT_ATTRIB_MAX);
1540
      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1541
      save->current[i] = ctx->ListState.CurrentMaterial[j];
1542
   }
1543
}
1544
 
1545
 
1546
/**
1547
 * Initialize the display list compiler.  Called during context creation.
1548
 */
1549
void
1550
vbo_save_api_init(struct vbo_save_context *save)
1551
{
1552
   struct gl_context *ctx = save->ctx;
1553
   GLuint i;
1554
 
1555
   save->opcode_vertex_list =
1556
      _mesa_dlist_alloc_opcode(ctx,
1557
                               sizeof(struct vbo_save_vertex_list),
1558
                               vbo_save_playback_vertex_list,
1559
                               vbo_destroy_vertex_list,
1560
                               vbo_print_vertex_list);
1561
 
1562
   ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1563
 
1564
   _save_vtxfmt_init(ctx);
1565
   _save_current_init(ctx);
1566
   _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1567
 
1568
   /* These will actually get set again when binding/drawing */
1569
   for (i = 0; i < VBO_ATTRIB_MAX; i++)
1570
      save->inputs[i] = &save->arrays[i];
1571
}