Fix propogation of material values in VB's that don't reach the lighting
[mesa.git] / src / mesa / tnl / t_array_api.c
1 /* $Id: t_array_api.c,v 1.6 2001/02/15 01:33:52 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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 * Authors:
27 * Keith Whitwell <keithw@valinux.com>
28 */
29
30 #include "glheader.h"
31 #include "api_validate.h"
32 #include "context.h"
33 #include "macros.h"
34 #include "mmath.h"
35 #include "mem.h"
36 #include "state.h"
37 #include "mtypes.h"
38
39 #include "array_cache/acache.h"
40
41 #include "t_array_api.h"
42 #include "t_array_import.h"
43 #include "t_imm_api.h"
44 #include "t_imm_exec.h"
45 #include "t_context.h"
46 #include "t_pipeline.h"
47
48 static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
49 GLsizei count )
50 {
51 /* Need to produce immediate structs, either for compiling or
52 * because the array range is too large to process in a single
53 * VB. In GL_EXECUTE mode, this introduces two redundant
54 * operations: producing the flag array and computing the orflag
55 * of the flag array.
56 */
57 #if 1
58 if (_tnl_hard_begin( ctx, mode )) {
59 GLuint j;
60 for (j = 0 ; j < count ; ) {
61 struct immediate *IM = TNL_CURRENT_IM(ctx);
62 GLuint nr = MIN2( IMM_MAXDATA - IM->Start, count - j );
63 GLuint sf = IM->Flag[IM->Start];
64
65 _tnl_fill_immediate_drawarrays( ctx, IM, j, j+nr );
66
67 if (j == 0) IM->Flag[IM->Start] |= sf;
68
69 IM->Count = IM->Start + nr;
70 j += nr;
71
72 if (j == count)
73 _tnl_end( ctx );
74
75 _tnl_flush_immediate( IM );
76 }
77 }
78 #else
79 /* Simple alternative to above code.
80 */
81 if (_tnl_hard_begin( ctx, mode ))
82 {
83 GLuint i;
84 for (i=start;i<count;i++) {
85 _tnl_array_element( ctx, i );
86 }
87 _tnl_end( ctx );
88 }
89 #endif
90 }
91
92
93 static void _tnl_draw_elements( GLcontext *ctx, GLenum mode, GLsizei count,
94 const GLuint *indices)
95 {
96 #if 1
97 /* Optimized code that fakes the effect of calling
98 * _tnl_array_element for each index in the list.
99 */
100 if (_tnl_hard_begin( ctx, mode )) {
101 GLuint i,j;
102 for (j = 0 ; j < count ; ) {
103 struct immediate *IM = TNL_CURRENT_IM(ctx);
104 GLuint start = IM->Start;
105 GLuint nr = MIN2( IMM_MAXDATA - start, count - j ) + start;
106 GLuint sf = IM->Flag[start];
107 IM->FlushElt |= 1;
108
109 for (i = start ; i < nr ; i++) {
110 IM->Elt[i] = (GLuint) *indices++;
111 IM->Flag[i] = VERT_ELT;
112 }
113
114 if (j == 0) IM->Flag[start] |= sf;
115
116 IM->Count = nr;
117 j += nr - start;
118
119 if (j == count)
120 _tnl_end( ctx );
121
122 _tnl_flush_immediate( IM );
123 }
124 }
125 #else
126 /* Simple version of the above code.
127 */
128 if (_tnl_hard_begin(ctx, mode)) {
129 GLuint i;
130 for (i = 0 ; i < count ; i++)
131 _tnl_array_element( ctx, indices[i] );
132 _tnl_end( ctx );
133 }
134 #endif
135 }
136
137
138 static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
139 GLuint start, GLuint end,
140 GLsizei count, const GLuint *indices )
141
142 {
143 TNLcontext *tnl = TNL_CONTEXT(ctx);
144 FLUSH_CURRENT( ctx, 0 );
145
146 _tnl_vb_bind_arrays( ctx, start, end );
147
148 tnl->vb.FirstPrimitive = 0;
149 tnl->vb.Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
150 tnl->vb.PrimitiveLength[0] = count;
151 tnl->vb.Elts = (GLuint *)indices;
152
153 if (ctx->Array.LockCount)
154 _tnl_run_pipeline( ctx );
155 else {
156 /* Note that arrays may have changed before/after execution.
157 */
158 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
159 _tnl_run_pipeline( ctx );
160 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
161 }
162 }
163
164
165
166
167 void
168 _tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
169 {
170 GET_CURRENT_CONTEXT(ctx);
171 TNLcontext *tnl = TNL_CONTEXT(ctx);
172 struct vertex_buffer *VB = &tnl->vb;
173
174 /* Check arguments, etc.
175 */
176 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
177 return;
178
179 if (tnl->pipeline.build_state_changes)
180 _tnl_validate_pipeline( ctx );
181
182 if (!ctx->CompileFlag && count - start < ctx->Const.MaxArrayLockSize) {
183 FLUSH_CURRENT( ctx, 0 );
184
185 if (ctx->Array.LockCount)
186 {
187 if (start < ctx->Array.LockFirst) start = ctx->Array.LockFirst;
188 if (count > ctx->Array.LockCount) count = ctx->Array.LockCount;
189 if (start >= count) return;
190
191 /* Locked drawarrays. Reuse any previously transformed data.
192 */
193 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
194 VB->FirstPrimitive = start;
195 VB->Primitive[start] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
196 VB->PrimitiveLength[start] = count - start;
197 _tnl_run_pipeline( ctx );
198 } else {
199 /* The arrays are small enough to fit in a single VB; just bind
200 * them and go. Any untransformed data will be copied on
201 * clipping.
202 *
203 * Invalidate any locked data dependent on these arrays.
204 */
205 _tnl_vb_bind_arrays( ctx, start, count );
206 VB->FirstPrimitive = 0;
207 VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
208 VB->PrimitiveLength[0] = count - start;
209 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
210 _tnl_run_pipeline( ctx );
211 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
212 }
213 }
214 else if (!ctx->CompileFlag && mode == GL_TRIANGLE_STRIP) {
215 int bufsz = (ctx->Const.MaxArrayLockSize - 2) & ~1;
216 int j, nr;
217
218 FLUSH_CURRENT( ctx, 0 );
219
220 /* TODO: other non-fan primitives.
221 */
222 for (j = start ; j < count - 2; j += nr - 2 ) {
223 nr = MIN2( bufsz, count - j );
224 _tnl_vb_bind_arrays( ctx, j, j + nr );
225 VB->FirstPrimitive = 0;
226 VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
227 VB->PrimitiveLength[0] = nr;
228 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
229 _tnl_run_pipeline( ctx );
230 tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
231 }
232 } else {
233 fallback_drawarrays( ctx, mode, start, count );
234 }
235 }
236
237
238 void
239 _tnl_DrawRangeElements(GLenum mode,
240 GLuint start, GLuint end,
241 GLsizei count, GLenum type, const GLvoid *indices)
242 {
243 GET_CURRENT_CONTEXT(ctx);
244 TNLcontext *tnl = TNL_CONTEXT(ctx);
245 GLuint *ui_indices;
246
247 /* Check arguments, etc.
248 */
249 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
250 type, indices ))
251 return;
252
253 if (tnl->pipeline.build_state_changes)
254 _tnl_validate_pipeline( ctx );
255
256 ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
257 count, type, indices );
258
259
260 if (ctx->Array.LockCount) {
261 /* Are the arrays already locked? If so we currently have to look
262 * at the whole locked range.
263 */
264 if (start >= ctx->Array.LockFirst && end <= ctx->Array.LockCount)
265 _tnl_draw_range_elements( ctx, mode,
266 ctx->Array.LockFirst,
267 ctx->Array.LockCount,
268 count, ui_indices );
269 else {
270 /* The spec says referencing elements outside the locked
271 * range is undefined. I'm going to make it a noop this time
272 * round, maybe come up with something beter before 3.6.
273 *
274 * May be able to get away with just setting LockCount==0,
275 * though this raises the problems of dependent state. May
276 * have to call glUnlockArrays() directly?
277 *
278 * Or scan the list and replace bad indices?
279 */
280 gl_problem( ctx,
281 "DrawRangeElements references "
282 "elements outside locked range.");
283 }
284 }
285 else if (end + 1 - start < ctx->Const.MaxArrayLockSize) {
286 /* The arrays aren't locked but we can still fit them inside a
287 * single vertexbuffer.
288 */
289 _tnl_draw_range_elements( ctx, mode, start, end + 1, count, ui_indices );
290 } else {
291 /* Range is too big to optimize:
292 */
293 _tnl_draw_elements( ctx, mode, count, ui_indices );
294 }
295 }
296
297
298
299 void
300 _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
301 const GLvoid *indices)
302 {
303 GET_CURRENT_CONTEXT(ctx);
304 TNLcontext *tnl = TNL_CONTEXT(ctx);
305 GLuint *ui_indices;
306
307 /* Check arguments, etc.
308 */
309 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
310 return;
311
312 if (tnl->pipeline.build_state_changes)
313 _tnl_validate_pipeline( ctx );
314
315 ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
316 count, type, indices );
317
318 if (ctx->Array.LockCount) {
319 _tnl_draw_range_elements( ctx, mode,
320 ctx->Array.LockFirst,
321 ctx->Array.LockCount,
322 count, ui_indices );
323 }
324 else {
325 /* Scan the index list and see if we can use the locked path anyway.
326 */
327 GLuint max_elt = 0;
328 GLuint i;
329
330 for (i = 0 ; i < count ; i++)
331 if (ui_indices[i] > max_elt) max_elt = ui_indices[i];
332
333 if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */
334 max_elt < count) /* do we want to use it? */
335 _tnl_draw_range_elements( ctx, mode, 0, max_elt+1, count, ui_indices );
336 else
337 _tnl_draw_elements( ctx, mode, count, ui_indices );
338 }
339 }
340
341
342 void _tnl_array_init( GLcontext *ctx )
343 {
344 TNLcontext *tnl = TNL_CONTEXT(ctx);
345 struct vertex_arrays *tmp = &tnl->array_inputs;
346 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
347 GLuint i;
348
349 vfmt->DrawArrays = _tnl_DrawArrays;
350 vfmt->DrawElements = _tnl_DrawElements;
351 vfmt->DrawRangeElements = _tnl_DrawRangeElements;
352
353 /* Setup vector pointers that will be used to bind arrays to VB's.
354 */
355 gl_vector4f_init( &tmp->Obj, 0, 0 );
356 gl_vector3f_init( &tmp->Normal, 0, 0 );
357 #if CHAN_TYPE == GL_UNSIGNED_BYTE
358 gl_vector4ub_init( &tmp->Color, 0, 0 );
359 gl_vector4ub_init( &tmp->SecondaryColor, 0, 0 );
360 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
361 gl_vector4us_init( &tmp->Color, 0, 0 );
362 gl_vector4us_init( &tmp->SecondaryColor, 0, 0 );
363 #elif CHAN_TYPE == GL_FLOAT
364 gl_vector4f_init( &tmp->Color, 0, 0 );
365 gl_vector4f_init( &tmp->SecondaryColor, 0, 0 );
366 #endif
367 gl_vector1f_init( &tmp->FogCoord, 0, 0 );
368 gl_vector1ui_init( &tmp->Index, 0, 0 );
369 gl_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
370
371 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
372 gl_vector4f_init( &tmp->TexCoord[i], 0, 0);
373
374 tnl->tmp_primitive = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
375 tnl->tmp_primitive_length = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
376 }
377
378
379 void _tnl_array_destroy( GLcontext *ctx )
380 {
381 TNLcontext *tnl = TNL_CONTEXT(ctx);
382 if (tnl->tmp_primitive_length) FREE(tnl->tmp_primitive_length);
383 if (tnl->tmp_primitive) FREE(tnl->tmp_primitive);
384 }