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
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Keith Whitwell 
26
 */
27
28
 
29
 */
30
31
 
32
#include "main/bufferobj.h"
33
#include "main/imports.h"
34
#include "main/glformats.h"
35
#include "main/macros.h"
36
#include "main/mtypes.h"
37
38
 
39
#include "vbo.h"
40
41
 
42
 
43
44
 
45
 * Used for vertex-level splitting of indexed buffers.  Note that
46
 * non-indexed primitives may be converted to indexed in some cases
47
 * (eg loops, fans) in order to use this splitting path.
48
 */
49
struct copy_context {
50
51
 
52
   const struct gl_client_array **array;
53
   const struct _mesa_prim *prim;
54
   GLuint nr_prims;
55
   const struct _mesa_index_buffer *ib;
56
   vbo_draw_func draw;
57
58
 
59
60
 
61
      GLuint attr;
62
      GLuint size;
63
      const struct gl_client_array *array;
64
      const GLubyte *src_ptr;
65
66
 
67
68
 
69
   GLuint nr_varying;
70
71
 
72
   struct _mesa_index_buffer dstib;
73
74
 
75
   const GLuint *srcelt;
76
77
 
78
    * vertices when splitting indexed primitives.
79
    */
80
   struct {
81
      GLuint in;
82
      GLuint out;
83
   } vert_cache[ELT_TABLE_SIZE];
84
85
 
86
   GLubyte *dstbuf;
87
   GLubyte *dstptr;     /**< dstptr == dstbuf + dstelt_max * vertsize */
88
   GLuint dstbuf_size;  /**< in vertices */
89
   GLuint dstbuf_nr;    /**< count of emitted vertices, also the largest value
90
                         * in dstelt.  Our MaxIndex.
91
                         */
92
93
 
94
   GLuint dstelt_nr;
95
   GLuint dstelt_size;
96
97
 
98
   struct _mesa_prim dstprim[MAX_PRIM];
99
   GLuint dstprim_nr;
100
101
 
102
103
 
104
 
105
{
106
   return array->Size * _mesa_sizeof_type(array->Type);
107
}
108
109
 
110
 
111
 * Starts returning true slightly before the buffer fills, to ensure
112
 * that there is sufficient room for any remaining vertices to finish
113
 * off the prim:
114
 */
115
static GLboolean
116
check_flush( struct copy_context *copy )
117
{
118
   GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
119
120
 
121
       copy->dstelt_nr & 1) { /* see bug9962 */
122
       return GL_FALSE;
123
   }
124
125
 
126
      return GL_TRUE;
127
128
 
129
      return GL_TRUE;
130
131
 
132
}
133
134
 
135
 
136
 * Dump the parameters/info for a vbo->draw() call.
137
 */
138
static void
139
dump_draw_info(struct gl_context *ctx,
140
               const struct gl_client_array **arrays,
141
               const struct _mesa_prim *prims,
142
               GLuint nr_prims,
143
               const struct _mesa_index_buffer *ib,
144
               GLuint min_index,
145
               GLuint max_index)
146
{
147
   GLuint i, j;
148
149
 
150
   for (i = 0; i < nr_prims; i++) {
151
      printf("Prim %u of %u\n", i, nr_prims);
152
      printf("  Prim mode 0x%x\n", prims[i].mode);
153
      printf("  IB: %p\n", (void*) ib);
154
      for (j = 0; j < VERT_ATTRIB_MAX; j++) {
155
         printf("    array %d at %p:\n", j, (void*) arrays[j]);
156
         printf("      enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
157
		arrays[j]->Enabled, arrays[j]->Ptr,
158
		arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
159
         if (0) {
160
            GLint k = prims[i].start + prims[i].count - 1;
161
            GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
162
            printf("        last: %f %f %f\n",
163
		   last[0], last[1], last[2]);
164
         }
165
      }
166
   }
167
}
168
169
 
170
 
171
flush( struct copy_context *copy )
172
{
173
   struct gl_context *ctx = copy->ctx;
174
   const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
175
   GLuint i;
176
177
 
178
    */
179
   copy->dstib.count = copy->dstelt_nr;
180
181
 
182
   dump_draw_info(copy->ctx,
183
                  copy->dstarray_ptr,
184
                  copy->dstprim,
185
                  copy->dstprim_nr,
186
                  ©->dstib,
187
                  0,
188
                  copy->dstbuf_nr);
189
#else
190
   (void) dump_draw_info;
191
#endif
192
193
 
194
   ctx->NewDriverState |= ctx->DriverFlags.NewArray;
195
196
 
197
	       copy->dstprim,
198
	       copy->dstprim_nr,
199
	       ©->dstib,
200
	       GL_TRUE,
201
	       0,
202
	       copy->dstbuf_nr - 1,
203
	       NULL );
204
205
 
206
   ctx->NewDriverState |= ctx->DriverFlags.NewArray;
207
208
 
209
    */
210
   copy->dstprim_nr = 0;
211
   copy->dstelt_nr = 0;
212
   copy->dstbuf_nr = 0;
213
   copy->dstptr = copy->dstbuf;
214
215
 
216
    */
217
   for (i = 0; i < ELT_TABLE_SIZE; i++)
218
      copy->vert_cache[i].in = ~0;
219
}
220
221
 
222
 
223
 * Called at begin of each primitive during replay.
224
 */
225
static void
226
begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
227
{
228
   struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
229
230
 
231
   prim->begin = begin_flag;
232
   prim->num_instances = 1;
233
}
234
235
 
236
 
237
 * Use a hashtable to attempt to identify recently-emitted vertices
238
 * and avoid re-emitting them.
239
 */
240
static GLuint
241
elt(struct copy_context *copy, GLuint elt_idx)
242
{
243
   GLuint elt = copy->srcelt[elt_idx];
244
   GLuint slot = elt & (ELT_TABLE_SIZE-1);
245
246
 
247
248
 
249
    * necessary.
250
    */
251
   if (copy->vert_cache[slot].in != elt) {
252
      GLubyte *csr = copy->dstptr;
253
      GLuint i;
254
255
 
256
257
 
258
	 const struct gl_client_array *srcarray = copy->varying[i].array;
259
	 const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
260
261
 
262
	 csr += copy->varying[i].size;
263
264
 
265
         if (srcarray->Type == GL_FLOAT) {
266
            GLuint k;
267
            GLfloat *f = (GLfloat *) srcptr;
268
            for (k = 0; k < srcarray->Size; k++) {
269
               assert(!IS_INF_OR_NAN(f[k]));
270
               assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
271
            }
272
         }
273
#endif
274
275
 
276
	 {
277
	    const GLuint *f = (const GLuint *)srcptr;
278
	    GLuint j;
279
	    printf("  varying %d: ", i);
280
	    for(j = 0; j < copy->varying[i].size / 4; j++)
281
	       printf("%x ", f[j]);
282
	    printf("\n");
283
	 }
284
      }
285
286
 
287
      copy->vert_cache[slot].out = copy->dstbuf_nr++;
288
      copy->dstptr += copy->vertex_size;
289
290
 
291
      assert(copy->dstptr == (copy->dstbuf +
292
                              copy->dstbuf_nr * copy->vertex_size));
293
   }
294
/*    else */
295
/*       printf("  --> reuse vertex\n"); */
296
297
 
298
   copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
299
   return check_flush(copy);
300
}
301
302
 
303
 
304
 * Called at end of each primitive during replay.
305
 */
306
static void
307
end( struct copy_context *copy, GLboolean end_flag )
308
{
309
   struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
310
311
 
312
313
 
314
   prim->count = copy->dstelt_nr - prim->start;
315
316
 
317
       check_flush(copy))
318
      flush(copy);
319
}
320
321
 
322
 
323
replay_elts( struct copy_context *copy )
324
{
325
   GLuint i, j, k;
326
   GLboolean split;
327
328
 
329
      const struct _mesa_prim *prim = ©->prim[i];
330
      const GLuint start = prim->start;
331
      GLuint first, incr;
332
333
 
334
335
 
336
	 /* Convert to linestrip and emit the final vertex explicitly,
337
	  * but only in the resultant strip that requires it.
338
	  */
339
	 j = 0;
340
	 while (j != prim->count) {
341
	    begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
342
343
 
344
	       split = elt(copy, start + j);
345
346
 
347
	       /* Done, emit final line.  Split doesn't matter as
348
		* it is always raised a bit early so we can emit
349
		* the last verts if necessary!
350
		*/
351
	       if (prim->end)
352
		  (void)elt(copy, start + 0);
353
354
 
355
	    }
356
	    else {
357
	       /* Wrap
358
		*/
359
	       assert(split);
360
	       end(copy, 0);
361
	       j--;
362
	    }
363
	 }
364
	 break;
365
366
 
367
      case GL_POLYGON:
368
	 j = 2;
369
	 while (j != prim->count) {
370
	    begin(copy, prim->mode, prim->begin && j == 0);
371
372
 
373
	    assert(!split);
374
375
 
376
	    assert(!split);
377
378
 
379
	       split = elt(copy, start+j);
380
381
 
382
383
 
384
	       /* Wrapped the primitive, need to repeat some vertices:
385
		*/
386
	       j -= 1;
387
	    }
388
	 }
389
	 break;
390
391
 
392
	 (void)split_prim_inplace(prim->mode, &first, &incr);
393
394
 
395
	 while (j != prim->count) {
396
397
 
398
399
 
400
	    for (k = 0; k < first; k++, j++)
401
	       split |= elt(copy, start+j);
402
403
 
404
405
 
406
	       for (k = 0; k < incr; k++, j++)
407
		  split |= elt(copy, start+j);
408
409
 
410
411
 
412
	       /* Wrapped the primitive, need to repeat some vertices:
413
		*/
414
	       assert(j > first - incr);
415
	       j -= (first - incr);
416
	    }
417
	 }
418
	 break;
419
      }
420
   }
421
422
 
423
      flush(copy);
424
}
425
426
 
427
 
428
replay_init( struct copy_context *copy )
429
{
430
   struct gl_context *ctx = copy->ctx;
431
   GLuint i;
432
   GLuint offset;
433
   const GLvoid *srcptr;
434
435
 
436
    * calculate vertex size.
437
    */
438
   copy->vertex_size = 0;
439
   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
440
      struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
441
442
 
443
	 copy->dstarray_ptr[i] = copy->array[i];
444
      }
445
      else {
446
	 GLuint j = copy->nr_varying++;
447
448
 
449
	 copy->varying[j].array = copy->array[i];
450
	 copy->varying[j].size = attr_size(copy->array[i]);
451
	 copy->vertex_size += attr_size(copy->array[i]);
452
453
 
454
	    ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo);
455
456
 
457
						 copy->array[i]->Ptr);
458
459
 
460
      }
461
   }
462
463
 
464
    * caller convert non-indexed prims to indexed.  Could alternately
465
    * do it internally.
466
    */
467
   if (_mesa_is_bufferobj(copy->ib->obj) &&
468
       !_mesa_bufferobj_mapped(copy->ib->obj))
469
      ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
470
				 copy->ib->obj);
471
472
 
473
                                           copy->ib->ptr);
474
475
 
476
   case GL_UNSIGNED_BYTE:
477
      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
478
      copy->srcelt = copy->translated_elt_buf;
479
480
 
481
	 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
482
      break;
483
484
 
485
      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
486
      copy->srcelt = copy->translated_elt_buf;
487
488
 
489
	 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
490
      break;
491
492
 
493
      copy->translated_elt_buf = NULL;
494
      copy->srcelt = (const GLuint *)srcptr;
495
      break;
496
   }
497
498
 
499
    */
500
   if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
501
      copy->dstbuf_size = copy->limits->max_verts;
502
   }
503
   else {
504
      copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
505
   }
506
507
 
508
    *
509
    * XXX:  This should be a VBO!
510
    */
511
   copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
512
   copy->dstptr = copy->dstbuf;
513
514
 
515
    */
516
   for (offset = 0, i = 0; i < copy->nr_varying; i++) {
517
      const struct gl_client_array *src = copy->varying[i].array;
518
      struct gl_client_array *dst = ©->varying[i].dstarray;
519
520
 
521
      dst->Type = src->Type;
522
      dst->Format = GL_RGBA;
523
      dst->Stride = copy->vertex_size;
524
      dst->StrideB = copy->vertex_size;
525
      dst->Ptr = copy->dstbuf + offset;
526
      dst->Enabled = GL_TRUE;
527
      dst->Normalized = src->Normalized;
528
      dst->Integer = src->Integer;
529
      dst->BufferObj = ctx->Shared->NullBufferObj;
530
      dst->_ElementSize = src->_ElementSize;
531
      dst->_MaxElement = copy->dstbuf_size; /* may be less! */
532
533
 
534
   }
535
536
 
537
    */
538
   copy->dstelt_size = MIN2(65536,
539
			    copy->ib->count * 2 + 3);
540
   copy->dstelt_size = MIN2(copy->dstelt_size,
541
			    copy->limits->max_indices);
542
   copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
543
   copy->dstelt_nr = 0;
544
545
 
546
    * list:
547
    */
548
   copy->dstib.count = 0;	/* duplicates dstelt_nr */
549
   copy->dstib.type = GL_UNSIGNED_INT;
550
   copy->dstib.obj = ctx->Shared->NullBufferObj;
551
   copy->dstib.ptr = copy->dstelt;
552
}
553
554
 
555
 
556
 * Free up everything allocated during split/replay.
557
 */
558
static void
559
replay_finish( struct copy_context *copy )
560
{
561
   struct gl_context *ctx = copy->ctx;
562
   GLuint i;
563
564
 
565
    */
566
   free(copy->translated_elt_buf);
567
   free(copy->dstbuf);
568
   free(copy->dstelt);
569
570
 
571
    */
572
   for (i = 0; i < copy->nr_varying; i++) {
573
      struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
574
      if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
575
	 ctx->Driver.UnmapBuffer(ctx, vbo);
576
   }
577
578
 
579
    */
580
   if (_mesa_is_bufferobj(copy->ib->obj) &&
581
       _mesa_bufferobj_mapped(copy->ib->obj)) {
582
      ctx->Driver.UnmapBuffer(ctx, copy->ib->obj);
583
   }
584
}
585
586
 
587
 
588
 * Split VBO into smaller pieces, draw the pieces.
589
 */
590
void vbo_split_copy( struct gl_context *ctx,
591
		     const struct gl_client_array *arrays[],
592
		     const struct _mesa_prim *prim,
593
		     GLuint nr_prims,
594
		     const struct _mesa_index_buffer *ib,
595
		     vbo_draw_func draw,
596
		     const struct split_limits *limits )
597
{
598
   struct copy_context copy;
599
   GLuint i, this_nr_prims;
600
601
 
602
      /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
603
       * will rebase the elements to the basevertex, and we'll only
604
       * emit strings of prims with the same basevertex in one draw call.
605
       */
606
      for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
607
	   this_nr_prims++) {
608
	 if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
609
	    break;
610
      }
611
612
 
613
614
 
615
       */
616
      assert(ib);
617
618
 
619
      copy.array = arrays;
620
      copy.prim = &prim[i];
621
      copy.nr_prims = this_nr_prims;
622
      copy.ib = ib;
623
      copy.draw = draw;
624
      copy.limits = limits;
625
626
 
627
       */
628
      for (i = 0; i < ELT_TABLE_SIZE; i++)
629
	 copy.vert_cache[i].in = ~0;
630
631
 
632
      replay_elts(©);
633
      replay_finish(©);
634
   }
635
}
636