2 * Mesa 3-D graphics library
5 * Copyright (C) 2007 Tungsten Graphics All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * TUNGSTEN GRAPHICS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Create a vertex program to execute the current fixed function T&L pipeline.
29 * \author Keith Whitwell
33 #include "main/glheader.h"
34 #include "main/ffvertex_prog.h"
35 #include "t_vp_build.h"
39 unsigned light_global_enabled
:1;
40 unsigned light_local_viewer
:1;
41 unsigned light_twoside
:1;
42 unsigned light_color_material
:1;
43 unsigned light_color_material_mask
:12;
44 unsigned light_material_mask
:12;
47 unsigned rescale_normals
:1;
48 unsigned fog_source_is_depth
:1;
49 unsigned tnl_do_vertex_fog
:1;
50 unsigned separate_specular
:1;
52 unsigned point_attenuated
:1;
53 unsigned texture_enabled_global
:1;
54 unsigned fragprog_inputs_read
:12;
57 unsigned light_enabled
:1;
58 unsigned light_eyepos3_is_zero
:1;
59 unsigned light_spotcutoff_is_180
:1;
60 unsigned light_attenuated
:1;
61 unsigned texunit_really_enabled
:1;
62 unsigned texmat_enabled
:1;
63 unsigned texgen_enabled
:4;
64 unsigned texgen_mode0
:4;
65 unsigned texgen_mode1
:4;
66 unsigned texgen_mode2
:4;
67 unsigned texgen_mode3
:4;
78 static GLuint
translate_fog_mode( GLenum mode
)
81 case GL_LINEAR
: return FOG_LINEAR
;
82 case GL_EXP
: return FOG_EXP
;
83 case GL_EXP2
: return FOG_EXP2
;
84 default: return FOG_NONE
;
89 #define TXG_OBJ_LINEAR 1
90 #define TXG_EYE_LINEAR 2
91 #define TXG_SPHERE_MAP 3
92 #define TXG_REFLECTION_MAP 4
93 #define TXG_NORMAL_MAP 5
95 static GLuint
translate_texgen( GLboolean enabled
, GLenum mode
)
101 case GL_OBJECT_LINEAR
: return TXG_OBJ_LINEAR
;
102 case GL_EYE_LINEAR
: return TXG_EYE_LINEAR
;
103 case GL_SPHERE_MAP
: return TXG_SPHERE_MAP
;
104 case GL_REFLECTION_MAP_NV
: return TXG_REFLECTION_MAP
;
105 case GL_NORMAL_MAP_NV
: return TXG_NORMAL_MAP
;
106 default: return TXG_NONE
;
110 static struct state_key
*make_state_key( GLcontext
*ctx
)
112 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
113 struct vertex_buffer
*VB
= &tnl
->vb
;
114 const struct gl_fragment_program
*fp
= ctx
->FragmentProgram
._Current
;
115 struct state_key
*key
= CALLOC_STRUCT(state_key
);
118 /* This now relies on texenvprogram.c being active:
122 key
->fragprog_inputs_read
= fp
->Base
.InputsRead
;
124 key
->separate_specular
= (ctx
->Light
.Model
.ColorControl
==
125 GL_SEPARATE_SPECULAR_COLOR
);
127 if (ctx
->Light
.Enabled
) {
128 key
->light_global_enabled
= 1;
130 if (ctx
->Light
.Model
.LocalViewer
)
131 key
->light_local_viewer
= 1;
133 if (ctx
->Light
.Model
.TwoSide
)
134 key
->light_twoside
= 1;
136 if (ctx
->Light
.ColorMaterialEnabled
) {
137 key
->light_color_material
= 1;
138 key
->light_color_material_mask
= ctx
->Light
.ColorMaterialBitmask
;
141 for (i
= _TNL_FIRST_MAT
; i
<= _TNL_LAST_MAT
; i
++)
142 if (VB
->AttribPtr
[i
]->stride
)
143 key
->light_material_mask
|= 1<<(i
-_TNL_ATTRIB_MAT_FRONT_AMBIENT
);
145 for (i
= 0; i
< MAX_LIGHTS
; i
++) {
146 struct gl_light
*light
= &ctx
->Light
.Light
[i
];
148 if (light
->Enabled
) {
149 key
->unit
[i
].light_enabled
= 1;
151 if (light
->EyePosition
[3] == 0.0)
152 key
->unit
[i
].light_eyepos3_is_zero
= 1;
154 if (light
->SpotCutoff
== 180.0)
155 key
->unit
[i
].light_spotcutoff_is_180
= 1;
157 if (light
->ConstantAttenuation
!= 1.0 ||
158 light
->LinearAttenuation
!= 0.0 ||
159 light
->QuadraticAttenuation
!= 0.0)
160 key
->unit
[i
].light_attenuated
= 1;
165 if (ctx
->Transform
.Normalize
)
168 if (ctx
->Transform
.RescaleNormals
)
169 key
->rescale_normals
= 1;
171 key
->fog_mode
= translate_fog_mode(fp
->FogOption
);
173 if (ctx
->Fog
.FogCoordinateSource
== GL_FRAGMENT_DEPTH_EXT
)
174 key
->fog_source_is_depth
= 1;
176 if (tnl
->_DoVertexFog
)
177 key
->tnl_do_vertex_fog
= 1;
179 if (ctx
->Point
._Attenuated
)
180 key
->point_attenuated
= 1;
182 if (ctx
->Texture
._TexGenEnabled
||
183 ctx
->Texture
._TexMatEnabled
||
184 ctx
->Texture
._EnabledUnits
)
185 key
->texture_enabled_global
= 1;
187 for (i
= 0; i
< MAX_TEXTURE_UNITS
; i
++) {
188 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
190 if (texUnit
->_ReallyEnabled
)
191 key
->unit
[i
].texunit_really_enabled
= 1;
193 if (ctx
->Texture
._TexMatEnabled
& ENABLE_TEXMAT(i
))
194 key
->unit
[i
].texmat_enabled
= 1;
196 if (texUnit
->TexGenEnabled
) {
197 key
->unit
[i
].texgen_enabled
= 1;
199 key
->unit
[i
].texgen_mode0
=
200 translate_texgen( texUnit
->TexGenEnabled
& (1<<0),
202 key
->unit
[i
].texgen_mode1
=
203 translate_texgen( texUnit
->TexGenEnabled
& (1<<1),
205 key
->unit
[i
].texgen_mode2
=
206 translate_texgen( texUnit
->TexGenEnabled
& (1<<2),
208 key
->unit
[i
].texgen_mode3
=
209 translate_texgen( texUnit
->TexGenEnabled
& (1<<3),
219 /* Very useful debugging tool - produces annotated listing of
220 * generated program with line/function references for each
221 * instruction back into this file:
223 #define DISASSEM (MESA_VERBOSE&VERBOSE_DISASSEM)
225 /* Should be tunable by the driver - do we want to do matrix
226 * multiplications with DP4's or with MUL/MAD's? SSE works better
227 * with the latter, drivers may differ.
233 /* Use uregs to represent registers internally, translate to Mesa's
234 * expected formats on emit.
236 * NOTE: These are passed by value extensively in this file rather
237 * than as usual by pointer reference. If this disturbs you, try
238 * remembering they are just 32bits in size.
240 * GCC is smart enough to deal with these dword-sized structures in
241 * much the same way as if I had defined them as dwords and was using
242 * macros to access and set the fields. This is much nicer and easier
247 GLint idx
:8; /* relative addressing may be negative */
255 const struct state_key
*state
;
256 struct gl_vertex_program
*program
;
259 GLuint temp_reserved
;
261 struct ureg eye_position
;
262 struct ureg eye_position_normalized
;
263 struct ureg eye_normal
;
264 struct ureg identity
;
267 GLuint color_materials
;
271 static const struct ureg undef
= {
289 static struct ureg
make_ureg(GLuint file
, GLint idx
)
295 reg
.swz
= SWIZZLE_NOOP
;
302 static struct ureg
negate( struct ureg reg
)
309 static struct ureg
swizzle( struct ureg reg
, int x
, int y
, int z
, int w
)
311 reg
.swz
= MAKE_SWIZZLE4(GET_SWZ(reg
.swz
, x
),
314 GET_SWZ(reg
.swz
, w
));
319 static struct ureg
swizzle1( struct ureg reg
, int x
)
321 return swizzle(reg
, x
, x
, x
, x
);
324 static struct ureg
get_temp( struct tnl_program
*p
)
326 int bit
= _mesa_ffs( ~p
->temp_in_use
);
328 _mesa_problem(NULL
, "%s: out of temporaries\n", __FILE__
);
332 if ((GLuint
) bit
> p
->program
->Base
.NumTemporaries
)
333 p
->program
->Base
.NumTemporaries
= bit
;
335 p
->temp_in_use
|= 1<<(bit
-1);
336 return make_ureg(PROGRAM_TEMPORARY
, bit
-1);
339 static struct ureg
reserve_temp( struct tnl_program
*p
)
341 struct ureg temp
= get_temp( p
);
342 p
->temp_reserved
|= 1<<temp
.idx
;
346 static void release_temp( struct tnl_program
*p
, struct ureg reg
)
348 if (reg
.file
== PROGRAM_TEMPORARY
) {
349 p
->temp_in_use
&= ~(1<<reg
.idx
);
350 p
->temp_in_use
|= p
->temp_reserved
; /* can't release reserved temps */
354 static void release_temps( struct tnl_program
*p
)
356 p
->temp_in_use
= p
->temp_reserved
;
361 static struct ureg
register_input( struct tnl_program
*p
, GLuint input
)
363 p
->program
->Base
.InputsRead
|= (1<<input
);
364 return make_ureg(PROGRAM_INPUT
, input
);
367 static struct ureg
register_output( struct tnl_program
*p
, GLuint output
)
369 p
->program
->Base
.OutputsWritten
|= (1<<output
);
370 return make_ureg(PROGRAM_OUTPUT
, output
);
373 static struct ureg
register_const4f( struct tnl_program
*p
,
386 idx
= _mesa_add_unnamed_constant( p
->program
->Base
.Parameters
, values
, 4,
388 ASSERT(swizzle
== SWIZZLE_NOOP
);
389 return make_ureg(PROGRAM_STATE_VAR
, idx
);
392 #define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1)
393 #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
394 #define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1)
395 #define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
397 static GLboolean
is_undef( struct ureg reg
)
399 return reg
.file
== PROGRAM_UNDEFINED
;
402 static struct ureg
get_identity_param( struct tnl_program
*p
)
404 if (is_undef(p
->identity
))
405 p
->identity
= register_const4f(p
, 0,0,0,1);
410 static struct ureg
register_param5(struct tnl_program
*p
,
417 gl_state_index tokens
[STATE_LENGTH
];
424 idx
= _mesa_add_state_reference( p
->program
->Base
.Parameters
, tokens
);
425 return make_ureg(PROGRAM_STATE_VAR
, idx
);
429 #define register_param1(p,s0) register_param5(p,s0,0,0,0,0)
430 #define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0)
431 #define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0)
432 #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
435 static void register_matrix_param5( struct tnl_program
*p
,
436 GLint s0
, /* modelview, projection, etc */
437 GLint s1
, /* texture matrix number */
438 GLint s2
, /* first row */
439 GLint s3
, /* last row */
440 GLint s4
, /* inverse, transpose, etc */
441 struct ureg
*matrix
)
445 /* This is a bit sad as the support is there to pull the whole
446 * matrix out in one go:
448 for (i
= 0; i
<= s3
- s2
; i
++)
449 matrix
[i
] = register_param5( p
, s0
, s1
, i
, i
, s4
);
454 * Convert a ureg source register to a prog_src_register.
456 static void emit_arg( struct prog_src_register
*src
,
459 assert(reg
.file
!= PROGRAM_OUTPUT
);
460 src
->File
= reg
.file
;
461 src
->Index
= reg
.idx
;
462 src
->Swizzle
= reg
.swz
;
463 src
->NegateBase
= reg
.negate
? NEGATE_XYZW
: 0;
470 * XXX This should go away someday, but still referenced by some drivers...
472 void _tnl_UpdateFixedFunctionProgram( GLcontext
*ctx
)
474 const struct gl_vertex_program
*prev
= ctx
->VertexProgram
._Current
;
476 if (!ctx
->VertexProgram
._Current
||
477 ctx
->VertexProgram
._Current
== ctx
->VertexProgram
._TnlProgram
) {
478 struct gl_vertex_program
*newProg
;
480 newProg
= _mesa_get_fixed_func_vertex_program(ctx
);
482 _mesa_reference_vertprog(ctx
, &ctx
->VertexProgram
._TnlProgram
, newProg
);
483 _mesa_reference_vertprog(ctx
, &ctx
->VertexProgram
._Current
, newProg
);
486 /* Tell the driver about the change. Could define a new target for
489 if (ctx
->VertexProgram
._Current
!= prev
&& ctx
->Driver
.BindProgram
) {
490 ctx
->Driver
.BindProgram(ctx
, GL_VERTEX_PROGRAM_ARB
,
491 (struct gl_program
*) ctx
->VertexProgram
._Current
);