b613911b06d93dc978de047efefb9d5da96a48f4
[mesa.git] / src / mesa / drivers / dri / r200 / r200_tcl.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r200/r200_tcl.c,v 1.2 2002/12/16 16:18:55 dawes Exp $ */
2 /*
3 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4
5 The Weather Channel (TM) funded Tungsten Graphics to develop the
6 initial release of the Radeon 8500 driver under the XFree86 license.
7 This notice must be preserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 /*
32 * Authors:
33 * Keith Whitwell <keith@tungstengraphics.com>
34 */
35
36 #include "glheader.h"
37 #include "imports.h"
38 #include "mtypes.h"
39 #include "enums.h"
40 #include "colormac.h"
41 #include "light.h"
42
43 #include "array_cache/acache.h"
44 #include "tnl/tnl.h"
45 #include "tnl/t_pipeline.h"
46
47 #include "r200_context.h"
48 #include "r200_state.h"
49 #include "r200_ioctl.h"
50 #include "r200_tex.h"
51 #include "r200_tcl.h"
52 #include "r200_swtcl.h"
53 #include "r200_maos.h"
54
55
56
57 #define HAVE_POINTS 1
58 #define HAVE_LINES 1
59 #define HAVE_LINE_LOOP 0
60 #define HAVE_LINE_STRIPS 1
61 #define HAVE_TRIANGLES 1
62 #define HAVE_TRI_STRIPS 1
63 #define HAVE_TRI_STRIP_1 0
64 #define HAVE_TRI_FANS 1
65 #define HAVE_QUADS 0 /* hw quad verts in wrong order??? */
66 #define HAVE_QUAD_STRIPS 1
67 #define HAVE_POLYGONS 1
68 #define HAVE_ELTS 1
69
70
71 #define HW_POINTS R200_VF_PRIM_POINTS
72 #define HW_LINES R200_VF_PRIM_LINES
73 #define HW_LINE_LOOP 0
74 #define HW_LINE_STRIP R200_VF_PRIM_LINE_STRIP
75 #define HW_TRIANGLES R200_VF_PRIM_TRIANGLES
76 #define HW_TRIANGLE_STRIP_0 R200_VF_PRIM_TRIANGLE_STRIP
77 #define HW_TRIANGLE_STRIP_1 0
78 #define HW_TRIANGLE_FAN R200_VF_PRIM_TRIANGLE_FAN
79 #define HW_QUADS R200_VF_PRIM_QUADS
80 #define HW_QUAD_STRIP R200_VF_PRIM_QUAD_STRIP
81 #define HW_POLYGON R200_VF_PRIM_POLYGON
82
83
84 static GLboolean discrete_prim[0x10] = {
85 0, /* 0 none */
86 1, /* 1 points */
87 1, /* 2 lines */
88 0, /* 3 line_strip */
89 1, /* 4 tri_list */
90 0, /* 5 tri_fan */
91 0, /* 6 tri_strip */
92 0, /* 7 tri_w_flags */
93 1, /* 8 rect list (unused) */
94 1, /* 9 3vert point */
95 1, /* a 3vert line */
96 0, /* b point sprite */
97 0, /* c line loop */
98 1, /* d quads */
99 0, /* e quad strip */
100 0, /* f polygon */
101 };
102
103
104 #define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx)
105 #define ELT_TYPE GLushort
106
107 #define ELT_INIT(prim, hw_prim) \
108 r200TclPrimitive( ctx, prim, hw_prim | R200_VF_PRIM_WALK_IND )
109
110 #define GET_MESA_ELTS() rmesa->tcl.Elts
111
112
113 /* Don't really know how many elts will fit in what's left of cmdbuf,
114 * as there is state to emit, etc:
115 */
116
117 /* Testing on isosurf shows a maximum around here. Don't know if it's
118 * the card or driver or kernel module that is causing the behaviour.
119 */
120 #define GET_MAX_HW_ELTS() 300
121
122 #define RESET_STIPPLE() do { \
123 R200_STATECHANGE( rmesa, lin ); \
124 r200EmitState( rmesa ); \
125 } while (0)
126
127 #define AUTO_STIPPLE( mode ) do { \
128 R200_STATECHANGE( rmesa, lin ); \
129 if (mode) \
130 rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \
131 R200_LINE_PATTERN_AUTO_RESET; \
132 else \
133 rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \
134 ~R200_LINE_PATTERN_AUTO_RESET; \
135 r200EmitState( rmesa ); \
136 } while (0)
137
138
139 #define ALLOC_ELTS(nr) r200AllocElts( rmesa, nr )
140
141 static GLushort *r200AllocElts( r200ContextPtr rmesa, GLuint nr )
142 {
143 if (rmesa->dma.flush)
144 rmesa->dma.flush( rmesa );
145
146 r200EnsureCmdBufSpace( rmesa, AOS_BUFSZ(rmesa->tcl.nr_aos_components) +
147 rmesa->hw.max_state_size + ELTS_BUFSZ(nr) );
148
149 r200EmitAOS( rmesa,
150 rmesa->tcl.aos_components,
151 rmesa->tcl.nr_aos_components, 0 );
152
153 return r200AllocEltsOpenEnded( rmesa, rmesa->tcl.hw_primitive, nr );
154 }
155
156
157 #define CLOSE_ELTS() R200_NEWPRIM( rmesa )
158
159
160 /* TODO: Try to extend existing primitive if both are identical,
161 * discrete and there are no intervening state changes. (Somewhat
162 * duplicates changes to DrawArrays code)
163 */
164 static void EMIT_PRIM( GLcontext *ctx,
165 GLenum prim,
166 GLuint hwprim,
167 GLuint start,
168 GLuint count)
169 {
170 r200ContextPtr rmesa = R200_CONTEXT( ctx );
171 r200TclPrimitive( ctx, prim, hwprim );
172
173 r200EnsureCmdBufSpace( rmesa, AOS_BUFSZ(rmesa->tcl.nr_aos_components) +
174 rmesa->hw.max_state_size + VBUF_BUFSZ );
175
176 r200EmitAOS( rmesa,
177 rmesa->tcl.aos_components,
178 rmesa->tcl.nr_aos_components,
179 start );
180
181 /* Why couldn't this packet have taken an offset param?
182 */
183 r200EmitVbufPrim( rmesa,
184 rmesa->tcl.hw_primitive,
185 count - start );
186 }
187
188
189
190 /* Try & join small primitives
191 */
192 #if 0
193 #define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) 0
194 #else
195 #define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) \
196 ((NR) < 20 || \
197 ((NR) < 40 && \
198 rmesa->tcl.hw_primitive == (PRIM| \
199 R200_VF_TCL_OUTPUT_VTX_ENABLE| \
200 R200_VF_PRIM_WALK_IND)))
201 #endif
202
203 #ifdef MESA_BIG_ENDIAN
204 /* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
205 #define EMIT_ELT(dest, offset, x) do { \
206 int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \
207 GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \
208 (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
209 #else
210 #define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x)
211 #endif
212
213 #define EMIT_TWO_ELTS(dest, offset, x, y) *(GLuint *)((dest)+offset) = ((y)<<16)|(x);
214
215
216
217 #define TAG(x) tcl_##x
218 #include "tnl_dd/t_dd_dmatmp2.h"
219
220 /**********************************************************************/
221 /* External entrypoints */
222 /**********************************************************************/
223
224 void r200EmitPrimitive( GLcontext *ctx,
225 GLuint first,
226 GLuint last,
227 GLuint flags )
228 {
229 tcl_render_tab_verts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
230 }
231
232 void r200EmitEltPrimitive( GLcontext *ctx,
233 GLuint first,
234 GLuint last,
235 GLuint flags )
236 {
237 tcl_render_tab_elts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
238 }
239
240 void r200TclPrimitive( GLcontext *ctx,
241 GLenum prim,
242 int hw_prim )
243 {
244 r200ContextPtr rmesa = R200_CONTEXT(ctx);
245 GLuint newprim = hw_prim | R200_VF_TCL_OUTPUT_VTX_ENABLE;
246
247 if (newprim != rmesa->tcl.hw_primitive ||
248 !discrete_prim[hw_prim&0xf]) {
249 R200_NEWPRIM( rmesa );
250 rmesa->tcl.hw_primitive = newprim;
251 }
252 }
253
254
255 /**********************************************************************/
256 /* Render pipeline stage */
257 /**********************************************************************/
258
259
260 /* TCL render.
261 */
262 static GLboolean r200_run_tcl_render( GLcontext *ctx,
263 struct tnl_pipeline_stage *stage )
264 {
265 r200ContextPtr rmesa = R200_CONTEXT(ctx);
266 TNLcontext *tnl = TNL_CONTEXT(ctx);
267 struct vertex_buffer *VB = &tnl->vb;
268 GLuint i;
269
270 /* TODO: separate this from the swtnl pipeline
271 */
272 if (rmesa->TclFallback)
273 return GL_TRUE; /* fallback to software t&l */
274
275 if (R200_DEBUG & DEBUG_PRIMS)
276 fprintf(stderr, "%s\n", __FUNCTION__);
277
278 if (VB->Count == 0)
279 return GL_FALSE;
280
281 r200ReleaseArrays( ctx, ~0 /* stage->changed_inputs */ );
282 r200EmitArrays( ctx, stage->inputs );
283
284 rmesa->tcl.Elts = VB->Elts;
285
286 for (i = 0 ; i < VB->PrimitiveCount ; i++)
287 {
288 GLuint prim = VB->Primitive[i].mode;
289 GLuint start = VB->Primitive[i].start;
290 GLuint length = VB->Primitive[i].count;
291
292 if (!length)
293 continue;
294
295 if (rmesa->tcl.Elts)
296 r200EmitEltPrimitive( ctx, start, start+length, prim );
297 else
298 r200EmitPrimitive( ctx, start, start+length, prim );
299 }
300
301 return GL_FALSE; /* finished the pipe */
302 }
303
304
305
306 static void r200_check_tcl_render( GLcontext *ctx,
307 struct tnl_pipeline_stage *stage )
308 {
309 r200ContextPtr rmesa = R200_CONTEXT(ctx);
310 GLuint inputs = VERT_BIT_POS;
311 GLuint unit;
312
313 /* Validate state:
314 */
315 if (rmesa->NewGLState)
316 r200ValidateState( ctx );
317
318 if (ctx->RenderMode == GL_RENDER) {
319 /* Make all this event-driven:
320 */
321 if (ctx->Light.Enabled) {
322 inputs |= VERT_BIT_NORMAL;
323
324 if (1 || ctx->Light.ColorMaterialEnabled) {
325 inputs |= VERT_BIT_COLOR0;
326 }
327 }
328 else {
329 inputs |= VERT_BIT_COLOR0;
330
331 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
332 inputs |= VERT_BIT_COLOR1;
333 }
334 }
335
336 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) {
337 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
338 if (ctx->Texture.Unit[unit].TexGenEnabled) {
339 if (rmesa->TexGenNeedNormals[unit]) {
340 inputs |= VERT_BIT_NORMAL;
341 }
342 } else {
343 inputs |= VERT_BIT_TEX(unit);
344 }
345 }
346 }
347
348 stage->inputs = inputs;
349 stage->active = 1;
350 }
351 else
352 stage->active = 0;
353 }
354
355 static void r200_init_tcl_render( GLcontext *ctx,
356 struct tnl_pipeline_stage *stage )
357 {
358 stage->check = r200_check_tcl_render;
359 stage->check( ctx, stage );
360 }
361
362 static void dtr( struct tnl_pipeline_stage *stage )
363 {
364 (void)stage;
365 }
366
367
368 /* Initial state for tcl stage.
369 */
370 const struct tnl_pipeline_stage _r200_tcl_stage =
371 {
372 "r200 render",
373 (_DD_NEW_SEPARATE_SPECULAR |
374 _NEW_LIGHT|
375 _NEW_TEXTURE|
376 _NEW_FOG|
377 _NEW_RENDERMODE), /* re-check (new inputs) */
378 0, /* re-run (always runs) */
379 GL_TRUE, /* active */
380 0, 0, /* inputs (set in check_render), outputs */
381 0, 0, /* changed_inputs, private */
382 dtr, /* destructor */
383 r200_init_tcl_render, /* check - initially set to alloc data */
384 r200_run_tcl_render /* run */
385 };
386
387
388
389 /**********************************************************************/
390 /* Validate state at pipeline start */
391 /**********************************************************************/
392
393
394 /*-----------------------------------------------------------------------
395 * Manage TCL fallbacks
396 */
397
398
399 static void transition_to_swtnl( GLcontext *ctx )
400 {
401 r200ContextPtr rmesa = R200_CONTEXT(ctx);
402 TNLcontext *tnl = TNL_CONTEXT(ctx);
403
404 R200_NEWPRIM( rmesa );
405
406 r200ChooseVertexState( ctx );
407 r200ChooseRenderState( ctx );
408
409 _mesa_validate_all_lighting_tables( ctx );
410
411 tnl->Driver.NotifyMaterialChange =
412 _mesa_validate_all_lighting_tables;
413
414 r200ReleaseArrays( ctx, ~0 );
415
416 /* Still using the D3D based hardware-rasterizer from the radeon;
417 * need to put the card into D3D mode to make it work:
418 */
419 R200_STATECHANGE( rmesa, vap );
420 rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~R200_VAP_TCL_ENABLE;
421 rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_D3D_TEX_DEFAULT;
422
423 R200_STATECHANGE( rmesa, vte );
424 rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~R200_VTX_W0_FMT;
425
426 R200_STATECHANGE( rmesa, set );
427 rmesa->hw.set.cmd[SET_RE_CNTL] |= (R200_VTX_STQ0_D3D |
428 R200_VTX_STQ1_D3D |
429 R200_VTX_STQ2_D3D |
430 R200_VTX_STQ3_D3D |
431 R200_VTX_STQ4_D3D |
432 R200_VTX_STQ5_D3D);
433 }
434
435 static void transition_to_hwtnl( GLcontext *ctx )
436 {
437 r200ContextPtr rmesa = R200_CONTEXT(ctx);
438 TNLcontext *tnl = TNL_CONTEXT(ctx);
439
440 _tnl_need_projected_coords( ctx, GL_FALSE );
441
442 r200UpdateMaterial( ctx );
443
444 tnl->Driver.NotifyMaterialChange = r200UpdateMaterial;
445
446 if ( rmesa->dma.flush )
447 rmesa->dma.flush( rmesa );
448
449 rmesa->dma.flush = 0;
450
451 if (rmesa->swtcl.indexed_verts.buf)
452 r200ReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts,
453 __FUNCTION__ );
454
455 R200_STATECHANGE( rmesa, vap );
456 rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_TCL_ENABLE;
457 rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~(R200_VAP_FORCE_W_TO_ONE |
458 R200_VAP_D3D_TEX_DEFAULT);
459
460 R200_STATECHANGE( rmesa, vte );
461 rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~(R200_VTX_XY_FMT|R200_VTX_Z_FMT);
462 rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] |= R200_VTX_W0_FMT;
463
464 R200_STATECHANGE( rmesa, set );
465 rmesa->hw.set.cmd[SET_RE_CNTL] &= ~(R200_VTX_STQ0_D3D |
466 R200_VTX_STQ1_D3D |
467 R200_VTX_STQ2_D3D |
468 R200_VTX_STQ3_D3D |
469 R200_VTX_STQ4_D3D |
470 R200_VTX_STQ5_D3D);
471
472
473 if (R200_DEBUG & DEBUG_FALLBACKS)
474 fprintf(stderr, "R200 end tcl fallback\n");
475 }
476
477
478 static char *fallbackStrings[] = {
479 "Rasterization fallback",
480 "Unfilled triangles",
481 "Twosided lighting, differing materials",
482 "Materials in VB (maybe between begin/end)",
483 "Texgen unit 0",
484 "Texgen unit 1",
485 "Texgen unit 2",
486 "Texgen unit 3",
487 "Texgen unit 4",
488 "Texgen unit 5",
489 "User disable",
490 "Bitmap as points"
491 };
492
493
494 static char *getFallbackString(GLuint bit)
495 {
496 int i = 0;
497 while (bit > 1) {
498 i++;
499 bit >>= 1;
500 }
501 return fallbackStrings[i];
502 }
503
504
505
506 void r200TclFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
507 {
508 r200ContextPtr rmesa = R200_CONTEXT(ctx);
509 GLuint oldfallback = rmesa->TclFallback;
510
511 if (mode) {
512 rmesa->TclFallback |= bit;
513 if (oldfallback == 0) {
514 if (R200_DEBUG & DEBUG_FALLBACKS)
515 fprintf(stderr, "R200 begin tcl fallback %s\n",
516 getFallbackString( bit ));
517 transition_to_swtnl( ctx );
518 }
519 }
520 else {
521 rmesa->TclFallback &= ~bit;
522 if (oldfallback == bit) {
523 if (R200_DEBUG & DEBUG_FALLBACKS)
524 fprintf(stderr, "R200 end tcl fallback %s\n",
525 getFallbackString( bit ));
526 transition_to_hwtnl( ctx );
527 }
528 }
529 }