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