Subversion Repositories shark

Rev

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

Rev Author Line No. Line
56 pj 1
/* $Id: t_array_api.c,v 1.1 2003-02-28 11:48:06 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
/**
28
 * \file vpexec.c
29
 * \brief Vertex array API functions (glDrawArrays, etc)
30
 * \author Keith Whitwell
31
 */
32
 
33
#include "glheader.h"
34
#include "api_validate.h"
35
#include "context.h"
36
#include "imports.h"
37
#include "macros.h"
38
#include "mmath.h"
39
#include "mtypes.h"
40
#include "state.h"
41
 
42
#include "array_cache/acache.h"
43
 
44
#include "t_array_api.h"
45
#include "t_array_import.h"
46
#include "t_imm_api.h"
47
#include "t_imm_exec.h"
48
#include "t_context.h"
49
#include "t_pipeline.h"
50
 
51
static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
52
                                 GLsizei count )
53
{
54
   if (_tnl_hard_begin( ctx, mode )) {
55
      GLint i;
56
      for (i = start; i < count; i++)
57
         glArrayElement( i );
58
      glEnd();
59
   }
60
}
61
 
62
 
63
static void fallback_drawelements( GLcontext *ctx, GLenum mode, GLsizei count,
64
                                   const GLuint *indices)
65
{
66
   if (_tnl_hard_begin(ctx, mode)) {
67
      GLint i;
68
      for (i = 0 ; i < count ; i++)
69
         glArrayElement( indices[i] );
70
      glEnd();
71
   }
72
}
73
 
74
 
75
static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
76
                                      GLuint start, GLuint end,
77
                                      GLsizei count, const GLuint *indices )
78
 
79
{
80
   TNLcontext *tnl = TNL_CONTEXT(ctx);
81
   FLUSH_CURRENT( ctx, 0 );
82
 
83
   /*  _mesa_debug(ctx, "%s\n", __FUNCTION__); */
84
   if (tnl->pipeline.build_state_changes)
85
      _tnl_validate_pipeline( ctx );
86
 
87
   _tnl_vb_bind_arrays( ctx, start, end );
88
 
89
   tnl->vb.FirstPrimitive = 0;
90
   tnl->vb.Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
91
   tnl->vb.PrimitiveLength[0] = count;
92
   tnl->vb.Elts = (GLuint *)indices;
93
 
94
   if (ctx->Array.LockCount)
95
      tnl->Driver.RunPipeline( ctx );
96
   else {
97
      /* Note that arrays may have changed before/after execution.
98
       */
99
      tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
100
      tnl->Driver.RunPipeline( ctx );
101
      tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
102
   }
103
}
104
 
105
 
106
 
107
/**
108
 * Called via the GL API dispatcher.
109
 */
110
void
111
_tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
112
{
113
   GET_CURRENT_CONTEXT(ctx);
114
   TNLcontext *tnl = TNL_CONTEXT(ctx);
115
   struct vertex_buffer *VB = &tnl->vb;
116
   GLuint thresh = (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) ? 30 : 10;
117
 
118
   if (MESA_VERBOSE & VERBOSE_API)
119
      _mesa_debug(NULL, "_tnl_DrawArrays %d %d\n", start, count);
120
 
121
   /* Check arguments, etc.
122
    */
123
   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
124
      return;
125
 
126
   if (tnl->pipeline.build_state_changes)
127
      _tnl_validate_pipeline( ctx );
128
 
129
   if (ctx->CompileFlag) {
130
      fallback_drawarrays( ctx, mode, start, start + count );
131
   }    
132
   else if (!ctx->Array.LockCount && (GLuint) count < thresh) {
133
      /* Small primitives: attempt to share a vb (at the expense of
134
       * using the immediate interface).
135
      */
136
      fallback_drawarrays( ctx, mode, start, start + count );
137
   }
138
   else if (ctx->Array.LockCount &&
139
            count < (GLint) ctx->Const.MaxArrayLockSize) {
140
 
141
      /* Locked primitives which can fit in a single vertex buffer:
142
       */
143
      FLUSH_CURRENT( ctx, 0 );
144
 
145
      if (start < (GLint) ctx->Array.LockFirst)
146
         start = ctx->Array.LockFirst;
147
      if (start + count > (GLint) ctx->Array.LockCount)
148
         count = ctx->Array.LockCount - start;
149
 
150
      /* Locked drawarrays.  Reuse any previously transformed data.
151
       */
152
      _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
153
      VB->FirstPrimitive = start;
154
      VB->Primitive[start] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
155
      VB->PrimitiveLength[start] = count;
156
      tnl->Driver.RunPipeline( ctx );
157
   }
158
   else {
159
      int bufsz = 256;          /* Use a small buffer for cache goodness */
160
      int j, nr;
161
      int minimum, modulo, skip;
162
 
163
      /* Large primitives requiring decomposition to multiple vertex
164
       * buffers:
165
       */
166
      switch (mode) {
167
      case GL_POINTS:
168
         minimum = 0;
169
         modulo = 1;
170
         skip = 0;
171
      case GL_LINES:
172
         minimum = 1;
173
         modulo = 2;
174
         skip = 1;
175
      case GL_LINE_STRIP:
176
         minimum = 1;
177
         modulo = 1;
178
         skip = 0;
179
         break;
180
      case GL_TRIANGLES:
181
         minimum = 2;
182
         modulo = 3;
183
         skip = 2;
184
         break;
185
      case GL_TRIANGLE_STRIP:
186
         minimum = 2;
187
         modulo = 1;
188
         skip = 0;
189
         break;
190
      case GL_QUADS:
191
         minimum = 3;
192
         modulo = 4;
193
         skip = 3;
194
         break;
195
      case GL_QUAD_STRIP:
196
         minimum = 3;
197
         modulo = 2;
198
         skip = 0;
199
         break;
200
      case GL_LINE_LOOP:
201
      case GL_TRIANGLE_FAN:
202
      case GL_POLYGON:
203
      default:
204
         /* Primitives requiring a copied vertex (fan-like primitives)
205
          * must use the slow path if they cannot fit in a single
206
          * vertex buffer.  
207
          */
208
         if (count < (GLint) ctx->Const.MaxArrayLockSize) {
209
            bufsz = ctx->Const.MaxArrayLockSize;
210
            minimum = 0;
211
            modulo = 1;
212
            skip = 0;
213
         }
214
         else {
215
            fallback_drawarrays( ctx, mode, start, start + count );
216
            return;
217
         }
218
      }
219
 
220
      FLUSH_CURRENT( ctx, 0 );
221
 
222
      bufsz -= bufsz % modulo;
223
      bufsz -= minimum;
224
      count += start;
225
 
226
      for (j = start + minimum ; j < count ; j += nr + skip ) {
227
 
228
         nr = MIN2( bufsz, count - j );
229
 
230
         _tnl_vb_bind_arrays( ctx, j - minimum, j + nr );
231
 
232
         VB->FirstPrimitive = 0;
233
         VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
234
         VB->PrimitiveLength[0] = nr + minimum;
235
         tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
236
         tnl->Driver.RunPipeline( ctx );
237
         tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
238
      }
239
   }
240
}
241
 
242
 
243
/**
244
 * Called via the GL API dispatcher.
245
 */
246
void
247
_tnl_DrawRangeElements(GLenum mode,
248
                       GLuint start, GLuint end,
249
                       GLsizei count, GLenum type, const GLvoid *indices)
250
{
251
   GET_CURRENT_CONTEXT(ctx);
252
   GLuint *ui_indices;
253
 
254
   if (MESA_VERBOSE & VERBOSE_API)
255
      _mesa_debug(NULL, "_tnl_DrawRangeElements %d %d %d\n", start, end, count);
256
 
257
   /* Check arguments, etc.
258
    */
259
   if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
260
                                          type, indices ))
261
      return;
262
 
263
   ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
264
                                               count, type, indices );
265
 
266
 
267
   if (ctx->CompileFlag) {
268
      /* Can't do anything when compiling:
269
       */
270
      fallback_drawelements( ctx, mode, count, ui_indices );
271
   }
272
   else if (ctx->Array.LockCount) {
273
      /* Are the arrays already locked?  If so we currently have to look
274
       * at the whole locked range.
275
       */
276
      if (start >= ctx->Array.LockFirst && end <= ctx->Array.LockCount)
277
         _tnl_draw_range_elements( ctx, mode,
278
                                   ctx->Array.LockFirst,
279
                                   ctx->Array.LockCount,
280
                                   count, ui_indices );
281
      else {
282
         /* The spec says referencing elements outside the locked
283
          * range is undefined.  I'm going to make it a noop this time
284
          * round, maybe come up with something beter before 3.6.
285
          *
286
          * May be able to get away with just setting LockCount==0,
287
          * though this raises the problems of dependent state.  May
288
          * have to call glUnlockArrays() directly?
289
          *
290
          * Or scan the list and replace bad indices?
291
          */
292
         _mesa_problem( ctx,
293
                     "DrawRangeElements references "
294
                     "elements outside locked range.");
295
      }
296
   }
297
   else if (end + 1 - start < ctx->Const.MaxArrayLockSize) {
298
      /* The arrays aren't locked but we can still fit them inside a
299
       * single vertexbuffer.
300
       */
301
      _tnl_draw_range_elements( ctx, mode, start, end + 1, count, ui_indices );
302
   } else {
303
      /* Range is too big to optimize:
304
       */
305
      fallback_drawelements( ctx, mode, count, ui_indices );
306
   }
307
}
308
 
309
 
310
 
311
/**
312
 * Called via the GL API dispatcher.
313
 */
314
void
315
_tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
316
                  const GLvoid *indices)
317
{
318
   GET_CURRENT_CONTEXT(ctx);
319
   GLuint *ui_indices;
320
 
321
   if (MESA_VERBOSE & VERBOSE_API)
322
      _mesa_debug(NULL, "_tnl_DrawElements %d\n", count);
323
 
324
   /* Check arguments, etc.
325
    */
326
   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
327
      return;
328
 
329
   ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
330
                                               count, type, indices );
331
 
332
   if (ctx->CompileFlag) {
333
      /* Can't do anything when compiling:
334
       */
335
      fallback_drawelements( ctx, mode, count, ui_indices );
336
   }
337
   else if (ctx->Array.LockCount) {
338
      _tnl_draw_range_elements( ctx, mode,
339
                                ctx->Array.LockFirst,
340
                                ctx->Array.LockCount,
341
                                count, ui_indices );
342
   }
343
   else {
344
      /* Scan the index list and see if we can use the locked path anyway.
345
       */
346
      GLuint max_elt = 0;
347
      GLint i;
348
 
349
      for (i = 0 ; i < count ; i++)
350
         if (ui_indices[i] > max_elt)
351
            max_elt = ui_indices[i];
352
 
353
      if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */
354
          max_elt < (GLuint) count)                /* do we want to use it? */
355
         _tnl_draw_range_elements( ctx, mode, 0, max_elt+1, count, ui_indices );
356
      else
357
         fallback_drawelements( ctx, mode, count, ui_indices );
358
   }
359
}
360
 
361
 
362
/**
363
 * Initialize context's vertex array fields.  Called during T 'n L context
364
 * creation.
365
 */
366
void _tnl_array_init( GLcontext *ctx )
367
{
368
   TNLcontext *tnl = TNL_CONTEXT(ctx);
369
   struct vertex_arrays *tmp = &tnl->array_inputs;
370
   GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
371
   GLuint i;
372
 
373
   vfmt->DrawArrays = _tnl_DrawArrays;
374
   vfmt->DrawElements = _tnl_DrawElements;
375
   vfmt->DrawRangeElements = _tnl_DrawRangeElements;
376
 
377
   /* Setup vector pointers that will be used to bind arrays to VB's.
378
    */
379
   _mesa_vector4f_init( &tmp->Obj, 0, 0 );
380
   _mesa_vector4f_init( &tmp->Normal, 0, 0 );  
381
   _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
382
   _mesa_vector1ui_init( &tmp->Index, 0, 0 );
383
   _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
384
 
385
   for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
386
      _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
387
 
388
   tnl->tmp_primitive = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
389
   tnl->tmp_primitive_length = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
390
}
391
 
392
 
393
/**
394
 * Destroy the context's vertex array stuff.
395
 * Called during T 'n L context destruction.
396
 */
397
void _tnl_array_destroy( GLcontext *ctx )
398
{
399
   TNLcontext *tnl = TNL_CONTEXT(ctx);
400
   if (tnl->tmp_primitive_length) FREE(tnl->tmp_primitive_length);
401
   if (tnl->tmp_primitive) FREE(tnl->tmp_primitive);
402
}