Allow different max texture sizes for 1/2D, 3D and cube maps.
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.20 2001/06/04 16:09:28 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
31 #include "glheader.h"
32 #include "context.h"
33 #include "dlist.h"
34 #include "debug.h"
35 #include "mmath.h"
36 #include "mem.h"
37 #include "state.h"
38
39 #include "t_context.h"
40 #include "t_imm_api.h"
41 #include "t_imm_elt.h"
42 #include "t_imm_alloc.h"
43 #include "t_imm_dlist.h"
44 #include "t_imm_debug.h"
45 #include "t_imm_exec.h"
46 #include "t_imm_fixup.h"
47 #include "t_pipeline.h"
48
49 typedef struct {
50 struct immediate *IM;
51 GLuint Start;
52 GLuint Count;
53 GLuint BeginState;
54 GLuint SavedBeginState;
55 GLuint OrFlag;
56 GLuint AndFlag;
57 GLuint TexSize;
58 GLuint LastData;
59 GLuint LastPrimitive;
60 GLuint LastMaterial;
61 GLuint MaterialOrMask;
62 GLuint MaterialAndMask;
63 } TNLvertexcassette;
64
65 static void execute_compiled_cassette( GLcontext *ctx, void *data );
66 static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM );
67
68
69 /* Insert the active immediate struct onto the display list currently
70 * being built.
71 */
72 void
73 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
74 {
75 struct immediate *im = TNL_CURRENT_IM(ctx);
76 TNLcontext *tnl = TNL_CONTEXT(ctx);
77 TNLvertexcassette *node;
78 GLuint new_beginstate;
79
80 if (IM->FlushElt) {
81 ASSERT (IM->FlushElt == FLUSH_ELT_LAZY);
82 _tnl_translate_array_elts( ctx, IM, IM->Start, IM->Count );
83 }
84
85 _tnl_compute_orflag( IM, IM->Start );
86
87 /* Need to clear this flag, or fixup gets confused. (The elements
88 * have been translated away by now.)
89 */
90 IM->OrFlag &= ~VERT_ELT;
91 IM->AndFlag &= ~VERT_ELT;
92
93 _tnl_fixup_input( ctx, IM );
94 /* _tnl_print_cassette( IM ); */
95
96 node = (TNLvertexcassette *)
97 _mesa_alloc_instruction(ctx,
98 tnl->opcode_vertex_cassette,
99 sizeof(TNLvertexcassette));
100 if (!node)
101 return;
102
103 node->IM = im; im->ref_count++;
104 node->Start = im->Start;
105 node->Count = im->Count;
106 node->BeginState = im->BeginState;
107 node->SavedBeginState = im->SavedBeginState;
108 node->OrFlag = im->OrFlag;
109 node->TexSize = im->TexSize;
110 node->AndFlag = im->AndFlag;
111 node->LastData = im->LastData;
112 node->LastPrimitive = im->LastPrimitive;
113 node->LastMaterial = im->LastMaterial;
114 node->MaterialOrMask = im->MaterialOrMask;
115 node->MaterialAndMask = im->MaterialAndMask;
116
117 if (ctx->ExecuteFlag) {
118 execute_compiled_cassette( ctx, (void *)node );
119 }
120
121 /* Discard any errors raised in the last cassette.
122 */
123 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
124
125 /* Decide whether this immediate struct is full, or can be used for
126 * the next batch of vertices as well.
127 */
128 if (im->Count > IMM_MAXDATA - 16) {
129 /* Call it full...
130 */
131 struct immediate *new_im = _tnl_alloc_immediate(ctx);
132 new_im->ref_count++;
133 im->ref_count--; /* remove CURRENT_IM reference */
134 ASSERT(im->ref_count > 0); /* it is compiled into a display list */
135 SET_IMMEDIATE( ctx, new_im );
136 _tnl_reset_compile_input( ctx, IMM_MAX_COPIED_VERTS,
137 new_beginstate, node->SavedBeginState );
138 } else {
139 /* Still some room in the current immediate.
140 */
141 _tnl_reset_compile_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
142 new_beginstate, node->SavedBeginState);
143 }
144 }
145
146
147 static void fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM )
148 {
149 TNLcontext *tnl = TNL_CONTEXT(ctx);
150
151 /* Can potentially overwrite primitive details - need to save the
152 * first slot:
153 */
154 tnl->DlistPrimitive = IM->Primitive[IM->Start];
155 tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start];
156 tnl->DlistLastPrimitive = IM->LastPrimitive;
157
158 /* The first primitive may be different from what was recorded in
159 * the immediate struct. Consider an immediate that starts with a
160 * glBegin, compiled in a display list, which is called from within
161 * an existing Begin/End object.
162 */
163 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
164 GLuint i;
165
166 if (IM->BeginState & VERT_ERROR_1)
167 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
168
169 for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
170 if (IM->Flag[i] & (VERT_BEGIN|VERT_END_VB))
171 break;
172
173 /* Would like to just ignore vertices upto this point. Can't
174 * set copystart because it might skip materials?
175 */
176 ASSERT(IM->Start == IM->CopyStart);
177 if (i > IM->CopyStart) {
178 IM->Primitive[IM->CopyStart] = GL_POLYGON+1;
179 IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
180 if (IM->Flag[i] & VERT_END_VB) {
181 IM->Primitive[IM->CopyStart] |= PRIM_LAST;
182 IM->LastPrimitive = IM->CopyStart;
183 }
184 }
185 } else {
186 GLuint i;
187
188 if (IM->BeginState & VERT_ERROR_0)
189 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
190
191 if (IM->CopyStart == IM->Start &&
192 IM->Flag[IM->Start] & (VERT_END|VERT_END_VB))
193 {
194 }
195 else
196 {
197 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
198 if (tnl->ExecParity)
199 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
200
201 /* one of these should be true, else we'll be in an infinite loop
202 */
203 ASSERT(IM->PrimitiveLength[IM->Start] > 0 ||
204 IM->Flag[IM->Start] & (VERT_END|VERT_END_VB));
205
206 for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
207 if (IM->Flag[i] & (VERT_END|VERT_END_VB)) {
208 IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
209 if (IM->Flag[i] & VERT_END_VB) {
210 IM->Primitive[IM->CopyStart] |= PRIM_LAST;
211 IM->LastPrimitive = IM->CopyStart;
212 }
213 if (IM->Flag[i] & VERT_END) {
214 IM->Primitive[IM->CopyStart] |= PRIM_END;
215 }
216 break;
217 }
218 }
219 }
220 }
221
222 /* Undo any changes potentially made to the immediate in the range
223 * IM->Start..IM->Count above.
224 */
225 static void restore_compiled_primitives( GLcontext *ctx, struct immediate *IM )
226 {
227 TNLcontext *tnl = TNL_CONTEXT(ctx);
228 IM->Primitive[IM->Start] = tnl->DlistPrimitive;
229 IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
230 }
231
232
233
234 static void
235 execute_compiled_cassette( GLcontext *ctx, void *data )
236 {
237 TNLcontext *tnl = TNL_CONTEXT(ctx);
238 TNLvertexcassette *node = (TNLvertexcassette *)data;
239 struct immediate *IM = node->IM;
240
241 /* fprintf(stderr, "%s\n", __FUNCTION__); */
242
243 IM->Start = node->Start;
244 IM->CopyStart = node->Start;
245 IM->Count = node->Count;
246 IM->BeginState = node->BeginState;
247 IM->SavedBeginState = node->SavedBeginState;
248 IM->OrFlag = node->OrFlag;
249 IM->TexSize = node->TexSize;
250 IM->AndFlag = node->AndFlag;
251 IM->LastData = node->LastData;
252 IM->LastPrimitive = node->LastPrimitive;
253 IM->LastMaterial = node->LastMaterial;
254 IM->MaterialOrMask = node->MaterialOrMask;
255 IM->MaterialAndMask = node->MaterialAndMask;
256
257 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
258 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
259 _tnl_print_cassette( IM );
260
261 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
262 fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
263 IM->id,
264 IM->Start, IM->Count, IM->BeginState);
265 _tnl_print_vert_flags("orflag", IM->OrFlag);
266 }
267
268
269 /* Need to respect 'HardBeginEnd' even if the commands are looped
270 * back to a driver tnl module.
271 */
272 if (IM->SavedBeginState) {
273 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
274 tnl->ReplayHardBeginEnd = 1;
275 if (!tnl->ReplayHardBeginEnd) {
276 /* This is a user error. Whatever operation (like glRectf)
277 * decomposed to this hard begin/end pair is now being run
278 * inside a begin/end object -- illegally. Reject it and
279 * raise an error.
280 */
281 _mesa_error(ctx, GL_INVALID_OPERATION, "hard replay");
282 return;
283 }
284 }
285
286 if (tnl->LoopbackDListCassettes) {
287 fixup_compiled_primitives( ctx, IM );
288 loopback_compiled_cassette( ctx, IM );
289 restore_compiled_primitives( ctx, IM );
290 }
291 else if (IM->Count == IM->Start) {
292 _tnl_copy_to_current( ctx, IM, IM->OrFlag );
293 }
294 else {
295 if (ctx->NewState)
296 _mesa_update_state(ctx);
297
298 if (tnl->pipeline.build_state_changes)
299 _tnl_validate_pipeline( ctx );
300
301 _tnl_fixup_compiled_cassette( ctx, IM );
302 fixup_compiled_primitives( ctx, IM );
303
304 if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
305 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
306 else
307 ctx->Driver.CurrentExecPrimitive =
308 IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
309
310 _tnl_get_exec_copy_verts( ctx, IM );
311 _tnl_run_cassette( ctx, IM );
312
313 restore_compiled_primitives( ctx, IM );
314 }
315
316 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
317 tnl->ReplayHardBeginEnd = 0;
318 }
319
320 static void
321 destroy_compiled_cassette( GLcontext *ctx, void *data )
322 {
323 TNLvertexcassette *node = (TNLvertexcassette *)data;
324
325 if ( --node->IM->ref_count == 0 )
326 _tnl_free_immediate( node->IM );
327 }
328
329
330 static void
331 print_compiled_cassette( GLcontext *ctx, void *data )
332 {
333 TNLvertexcassette *node = (TNLvertexcassette *)data;
334 struct immediate *IM = node->IM;
335
336 fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
337 node->IM->id, node->Start, node->Count);
338
339 IM->Start = node->Start;
340 IM->Count = node->Count;
341 IM->BeginState = node->BeginState;
342 IM->OrFlag = node->OrFlag;
343 IM->TexSize = node->TexSize;
344 IM->AndFlag = node->AndFlag;
345 IM->LastData = node->LastData;
346 IM->LastPrimitive = node->LastPrimitive;
347 IM->LastMaterial = node->LastMaterial;
348 IM->MaterialOrMask = node->MaterialOrMask;
349 IM->MaterialAndMask = node->MaterialAndMask;
350
351 _tnl_print_cassette( node->IM );
352 }
353
354 void
355 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
356 {
357 (void) ctx;
358 (void) list;
359 FLUSH_CURRENT(ctx, 0);
360 }
361
362
363 /* Called at the tail of a CallList. Nothing to do.
364 */
365 void
366 _tnl_EndCallList( GLcontext *ctx )
367 {
368 }
369
370
371 void
372 _tnl_EndList( GLcontext *ctx )
373 {
374 struct immediate *IM = TNL_CURRENT_IM(ctx);
375
376 ctx->swtnl_im = 0;
377 IM->ref_count--;
378
379 /* outside begin/end, even in COMPILE_AND_EXEC,
380 * so no vertices to copy, right?
381 */
382 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
383
384 /* If this one isn't free, get a clean one. (Otherwise we'll be
385 * using one that's already half full).
386 */
387 if (IM->ref_count != 0)
388 IM = _tnl_alloc_immediate( ctx );
389
390 ASSERT(IM->ref_count == 0);
391
392 SET_IMMEDIATE( ctx, IM );
393 IM->ref_count++;
394
395 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
396 }
397
398
399 void
400 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
401 {
402 struct immediate *IM = TNL_CURRENT_IM(ctx);
403
404 /* Use the installed immediate struct. No vertices in the current
405 * immediate, no copied vertices in the system.
406 */
407 ASSERT(TNL_CURRENT_IM(ctx));
408 ASSERT(TNL_CURRENT_IM(ctx)->Start == IMM_MAX_COPIED_VERTS);
409 ASSERT(TNL_CURRENT_IM(ctx)->Start == TNL_CURRENT_IM(ctx)->Count);
410 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
411
412 /* Set current Begin/End state to unknown:
413 */
414 IM->BeginState = VERT_BEGIN_0;
415 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
416 }
417
418
419 void
420 _tnl_dlist_init( GLcontext *ctx )
421 {
422 TNLcontext *tnl = TNL_CONTEXT(ctx);
423
424 tnl->opcode_vertex_cassette =
425 _mesa_alloc_opcode( ctx,
426 sizeof(TNLvertexcassette),
427 execute_compiled_cassette,
428 destroy_compiled_cassette,
429 print_compiled_cassette );
430 }
431
432
433 static void emit_material( struct gl_material *src, GLuint bitmask )
434 {
435 if (bitmask & FRONT_EMISSION_BIT)
436 glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission );
437
438 if (bitmask & BACK_EMISSION_BIT)
439 glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission );
440
441 if (bitmask & FRONT_AMBIENT_BIT)
442 glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient );
443
444 if (bitmask & BACK_AMBIENT_BIT)
445 glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient );
446
447 if (bitmask & FRONT_DIFFUSE_BIT)
448 glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse );
449
450 if (bitmask & BACK_DIFFUSE_BIT)
451 glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse );
452
453 if (bitmask & FRONT_SPECULAR_BIT)
454 glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular );
455
456 if (bitmask & BACK_SPECULAR_BIT)
457 glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular );
458
459 if (bitmask & FRONT_SHININESS_BIT)
460 glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess );
461
462 if (bitmask & BACK_SHININESS_BIT)
463 glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess );
464
465 if (bitmask & FRONT_INDEXES_BIT) {
466 GLfloat ind[3];
467 ind[0] = src[0].AmbientIndex;
468 ind[1] = src[0].DiffuseIndex;
469 ind[2] = src[0].SpecularIndex;
470 glMaterialfv( GL_FRONT, GL_COLOR_INDEXES, ind );
471 }
472
473 if (bitmask & BACK_INDEXES_BIT) {
474 GLfloat ind[3];
475 ind[0] = src[1].AmbientIndex;
476 ind[1] = src[1].DiffuseIndex;
477 ind[2] = src[1].SpecularIndex;
478 glMaterialfv( GL_BACK, GL_COLOR_INDEXES, ind );
479 }
480 }
481
482
483 /* Low-performance helper function to allow driver-supplied tnl
484 * modules to process tnl display lists. This is primarily supplied
485 * to avoid fallbacks if CallList is invoked inside a Begin/End pair.
486 * For higher performance, drivers should fallback to tnl (if outside
487 * begin/end), or (for tnl hardware) implement their own display list
488 * mechanism.
489 */
490 static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
491 {
492 GLuint i;
493 GLuint *flags = IM->Flag;
494 GLuint orflag = IM->OrFlag;
495 GLuint j;
496 void (*vertex)( const GLfloat * );
497 void (*texcoordfv[MAX_TEXTURE_UNITS])( GLuint, const GLfloat * );
498 GLuint maxtex = 0;
499 GLuint p, length, prim = 0;
500
501 if (orflag & VERT_OBJ_234)
502 vertex = glVertex4fv;
503 else
504 vertex = glVertex3fv;
505
506 if (orflag & VERT_TEX_ANY) {
507 for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
508 if (orflag & VERT_TEX(j)) {
509 maxtex = j+1;
510 if ((IM->TexSize & TEX_SIZE_4(j)) == TEX_SIZE_4(j))
511 texcoordfv[j] = glMultiTexCoord4fvARB;
512 else if (IM->TexSize & TEX_SIZE_3(j))
513 texcoordfv[j] = glMultiTexCoord3fvARB;
514 else
515 texcoordfv[j] = glMultiTexCoord2fvARB;
516 }
517 }
518 }
519
520 for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length)
521 {
522 prim = IM->Primitive[p];
523 length= IM->PrimitiveLength[p];
524 ASSERT(length || (prim & PRIM_LAST));
525 ASSERT((prim & PRIM_MODE_MASK) <= GL_POLYGON+1);
526
527 if (prim & PRIM_BEGIN) {
528 /* fprintf(stderr, "begin %s\n", _mesa_prim_name[prim&PRIM_MODE_MASK]); */
529 glBegin(prim & PRIM_MODE_MASK);
530 }
531
532 for ( i = p ; i <= p+length ; i++) {
533 if (flags[i] & VERT_TEX_ANY) {
534 GLuint k;
535 for (k = 0 ; k < maxtex ; k++) {
536 if (flags[i] & VERT_TEX(k)) {
537 texcoordfv[k]( GL_TEXTURE0_ARB + k, IM->TexCoord[k][i] );
538 }
539 }
540 }
541
542 if (flags[i] & VERT_NORM) {
543 /* fprintf(stderr, "normal %d: %f %f %f\n", i, */
544 /* IM->Normal[i][0], IM->Normal[i][1], IM->Normal[i][2]); */
545 glNormal3fv(IM->Normal[i]);
546 }
547
548 if (flags[i] & VERT_RGBA) {
549 /* fprintf(stderr, "color %d: %f %f %f\n", i, */
550 /* IM->Color[i][0], IM->Color[i][1], IM->Color[i][2]); */
551 glColor4fv( IM->Color[i] );
552 }
553
554 if (flags[i] & VERT_SPEC_RGB)
555 glSecondaryColor3fvEXT( IM->SecondaryColor[i] );
556
557 if (flags[i] & VERT_FOG_COORD)
558 glFogCoordfEXT( IM->FogCoord[i] );
559
560 if (flags[i] & VERT_INDEX)
561 glIndexi( IM->Index[i] );
562
563 if (flags[i] & VERT_EDGE)
564 glEdgeFlag( IM->EdgeFlag[i] );
565
566 if (flags[i] & VERT_MATERIAL)
567 emit_material( IM->Material[i], IM->MaterialMask[i] );
568
569 if (flags[i]&VERT_OBJ_234) {
570 /* fprintf(stderr, "vertex %d: %f %f %f\n", i, */
571 /* IM->Obj[i][0], IM->Obj[i][1], IM->Obj[i][2]); */
572 vertex( IM->Obj[i] );
573 }
574 else if (flags[i] & VERT_EVAL_C1)
575 glEvalCoord1f(IM->Obj[i][0]);
576 else if (flags[i] & VERT_EVAL_P1)
577 glEvalPoint1(IM->Obj[i][0]);
578 else if (flags[i] & VERT_EVAL_C2)
579 glEvalCoord2f( IM->Obj[i][0], IM->Obj[i][1]);
580 else if (flags[i] & VERT_EVAL_P2)
581 glEvalPoint2( IM->Obj[i][0], IM->Obj[i][1]);
582 }
583
584 if (prim & PRIM_END) {
585 /* fprintf(stderr, "end\n"); */
586 glEnd();
587 }
588 }
589 }