r200_tcl.c revision 05e1a49ab4b0d34aba4bdf55ed7ffe5b6d4411f8
1/* $XFree86: xc/lib/GL/mesa/src/drv/r200/r200_tcl.c,v 1.2 2002/12/16 16:18:55 dawes Exp $ */
2/*
3Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
4
5The Weather Channel (TM) funded Tungsten Graphics to develop the
6initial release of the Radeon 8500 driver under the XFree86 license.
7This notice must be preserved.
8
9Permission is hereby granted, free of charge, to any person obtaining
10a copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice (including the
18next paragraph) shall be included in all copies or substantial
19portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27WITH 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       1
66#define HAVE_QUAD_STRIPS 1
67#define HAVE_POLYGONS    1
68#define HAVE_ELTS        1
69
70
71#define HW_POINTS           ((ctx->_TriangleCaps & DD_POINT_SIZE) ? \
72				R200_VF_PRIM_POINT_SPRITES : 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
85static 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
142static GLushort *r200AllocElts( r200ContextPtr rmesa, GLuint nr )
143{
144   if (rmesa->dma.flush == r200FlushElts &&
145       rmesa->store.cmd_used + nr*2 < R200_CMD_BUF_SZ) {
146
147      GLushort *dest = (GLushort *)(rmesa->store.cmd_buf +
148				    rmesa->store.cmd_used);
149
150      rmesa->store.cmd_used += nr*2;
151
152      return dest;
153   }
154   else {
155      if (rmesa->dma.flush)
156	 rmesa->dma.flush( rmesa );
157
158      r200EnsureCmdBufSpace( rmesa, AOS_BUFSZ(rmesa->tcl.nr_aos_components) +
159			     rmesa->hw.max_state_size + ELTS_BUFSZ(nr) );
160
161      r200EmitAOS( rmesa,
162		   rmesa->tcl.aos_components,
163		   rmesa->tcl.nr_aos_components, 0 );
164
165      return r200AllocEltsOpenEnded( rmesa, rmesa->tcl.hw_primitive, nr );
166   }
167}
168
169
170#define CLOSE_ELTS() 				\
171do {						\
172   if (0) R200_NEWPRIM( rmesa );		\
173}						\
174while (0)
175
176
177/* TODO: Try to extend existing primitive if both are identical,
178 * discrete and there are no intervening state changes.  (Somewhat
179 * duplicates changes to DrawArrays code)
180 */
181static void r200EmitPrim( GLcontext *ctx,
182		          GLenum prim,
183		          GLuint hwprim,
184		          GLuint start,
185		          GLuint count)
186{
187   r200ContextPtr rmesa = R200_CONTEXT( ctx );
188   r200TclPrimitive( ctx, prim, hwprim );
189
190   r200EnsureCmdBufSpace( rmesa, AOS_BUFSZ(rmesa->tcl.nr_aos_components) +
191			  rmesa->hw.max_state_size + VBUF_BUFSZ );
192
193   r200EmitAOS( rmesa,
194		  rmesa->tcl.aos_components,
195		  rmesa->tcl.nr_aos_components,
196		  start );
197
198   /* Why couldn't this packet have taken an offset param?
199    */
200   r200EmitVbufPrim( rmesa,
201		     rmesa->tcl.hw_primitive,
202		     count - start );
203}
204
205#define EMIT_PRIM(ctx, prim, hwprim, start, count) do {         \
206   r200EmitPrim( ctx, prim, hwprim, start, count );             \
207   (void) rmesa; } while (0)
208
209/* Try & join small primitives
210 */
211#if 0
212#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) 0
213#else
214#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM )			\
215  ((NR) < 20 ||							\
216   ((NR) < 40 &&						\
217    rmesa->tcl.hw_primitive == (PRIM|				\
218			    R200_VF_TCL_OUTPUT_VTX_ENABLE|	\
219			        R200_VF_PRIM_WALK_IND)))
220#endif
221
222#ifdef MESA_BIG_ENDIAN
223/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
224#define EMIT_ELT(dest, offset, x) do {                          \
225        int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 );     \
226        GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 );    \
227        (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x);	\
228	(void)rmesa; } while (0)
229#else
230#define EMIT_ELT(dest, offset, x) do {				\
231	(dest)[offset] = (GLushort) (x);			\
232	(void)rmesa; } while (0)
233#endif
234
235#define EMIT_TWO_ELTS(dest, offset, x, y)  *(GLuint *)((dest)+offset) = ((y)<<16)|(x);
236
237
238
239#define TAG(x) tcl_##x
240#include "tnl_dd/t_dd_dmatmp2.h"
241
242/**********************************************************************/
243/*                          External entrypoints                     */
244/**********************************************************************/
245
246void r200EmitPrimitive( GLcontext *ctx,
247			  GLuint first,
248			  GLuint last,
249			  GLuint flags )
250{
251   tcl_render_tab_verts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
252}
253
254void r200EmitEltPrimitive( GLcontext *ctx,
255			     GLuint first,
256			     GLuint last,
257			     GLuint flags )
258{
259   tcl_render_tab_elts[flags&PRIM_MODE_MASK]( ctx, first, last, flags );
260}
261
262void r200TclPrimitive( GLcontext *ctx,
263			 GLenum prim,
264			 int hw_prim )
265{
266   r200ContextPtr rmesa = R200_CONTEXT(ctx);
267   GLuint newprim = hw_prim | R200_VF_TCL_OUTPUT_VTX_ENABLE;
268
269   if (newprim != rmesa->tcl.hw_primitive ||
270       !discrete_prim[hw_prim&0xf]) {
271      R200_NEWPRIM( rmesa );
272      rmesa->tcl.hw_primitive = newprim;
273   }
274}
275
276
277/**********************************************************************/
278/*             Fog blend factor computation for hw tcl                */
279/*             same calculation used as in t_vb_fog.c                 */
280/**********************************************************************/
281
282#define FOG_EXP_TABLE_SIZE 256
283#define FOG_MAX (10.0)
284#define EXP_FOG_MAX .0006595
285#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE)
286static GLfloat exp_table[FOG_EXP_TABLE_SIZE];
287
288#if 1
289#define NEG_EXP( result, narg )						\
290do {									\
291   GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR));			\
292   GLint k = (GLint) f;							\
293   if (k > FOG_EXP_TABLE_SIZE-2) 					\
294      result = (GLfloat) EXP_FOG_MAX;					\
295   else									\
296      result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]);	\
297} while (0)
298#else
299#define NEG_EXP( result, narg )					\
300do {								\
301   result = exp(-narg);						\
302} while (0)
303#endif
304
305
306/**
307 * Initialize the exp_table[] lookup table for approximating exp().
308 */
309void
310r200InitStaticFogData( void )
311{
312   GLfloat f = 0.0F;
313   GLint i = 0;
314   for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) {
315      exp_table[i] = (GLfloat) exp(-f);
316   }
317}
318
319
320/**
321 * Compute per-vertex fog blend factors from fog coordinates by
322 * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function.
323 * Fog coordinates are distances from the eye (typically between the
324 * near and far clip plane distances).
325 * Note the fog (eye Z) coords may be negative so we use ABS(z) below.
326 * Fog blend factors are in the range [0,1].
327 */
328float
329r200ComputeFogBlendFactor( GLcontext *ctx, GLfloat fogcoord )
330{
331   GLfloat end  = ctx->Fog.End;
332   GLfloat d, temp;
333   const GLfloat z = FABSF(fogcoord);
334
335   switch (ctx->Fog.Mode) {
336   case GL_LINEAR:
337      if (ctx->Fog.Start == ctx->Fog.End)
338         d = 1.0F;
339      else
340         d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
341      temp = (end - z) * d;
342      return CLAMP(temp, 0.0F, 1.0F);
343      break;
344   case GL_EXP:
345      d = ctx->Fog.Density;
346      NEG_EXP( temp, d * z );
347      return temp;
348      break;
349   case GL_EXP2:
350      d = ctx->Fog.Density*ctx->Fog.Density;
351      NEG_EXP( temp, d * z * z );
352      return temp;
353      break;
354   default:
355      _mesa_problem(ctx, "Bad fog mode in make_fog_coord");
356      return 0;
357   }
358}
359
360
361/**********************************************************************/
362/*                          Render pipeline stage                     */
363/**********************************************************************/
364
365
366/* TCL render.
367 */
368static GLboolean r200_run_tcl_render( GLcontext *ctx,
369				      struct tnl_pipeline_stage *stage )
370{
371   r200ContextPtr rmesa = R200_CONTEXT(ctx);
372   TNLcontext *tnl = TNL_CONTEXT(ctx);
373   struct vertex_buffer *VB = &tnl->vb;
374   GLuint inputs = VERT_BIT_POS | VERT_BIT_COLOR0;
375   GLuint i;
376
377   /* TODO: separate this from the swtnl pipeline
378    */
379   if (rmesa->TclFallback)
380      return GL_TRUE;	/* fallback to software t&l */
381
382   if (R200_DEBUG & DEBUG_PRIMS)
383      fprintf(stderr, "%s\n", __FUNCTION__);
384
385   if (VB->Count == 0)
386      return GL_FALSE;
387
388   /* Validate state:
389    */
390   if (rmesa->NewGLState)
391      r200ValidateState( ctx );
392
393   /* NOTE: inputs != tnl->render_inputs - these are the untransformed
394    * inputs.
395    */
396   if (ctx->Light.Enabled) {
397      inputs |= VERT_BIT_NORMAL;
398      if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
399	 inputs |= VERT_BIT_COLOR1;
400      }
401   }
402
403   if ( (ctx->Fog.FogCoordinateSource == GL_FOG_COORD) && ctx->Fog.Enabled ) {
404      inputs |= VERT_BIT_FOG;
405   }
406
407   for (i = 0 ; i < ctx->Const.MaxTextureUnits; i++) {
408      if (ctx->Texture.Unit[i]._ReallyEnabled) {
409	 if (rmesa->TexGenNeedNormals[i]) {
410	    inputs |= VERT_BIT_NORMAL;
411	 }
412	 inputs |= VERT_BIT_TEX(i);
413      }
414   }
415
416   /* Do the actual work:
417    */
418   r200ReleaseArrays( ctx, ~0 /* stage->changed_inputs */ );
419   r200EmitArrays( ctx, inputs );
420
421   rmesa->tcl.Elts = VB->Elts;
422
423   for (i = 0 ; i < VB->PrimitiveCount ; i++)
424   {
425      GLuint prim = VB->Primitive[i].mode;
426      GLuint start = VB->Primitive[i].start;
427      GLuint length = VB->Primitive[i].count;
428
429      if (!length)
430	 continue;
431
432      if (rmesa->tcl.Elts)
433	 r200EmitEltPrimitive( ctx, start, start+length, prim );
434      else
435	 r200EmitPrimitive( ctx, start, start+length, prim );
436   }
437
438   return GL_FALSE;		/* finished the pipe */
439}
440
441
442
443/* Initial state for tcl stage.
444 */
445const struct tnl_pipeline_stage _r200_tcl_stage =
446{
447   "r200 render",
448   NULL,			/*  private */
449   NULL,
450   NULL,
451   NULL,
452   r200_run_tcl_render	/* run */
453};
454
455
456
457/**********************************************************************/
458/*                 Validate state at pipeline start                   */
459/**********************************************************************/
460
461
462/*-----------------------------------------------------------------------
463 * Manage TCL fallbacks
464 */
465
466
467static void transition_to_swtnl( GLcontext *ctx )
468{
469   r200ContextPtr rmesa = R200_CONTEXT(ctx);
470   TNLcontext *tnl = TNL_CONTEXT(ctx);
471
472   R200_NEWPRIM( rmesa );
473
474   r200ChooseVertexState( ctx );
475   r200ChooseRenderState( ctx );
476
477   _mesa_validate_all_lighting_tables( ctx );
478
479   tnl->Driver.NotifyMaterialChange =
480      _mesa_validate_all_lighting_tables;
481
482   r200ReleaseArrays( ctx, ~0 );
483
484   /* Still using the D3D based hardware-rasterizer from the radeon;
485    * need to put the card into D3D mode to make it work:
486    */
487   R200_STATECHANGE( rmesa, vap );
488   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~R200_VAP_TCL_ENABLE;
489}
490
491static void transition_to_hwtnl( GLcontext *ctx )
492{
493   r200ContextPtr rmesa = R200_CONTEXT(ctx);
494   TNLcontext *tnl = TNL_CONTEXT(ctx);
495
496   _tnl_need_projected_coords( ctx, GL_FALSE );
497
498   r200UpdateMaterial( ctx );
499
500   tnl->Driver.NotifyMaterialChange = r200UpdateMaterial;
501
502   if ( rmesa->dma.flush )
503      rmesa->dma.flush( rmesa );
504
505   rmesa->dma.flush = NULL;
506
507   if (rmesa->swtcl.indexed_verts.buf)
508      r200ReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts,
509			      __FUNCTION__ );
510
511   R200_STATECHANGE( rmesa, vap );
512   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_TCL_ENABLE;
513   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~R200_VAP_FORCE_W_TO_ONE;
514
515   if ( ((rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] & R200_FOG_USE_MASK)
516      == R200_FOG_USE_SPEC_ALPHA) &&
517      (ctx->Fog.FogCoordinateSource == GL_FOG_COORD )) {
518      R200_STATECHANGE( rmesa, ctx );
519      rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] &= ~R200_FOG_USE_MASK;
520      rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] |= R200_FOG_USE_VTX_FOG;
521   }
522
523   R200_STATECHANGE( rmesa, vte );
524   rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~(R200_VTX_XY_FMT|R200_VTX_Z_FMT);
525   rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] |= R200_VTX_W0_FMT;
526
527   if (R200_DEBUG & DEBUG_FALLBACKS)
528      fprintf(stderr, "R200 end tcl fallback\n");
529}
530
531
532static char *fallbackStrings[] = {
533   "Rasterization fallback",
534   "Unfilled triangles",
535   "Twosided lighting, differing materials",
536   "Materials in VB (maybe between begin/end)",
537   "Texgen unit 0",
538   "Texgen unit 1",
539   "Texgen unit 2",
540   "Texgen unit 3",
541   "Texgen unit 4",
542   "Texgen unit 5",
543   "User disable",
544   "Bitmap as points",
545   "Vertex program"
546};
547
548
549static char *getFallbackString(GLuint bit)
550{
551   int i = 0;
552   while (bit > 1) {
553      i++;
554      bit >>= 1;
555   }
556   return fallbackStrings[i];
557}
558
559
560
561void r200TclFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
562{
563   r200ContextPtr rmesa = R200_CONTEXT(ctx);
564   GLuint oldfallback = rmesa->TclFallback;
565
566   if (mode) {
567      rmesa->TclFallback |= bit;
568      if (oldfallback == 0) {
569	 if (R200_DEBUG & DEBUG_FALLBACKS)
570	    fprintf(stderr, "R200 begin tcl fallback %s\n",
571		    getFallbackString( bit ));
572	 transition_to_swtnl( ctx );
573      }
574   }
575   else {
576      rmesa->TclFallback &= ~bit;
577      if (oldfallback == bit) {
578	 if (R200_DEBUG & DEBUG_FALLBACKS)
579	    fprintf(stderr, "R200 end tcl fallback %s\n",
580		    getFallbackString( bit ));
581	 transition_to_hwtnl( ctx );
582      }
583   }
584}
585