pass context pointer to _tnl_free_immediate(), removed backref pointer
[mesa.git] / src / mesa / tnl / t_imm_exec.c
1 /* $Id: t_imm_exec.c,v 1.39 2002/04/19 12:32:14 brianp 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 tnl/t_imm_exec.c
29 * \brief Setup to execute immediate-mode vertex data.
30 * \author Keith Whitwell
31 */
32
33 #include "glheader.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "enums.h"
37 #include "dlist.h"
38 #include "macros.h"
39 #include "mem.h"
40 #include "mmath.h"
41 #include "light.h"
42 #include "state.h"
43 #include "mtypes.h"
44
45 #include "math/m_matrix.h"
46 #include "math/m_xform.h"
47
48 #include "t_context.h"
49 #include "t_array_import.h"
50 #include "t_imm_alloc.h"
51 #include "t_imm_api.h"
52 #include "t_imm_debug.h"
53 #include "t_imm_dlist.h"
54 #include "t_imm_eval.h"
55 #include "t_imm_elt.h"
56 #include "t_imm_exec.h"
57 #include "t_imm_fixup.h"
58 #include "t_pipeline.h"
59
60
61
62 static void reset_input( GLcontext *ctx,
63 GLuint start,
64 GLuint beginstate,
65 GLuint savedbeginstate )
66 {
67 struct immediate *IM = TNL_CURRENT_IM(ctx);
68
69 /* Clear the dirty part of the flag array.
70 */
71 if (start < IM->Count+2)
72 MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start));
73
74 if (MESA_VERBOSE & VERBOSE_IMMEDIATE)
75 fprintf(stderr, "reset_input: IM(%d) new %x\n",
76 IM->id, beginstate);
77
78 IM->Start = start;
79 IM->Count = start;
80 IM->LastMaterial = start;
81 IM->BeginState = beginstate;
82 IM->SavedBeginState = savedbeginstate;
83 IM->TexSize = 0;
84 IM->MaterialOrMask = 0;
85
86 if (IM->MaterialMask)
87 IM->MaterialMask[IM->Start] = 0;
88
89 IM->ArrayEltFlags = ~ctx->Array._Enabled;
90 IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
91 IM->ArrayEltFlush = ctx->Array.LockCount ? FLUSH_ELT_LAZY : FLUSH_ELT_EAGER;
92 }
93
94 void _tnl_reset_exec_input( GLcontext *ctx,
95 GLuint start,
96 GLuint beginstate,
97 GLuint savedbeginstate )
98 {
99 TNLcontext *tnl = TNL_CONTEXT(ctx);
100 struct immediate *IM = TNL_CURRENT_IM(ctx);
101
102 reset_input( ctx, start, beginstate, savedbeginstate );
103
104 IM->CopyStart = start - tnl->ExecCopyCount;
105
106 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
107 if (tnl->ExecParity)
108 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
109
110 IM->LastPrimitive = IM->CopyStart;
111 }
112
113
114 void _tnl_reset_compile_input( GLcontext *ctx,
115 GLuint start,
116 GLuint beginstate,
117 GLuint savedbeginstate )
118 {
119 struct immediate *IM = TNL_CURRENT_IM(ctx);
120
121 reset_input( ctx, start, beginstate, savedbeginstate );
122 IM->CopyStart = start;
123 IM->LastPrimitive = IM->Start;
124 }
125
126
127 /**
128 * Copy the last specified normal, color, texcoord, edge flag, etc
129 * from the immediate struct into the ctx->Current attribute group.
130 */
131 void _tnl_copy_to_current( GLcontext *ctx, struct immediate *IM,
132 GLuint flag, GLuint count )
133 {
134 if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
135 _tnl_print_vert_flags("copy to current", flag);
136
137 /* XXX should be able to replace these conditions with a loop over
138 * the 16 vertex attributes.
139 */
140 if (flag & VERT_BIT_NORMAL)
141 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_NORMAL],
142 IM->Attrib[VERT_ATTRIB_NORMAL][count]);
143
144 if (flag & VERT_BIT_INDEX)
145 ctx->Current.Index = IM->Index[count];
146
147 if (flag & VERT_BIT_EDGEFLAG)
148 ctx->Current.EdgeFlag = IM->EdgeFlag[count];
149
150 if (flag & VERT_BIT_COLOR0) {
151 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR0],
152 IM->Attrib[VERT_ATTRIB_COLOR0][count]);
153 if (ctx->Light.ColorMaterialEnabled) {
154 _mesa_update_color_material( ctx,
155 ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
156 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
157 }
158 }
159
160 if (flag & VERT_BIT_COLOR1)
161 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR1],
162 IM->Attrib[VERT_ATTRIB_COLOR1][count]);
163
164 if (flag & VERT_BIT_FOG)
165 ctx->Current.Attrib[VERT_ATTRIB_FOG][0] = IM->Attrib[VERT_ATTRIB_FOG][count][0];
166
167 if (flag & VERT_BITS_TEX_ANY) {
168 GLuint i;
169 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
170 if (flag & VERT_BIT_TEX(i)) {
171 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_TEX0 + i],
172 IM->Attrib[VERT_ATTRIB_TEX0 + i][count]);
173 }
174 }
175 }
176
177 if (flag & VERT_BIT_MATERIAL) {
178 _mesa_update_material( ctx,
179 IM->Material[IM->LastMaterial],
180 IM->MaterialOrMask );
181
182 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
183 }
184 }
185
186
187
188 void _tnl_compute_orflag( struct immediate *IM, GLuint start )
189 {
190 GLuint count = IM->Count;
191 GLuint orflag = 0;
192 GLuint andflag = ~0U;
193 GLuint i;
194
195 IM->LastData = count-1;
196
197
198 /* Compute the flags for the whole buffer.
199 */
200 for (i = start ; i < count ; i++) {
201 andflag &= IM->Flag[i];
202 orflag |= IM->Flag[i];
203 }
204
205 /* It is possible there will be data in the buffer arising from
206 * calls like 'glNormal', 'glMaterial' that occur after the final
207 * glVertex, glEval, etc. Additionally, a buffer can consist of
208 * eg. a single glMaterial call, in which case IM->Start ==
209 * IM->Count, but the buffer is definitely not empty.
210 */
211 if (IM->Flag[i] & VERT_BITS_DATA) {
212 IM->LastData++;
213 orflag |= IM->Flag[i];
214 }
215
216 IM->Flag[IM->LastData+1] |= VERT_BIT_END_VB;
217 IM->CopyAndFlag = IM->AndFlag = andflag;
218 IM->OrFlag = orflag;
219 IM->CopyOrFlag = orflag;
220 IM->Evaluated = 0;
221 }
222
223
224 /**
225 * This is where the vertex data is transfered from the 'struct immediate
226 * into the 'struct vertex_buffer'.
227 *
228 * Note: The 'start' member of the GLvector structs is now redundant
229 * because we always re-transform copied vertices, and the vectors
230 * below are set up so that the first copied vertex (if any) appears
231 * at position zero.
232 */
233 static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
234 {
235 TNLcontext *tnl = TNL_CONTEXT(ctx);
236 struct vertex_buffer *VB = &tnl->vb;
237 struct vertex_arrays *tmp = &tnl->imm_inputs;
238 GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
239 const GLuint start = IM->CopyStart;
240 const GLuint count = IM->Count - start;
241
242 /* TODO: optimize the case where nothing has changed. (Just bind
243 * tmp to vb).
244 */
245
246 /* Setup constant data in the VB.
247 */
248 VB->Count = count;
249 VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
250 VB->import_data = NULL;
251 VB->importable_data = 0;
252
253 /* Need an IM->FirstPrimitive?
254 */
255 VB->Primitive = IM->Primitive + IM->CopyStart;
256 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
257 VB->FirstPrimitive = 0;
258
259 VB->Flag = IM->Flag + start;
260
261 /* TexCoordPtr's are zeroed in loop below.
262 */
263 VB->NormalPtr = NULL;
264 VB->NormalLengthPtr = NULL;
265 VB->EdgeFlag = NULL;
266 VB->IndexPtr[0] = NULL;
267 VB->IndexPtr[1] = NULL;
268 VB->ColorPtr[0] = NULL;
269 VB->ColorPtr[1] = NULL;
270 VB->SecondaryColorPtr[0] = NULL;
271 VB->SecondaryColorPtr[1] = NULL;
272 VB->Elts = NULL;
273 VB->MaterialMask = NULL;
274 VB->Material = NULL;
275
276 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
277 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
278 /* _tnl_print_vert_flags("inputs", inputs); */
279
280 /* Setup the initial values of array pointers in the vb.
281 */
282 if (inputs & VERT_BIT_POS) {
283 tmp->Obj.data = IM->Attrib[VERT_ATTRIB_POS] + start;
284 tmp->Obj.start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_POS] + start);
285 tmp->Obj.count = count;
286 VB->ObjPtr = &tmp->Obj;
287 if ((IM->CopyOrFlag & VERT_BITS_OBJ_234) == VERT_BITS_OBJ_234)
288 tmp->Obj.size = 4;
289 else if ((IM->CopyOrFlag & VERT_BITS_OBJ_234) == VERT_BITS_OBJ_23)
290 tmp->Obj.size = 3;
291 else
292 tmp->Obj.size = 2;
293 }
294
295 if (inputs & VERT_BIT_NORMAL) {
296 tmp->Normal.data = IM->Attrib[VERT_ATTRIB_NORMAL] + start;
297 tmp->Normal.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_NORMAL] + start);
298 tmp->Normal.count = count;
299 VB->NormalPtr = &tmp->Normal;
300 if (IM->NormalLengthPtr)
301 VB->NormalLengthPtr = IM->NormalLengthPtr + start;
302 }
303
304 if (inputs & VERT_BIT_INDEX) {
305 tmp->Index.count = count;
306 tmp->Index.data = IM->Index + start;
307 tmp->Index.start = IM->Index + start;
308 VB->IndexPtr[0] = &tmp->Index;
309 }
310
311 if (inputs & VERT_BIT_FOG) {
312 tmp->FogCoord.data = IM->Attrib[VERT_ATTRIB_FOG] + start;
313 tmp->FogCoord.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_FOG] + start);
314 tmp->FogCoord.count = count;
315 VB->FogCoordPtr = &tmp->FogCoord;
316 }
317
318 if (inputs & VERT_BIT_COLOR1) {
319 tmp->SecondaryColor.Ptr = IM->Attrib[VERT_ATTRIB_COLOR1] + start;
320 VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
321 }
322
323 if (inputs & VERT_BIT_EDGEFLAG) {
324 VB->EdgeFlag = IM->EdgeFlag + start;
325 }
326
327 if (inputs & VERT_BIT_COLOR0) {
328 if (IM->CopyOrFlag & VERT_BIT_COLOR0) {
329 tmp->Color.Ptr = IM->Attrib[VERT_ATTRIB_COLOR0] + start;
330 tmp->Color.StrideB = 4 * sizeof(GLfloat);
331 tmp->Color.Flags = 0;
332 }
333 else {
334 tmp->Color.Ptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
335 tmp->Color.StrideB = 0;
336 tmp->Color.Flags = CA_CLIENT_DATA; /* hack */
337 VB->import_source = IM;
338 VB->importable_data |= VERT_BIT_COLOR0;
339 VB->import_data = _tnl_upgrade_current_data;
340 }
341 VB->ColorPtr[0] = &tmp->Color;
342 }
343
344 if (inputs & VERT_BITS_TEX_ANY) {
345 GLuint i;
346 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
347 VB->TexCoordPtr[i] = NULL;
348 if (inputs & VERT_BIT_TEX(i)) {
349 tmp->TexCoord[i].count = count;
350 tmp->TexCoord[i].data = IM->Attrib[VERT_ATTRIB_TEX0 + i] + start;
351 tmp->TexCoord[i].start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_TEX0 + i] + start);
352 tmp->TexCoord[i].size = 2;
353 if (IM->TexSize & TEX_SIZE_3(i)) {
354 tmp->TexCoord[i].size = 3;
355 if (IM->TexSize & TEX_SIZE_4(i))
356 tmp->TexCoord[i].size = 4;
357 }
358 VB->TexCoordPtr[i] = &tmp->TexCoord[i];
359 }
360 }
361 }
362
363 if ((inputs & IM->OrFlag & VERT_BIT_MATERIAL) && IM->Material) {
364 VB->MaterialMask = IM->MaterialMask + start;
365 VB->Material = IM->Material + start;
366 }
367
368 /* GL_NV_vertex_program */
369 if (ctx->VertexProgram.Enabled) {
370 GLuint attr;
371 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
372 tmp->Attribs[attr].count = count;
373 tmp->Attribs[attr].data = IM->Attrib[attr] + start;
374 tmp->Attribs[attr].start = (GLfloat *) (IM->Attrib[attr] + start);
375 tmp->Attribs[attr].size = 4;
376 VB->AttribPtr[attr] = &(tmp->Attribs[attr]);
377 }
378 }
379 }
380
381
382
383
384 /**
385 * Called by exec_vert_cassette, execute_compiled_cassette, but not
386 * exec_elt_cassette.
387 */
388 void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
389 {
390 TNLcontext *tnl = TNL_CONTEXT(ctx);
391
392 _tnl_vb_bind_immediate( ctx, IM );
393
394 if (IM->OrFlag & VERT_BITS_EVAL_ANY)
395 _tnl_eval_immediate( ctx, IM );
396
397 /* Invalidate all stored data before and after run:
398 */
399 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
400 tnl->Driver.RunPipeline( ctx );
401 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
402
403 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
404 }
405
406
407 /**
408 * Called for regular vertex cassettes.
409 */
410 static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
411 {
412 /* fprintf(stderr, "%s\n", __FUNCTION__); */
413
414 if (IM->FlushElt) {
415 /* Orflag is computed twice, but only reach this code if app is
416 * using a mixture of glArrayElement() and glVertex() while
417 * arrays are locked (else would be in exec_elt_cassette now).
418 */
419 ASSERT(ctx->Array.LockCount);
420 ASSERT(IM->FlushElt == FLUSH_ELT_LAZY);
421 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->Count );
422 _tnl_compute_orflag( IM, IM->CopyStart );
423 }
424
425 _tnl_fixup_input( ctx, IM );
426 /* _tnl_print_cassette( IM ); */
427 _tnl_run_cassette( ctx, IM );
428 }
429
430
431 /* Called for pure, locked VERT_BIT_ELT cassettes instead of
432 * _tnl_run_cassette.
433 */
434 static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
435 {
436 TNLcontext *tnl = TNL_CONTEXT(ctx);
437 struct vertex_buffer *VB = &tnl->vb;
438
439 /* fprintf(stderr, "%s\n", __FUNCTION__); */
440
441 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
442
443 /* Take only elements and primitive information from the immediate:
444 */
445 VB->Elts = IM->Elt + IM->CopyStart;
446 VB->Primitive = IM->Primitive + IM->CopyStart;
447 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
448 VB->FirstPrimitive = 0;
449
450 /* Run the pipeline. No input changes as a result of this action.
451 */
452 tnl->Driver.RunPipeline( ctx );
453
454 /* Still need to update current values:
455 */
456 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
457 _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
458 _tnl_copy_to_current( ctx, IM, ctx->Array._Enabled, IM->LastData );
459 }
460 }
461
462
463 static void
464 exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
465 {
466 if (IM->FlushElt)
467 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->CopyStart );
468
469 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
470 }
471
472
473
474 /**
475 * Called for all cassettes when not compiling or playing a display
476 * list.
477 */
478 void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
479 {
480 TNLcontext *tnl = TNL_CONTEXT(ctx);
481
482 _tnl_compute_orflag( IM, IM->Start );
483 _tnl_copy_immediate_vertices( ctx, IM );
484 _tnl_get_exec_copy_verts( ctx, IM );
485
486 if (tnl->pipeline.build_state_changes)
487 _tnl_validate_pipeline( ctx );
488
489 if (IM->CopyStart == IM->Count) {
490 exec_empty_cassette( ctx, IM );
491 }
492 else if ((IM->CopyOrFlag & VERT_BITS_DATA) == VERT_BIT_ELT &&
493 ctx->Array.LockCount &&
494 ctx->Array.Vertex.Enabled) {
495 exec_elt_cassette( ctx, IM );
496 }
497 else {
498 exec_vert_cassette( ctx, IM );
499 }
500
501 /* Only reuse the immediate if there are no copied vertices living
502 * inside it:
503 */
504 {
505 GLuint begin_state = IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
506 GLuint saved_begin_state = IM->SavedBeginState;
507
508 if (--IM->ref_count != 0) {
509 IM = _tnl_alloc_immediate( ctx );
510 SET_IMMEDIATE( ctx, IM );
511 }
512
513 IM->ref_count++;
514
515 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS,
516 begin_state, saved_begin_state );
517 }
518
519 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
520 ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
521
522 /* fprintf(stderr, "%s: NeedFlush: %x\n", __FUNCTION__, */
523 /* ctx->Driver.NeedFlush); */
524 }
525
526
527
528
529 /**
530 * Setup vector pointers that will be used to bind immediates to VB's.
531 */
532 void _tnl_imm_init( GLcontext *ctx )
533 {
534 TNLcontext *tnl = TNL_CONTEXT(ctx);
535 struct vertex_arrays *tmp = &tnl->imm_inputs;
536 GLuint i;
537 static int firsttime = 1;
538
539 if (firsttime) {
540 firsttime = 0;
541 _tnl_imm_elt_init();
542 }
543
544 ctx->swtnl_im = _tnl_alloc_immediate( ctx );
545 TNL_CURRENT_IM(ctx)->ref_count++;
546
547 tnl->ExecCopyTexSize = 0;
548 tnl->ExecCopyCount = 0;
549 tnl->ExecCopySource = 0;
550
551 TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
552
553 _mesa_vector4f_init( &tmp->Obj, 0, 0 );
554 _mesa_vector4f_init( &tmp->Normal, 0, 0 );
555
556 tmp->Color.Ptr = NULL;
557 tmp->Color.Type = GL_FLOAT;
558 tmp->Color.Size = 4;
559 tmp->Color.Stride = 0;
560 tmp->Color.StrideB = 4 * sizeof(GLfloat);
561 tmp->Color.Flags = 0;
562
563 tmp->SecondaryColor.Ptr = NULL;
564 tmp->SecondaryColor.Type = GL_FLOAT;
565 tmp->SecondaryColor.Size = 4;
566 tmp->SecondaryColor.Stride = 0;
567 tmp->SecondaryColor.StrideB = 4 * sizeof(GLfloat);
568 tmp->SecondaryColor.Flags = 0;
569
570 _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
571 _mesa_vector1ui_init( &tmp->Index, 0, 0 );
572 _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
573
574 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
575 _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
576
577 /* Install the first immediate. Intially outside begin/end.
578 */
579 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
580 tnl->ReplayHardBeginEnd = 0;
581
582 _tnl_imm_vtxfmt_init( ctx );
583 }
584
585
586 /**
587 * Deallocate the immediate-mode buffer for the given context, if
588 * its reference count goes to zero.
589 */
590 void _tnl_imm_destroy( GLcontext *ctx )
591 {
592 if (TNL_CURRENT_IM(ctx)) {
593 TNL_CURRENT_IM(ctx)->ref_count--;
594 if (TNL_CURRENT_IM(ctx)->ref_count == 0)
595 _tnl_free_immediate( ctx, TNL_CURRENT_IM(ctx) );
596 /*
597 * Don't use SET_IMMEDIATE here, or else we'll whack the
598 * _tnl_CurrentInput pointer - not good when another
599 * context has already been made current.
600 * So we just set the context's own tnl immediate pointer
601 * to 0.
602 */
603 ctx->swtnl_im = NULL;
604 }
605 }