gl_error clean-ups
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.7 2001/02/13 23:51:34 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999 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 * Author:
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 GLboolean have_normal_lengths;
61 } TNLvertexcassette;
62
63 static void execute_compiled_cassette( GLcontext *ctx, void *data );
64
65
66 /* Insert the active immediate struct onto the display list currently
67 * being built.
68 */
69 void
70 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
71 {
72 struct immediate *im = TNL_CURRENT_IM(ctx);
73 TNLcontext *tnl = TNL_CONTEXT(ctx);
74 TNLvertexcassette *node;
75 GLuint new_beginstate;
76
77
78 _tnl_compute_orflag( IM );
79
80 IM->CopyStart = IM->Start;
81
82 if (IM->OrFlag & VERT_ELT) {
83 GLuint andflag = ~0;
84 GLuint i;
85 GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
86 _tnl_translate_array_elts( ctx, IM, start, IM->Count );
87
88 /* Need to recompute andflag.
89 */
90 if (IM->AndFlag & VERT_ELT)
91 IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
92 else {
93 for (i = IM->CopyStart ; i < IM->Count ; i++)
94 andflag &= IM->Flag[i];
95 IM->CopyAndFlag = IM->AndFlag = andflag;
96 }
97 }
98
99 _tnl_fixup_input( ctx, IM );
100
101 /* Mark the last primitive:
102 */
103 IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
104 ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
105
106
107 node = (TNLvertexcassette *)
108 _mesa_alloc_instruction(ctx,
109 tnl->opcode_vertex_cassette,
110 sizeof(TNLvertexcassette));
111 if (!node)
112 return;
113
114 node->IM = im; im->ref_count++;
115 node->Start = im->Start;
116 node->Count = im->Count;
117 node->BeginState = im->BeginState;
118 node->SavedBeginState = im->SavedBeginState;
119 node->OrFlag = im->OrFlag;
120 node->TexSize = im->TexSize;
121 node->AndFlag = im->AndFlag;
122 node->LastData = im->LastData;
123 node->LastPrimitive = im->LastPrimitive;
124 node->have_normal_lengths = GL_FALSE;
125
126 if (ctx->ExecuteFlag) {
127 execute_compiled_cassette( ctx, (void *)node );
128 }
129
130
131 /* Discard any errors raised in the last cassette.
132 */
133 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
134
135 /* Decide whether this immediate struct is full, or can be used for
136 * the next batch of vertices as well.
137 */
138 if (im->Count > IMM_MAXDATA - 16) {
139 /* Call it full...
140 */
141 struct immediate *new_im = _tnl_alloc_immediate(ctx);
142 if (!new_im) return;
143 new_im->ref_count++;
144 im->ref_count--; /* remove CURRENT_IM reference */
145 ASSERT(im->ref_count > 0);
146 SET_IMMEDIATE( ctx, new_im );
147 _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS,
148 new_beginstate, node->SavedBeginState );
149 } else {
150 /* Still some room in the current immediate.
151 */
152 _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
153 new_beginstate, node->SavedBeginState);
154 }
155 }
156
157
158
159 #if 0
160 /* Drivers to turn this on?
161 */
162 static void calc_normal_lengths( GLfloat *dest,
163 CONST GLfloat (*data)[3],
164 GLuint *flags,
165 GLuint count )
166 {
167 GLuint i;
168 GLint tmpflag = flags[0];
169
170 flags[0] |= VERT_NORM;
171
172 for (i = 0 ; i < count ; i++ )
173 if (flags[i] & VERT_NORM) {
174 GLfloat tmp = (GLfloat) LEN_3FV( data[i] );
175 dest[i] = 0;
176 if (tmp > 0)
177 dest[i] = 1.0F / tmp;
178 } else
179 dest[i] = dest[i-1];
180
181 flags[0] = tmpflag;
182 }
183 #endif
184
185
186 static void
187 execute_compiled_cassette( GLcontext *ctx, void *data )
188 {
189 TNLcontext *tnl = TNL_CONTEXT(ctx);
190 TNLvertexcassette *node = (TNLvertexcassette *)data;
191 struct immediate *IM = node->IM;
192
193 if (ctx->NewState)
194 gl_update_state(ctx);
195
196 if (tnl->pipeline.build_state_changes)
197 _tnl_validate_pipeline( ctx );
198
199 IM->Start = node->Start;
200 IM->CopyStart = node->Start;
201 IM->Count = node->Count;
202 IM->BeginState = node->BeginState;
203 IM->SavedBeginState = node->SavedBeginState;
204 IM->OrFlag = node->OrFlag;
205 IM->TexSize = node->TexSize;
206 IM->AndFlag = node->AndFlag;
207 IM->LastData = node->LastData;
208 IM->LastPrimitive = node->LastPrimitive;
209
210 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
211 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
212 _tnl_print_cassette( IM );
213
214 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
215 fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
216 IM->id,
217 IM->Start, IM->Count, IM->BeginState);
218 _tnl_print_vert_flags("orflag", IM->OrFlag);
219 }
220
221 if (IM->Count == IM->Start) {
222 _tnl_run_empty_cassette( ctx, IM );
223 return;
224 }
225
226 if (IM->SavedBeginState) {
227 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
228 tnl->ReplayHardBeginEnd = 1;
229 if (!tnl->ReplayHardBeginEnd) {
230 /* XXX is this really an OpenGL error or an implementation problem? */
231 gl_error(ctx, GL_INVALID_OPERATION, "hard replay");
232 return;
233 }
234 }
235
236
237 /* Lazy optimization of the cassette. Need to make these switchable
238 * or otherwise more useful for t&l cards.
239 */
240 #if 0
241 if (ctx->Transform.Normalize && !node->have_normal_lengths) {
242
243 if (!IM->NormalLengths)
244 IM->NormalLengths = (GLfloat *)MALLOC(sizeof(GLfloat) * IMM_SIZE);
245
246 calc_normal_lengths( IM->NormalLengths + IM->Start,
247 (const GLfloat (*)[3])(IM->Normal + IM->Start),
248 IM->Flag + IM->Start,
249 IM->Count - IM->Start);
250
251 node->have_normal_lengths = GL_TRUE;
252 }
253 #endif
254
255
256 #if 0
257 if (0 && im->v.Obj.size < 4 && im->Count > 15) {
258 im->Bounds = (GLfloat (*)[3]) MALLOC(6 * sizeof(GLfloat));
259 (_tnl_calc_bound_tab[im->v.Obj.size])( im->Bounds, &im->v.Obj );
260 }
261 #endif
262
263
264 _tnl_fixup_compiled_cassette( ctx, IM );
265 _tnl_get_exec_copy_verts( ctx, IM );
266 _tnl_run_cassette( ctx, IM );
267 _tnl_restore_compiled_cassette( ctx, IM );
268
269 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
270 tnl->ReplayHardBeginEnd = 0;
271 }
272
273 static void
274 destroy_compiled_cassette( GLcontext *ctx, void *data )
275 {
276 TNLvertexcassette *node = (TNLvertexcassette *)data;
277
278 /* fprintf(stderr, "destroy_compiled_cassette node->IM id %d ref_count: %d\n", */
279 /* node->IM->id, */
280 /* node->IM->ref_count-1); */
281
282 if ( --node->IM->ref_count == 0 )
283 _tnl_free_immediate( node->IM );
284 }
285
286
287 static void
288 print_compiled_cassette( GLcontext *ctx, void *data )
289 {
290 TNLvertexcassette *node = (TNLvertexcassette *)data;
291 struct immediate *IM = node->IM;
292
293 fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
294 node->IM->id, node->Start, node->Count);
295
296 IM->Start = node->Start;
297 IM->Count = node->Count;
298 IM->BeginState = node->BeginState;
299 IM->OrFlag = node->OrFlag;
300 IM->TexSize = node->TexSize;
301 IM->AndFlag = node->AndFlag;
302 IM->LastData = node->LastData;
303 IM->LastPrimitive = node->LastPrimitive;
304
305 _tnl_print_cassette( node->IM );
306 }
307
308 void
309 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
310 {
311 (void) ctx;
312 (void) list;
313 FLUSH_CURRENT(ctx, 0);
314 }
315
316
317 /* Called at the tail of a CallList. Copy vertices out of the display
318 * list if necessary.
319 */
320 void
321 _tnl_EndCallList( GLcontext *ctx )
322 {
323 /* May have to copy vertices from a dangling begin/end inside the
324 * list to the current immediate.
325 */
326 if (ctx->CallDepth == 0) {
327 TNLcontext *tnl = TNL_CONTEXT(ctx);
328 struct immediate *IM = TNL_CURRENT_IM(ctx);
329
330 if (tnl->ExecCopySource != IM)
331 _tnl_copy_immediate_vertices( ctx, IM );
332 }
333 }
334
335
336 void
337 _tnl_EndList( GLcontext *ctx )
338 {
339 TNLcontext *tnl = TNL_CONTEXT(ctx);
340 struct immediate *IM = TNL_CURRENT_IM(ctx);
341
342 ctx->swtnl_im = 0;
343 IM->ref_count--;
344 if (IM == tnl->ExecCopySource) {
345 IM->ref_count--;
346 } else {
347 if ( --tnl->ExecCopySource->ref_count == 0 )
348 _tnl_free_immediate( tnl->ExecCopySource );
349 }
350
351 /* If this one isn't free, get a clean one. (Otherwise we'll be
352 * using one that's already half full).
353 */
354 if (IM->ref_count != 0)
355 IM = _tnl_alloc_immediate( ctx );
356
357 ASSERT(IM->ref_count == 0);
358
359 tnl->ExecCopySource = IM;
360 IM->ref_count++;
361
362
363 SET_IMMEDIATE( ctx, IM );
364 IM->ref_count++;
365
366 _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
367
368 /* outside begin/end, even in COMPILE_AND_EXEC,
369 * so no vertices to copy, right?
370 */
371 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
372 }
373
374
375 void
376 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
377 {
378 struct immediate *IM = TNL_CURRENT_IM(ctx);
379
380 /* Use the installed immediate struct. No vertices in the current
381 * immediate, no copied vertices in the system.
382 */
383 ASSERT(TNL_CURRENT_IM(ctx));
384 ASSERT(TNL_CURRENT_IM(ctx)->Start == IMM_MAX_COPIED_VERTS);
385 ASSERT(TNL_CURRENT_IM(ctx)->Start == TNL_CURRENT_IM(ctx)->Count);
386 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
387
388 /* Set current Begin/End state to unknown:
389 */
390 IM->BeginState = VERT_BEGIN_0;
391 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
392 }
393
394
395 void
396 _tnl_dlist_init( GLcontext *ctx )
397 {
398 TNLcontext *tnl = TNL_CONTEXT(ctx);
399
400 tnl->opcode_vertex_cassette =
401 _mesa_alloc_opcode( ctx,
402 sizeof(TNLvertexcassette),
403 execute_compiled_cassette,
404 destroy_compiled_cassette,
405 print_compiled_cassette );
406 }
407