1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2007 VMware, Inc.
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg/**
29848b8605Smrg * \file ffvertex_prog.c
30848b8605Smrg *
31848b8605Smrg * Create a vertex program to execute the current fixed function T&L pipeline.
32848b8605Smrg * \author Keith Whitwell
33848b8605Smrg */
34848b8605Smrg
35848b8605Smrg
36b8e80941Smrg#include "main/errors.h"
37848b8605Smrg#include "main/glheader.h"
38848b8605Smrg#include "main/mtypes.h"
39848b8605Smrg#include "main/macros.h"
40848b8605Smrg#include "main/enums.h"
41848b8605Smrg#include "main/ffvertex_prog.h"
42848b8605Smrg#include "program/program.h"
43848b8605Smrg#include "program/prog_cache.h"
44848b8605Smrg#include "program/prog_instruction.h"
45848b8605Smrg#include "program/prog_parameter.h"
46848b8605Smrg#include "program/prog_print.h"
47848b8605Smrg#include "program/prog_statevars.h"
48b8e80941Smrg#include "util/bitscan.h"
49848b8605Smrg
50848b8605Smrg
51848b8605Smrg/** Max of number of lights and texture coord units */
52848b8605Smrg#define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS)
53848b8605Smrg
54848b8605Smrgstruct state_key {
55b8e80941Smrg   GLbitfield varying_vp_inputs;
56b8e80941Smrg
57b8e80941Smrg   unsigned fragprog_inputs_read:12;
58b8e80941Smrg
59848b8605Smrg   unsigned light_color_material_mask:12;
60848b8605Smrg   unsigned light_global_enabled:1;
61848b8605Smrg   unsigned light_local_viewer:1;
62848b8605Smrg   unsigned light_twoside:1;
63848b8605Smrg   unsigned material_shininess_is_zero:1;
64848b8605Smrg   unsigned need_eye_coords:1;
65848b8605Smrg   unsigned normalize:1;
66848b8605Smrg   unsigned rescale_normals:1;
67848b8605Smrg
68848b8605Smrg   unsigned fog_distance_mode:2;
69848b8605Smrg   unsigned separate_specular:1;
70848b8605Smrg   unsigned point_attenuated:1;
71848b8605Smrg
72848b8605Smrg   struct {
73b8e80941Smrg      unsigned char light_enabled:1;
74b8e80941Smrg      unsigned char light_eyepos3_is_zero:1;
75b8e80941Smrg      unsigned char light_spotcutoff_is_180:1;
76b8e80941Smrg      unsigned char light_attenuated:1;
77b8e80941Smrg      unsigned char texmat_enabled:1;
78b8e80941Smrg      unsigned char coord_replace:1;
79b8e80941Smrg      unsigned char texgen_enabled:1;
80b8e80941Smrg      unsigned char texgen_mode0:4;
81b8e80941Smrg      unsigned char texgen_mode1:4;
82b8e80941Smrg      unsigned char texgen_mode2:4;
83b8e80941Smrg      unsigned char texgen_mode3:4;
84848b8605Smrg   } unit[NUM_UNITS];
85848b8605Smrg};
86848b8605Smrg
87848b8605Smrg
88848b8605Smrg#define TXG_NONE           0
89848b8605Smrg#define TXG_OBJ_LINEAR     1
90848b8605Smrg#define TXG_EYE_LINEAR     2
91848b8605Smrg#define TXG_SPHERE_MAP     3
92848b8605Smrg#define TXG_REFLECTION_MAP 4
93848b8605Smrg#define TXG_NORMAL_MAP     5
94848b8605Smrg
95848b8605Smrgstatic GLuint translate_texgen( GLboolean enabled, GLenum mode )
96848b8605Smrg{
97848b8605Smrg   if (!enabled)
98848b8605Smrg      return TXG_NONE;
99848b8605Smrg
100848b8605Smrg   switch (mode) {
101848b8605Smrg   case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR;
102848b8605Smrg   case GL_EYE_LINEAR: return TXG_EYE_LINEAR;
103848b8605Smrg   case GL_SPHERE_MAP: return TXG_SPHERE_MAP;
104848b8605Smrg   case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP;
105848b8605Smrg   case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP;
106848b8605Smrg   default: return TXG_NONE;
107848b8605Smrg   }
108848b8605Smrg}
109848b8605Smrg
110848b8605Smrg#define FDM_EYE_RADIAL    0
111848b8605Smrg#define FDM_EYE_PLANE     1
112848b8605Smrg#define FDM_EYE_PLANE_ABS 2
113b8e80941Smrg#define FDM_FROM_ARRAY    3
114848b8605Smrg
115b8e80941Smrgstatic GLuint translate_fog_distance_mode(GLenum source, GLenum mode)
116848b8605Smrg{
117b8e80941Smrg   if (source == GL_FRAGMENT_DEPTH_EXT) {
118b8e80941Smrg      switch (mode) {
119b8e80941Smrg      case GL_EYE_RADIAL_NV:
120b8e80941Smrg         return FDM_EYE_RADIAL;
121b8e80941Smrg      case GL_EYE_PLANE:
122b8e80941Smrg         return FDM_EYE_PLANE;
123b8e80941Smrg      default: /* shouldn't happen; fall through to a sensible default */
124b8e80941Smrg      case GL_EYE_PLANE_ABSOLUTE_NV:
125b8e80941Smrg         return FDM_EYE_PLANE_ABS;
126b8e80941Smrg      }
127b8e80941Smrg   } else {
128b8e80941Smrg      return FDM_FROM_ARRAY;
129848b8605Smrg   }
130848b8605Smrg}
131848b8605Smrg
132848b8605Smrgstatic GLboolean check_active_shininess( struct gl_context *ctx,
133848b8605Smrg                                         const struct state_key *key,
134848b8605Smrg                                         GLuint side )
135848b8605Smrg{
136848b8605Smrg   GLuint attr = MAT_ATTRIB_FRONT_SHININESS + side;
137848b8605Smrg
138848b8605Smrg   if ((key->varying_vp_inputs & VERT_BIT_COLOR0) &&
139848b8605Smrg       (key->light_color_material_mask & (1 << attr)))
140848b8605Smrg      return GL_TRUE;
141848b8605Smrg
142b8e80941Smrg   if (key->varying_vp_inputs & VERT_BIT_MAT(attr))
143848b8605Smrg      return GL_TRUE;
144848b8605Smrg
145848b8605Smrg   if (ctx->Light.Material.Attrib[attr][0] != 0.0F)
146848b8605Smrg      return GL_TRUE;
147848b8605Smrg
148848b8605Smrg   return GL_FALSE;
149848b8605Smrg}
150848b8605Smrg
151848b8605Smrg
152848b8605Smrgstatic void make_state_key( struct gl_context *ctx, struct state_key *key )
153848b8605Smrg{
154b8e80941Smrg   const struct gl_program *fp = ctx->FragmentProgram._Current;
155b8e80941Smrg   GLbitfield mask;
156848b8605Smrg
157848b8605Smrg   memset(key, 0, sizeof(struct state_key));
158848b8605Smrg
159848b8605Smrg   /* This now relies on texenvprogram.c being active:
160848b8605Smrg    */
161848b8605Smrg   assert(fp);
162848b8605Smrg
163848b8605Smrg   key->need_eye_coords = ctx->_NeedEyeCoords;
164848b8605Smrg
165b8e80941Smrg   key->fragprog_inputs_read = fp->info.inputs_read;
166848b8605Smrg   key->varying_vp_inputs = ctx->varying_vp_inputs;
167848b8605Smrg
168848b8605Smrg   if (ctx->RenderMode == GL_FEEDBACK) {
169848b8605Smrg      /* make sure the vertprog emits color and tex0 */
170848b8605Smrg      key->fragprog_inputs_read |= (VARYING_BIT_COL0 | VARYING_BIT_TEX0);
171848b8605Smrg   }
172848b8605Smrg
173848b8605Smrg   if (ctx->Light.Enabled) {
174848b8605Smrg      key->light_global_enabled = 1;
175848b8605Smrg
176848b8605Smrg      if (ctx->Light.Model.LocalViewer)
177848b8605Smrg	 key->light_local_viewer = 1;
178848b8605Smrg
179848b8605Smrg      if (ctx->Light.Model.TwoSide)
180848b8605Smrg	 key->light_twoside = 1;
181848b8605Smrg
182b8e80941Smrg      if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
183b8e80941Smrg         key->separate_specular = 1;
184b8e80941Smrg
185848b8605Smrg      if (ctx->Light.ColorMaterialEnabled) {
186848b8605Smrg	 key->light_color_material_mask = ctx->Light._ColorMaterialBitmask;
187848b8605Smrg      }
188848b8605Smrg
189b8e80941Smrg      mask = ctx->Light._EnabledLights;
190b8e80941Smrg      while (mask) {
191b8e80941Smrg         const int i = u_bit_scan(&mask);
192b8e80941Smrg         struct gl_light *light = &ctx->Light.Light[i];
193848b8605Smrg
194b8e80941Smrg         key->unit[i].light_enabled = 1;
195848b8605Smrg
196b8e80941Smrg         if (light->EyePosition[3] == 0.0F)
197b8e80941Smrg            key->unit[i].light_eyepos3_is_zero = 1;
198848b8605Smrg
199b8e80941Smrg         if (light->SpotCutoff == 180.0F)
200b8e80941Smrg            key->unit[i].light_spotcutoff_is_180 = 1;
201848b8605Smrg
202b8e80941Smrg         if (light->ConstantAttenuation != 1.0F ||
203b8e80941Smrg             light->LinearAttenuation != 0.0F ||
204b8e80941Smrg             light->QuadraticAttenuation != 0.0F)
205b8e80941Smrg            key->unit[i].light_attenuated = 1;
206848b8605Smrg      }
207848b8605Smrg
208848b8605Smrg      if (check_active_shininess(ctx, key, 0)) {
209848b8605Smrg         key->material_shininess_is_zero = 0;
210848b8605Smrg      }
211848b8605Smrg      else if (key->light_twoside &&
212848b8605Smrg               check_active_shininess(ctx, key, 1)) {
213848b8605Smrg         key->material_shininess_is_zero = 0;
214848b8605Smrg      }
215848b8605Smrg      else {
216848b8605Smrg         key->material_shininess_is_zero = 1;
217848b8605Smrg      }
218848b8605Smrg   }
219848b8605Smrg
220848b8605Smrg   if (ctx->Transform.Normalize)
221848b8605Smrg      key->normalize = 1;
222848b8605Smrg
223848b8605Smrg   if (ctx->Transform.RescaleNormals)
224848b8605Smrg      key->rescale_normals = 1;
225848b8605Smrg
226b8e80941Smrg   /* Only distinguish fog parameters if we actually need */
227b8e80941Smrg   if (key->fragprog_inputs_read & VARYING_BIT_FOGC)
228b8e80941Smrg      key->fog_distance_mode =
229b8e80941Smrg         translate_fog_distance_mode(ctx->Fog.FogCoordinateSource,
230b8e80941Smrg                                     ctx->Fog.FogDistanceMode);
231848b8605Smrg
232848b8605Smrg   if (ctx->Point._Attenuated)
233848b8605Smrg      key->point_attenuated = 1;
234848b8605Smrg
235b8e80941Smrg   mask = ctx->Texture._EnabledCoordUnits | ctx->Texture._TexGenEnabled
236b8e80941Smrg      | ctx->Texture._TexMatEnabled | ctx->Point.CoordReplace;
237b8e80941Smrg   while (mask) {
238b8e80941Smrg      const int i = u_bit_scan(&mask);
239b8e80941Smrg      struct gl_fixedfunc_texture_unit *texUnit =
240b8e80941Smrg         &ctx->Texture.FixedFuncUnit[i];
241848b8605Smrg
242848b8605Smrg      if (ctx->Point.PointSprite)
243b8e80941Smrg	 if (ctx->Point.CoordReplace & (1u << i))
244848b8605Smrg	    key->unit[i].coord_replace = 1;
245848b8605Smrg
246848b8605Smrg      if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i))
247848b8605Smrg	 key->unit[i].texmat_enabled = 1;
248848b8605Smrg
249848b8605Smrg      if (texUnit->TexGenEnabled) {
250848b8605Smrg	 key->unit[i].texgen_enabled = 1;
251848b8605Smrg
252848b8605Smrg	 key->unit[i].texgen_mode0 =
253848b8605Smrg	    translate_texgen( texUnit->TexGenEnabled & (1<<0),
254848b8605Smrg			      texUnit->GenS.Mode );
255848b8605Smrg	 key->unit[i].texgen_mode1 =
256848b8605Smrg	    translate_texgen( texUnit->TexGenEnabled & (1<<1),
257848b8605Smrg			      texUnit->GenT.Mode );
258848b8605Smrg	 key->unit[i].texgen_mode2 =
259848b8605Smrg	    translate_texgen( texUnit->TexGenEnabled & (1<<2),
260848b8605Smrg			      texUnit->GenR.Mode );
261848b8605Smrg	 key->unit[i].texgen_mode3 =
262848b8605Smrg	    translate_texgen( texUnit->TexGenEnabled & (1<<3),
263848b8605Smrg			      texUnit->GenQ.Mode );
264848b8605Smrg      }
265848b8605Smrg   }
266848b8605Smrg}
267848b8605Smrg
268848b8605Smrg
269848b8605Smrg
270848b8605Smrg/* Very useful debugging tool - produces annotated listing of
271848b8605Smrg * generated program with line/function references for each
272848b8605Smrg * instruction back into this file:
273848b8605Smrg */
274848b8605Smrg#define DISASSEM 0
275848b8605Smrg
276848b8605Smrg
277848b8605Smrg/* Use uregs to represent registers internally, translate to Mesa's
278848b8605Smrg * expected formats on emit.
279848b8605Smrg *
280848b8605Smrg * NOTE: These are passed by value extensively in this file rather
281848b8605Smrg * than as usual by pointer reference.  If this disturbs you, try
282848b8605Smrg * remembering they are just 32bits in size.
283848b8605Smrg *
284848b8605Smrg * GCC is smart enough to deal with these dword-sized structures in
285848b8605Smrg * much the same way as if I had defined them as dwords and was using
286848b8605Smrg * macros to access and set the fields.  This is much nicer and easier
287848b8605Smrg * to evolve.
288848b8605Smrg */
289848b8605Smrgstruct ureg {
290848b8605Smrg   GLuint file:4;
291848b8605Smrg   GLint idx:9;      /* relative addressing may be negative */
292848b8605Smrg                     /* sizeof(idx) should == sizeof(prog_src_reg::Index) */
293848b8605Smrg   GLuint negate:1;
294848b8605Smrg   GLuint swz:12;
295848b8605Smrg   GLuint pad:6;
296848b8605Smrg};
297848b8605Smrg
298848b8605Smrg
299848b8605Smrgstruct tnl_program {
300848b8605Smrg   const struct state_key *state;
301b8e80941Smrg   struct gl_program *program;
302b8e80941Smrg   GLuint max_inst;  /** number of instructions allocated for program */
303848b8605Smrg   GLboolean mvp_with_dp4;
304848b8605Smrg
305848b8605Smrg   GLuint temp_in_use;
306848b8605Smrg   GLuint temp_reserved;
307848b8605Smrg
308848b8605Smrg   struct ureg eye_position;
309848b8605Smrg   struct ureg eye_position_z;
310848b8605Smrg   struct ureg eye_position_normalized;
311848b8605Smrg   struct ureg transformed_normal;
312848b8605Smrg   struct ureg identity;
313848b8605Smrg
314848b8605Smrg   GLuint materials;
315848b8605Smrg   GLuint color_materials;
316848b8605Smrg};
317848b8605Smrg
318848b8605Smrg
319848b8605Smrgstatic const struct ureg undef = {
320848b8605Smrg   PROGRAM_UNDEFINED,
321848b8605Smrg   0,
322848b8605Smrg   0,
323848b8605Smrg   0,
324848b8605Smrg   0
325848b8605Smrg};
326848b8605Smrg
327848b8605Smrg/* Local shorthand:
328848b8605Smrg */
329848b8605Smrg#define X    SWIZZLE_X
330848b8605Smrg#define Y    SWIZZLE_Y
331848b8605Smrg#define Z    SWIZZLE_Z
332848b8605Smrg#define W    SWIZZLE_W
333848b8605Smrg
334848b8605Smrg
335848b8605Smrg/* Construct a ureg:
336848b8605Smrg */
337848b8605Smrgstatic struct ureg make_ureg(GLuint file, GLint idx)
338848b8605Smrg{
339848b8605Smrg   struct ureg reg;
340848b8605Smrg   reg.file = file;
341848b8605Smrg   reg.idx = idx;
342848b8605Smrg   reg.negate = 0;
343848b8605Smrg   reg.swz = SWIZZLE_NOOP;
344848b8605Smrg   reg.pad = 0;
345848b8605Smrg   return reg;
346848b8605Smrg}
347848b8605Smrg
348848b8605Smrg
349848b8605Smrgstatic struct ureg negate( struct ureg reg )
350848b8605Smrg{
351848b8605Smrg   reg.negate ^= 1;
352848b8605Smrg   return reg;
353848b8605Smrg}
354848b8605Smrg
355848b8605Smrg
356848b8605Smrgstatic struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
357848b8605Smrg{
358848b8605Smrg   reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
359848b8605Smrg			   GET_SWZ(reg.swz, y),
360848b8605Smrg			   GET_SWZ(reg.swz, z),
361848b8605Smrg			   GET_SWZ(reg.swz, w));
362848b8605Smrg   return reg;
363848b8605Smrg}
364848b8605Smrg
365848b8605Smrg
366848b8605Smrgstatic struct ureg swizzle1( struct ureg reg, int x )
367848b8605Smrg{
368848b8605Smrg   return swizzle(reg, x, x, x, x);
369848b8605Smrg}
370848b8605Smrg
371848b8605Smrg
372848b8605Smrgstatic struct ureg get_temp( struct tnl_program *p )
373848b8605Smrg{
374848b8605Smrg   int bit = ffs( ~p->temp_in_use );
375848b8605Smrg   if (!bit) {
376848b8605Smrg      _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
377848b8605Smrg      exit(1);
378848b8605Smrg   }
379848b8605Smrg
380b8e80941Smrg   if ((GLuint) bit > p->program->arb.NumTemporaries)
381b8e80941Smrg      p->program->arb.NumTemporaries = bit;
382848b8605Smrg
383848b8605Smrg   p->temp_in_use |= 1<<(bit-1);
384848b8605Smrg   return make_ureg(PROGRAM_TEMPORARY, bit-1);
385848b8605Smrg}
386848b8605Smrg
387848b8605Smrg
388848b8605Smrgstatic struct ureg reserve_temp( struct tnl_program *p )
389848b8605Smrg{
390848b8605Smrg   struct ureg temp = get_temp( p );
391848b8605Smrg   p->temp_reserved |= 1<<temp.idx;
392848b8605Smrg   return temp;
393848b8605Smrg}
394848b8605Smrg
395848b8605Smrg
396848b8605Smrgstatic void release_temp( struct tnl_program *p, struct ureg reg )
397848b8605Smrg{
398848b8605Smrg   if (reg.file == PROGRAM_TEMPORARY) {
399848b8605Smrg      p->temp_in_use &= ~(1<<reg.idx);
400848b8605Smrg      p->temp_in_use |= p->temp_reserved; /* can't release reserved temps */
401848b8605Smrg   }
402848b8605Smrg}
403848b8605Smrg
404848b8605Smrgstatic void release_temps( struct tnl_program *p )
405848b8605Smrg{
406848b8605Smrg   p->temp_in_use = p->temp_reserved;
407848b8605Smrg}
408848b8605Smrg
409848b8605Smrg
410848b8605Smrgstatic struct ureg register_param5(struct tnl_program *p,
411848b8605Smrg				   GLint s0,
412848b8605Smrg				   GLint s1,
413848b8605Smrg				   GLint s2,
414848b8605Smrg				   GLint s3,
415848b8605Smrg                                   GLint s4)
416848b8605Smrg{
417b8e80941Smrg   gl_state_index16 tokens[STATE_LENGTH];
418848b8605Smrg   GLint idx;
419848b8605Smrg   tokens[0] = s0;
420848b8605Smrg   tokens[1] = s1;
421848b8605Smrg   tokens[2] = s2;
422848b8605Smrg   tokens[3] = s3;
423848b8605Smrg   tokens[4] = s4;
424b8e80941Smrg   idx = _mesa_add_state_reference(p->program->Parameters, tokens );
425848b8605Smrg   return make_ureg(PROGRAM_STATE_VAR, idx);
426848b8605Smrg}
427848b8605Smrg
428848b8605Smrg
429848b8605Smrg#define register_param1(p,s0)          register_param5(p,s0,0,0,0,0)
430848b8605Smrg#define register_param2(p,s0,s1)       register_param5(p,s0,s1,0,0,0)
431848b8605Smrg#define register_param3(p,s0,s1,s2)    register_param5(p,s0,s1,s2,0,0)
432848b8605Smrg#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
433848b8605Smrg
434848b8605Smrg
435848b8605Smrg
436848b8605Smrg/**
437848b8605Smrg * \param input  one of VERT_ATTRIB_x tokens.
438848b8605Smrg */
439848b8605Smrgstatic struct ureg register_input( struct tnl_program *p, GLuint input )
440848b8605Smrg{
441848b8605Smrg   assert(input < VERT_ATTRIB_MAX);
442848b8605Smrg
443848b8605Smrg   if (p->state->varying_vp_inputs & VERT_BIT(input)) {
444b8e80941Smrg      p->program->info.inputs_read |= VERT_BIT(input);
445848b8605Smrg      return make_ureg(PROGRAM_INPUT, input);
446848b8605Smrg   }
447848b8605Smrg   else {
448848b8605Smrg      return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, input );
449848b8605Smrg   }
450848b8605Smrg}
451848b8605Smrg
452848b8605Smrg
453848b8605Smrg/**
454848b8605Smrg * \param input  one of VARYING_SLOT_x tokens.
455848b8605Smrg */
456848b8605Smrgstatic struct ureg register_output( struct tnl_program *p, GLuint output )
457848b8605Smrg{
458b8e80941Smrg   p->program->info.outputs_written |= BITFIELD64_BIT(output);
459848b8605Smrg   return make_ureg(PROGRAM_OUTPUT, output);
460848b8605Smrg}
461848b8605Smrg
462848b8605Smrg
463848b8605Smrgstatic struct ureg register_const4f( struct tnl_program *p,
464848b8605Smrg			      GLfloat s0,
465848b8605Smrg			      GLfloat s1,
466848b8605Smrg			      GLfloat s2,
467848b8605Smrg			      GLfloat s3)
468848b8605Smrg{
469848b8605Smrg   gl_constant_value values[4];
470848b8605Smrg   GLint idx;
471848b8605Smrg   GLuint swizzle;
472848b8605Smrg   values[0].f = s0;
473848b8605Smrg   values[1].f = s1;
474848b8605Smrg   values[2].f = s2;
475848b8605Smrg   values[3].f = s3;
476b8e80941Smrg   idx = _mesa_add_unnamed_constant(p->program->Parameters, values, 4,
477b8e80941Smrg                                    &swizzle );
478b8e80941Smrg   assert(swizzle == SWIZZLE_NOOP);
479848b8605Smrg   return make_ureg(PROGRAM_CONSTANT, idx);
480848b8605Smrg}
481848b8605Smrg
482848b8605Smrg#define register_const1f(p, s0)         register_const4f(p, s0, 0, 0, 1)
483848b8605Smrg#define register_scalar_const(p, s0)    register_const4f(p, s0, s0, s0, s0)
484848b8605Smrg#define register_const2f(p, s0, s1)     register_const4f(p, s0, s1, 0, 1)
485848b8605Smrg#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
486848b8605Smrg
487848b8605Smrgstatic GLboolean is_undef( struct ureg reg )
488848b8605Smrg{
489848b8605Smrg   return reg.file == PROGRAM_UNDEFINED;
490848b8605Smrg}
491848b8605Smrg
492848b8605Smrg
493848b8605Smrgstatic struct ureg get_identity_param( struct tnl_program *p )
494848b8605Smrg{
495848b8605Smrg   if (is_undef(p->identity))
496848b8605Smrg      p->identity = register_const4f(p, 0,0,0,1);
497848b8605Smrg
498848b8605Smrg   return p->identity;
499848b8605Smrg}
500848b8605Smrg
501848b8605Smrgstatic void register_matrix_param5( struct tnl_program *p,
502848b8605Smrg				    GLint s0, /* modelview, projection, etc */
503848b8605Smrg				    GLint s1, /* texture matrix number */
504848b8605Smrg				    GLint s2, /* first row */
505848b8605Smrg				    GLint s3, /* last row */
506848b8605Smrg				    GLint s4, /* inverse, transpose, etc */
507848b8605Smrg				    struct ureg *matrix )
508848b8605Smrg{
509848b8605Smrg   GLint i;
510848b8605Smrg
511848b8605Smrg   /* This is a bit sad as the support is there to pull the whole
512848b8605Smrg    * matrix out in one go:
513848b8605Smrg    */
514848b8605Smrg   for (i = 0; i <= s3 - s2; i++)
515848b8605Smrg      matrix[i] = register_param5( p, s0, s1, i, i, s4 );
516848b8605Smrg}
517848b8605Smrg
518848b8605Smrg
519848b8605Smrgstatic void emit_arg( struct prog_src_register *src,
520848b8605Smrg		      struct ureg reg )
521848b8605Smrg{
522848b8605Smrg   src->File = reg.file;
523848b8605Smrg   src->Index = reg.idx;
524848b8605Smrg   src->Swizzle = reg.swz;
525848b8605Smrg   src->Negate = reg.negate ? NEGATE_XYZW : NEGATE_NONE;
526848b8605Smrg   src->RelAddr = 0;
527848b8605Smrg   /* Check that bitfield sizes aren't exceeded */
528b8e80941Smrg   assert(src->Index == reg.idx);
529848b8605Smrg}
530848b8605Smrg
531848b8605Smrg
532848b8605Smrgstatic void emit_dst( struct prog_dst_register *dst,
533848b8605Smrg		      struct ureg reg, GLuint mask )
534848b8605Smrg{
535848b8605Smrg   dst->File = reg.file;
536848b8605Smrg   dst->Index = reg.idx;
537848b8605Smrg   /* allow zero as a shorthand for xyzw */
538848b8605Smrg   dst->WriteMask = mask ? mask : WRITEMASK_XYZW;
539848b8605Smrg   /* Check that bitfield sizes aren't exceeded */
540b8e80941Smrg   assert(dst->Index == reg.idx);
541848b8605Smrg}
542848b8605Smrg
543848b8605Smrg
544848b8605Smrgstatic void debug_insn( struct prog_instruction *inst, const char *fn,
545848b8605Smrg			GLuint line )
546848b8605Smrg{
547848b8605Smrg   if (DISASSEM) {
548848b8605Smrg      static const char *last_fn;
549848b8605Smrg
550848b8605Smrg      if (fn != last_fn) {
551848b8605Smrg	 last_fn = fn;
552848b8605Smrg	 printf("%s:\n", fn);
553848b8605Smrg      }
554848b8605Smrg
555848b8605Smrg      printf("%d:\t", line);
556848b8605Smrg      _mesa_print_instruction(inst);
557848b8605Smrg   }
558848b8605Smrg}
559848b8605Smrg
560848b8605Smrg
561848b8605Smrgstatic void emit_op3fn(struct tnl_program *p,
562848b8605Smrg                       enum prog_opcode op,
563848b8605Smrg		       struct ureg dest,
564848b8605Smrg		       GLuint mask,
565848b8605Smrg		       struct ureg src0,
566848b8605Smrg		       struct ureg src1,
567848b8605Smrg		       struct ureg src2,
568848b8605Smrg		       const char *fn,
569848b8605Smrg		       GLuint line)
570848b8605Smrg{
571848b8605Smrg   GLuint nr;
572848b8605Smrg   struct prog_instruction *inst;
573848b8605Smrg
574b8e80941Smrg   assert(p->program->arb.NumInstructions <= p->max_inst);
575848b8605Smrg
576b8e80941Smrg   if (p->program->arb.NumInstructions == p->max_inst) {
577848b8605Smrg      /* need to extend the program's instruction array */
578848b8605Smrg      struct prog_instruction *newInst;
579848b8605Smrg
580848b8605Smrg      /* double the size */
581848b8605Smrg      p->max_inst *= 2;
582848b8605Smrg
583b8e80941Smrg      newInst =
584b8e80941Smrg         rzalloc_array(p->program, struct prog_instruction, p->max_inst);
585848b8605Smrg      if (!newInst) {
586848b8605Smrg         _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build");
587848b8605Smrg         return;
588848b8605Smrg      }
589848b8605Smrg
590b8e80941Smrg      _mesa_copy_instructions(newInst, p->program->arb.Instructions,
591b8e80941Smrg                              p->program->arb.NumInstructions);
592848b8605Smrg
593b8e80941Smrg      ralloc_free(p->program->arb.Instructions);
594848b8605Smrg
595b8e80941Smrg      p->program->arb.Instructions = newInst;
596848b8605Smrg   }
597848b8605Smrg
598b8e80941Smrg   nr = p->program->arb.NumInstructions++;
599848b8605Smrg
600b8e80941Smrg   inst = &p->program->arb.Instructions[nr];
601848b8605Smrg   inst->Opcode = (enum prog_opcode) op;
602848b8605Smrg
603848b8605Smrg   emit_arg( &inst->SrcReg[0], src0 );
604848b8605Smrg   emit_arg( &inst->SrcReg[1], src1 );
605848b8605Smrg   emit_arg( &inst->SrcReg[2], src2 );
606848b8605Smrg
607848b8605Smrg   emit_dst( &inst->DstReg, dest, mask );
608848b8605Smrg
609848b8605Smrg   debug_insn(inst, fn, line);
610848b8605Smrg}
611848b8605Smrg
612848b8605Smrg
613848b8605Smrg#define emit_op3(p, op, dst, mask, src0, src1, src2) \
614b8e80941Smrg   emit_op3fn(p, op, dst, mask, src0, src1, src2, __func__, __LINE__)
615848b8605Smrg
616848b8605Smrg#define emit_op2(p, op, dst, mask, src0, src1) \
617b8e80941Smrg    emit_op3fn(p, op, dst, mask, src0, src1, undef, __func__, __LINE__)
618848b8605Smrg
619848b8605Smrg#define emit_op1(p, op, dst, mask, src0) \
620b8e80941Smrg    emit_op3fn(p, op, dst, mask, src0, undef, undef, __func__, __LINE__)
621848b8605Smrg
622848b8605Smrg
623848b8605Smrgstatic struct ureg make_temp( struct tnl_program *p, struct ureg reg )
624848b8605Smrg{
625848b8605Smrg   if (reg.file == PROGRAM_TEMPORARY &&
626848b8605Smrg       !(p->temp_reserved & (1<<reg.idx)))
627848b8605Smrg      return reg;
628848b8605Smrg   else {
629848b8605Smrg      struct ureg temp = get_temp(p);
630848b8605Smrg      emit_op1(p, OPCODE_MOV, temp, 0, reg);
631848b8605Smrg      return temp;
632848b8605Smrg   }
633848b8605Smrg}
634848b8605Smrg
635848b8605Smrg
636848b8605Smrg/* Currently no tracking performed of input/output/register size or
637848b8605Smrg * active elements.  Could be used to reduce these operations, as
638848b8605Smrg * could the matrix type.
639848b8605Smrg */
640848b8605Smrgstatic void emit_matrix_transform_vec4( struct tnl_program *p,
641848b8605Smrg					struct ureg dest,
642848b8605Smrg					const struct ureg *mat,
643848b8605Smrg					struct ureg src)
644848b8605Smrg{
645848b8605Smrg   emit_op2(p, OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]);
646848b8605Smrg   emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]);
647848b8605Smrg   emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]);
648848b8605Smrg   emit_op2(p, OPCODE_DP4, dest, WRITEMASK_W, src, mat[3]);
649848b8605Smrg}
650848b8605Smrg
651848b8605Smrg
652848b8605Smrg/* This version is much easier to implement if writemasks are not
653848b8605Smrg * supported natively on the target or (like SSE), the target doesn't
654848b8605Smrg * have a clean/obvious dotproduct implementation.
655848b8605Smrg */
656848b8605Smrgstatic void emit_transpose_matrix_transform_vec4( struct tnl_program *p,
657848b8605Smrg						  struct ureg dest,
658848b8605Smrg						  const struct ureg *mat,
659848b8605Smrg						  struct ureg src)
660848b8605Smrg{
661848b8605Smrg   struct ureg tmp;
662848b8605Smrg
663848b8605Smrg   if (dest.file != PROGRAM_TEMPORARY)
664848b8605Smrg      tmp = get_temp(p);
665848b8605Smrg   else
666848b8605Smrg      tmp = dest;
667848b8605Smrg
668848b8605Smrg   emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
669848b8605Smrg   emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
670848b8605Smrg   emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
671848b8605Smrg   emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
672848b8605Smrg
673848b8605Smrg   if (dest.file != PROGRAM_TEMPORARY)
674848b8605Smrg      release_temp(p, tmp);
675848b8605Smrg}
676848b8605Smrg
677848b8605Smrg
678848b8605Smrgstatic void emit_matrix_transform_vec3( struct tnl_program *p,
679848b8605Smrg					struct ureg dest,
680848b8605Smrg					const struct ureg *mat,
681848b8605Smrg					struct ureg src)
682848b8605Smrg{
683848b8605Smrg   emit_op2(p, OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]);
684848b8605Smrg   emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]);
685848b8605Smrg   emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Z, src, mat[2]);
686848b8605Smrg}
687848b8605Smrg
688848b8605Smrg
689848b8605Smrgstatic void emit_normalize_vec3( struct tnl_program *p,
690848b8605Smrg				 struct ureg dest,
691848b8605Smrg				 struct ureg src )
692848b8605Smrg{
693848b8605Smrg   struct ureg tmp = get_temp(p);
694848b8605Smrg   emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, src, src);
695848b8605Smrg   emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp);
696848b8605Smrg   emit_op2(p, OPCODE_MUL, dest, 0, src, swizzle1(tmp, X));
697848b8605Smrg   release_temp(p, tmp);
698848b8605Smrg}
699848b8605Smrg
700848b8605Smrg
701848b8605Smrgstatic void emit_passthrough( struct tnl_program *p,
702848b8605Smrg			      GLuint input,
703848b8605Smrg			      GLuint output )
704848b8605Smrg{
705848b8605Smrg   struct ureg out = register_output(p, output);
706848b8605Smrg   emit_op1(p, OPCODE_MOV, out, 0, register_input(p, input));
707848b8605Smrg}
708848b8605Smrg
709848b8605Smrg
710848b8605Smrgstatic struct ureg get_eye_position( struct tnl_program *p )
711848b8605Smrg{
712848b8605Smrg   if (is_undef(p->eye_position)) {
713848b8605Smrg      struct ureg pos = register_input( p, VERT_ATTRIB_POS );
714848b8605Smrg      struct ureg modelview[4];
715848b8605Smrg
716848b8605Smrg      p->eye_position = reserve_temp(p);
717848b8605Smrg
718848b8605Smrg      if (p->mvp_with_dp4) {
719848b8605Smrg	 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
720848b8605Smrg                                 0, modelview );
721848b8605Smrg
722848b8605Smrg	 emit_matrix_transform_vec4(p, p->eye_position, modelview, pos);
723848b8605Smrg      }
724848b8605Smrg      else {
725848b8605Smrg	 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
726848b8605Smrg				 STATE_MATRIX_TRANSPOSE, modelview );
727848b8605Smrg
728848b8605Smrg	 emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos);
729848b8605Smrg      }
730848b8605Smrg   }
731848b8605Smrg
732848b8605Smrg   return p->eye_position;
733848b8605Smrg}
734848b8605Smrg
735848b8605Smrg
736848b8605Smrgstatic struct ureg get_eye_position_z( struct tnl_program *p )
737848b8605Smrg{
738848b8605Smrg   if (!is_undef(p->eye_position))
739848b8605Smrg      return swizzle1(p->eye_position, Z);
740848b8605Smrg
741848b8605Smrg   if (is_undef(p->eye_position_z)) {
742848b8605Smrg      struct ureg pos = register_input( p, VERT_ATTRIB_POS );
743848b8605Smrg      struct ureg modelview[4];
744848b8605Smrg
745848b8605Smrg      p->eye_position_z = reserve_temp(p);
746848b8605Smrg
747848b8605Smrg      register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
748848b8605Smrg                              0, modelview );
749848b8605Smrg
750848b8605Smrg      emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]);
751848b8605Smrg   }
752848b8605Smrg
753848b8605Smrg   return p->eye_position_z;
754848b8605Smrg}
755848b8605Smrg
756848b8605Smrg
757848b8605Smrgstatic struct ureg get_eye_position_normalized( struct tnl_program *p )
758848b8605Smrg{
759848b8605Smrg   if (is_undef(p->eye_position_normalized)) {
760848b8605Smrg      struct ureg eye = get_eye_position(p);
761848b8605Smrg      p->eye_position_normalized = reserve_temp(p);
762848b8605Smrg      emit_normalize_vec3(p, p->eye_position_normalized, eye);
763848b8605Smrg   }
764848b8605Smrg
765848b8605Smrg   return p->eye_position_normalized;
766848b8605Smrg}
767848b8605Smrg
768848b8605Smrg
769848b8605Smrgstatic struct ureg get_transformed_normal( struct tnl_program *p )
770848b8605Smrg{
771848b8605Smrg   if (is_undef(p->transformed_normal) &&
772848b8605Smrg       !p->state->need_eye_coords &&
773848b8605Smrg       !p->state->normalize &&
774848b8605Smrg       !(p->state->need_eye_coords == p->state->rescale_normals))
775848b8605Smrg   {
776848b8605Smrg      p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL );
777848b8605Smrg   }
778848b8605Smrg   else if (is_undef(p->transformed_normal))
779848b8605Smrg   {
780848b8605Smrg      struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL );
781848b8605Smrg      struct ureg mvinv[3];
782848b8605Smrg      struct ureg transformed_normal = reserve_temp(p);
783848b8605Smrg
784848b8605Smrg      if (p->state->need_eye_coords) {
785848b8605Smrg         register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2,
786848b8605Smrg                                 STATE_MATRIX_INVTRANS, mvinv );
787848b8605Smrg
788848b8605Smrg         /* Transform to eye space:
789848b8605Smrg          */
790848b8605Smrg         emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal );
791848b8605Smrg         normal = transformed_normal;
792848b8605Smrg      }
793848b8605Smrg
794848b8605Smrg      /* Normalize/Rescale:
795848b8605Smrg       */
796848b8605Smrg      if (p->state->normalize) {
797848b8605Smrg	 emit_normalize_vec3( p, transformed_normal, normal );
798848b8605Smrg         normal = transformed_normal;
799848b8605Smrg      }
800848b8605Smrg      else if (p->state->need_eye_coords == p->state->rescale_normals) {
801848b8605Smrg         /* This is already adjusted for eye/non-eye rendering:
802848b8605Smrg          */
803848b8605Smrg	 struct ureg rescale = register_param2(p, STATE_INTERNAL,
804848b8605Smrg                                               STATE_NORMAL_SCALE);
805848b8605Smrg
806848b8605Smrg	 emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale );
807848b8605Smrg         normal = transformed_normal;
808848b8605Smrg      }
809848b8605Smrg
810848b8605Smrg      assert(normal.file == PROGRAM_TEMPORARY);
811848b8605Smrg      p->transformed_normal = normal;
812848b8605Smrg   }
813848b8605Smrg
814848b8605Smrg   return p->transformed_normal;
815848b8605Smrg}
816848b8605Smrg
817848b8605Smrg
818848b8605Smrgstatic void build_hpos( struct tnl_program *p )
819848b8605Smrg{
820848b8605Smrg   struct ureg pos = register_input( p, VERT_ATTRIB_POS );
821848b8605Smrg   struct ureg hpos = register_output( p, VARYING_SLOT_POS );
822848b8605Smrg   struct ureg mvp[4];
823848b8605Smrg
824848b8605Smrg   if (p->mvp_with_dp4) {
825848b8605Smrg      register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
826848b8605Smrg			      0, mvp );
827848b8605Smrg      emit_matrix_transform_vec4( p, hpos, mvp, pos );
828848b8605Smrg   }
829848b8605Smrg   else {
830848b8605Smrg      register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
831848b8605Smrg			      STATE_MATRIX_TRANSPOSE, mvp );
832848b8605Smrg      emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos );
833848b8605Smrg   }
834848b8605Smrg}
835848b8605Smrg
836848b8605Smrg
837848b8605Smrgstatic GLuint material_attrib( GLuint side, GLuint property )
838848b8605Smrg{
839848b8605Smrg   return (property - STATE_AMBIENT) * 2 + side;
840848b8605Smrg}
841848b8605Smrg
842848b8605Smrg
843848b8605Smrg/**
844848b8605Smrg * Get a bitmask of which material values vary on a per-vertex basis.
845848b8605Smrg */
846848b8605Smrgstatic void set_material_flags( struct tnl_program *p )
847848b8605Smrg{
848848b8605Smrg   p->color_materials = 0;
849848b8605Smrg   p->materials = 0;
850848b8605Smrg
851848b8605Smrg   if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) {
852848b8605Smrg      p->materials =
853848b8605Smrg	 p->color_materials = p->state->light_color_material_mask;
854848b8605Smrg   }
855848b8605Smrg
856b8e80941Smrg   p->materials |= ((p->state->varying_vp_inputs & VERT_BIT_MAT_ALL)
857b8e80941Smrg                    >> VERT_ATTRIB_MAT(0));
858848b8605Smrg}
859848b8605Smrg
860848b8605Smrg
861848b8605Smrgstatic struct ureg get_material( struct tnl_program *p, GLuint side,
862848b8605Smrg				 GLuint property )
863848b8605Smrg{
864848b8605Smrg   GLuint attrib = material_attrib(side, property);
865848b8605Smrg
866848b8605Smrg   if (p->color_materials & (1<<attrib))
867848b8605Smrg      return register_input(p, VERT_ATTRIB_COLOR0);
868848b8605Smrg   else if (p->materials & (1<<attrib)) {
869848b8605Smrg      /* Put material values in the GENERIC slots -- they are not used
870848b8605Smrg       * for anything in fixed function mode.
871848b8605Smrg       */
872b8e80941Smrg      return register_input( p, VERT_ATTRIB_MAT(attrib) );
873848b8605Smrg   }
874848b8605Smrg   else
875848b8605Smrg      return register_param3( p, STATE_MATERIAL, side, property );
876848b8605Smrg}
877848b8605Smrg
878848b8605Smrg#define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \
879848b8605Smrg				   MAT_BIT_FRONT_AMBIENT | \
880848b8605Smrg				   MAT_BIT_FRONT_DIFFUSE) << (side))
881848b8605Smrg
882848b8605Smrg
883848b8605Smrg/**
884848b8605Smrg * Either return a precalculated constant value or emit code to
885848b8605Smrg * calculate these values dynamically in the case where material calls
886848b8605Smrg * are present between begin/end pairs.
887848b8605Smrg *
888848b8605Smrg * Probably want to shift this to the program compilation phase - if
889848b8605Smrg * we always emitted the calculation here, a smart compiler could
890848b8605Smrg * detect that it was constant (given a certain set of inputs), and
891848b8605Smrg * lift it out of the main loop.  That way the programs created here
892848b8605Smrg * would be independent of the vertex_buffer details.
893848b8605Smrg */
894848b8605Smrgstatic struct ureg get_scenecolor( struct tnl_program *p, GLuint side )
895848b8605Smrg{
896848b8605Smrg   if (p->materials & SCENE_COLOR_BITS(side)) {
897848b8605Smrg      struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT);
898848b8605Smrg      struct ureg material_emission = get_material(p, side, STATE_EMISSION);
899848b8605Smrg      struct ureg material_ambient = get_material(p, side, STATE_AMBIENT);
900848b8605Smrg      struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE);
901848b8605Smrg      struct ureg tmp = make_temp(p, material_diffuse);
902848b8605Smrg      emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient,
903848b8605Smrg	       material_ambient, material_emission);
904848b8605Smrg      return tmp;
905848b8605Smrg   }
906848b8605Smrg   else
907848b8605Smrg      return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side );
908848b8605Smrg}
909848b8605Smrg
910848b8605Smrg
911848b8605Smrgstatic struct ureg get_lightprod( struct tnl_program *p, GLuint light,
912848b8605Smrg				  GLuint side, GLuint property )
913848b8605Smrg{
914848b8605Smrg   GLuint attrib = material_attrib(side, property);
915848b8605Smrg   if (p->materials & (1<<attrib)) {
916848b8605Smrg      struct ureg light_value =
917848b8605Smrg	 register_param3(p, STATE_LIGHT, light, property);
918848b8605Smrg      struct ureg material_value = get_material(p, side, property);
919848b8605Smrg      struct ureg tmp = get_temp(p);
920848b8605Smrg      emit_op2(p, OPCODE_MUL, tmp, 0, light_value, material_value);
921848b8605Smrg      return tmp;
922848b8605Smrg   }
923848b8605Smrg   else
924848b8605Smrg      return register_param4(p, STATE_LIGHTPROD, light, side, property);
925848b8605Smrg}
926848b8605Smrg
927848b8605Smrg
928848b8605Smrgstatic struct ureg calculate_light_attenuation( struct tnl_program *p,
929848b8605Smrg						GLuint i,
930848b8605Smrg						struct ureg VPpli,
931848b8605Smrg						struct ureg dist )
932848b8605Smrg{
933848b8605Smrg   struct ureg attenuation = register_param3(p, STATE_LIGHT, i,
934848b8605Smrg					     STATE_ATTENUATION);
935848b8605Smrg   struct ureg att = undef;
936848b8605Smrg
937848b8605Smrg   /* Calculate spot attenuation:
938848b8605Smrg    */
939848b8605Smrg   if (!p->state->unit[i].light_spotcutoff_is_180) {
940848b8605Smrg      struct ureg spot_dir_norm = register_param3(p, STATE_INTERNAL,
941848b8605Smrg						  STATE_LIGHT_SPOT_DIR_NORMALIZED, i);
942848b8605Smrg      struct ureg spot = get_temp(p);
943848b8605Smrg      struct ureg slt = get_temp(p);
944848b8605Smrg
945848b8605Smrg      att = get_temp(p);
946848b8605Smrg
947848b8605Smrg      emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm);
948848b8605Smrg      emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot);
949b8e80941Smrg      emit_op1(p, OPCODE_ABS, spot, 0, spot);
950848b8605Smrg      emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W));
951848b8605Smrg      emit_op2(p, OPCODE_MUL, att, 0, slt, spot);
952848b8605Smrg
953848b8605Smrg      release_temp(p, spot);
954848b8605Smrg      release_temp(p, slt);
955848b8605Smrg   }
956848b8605Smrg
957848b8605Smrg   /* Calculate distance attenuation(See formula (2.4) at glspec 2.1 page 62):
958848b8605Smrg    *
959848b8605Smrg    * Skip the calucation when _dist_ is undefined(light_eyepos3_is_zero)
960848b8605Smrg    */
961848b8605Smrg   if (p->state->unit[i].light_attenuated && !is_undef(dist)) {
962848b8605Smrg      if (is_undef(att))
963848b8605Smrg         att = get_temp(p);
964848b8605Smrg      /* 1/d,d,d,1/d */
965848b8605Smrg      emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist);
966848b8605Smrg      /* 1,d,d*d,1/d */
967848b8605Smrg      emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y));
968848b8605Smrg      /* 1/dist-atten */
969848b8605Smrg      emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist);
970848b8605Smrg
971848b8605Smrg      if (!p->state->unit[i].light_spotcutoff_is_180) {
972848b8605Smrg	 /* dist-atten */
973848b8605Smrg	 emit_op1(p, OPCODE_RCP, dist, 0, dist);
974848b8605Smrg	 /* spot-atten * dist-atten */
975848b8605Smrg	 emit_op2(p, OPCODE_MUL, att, 0, dist, att);
976848b8605Smrg      }
977848b8605Smrg      else {
978848b8605Smrg	 /* dist-atten */
979848b8605Smrg	 emit_op1(p, OPCODE_RCP, att, 0, dist);
980848b8605Smrg      }
981848b8605Smrg   }
982848b8605Smrg
983848b8605Smrg   return att;
984848b8605Smrg}
985848b8605Smrg
986848b8605Smrg
987848b8605Smrg/**
988848b8605Smrg * Compute:
989848b8605Smrg *   lit.y = MAX(0, dots.x)
990848b8605Smrg *   lit.z = SLT(0, dots.x)
991848b8605Smrg */
992848b8605Smrgstatic void emit_degenerate_lit( struct tnl_program *p,
993848b8605Smrg                                 struct ureg lit,
994848b8605Smrg                                 struct ureg dots )
995848b8605Smrg{
996848b8605Smrg   struct ureg id = get_identity_param(p);  /* id = {0,0,0,1} */
997848b8605Smrg
998848b8605Smrg   /* Note that lit.x & lit.w will not be examined.  Note also that
999848b8605Smrg    * dots.xyzw == dots.xxxx.
1000848b8605Smrg    */
1001848b8605Smrg
1002848b8605Smrg   /* MAX lit, id, dots;
1003848b8605Smrg    */
1004848b8605Smrg   emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots);
1005848b8605Smrg
1006848b8605Smrg   /* result[2] = (in > 0 ? 1 : 0)
1007848b8605Smrg    * SLT lit.z, id.z, dots;   # lit.z = (0 < dots.z) ? 1 : 0
1008848b8605Smrg    */
1009848b8605Smrg   emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots);
1010848b8605Smrg}
1011848b8605Smrg
1012848b8605Smrg
1013848b8605Smrg/* Need to add some addtional parameters to allow lighting in object
1014848b8605Smrg * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye
1015848b8605Smrg * space lighting.
1016848b8605Smrg */
1017848b8605Smrgstatic void build_lighting( struct tnl_program *p )
1018848b8605Smrg{
1019848b8605Smrg   const GLboolean twoside = p->state->light_twoside;
1020848b8605Smrg   const GLboolean separate = p->state->separate_specular;
1021848b8605Smrg   GLuint nr_lights = 0, count = 0;
1022848b8605Smrg   struct ureg normal = get_transformed_normal(p);
1023848b8605Smrg   struct ureg lit = get_temp(p);
1024848b8605Smrg   struct ureg dots = get_temp(p);
1025848b8605Smrg   struct ureg _col0 = undef, _col1 = undef;
1026848b8605Smrg   struct ureg _bfc0 = undef, _bfc1 = undef;
1027848b8605Smrg   GLuint i;
1028848b8605Smrg
1029848b8605Smrg   /*
1030848b8605Smrg    * NOTE:
1031848b8605Smrg    * dots.x = dot(normal, VPpli)
1032848b8605Smrg    * dots.y = dot(normal, halfAngle)
1033848b8605Smrg    * dots.z = back.shininess
1034848b8605Smrg    * dots.w = front.shininess
1035848b8605Smrg    */
1036848b8605Smrg
1037848b8605Smrg   for (i = 0; i < MAX_LIGHTS; i++)
1038848b8605Smrg      if (p->state->unit[i].light_enabled)
1039848b8605Smrg	 nr_lights++;
1040848b8605Smrg
1041848b8605Smrg   set_material_flags(p);
1042848b8605Smrg
1043848b8605Smrg   {
1044848b8605Smrg      if (!p->state->material_shininess_is_zero) {
1045848b8605Smrg         struct ureg shininess = get_material(p, 0, STATE_SHININESS);
1046848b8605Smrg         emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X));
1047848b8605Smrg         release_temp(p, shininess);
1048848b8605Smrg      }
1049848b8605Smrg
1050848b8605Smrg      _col0 = make_temp(p, get_scenecolor(p, 0));
1051848b8605Smrg      if (separate)
1052848b8605Smrg	 _col1 = make_temp(p, get_identity_param(p));
1053848b8605Smrg      else
1054848b8605Smrg	 _col1 = _col0;
1055848b8605Smrg   }
1056848b8605Smrg
1057848b8605Smrg   if (twoside) {
1058848b8605Smrg      if (!p->state->material_shininess_is_zero) {
1059848b8605Smrg         /* Note that we negate the back-face specular exponent here.
1060848b8605Smrg          * The negation will be un-done later in the back-face code below.
1061848b8605Smrg          */
1062848b8605Smrg         struct ureg shininess = get_material(p, 1, STATE_SHININESS);
1063848b8605Smrg         emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z,
1064848b8605Smrg                  negate(swizzle1(shininess,X)));
1065848b8605Smrg         release_temp(p, shininess);
1066848b8605Smrg      }
1067848b8605Smrg
1068848b8605Smrg      _bfc0 = make_temp(p, get_scenecolor(p, 1));
1069848b8605Smrg      if (separate)
1070848b8605Smrg	 _bfc1 = make_temp(p, get_identity_param(p));
1071848b8605Smrg      else
1072848b8605Smrg	 _bfc1 = _bfc0;
1073848b8605Smrg   }
1074848b8605Smrg
1075848b8605Smrg   /* If no lights, still need to emit the scenecolor.
1076848b8605Smrg    */
1077848b8605Smrg   {
1078848b8605Smrg      struct ureg res0 = register_output( p, VARYING_SLOT_COL0 );
1079848b8605Smrg      emit_op1(p, OPCODE_MOV, res0, 0, _col0);
1080848b8605Smrg   }
1081848b8605Smrg
1082848b8605Smrg   if (separate) {
1083848b8605Smrg      struct ureg res1 = register_output( p, VARYING_SLOT_COL1 );
1084848b8605Smrg      emit_op1(p, OPCODE_MOV, res1, 0, _col1);
1085848b8605Smrg   }
1086848b8605Smrg
1087848b8605Smrg   if (twoside) {
1088848b8605Smrg      struct ureg res0 = register_output( p, VARYING_SLOT_BFC0 );
1089848b8605Smrg      emit_op1(p, OPCODE_MOV, res0, 0, _bfc0);
1090848b8605Smrg   }
1091848b8605Smrg
1092848b8605Smrg   if (twoside && separate) {
1093848b8605Smrg      struct ureg res1 = register_output( p, VARYING_SLOT_BFC1 );
1094848b8605Smrg      emit_op1(p, OPCODE_MOV, res1, 0, _bfc1);
1095848b8605Smrg   }
1096848b8605Smrg
1097848b8605Smrg   if (nr_lights == 0) {
1098848b8605Smrg      release_temps(p);
1099848b8605Smrg      return;
1100848b8605Smrg   }
1101848b8605Smrg
1102848b8605Smrg   for (i = 0; i < MAX_LIGHTS; i++) {
1103848b8605Smrg      if (p->state->unit[i].light_enabled) {
1104848b8605Smrg	 struct ureg half = undef;
1105848b8605Smrg	 struct ureg att = undef, VPpli = undef;
1106848b8605Smrg	 struct ureg dist = undef;
1107848b8605Smrg
1108848b8605Smrg	 count++;
1109848b8605Smrg         if (p->state->unit[i].light_eyepos3_is_zero) {
1110848b8605Smrg             VPpli = register_param3(p, STATE_INTERNAL,
1111848b8605Smrg                                     STATE_LIGHT_POSITION_NORMALIZED, i);
1112848b8605Smrg         } else {
1113848b8605Smrg            struct ureg Ppli = register_param3(p, STATE_INTERNAL,
1114848b8605Smrg                                               STATE_LIGHT_POSITION, i);
1115848b8605Smrg            struct ureg V = get_eye_position(p);
1116848b8605Smrg
1117848b8605Smrg            VPpli = get_temp(p);
1118848b8605Smrg            dist = get_temp(p);
1119848b8605Smrg
1120848b8605Smrg            /* Calculate VPpli vector
1121848b8605Smrg             */
1122848b8605Smrg            emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V);
1123848b8605Smrg
1124848b8605Smrg            /* Normalize VPpli.  The dist value also used in
1125848b8605Smrg             * attenuation below.
1126848b8605Smrg             */
1127848b8605Smrg            emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli);
1128848b8605Smrg            emit_op1(p, OPCODE_RSQ, dist, 0, dist);
1129848b8605Smrg            emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist);
1130848b8605Smrg         }
1131848b8605Smrg
1132848b8605Smrg         /* Calculate attenuation:
1133848b8605Smrg          */
1134848b8605Smrg         att = calculate_light_attenuation(p, i, VPpli, dist);
1135848b8605Smrg         release_temp(p, dist);
1136848b8605Smrg
1137848b8605Smrg	 /* Calculate viewer direction, or use infinite viewer:
1138848b8605Smrg	  */
1139848b8605Smrg         if (!p->state->material_shininess_is_zero) {
1140848b8605Smrg            if (p->state->light_local_viewer) {
1141848b8605Smrg               struct ureg eye_hat = get_eye_position_normalized(p);
1142848b8605Smrg               half = get_temp(p);
1143848b8605Smrg               emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat);
1144848b8605Smrg               emit_normalize_vec3(p, half, half);
1145848b8605Smrg            } else if (p->state->unit[i].light_eyepos3_is_zero) {
1146848b8605Smrg               half = register_param3(p, STATE_INTERNAL,
1147848b8605Smrg                                      STATE_LIGHT_HALF_VECTOR, i);
1148848b8605Smrg            } else {
1149848b8605Smrg               struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z);
1150848b8605Smrg               half = get_temp(p);
1151848b8605Smrg               emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir);
1152848b8605Smrg               emit_normalize_vec3(p, half, half);
1153848b8605Smrg            }
1154848b8605Smrg	 }
1155848b8605Smrg
1156848b8605Smrg	 /* Calculate dot products:
1157848b8605Smrg	  */
1158848b8605Smrg         if (p->state->material_shininess_is_zero) {
1159848b8605Smrg            emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli);
1160848b8605Smrg         }
1161848b8605Smrg         else {
1162848b8605Smrg            emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli);
1163848b8605Smrg            emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half);
1164848b8605Smrg         }
1165848b8605Smrg
1166848b8605Smrg	 /* Front face lighting:
1167848b8605Smrg	  */
1168848b8605Smrg	 {
1169848b8605Smrg	    struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT);
1170848b8605Smrg	    struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE);
1171848b8605Smrg	    struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR);
1172848b8605Smrg	    struct ureg res0, res1;
1173848b8605Smrg	    GLuint mask0, mask1;
1174848b8605Smrg
1175848b8605Smrg	    if (count == nr_lights) {
1176848b8605Smrg	       if (separate) {
1177848b8605Smrg		  mask0 = WRITEMASK_XYZ;
1178848b8605Smrg		  mask1 = WRITEMASK_XYZ;
1179848b8605Smrg		  res0 = register_output( p, VARYING_SLOT_COL0 );
1180848b8605Smrg		  res1 = register_output( p, VARYING_SLOT_COL1 );
1181848b8605Smrg	       }
1182848b8605Smrg	       else {
1183848b8605Smrg		  mask0 = 0;
1184848b8605Smrg		  mask1 = WRITEMASK_XYZ;
1185848b8605Smrg		  res0 = _col0;
1186848b8605Smrg		  res1 = register_output( p, VARYING_SLOT_COL0 );
1187848b8605Smrg	       }
1188848b8605Smrg	    }
1189848b8605Smrg            else {
1190848b8605Smrg	       mask0 = 0;
1191848b8605Smrg	       mask1 = 0;
1192848b8605Smrg	       res0 = _col0;
1193848b8605Smrg	       res1 = _col1;
1194848b8605Smrg	    }
1195848b8605Smrg
1196848b8605Smrg	    if (!is_undef(att)) {
1197848b8605Smrg               /* light is attenuated by distance */
1198848b8605Smrg               emit_op1(p, OPCODE_LIT, lit, 0, dots);
1199848b8605Smrg               emit_op2(p, OPCODE_MUL, lit, 0, lit, att);
1200848b8605Smrg               emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0);
1201848b8605Smrg            }
1202848b8605Smrg            else if (!p->state->material_shininess_is_zero) {
1203848b8605Smrg               /* there's a non-zero specular term */
1204848b8605Smrg               emit_op1(p, OPCODE_LIT, lit, 0, dots);
1205848b8605Smrg               emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0);
1206848b8605Smrg            }
1207848b8605Smrg            else {
1208848b8605Smrg               /* no attenutation, no specular */
1209848b8605Smrg               emit_degenerate_lit(p, lit, dots);
1210848b8605Smrg               emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0);
1211848b8605Smrg            }
1212848b8605Smrg
1213848b8605Smrg	    emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0);
1214848b8605Smrg	    emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1);
1215848b8605Smrg
1216848b8605Smrg	    release_temp(p, ambient);
1217848b8605Smrg	    release_temp(p, diffuse);
1218848b8605Smrg	    release_temp(p, specular);
1219848b8605Smrg	 }
1220848b8605Smrg
1221848b8605Smrg	 /* Back face lighting:
1222848b8605Smrg	  */
1223848b8605Smrg	 if (twoside) {
1224848b8605Smrg	    struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT);
1225848b8605Smrg	    struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE);
1226848b8605Smrg	    struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR);
1227848b8605Smrg	    struct ureg res0, res1;
1228848b8605Smrg	    GLuint mask0, mask1;
1229848b8605Smrg
1230848b8605Smrg	    if (count == nr_lights) {
1231848b8605Smrg	       if (separate) {
1232848b8605Smrg		  mask0 = WRITEMASK_XYZ;
1233848b8605Smrg		  mask1 = WRITEMASK_XYZ;
1234848b8605Smrg		  res0 = register_output( p, VARYING_SLOT_BFC0 );
1235848b8605Smrg		  res1 = register_output( p, VARYING_SLOT_BFC1 );
1236848b8605Smrg	       }
1237848b8605Smrg	       else {
1238848b8605Smrg		  mask0 = 0;
1239848b8605Smrg		  mask1 = WRITEMASK_XYZ;
1240848b8605Smrg		  res0 = _bfc0;
1241848b8605Smrg		  res1 = register_output( p, VARYING_SLOT_BFC0 );
1242848b8605Smrg	       }
1243848b8605Smrg	    }
1244848b8605Smrg            else {
1245848b8605Smrg	       res0 = _bfc0;
1246848b8605Smrg	       res1 = _bfc1;
1247848b8605Smrg	       mask0 = 0;
1248848b8605Smrg	       mask1 = 0;
1249848b8605Smrg	    }
1250848b8605Smrg
1251848b8605Smrg            /* For the back face we need to negate the X and Y component
1252848b8605Smrg             * dot products.  dots.Z has the negated back-face specular
1253848b8605Smrg             * exponent.  We swizzle that into the W position.  This
1254848b8605Smrg             * negation makes the back-face specular term positive again.
1255848b8605Smrg             */
1256848b8605Smrg            dots = negate(swizzle(dots,X,Y,W,Z));
1257848b8605Smrg
1258848b8605Smrg	    if (!is_undef(att)) {
1259848b8605Smrg               emit_op1(p, OPCODE_LIT, lit, 0, dots);
1260848b8605Smrg	       emit_op2(p, OPCODE_MUL, lit, 0, lit, att);
1261848b8605Smrg               emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0);
1262848b8605Smrg            }
1263848b8605Smrg            else if (!p->state->material_shininess_is_zero) {
1264848b8605Smrg               emit_op1(p, OPCODE_LIT, lit, 0, dots);
1265848b8605Smrg               emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); /**/
1266848b8605Smrg            }
1267848b8605Smrg            else {
1268848b8605Smrg               emit_degenerate_lit(p, lit, dots);
1269848b8605Smrg               emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0);
1270848b8605Smrg            }
1271848b8605Smrg
1272848b8605Smrg	    emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0);
1273848b8605Smrg	    emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1);
1274848b8605Smrg            /* restore dots to its original state for subsequent lights
1275848b8605Smrg             * by negating and swizzling again.
1276848b8605Smrg             */
1277848b8605Smrg            dots = negate(swizzle(dots,X,Y,W,Z));
1278848b8605Smrg
1279848b8605Smrg	    release_temp(p, ambient);
1280848b8605Smrg	    release_temp(p, diffuse);
1281848b8605Smrg	    release_temp(p, specular);
1282848b8605Smrg	 }
1283848b8605Smrg
1284848b8605Smrg	 release_temp(p, half);
1285848b8605Smrg	 release_temp(p, VPpli);
1286848b8605Smrg	 release_temp(p, att);
1287848b8605Smrg      }
1288848b8605Smrg   }
1289848b8605Smrg
1290848b8605Smrg   release_temps( p );
1291848b8605Smrg}
1292848b8605Smrg
1293848b8605Smrg
1294848b8605Smrgstatic void build_fog( struct tnl_program *p )
1295848b8605Smrg{
1296848b8605Smrg   struct ureg fog = register_output(p, VARYING_SLOT_FOGC);
1297848b8605Smrg   struct ureg input;
1298848b8605Smrg
1299b8e80941Smrg   switch (p->state->fog_distance_mode) {
1300b8e80941Smrg   case FDM_EYE_RADIAL: { /* Z = sqrt(Xe*Xe + Ye*Ye + Ze*Ze) */
1301b8e80941Smrg      struct ureg tmp = get_temp(p);
1302b8e80941Smrg      input = get_eye_position(p);
1303b8e80941Smrg      emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, input, input);
1304b8e80941Smrg      emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp);
1305b8e80941Smrg      emit_op1(p, OPCODE_RCP, fog, WRITEMASK_X, tmp);
1306b8e80941Smrg      break;
1307848b8605Smrg   }
1308b8e80941Smrg   case FDM_EYE_PLANE: /* Z = Ze */
1309b8e80941Smrg      input = get_eye_position_z(p);
1310b8e80941Smrg      emit_op1(p, OPCODE_MOV, fog, WRITEMASK_X, input);
1311b8e80941Smrg      break;
1312b8e80941Smrg   case FDM_EYE_PLANE_ABS: /* Z = abs(Ze) */
1313b8e80941Smrg      input = get_eye_position_z(p);
1314b8e80941Smrg      emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input);
1315b8e80941Smrg      break;
1316b8e80941Smrg   case FDM_FROM_ARRAY:
1317848b8605Smrg      input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X);
1318848b8605Smrg      emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input);
1319b8e80941Smrg      break;
1320b8e80941Smrg   default:
1321b8e80941Smrg      assert(!"Bad fog mode in build_fog()");
1322b8e80941Smrg      break;
1323848b8605Smrg   }
1324848b8605Smrg
1325848b8605Smrg   emit_op1(p, OPCODE_MOV, fog, WRITEMASK_YZW, get_identity_param(p));
1326848b8605Smrg}
1327848b8605Smrg
1328848b8605Smrg
1329848b8605Smrgstatic void build_reflect_texgen( struct tnl_program *p,
1330848b8605Smrg				  struct ureg dest,
1331848b8605Smrg				  GLuint writemask )
1332848b8605Smrg{
1333848b8605Smrg   struct ureg normal = get_transformed_normal(p);
1334848b8605Smrg   struct ureg eye_hat = get_eye_position_normalized(p);
1335848b8605Smrg   struct ureg tmp = get_temp(p);
1336848b8605Smrg
1337848b8605Smrg   /* n.u */
1338848b8605Smrg   emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat);
1339848b8605Smrg   /* 2n.u */
1340848b8605Smrg   emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp);
1341848b8605Smrg   /* (-2n.u)n + u */
1342848b8605Smrg   emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat);
1343848b8605Smrg
1344848b8605Smrg   release_temp(p, tmp);
1345848b8605Smrg}
1346848b8605Smrg
1347848b8605Smrg
1348848b8605Smrgstatic void build_sphere_texgen( struct tnl_program *p,
1349848b8605Smrg				 struct ureg dest,
1350848b8605Smrg				 GLuint writemask )
1351848b8605Smrg{
1352848b8605Smrg   struct ureg normal = get_transformed_normal(p);
1353848b8605Smrg   struct ureg eye_hat = get_eye_position_normalized(p);
1354848b8605Smrg   struct ureg tmp = get_temp(p);
1355848b8605Smrg   struct ureg half = register_scalar_const(p, .5);
1356848b8605Smrg   struct ureg r = get_temp(p);
1357848b8605Smrg   struct ureg inv_m = get_temp(p);
1358848b8605Smrg   struct ureg id = get_identity_param(p);
1359848b8605Smrg
1360848b8605Smrg   /* Could share the above calculations, but it would be
1361848b8605Smrg    * a fairly odd state for someone to set (both sphere and
1362848b8605Smrg    * reflection active for different texture coordinate
1363848b8605Smrg    * components.  Of course - if two texture units enable
1364848b8605Smrg    * reflect and/or sphere, things start to tilt in favour
1365848b8605Smrg    * of seperating this out:
1366848b8605Smrg    */
1367848b8605Smrg
1368848b8605Smrg   /* n.u */
1369848b8605Smrg   emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat);
1370848b8605Smrg   /* 2n.u */
1371848b8605Smrg   emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp);
1372848b8605Smrg   /* (-2n.u)n + u */
1373848b8605Smrg   emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat);
1374848b8605Smrg   /* r + 0,0,1 */
1375848b8605Smrg   emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z));
1376848b8605Smrg   /* rx^2 + ry^2 + (rz+1)^2 */
1377848b8605Smrg   emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp);
1378848b8605Smrg   /* 2/m */
1379848b8605Smrg   emit_op1(p, OPCODE_RSQ, tmp, 0, tmp);
1380848b8605Smrg   /* 1/m */
1381848b8605Smrg   emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half);
1382848b8605Smrg   /* r/m + 1/2 */
1383848b8605Smrg   emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half);
1384848b8605Smrg
1385848b8605Smrg   release_temp(p, tmp);
1386848b8605Smrg   release_temp(p, r);
1387848b8605Smrg   release_temp(p, inv_m);
1388848b8605Smrg}
1389848b8605Smrg
1390848b8605Smrg
1391848b8605Smrgstatic void build_texture_transform( struct tnl_program *p )
1392848b8605Smrg{
1393848b8605Smrg   GLuint i, j;
1394848b8605Smrg
1395848b8605Smrg   for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
1396848b8605Smrg
1397848b8605Smrg      if (!(p->state->fragprog_inputs_read & VARYING_BIT_TEX(i)))
1398848b8605Smrg	 continue;
1399848b8605Smrg
1400848b8605Smrg      if (p->state->unit[i].coord_replace)
1401848b8605Smrg  	 continue;
1402848b8605Smrg
1403848b8605Smrg      if (p->state->unit[i].texgen_enabled ||
1404848b8605Smrg	  p->state->unit[i].texmat_enabled) {
1405848b8605Smrg
1406848b8605Smrg	 GLuint texmat_enabled = p->state->unit[i].texmat_enabled;
1407848b8605Smrg	 struct ureg out = register_output(p, VARYING_SLOT_TEX0 + i);
1408848b8605Smrg	 struct ureg out_texgen = undef;
1409848b8605Smrg
1410848b8605Smrg	 if (p->state->unit[i].texgen_enabled) {
1411848b8605Smrg	    GLuint copy_mask = 0;
1412848b8605Smrg	    GLuint sphere_mask = 0;
1413848b8605Smrg	    GLuint reflect_mask = 0;
1414848b8605Smrg	    GLuint normal_mask = 0;
1415848b8605Smrg	    GLuint modes[4];
1416848b8605Smrg
1417848b8605Smrg	    if (texmat_enabled)
1418848b8605Smrg	       out_texgen = get_temp(p);
1419848b8605Smrg	    else
1420848b8605Smrg	       out_texgen = out;
1421848b8605Smrg
1422848b8605Smrg	    modes[0] = p->state->unit[i].texgen_mode0;
1423848b8605Smrg	    modes[1] = p->state->unit[i].texgen_mode1;
1424848b8605Smrg	    modes[2] = p->state->unit[i].texgen_mode2;
1425848b8605Smrg	    modes[3] = p->state->unit[i].texgen_mode3;
1426848b8605Smrg
1427848b8605Smrg	    for (j = 0; j < 4; j++) {
1428848b8605Smrg	       switch (modes[j]) {
1429848b8605Smrg	       case TXG_OBJ_LINEAR: {
1430848b8605Smrg		  struct ureg obj = register_input(p, VERT_ATTRIB_POS);
1431848b8605Smrg		  struct ureg plane =
1432848b8605Smrg		     register_param3(p, STATE_TEXGEN, i,
1433848b8605Smrg				     STATE_TEXGEN_OBJECT_S + j);
1434848b8605Smrg
1435848b8605Smrg		  emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j,
1436848b8605Smrg			   obj, plane );
1437848b8605Smrg		  break;
1438848b8605Smrg	       }
1439848b8605Smrg	       case TXG_EYE_LINEAR: {
1440848b8605Smrg		  struct ureg eye = get_eye_position(p);
1441848b8605Smrg		  struct ureg plane =
1442848b8605Smrg		     register_param3(p, STATE_TEXGEN, i,
1443848b8605Smrg				     STATE_TEXGEN_EYE_S + j);
1444848b8605Smrg
1445848b8605Smrg		  emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j,
1446848b8605Smrg			   eye, plane );
1447848b8605Smrg		  break;
1448848b8605Smrg	       }
1449848b8605Smrg	       case TXG_SPHERE_MAP:
1450848b8605Smrg		  sphere_mask |= WRITEMASK_X << j;
1451848b8605Smrg		  break;
1452848b8605Smrg	       case TXG_REFLECTION_MAP:
1453848b8605Smrg		  reflect_mask |= WRITEMASK_X << j;
1454848b8605Smrg		  break;
1455848b8605Smrg	       case TXG_NORMAL_MAP:
1456848b8605Smrg		  normal_mask |= WRITEMASK_X << j;
1457848b8605Smrg		  break;
1458848b8605Smrg	       case TXG_NONE:
1459848b8605Smrg		  copy_mask |= WRITEMASK_X << j;
1460848b8605Smrg	       }
1461848b8605Smrg	    }
1462848b8605Smrg
1463848b8605Smrg	    if (sphere_mask) {
1464848b8605Smrg	       build_sphere_texgen(p, out_texgen, sphere_mask);
1465848b8605Smrg	    }
1466848b8605Smrg
1467848b8605Smrg	    if (reflect_mask) {
1468848b8605Smrg	       build_reflect_texgen(p, out_texgen, reflect_mask);
1469848b8605Smrg	    }
1470848b8605Smrg
1471848b8605Smrg	    if (normal_mask) {
1472848b8605Smrg	       struct ureg normal = get_transformed_normal(p);
1473848b8605Smrg	       emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal );
1474848b8605Smrg	    }
1475848b8605Smrg
1476848b8605Smrg	    if (copy_mask) {
1477848b8605Smrg	       struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i);
1478848b8605Smrg	       emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in );
1479848b8605Smrg	    }
1480848b8605Smrg	 }
1481848b8605Smrg
1482848b8605Smrg	 if (texmat_enabled) {
1483848b8605Smrg	    struct ureg texmat[4];
1484848b8605Smrg	    struct ureg in = (!is_undef(out_texgen) ?
1485848b8605Smrg			      out_texgen :
1486848b8605Smrg			      register_input(p, VERT_ATTRIB_TEX0+i));
1487848b8605Smrg	    if (p->mvp_with_dp4) {
1488848b8605Smrg	       register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
1489848b8605Smrg				       0, texmat );
1490848b8605Smrg	       emit_matrix_transform_vec4( p, out, texmat, in );
1491848b8605Smrg	    }
1492848b8605Smrg	    else {
1493848b8605Smrg	       register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
1494848b8605Smrg				       STATE_MATRIX_TRANSPOSE, texmat );
1495848b8605Smrg	       emit_transpose_matrix_transform_vec4( p, out, texmat, in );
1496848b8605Smrg	    }
1497848b8605Smrg	 }
1498848b8605Smrg
1499848b8605Smrg	 release_temps(p);
1500848b8605Smrg      }
1501848b8605Smrg      else {
1502848b8605Smrg	 emit_passthrough(p, VERT_ATTRIB_TEX0+i, VARYING_SLOT_TEX0+i);
1503848b8605Smrg      }
1504848b8605Smrg   }
1505848b8605Smrg}
1506848b8605Smrg
1507848b8605Smrg
1508848b8605Smrg/**
1509848b8605Smrg * Point size attenuation computation.
1510848b8605Smrg */
1511848b8605Smrgstatic void build_atten_pointsize( struct tnl_program *p )
1512848b8605Smrg{
1513848b8605Smrg   struct ureg eye = get_eye_position_z(p);
1514848b8605Smrg   struct ureg state_size = register_param2(p, STATE_INTERNAL, STATE_POINT_SIZE_CLAMPED);
1515848b8605Smrg   struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION);
1516848b8605Smrg   struct ureg out = register_output(p, VARYING_SLOT_PSIZ);
1517848b8605Smrg   struct ureg ut = get_temp(p);
1518848b8605Smrg
1519848b8605Smrg   /* dist = |eyez| */
1520848b8605Smrg   emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z));
1521848b8605Smrg   /* p1 + dist * (p2 + dist * p3); */
1522848b8605Smrg   emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y),
1523848b8605Smrg		swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y));
1524848b8605Smrg   emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y),
1525848b8605Smrg		ut, swizzle1(state_attenuation, X));
1526848b8605Smrg
1527848b8605Smrg   /* 1 / sqrt(factor) */
1528848b8605Smrg   emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut );
1529848b8605Smrg
1530848b8605Smrg#if 0
1531848b8605Smrg   /* out = pointSize / sqrt(factor) */
1532848b8605Smrg   emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size);
1533848b8605Smrg#else
1534848b8605Smrg   /* this is a good place to clamp the point size since there's likely
1535848b8605Smrg    * no hardware registers to clamp point size at rasterization time.
1536848b8605Smrg    */
1537848b8605Smrg   emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size);
1538848b8605Smrg   emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y));
1539848b8605Smrg   emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z));
1540848b8605Smrg#endif
1541848b8605Smrg
1542848b8605Smrg   release_temp(p, ut);
1543848b8605Smrg}
1544848b8605Smrg
1545848b8605Smrg
1546848b8605Smrg/**
1547848b8605Smrg * Pass-though per-vertex point size, from user's point size array.
1548848b8605Smrg */
1549848b8605Smrgstatic void build_array_pointsize( struct tnl_program *p )
1550848b8605Smrg{
1551848b8605Smrg   struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE);
1552848b8605Smrg   struct ureg out = register_output(p, VARYING_SLOT_PSIZ);
1553848b8605Smrg   emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in);
1554848b8605Smrg}
1555848b8605Smrg
1556848b8605Smrg
1557848b8605Smrgstatic void build_tnl_program( struct tnl_program *p )
1558848b8605Smrg{
1559848b8605Smrg   /* Emit the program, starting with the modelview, projection transforms:
1560848b8605Smrg    */
1561848b8605Smrg   build_hpos(p);
1562848b8605Smrg
1563848b8605Smrg   /* Lighting calculations:
1564848b8605Smrg    */
1565848b8605Smrg   if (p->state->fragprog_inputs_read & (VARYING_BIT_COL0|VARYING_BIT_COL1)) {
1566848b8605Smrg      if (p->state->light_global_enabled)
1567848b8605Smrg	 build_lighting(p);
1568848b8605Smrg      else {
1569848b8605Smrg	 if (p->state->fragprog_inputs_read & VARYING_BIT_COL0)
1570848b8605Smrg	    emit_passthrough(p, VERT_ATTRIB_COLOR0, VARYING_SLOT_COL0);
1571848b8605Smrg
1572848b8605Smrg	 if (p->state->fragprog_inputs_read & VARYING_BIT_COL1)
1573848b8605Smrg	    emit_passthrough(p, VERT_ATTRIB_COLOR1, VARYING_SLOT_COL1);
1574848b8605Smrg      }
1575848b8605Smrg   }
1576848b8605Smrg
1577848b8605Smrg   if (p->state->fragprog_inputs_read & VARYING_BIT_FOGC)
1578848b8605Smrg      build_fog(p);
1579848b8605Smrg
1580848b8605Smrg   if (p->state->fragprog_inputs_read & VARYING_BITS_TEX_ANY)
1581848b8605Smrg      build_texture_transform(p);
1582848b8605Smrg
1583848b8605Smrg   if (p->state->point_attenuated)
1584848b8605Smrg      build_atten_pointsize(p);
1585b8e80941Smrg   else if (p->state->varying_vp_inputs & VERT_BIT_POINT_SIZE)
1586848b8605Smrg      build_array_pointsize(p);
1587848b8605Smrg
1588848b8605Smrg   /* Finish up:
1589848b8605Smrg    */
1590848b8605Smrg   emit_op1(p, OPCODE_END, undef, 0, undef);
1591848b8605Smrg
1592848b8605Smrg   /* Disassemble:
1593848b8605Smrg    */
1594848b8605Smrg   if (DISASSEM) {
1595848b8605Smrg      printf ("\n");
1596848b8605Smrg   }
1597848b8605Smrg}
1598848b8605Smrg
1599848b8605Smrg
1600848b8605Smrgstatic void
1601848b8605Smrgcreate_new_program( const struct state_key *key,
1602b8e80941Smrg                    struct gl_program *program,
1603848b8605Smrg                    GLboolean mvp_with_dp4,
1604848b8605Smrg                    GLuint max_temps)
1605848b8605Smrg{
1606848b8605Smrg   struct tnl_program p;
1607848b8605Smrg
1608848b8605Smrg   memset(&p, 0, sizeof(p));
1609848b8605Smrg   p.state = key;
1610848b8605Smrg   p.program = program;
1611848b8605Smrg   p.eye_position = undef;
1612848b8605Smrg   p.eye_position_z = undef;
1613848b8605Smrg   p.eye_position_normalized = undef;
1614848b8605Smrg   p.transformed_normal = undef;
1615848b8605Smrg   p.identity = undef;
1616848b8605Smrg   p.temp_in_use = 0;
1617848b8605Smrg   p.mvp_with_dp4 = mvp_with_dp4;
1618848b8605Smrg
1619848b8605Smrg   if (max_temps >= sizeof(int) * 8)
1620848b8605Smrg      p.temp_reserved = 0;
1621848b8605Smrg   else
1622848b8605Smrg      p.temp_reserved = ~((1<<max_temps)-1);
1623848b8605Smrg
1624848b8605Smrg   /* Start by allocating 32 instructions.
1625848b8605Smrg    * If we need more, we'll grow the instruction array as needed.
1626848b8605Smrg    */
1627848b8605Smrg   p.max_inst = 32;
1628b8e80941Smrg   p.program->arb.Instructions =
1629b8e80941Smrg      rzalloc_array(program, struct prog_instruction, p.max_inst);
1630b8e80941Smrg   p.program->String = NULL;
1631b8e80941Smrg   p.program->arb.NumInstructions =
1632b8e80941Smrg   p.program->arb.NumTemporaries =
1633b8e80941Smrg   p.program->arb.NumParameters =
1634b8e80941Smrg   p.program->arb.NumAttributes = p.program->arb.NumAddressRegs = 0;
1635b8e80941Smrg   p.program->Parameters = _mesa_new_parameter_list();
1636b8e80941Smrg   p.program->info.inputs_read = 0;
1637b8e80941Smrg   p.program->info.outputs_written = 0;
1638848b8605Smrg
1639848b8605Smrg   build_tnl_program( &p );
1640848b8605Smrg}
1641848b8605Smrg
1642848b8605Smrg
1643848b8605Smrg/**
1644848b8605Smrg * Return a vertex program which implements the current fixed-function
1645848b8605Smrg * transform/lighting/texgen operations.
1646848b8605Smrg */
1647b8e80941Smrgstruct gl_program *
1648848b8605Smrg_mesa_get_fixed_func_vertex_program(struct gl_context *ctx)
1649848b8605Smrg{
1650b8e80941Smrg   struct gl_program *prog;
1651848b8605Smrg   struct state_key key;
1652848b8605Smrg
1653b8e80941Smrg   /* Grab all the relevant state and put it in a single structure:
1654848b8605Smrg    */
1655848b8605Smrg   make_state_key(ctx, &key);
1656848b8605Smrg
1657848b8605Smrg   /* Look for an already-prepared program for this state:
1658848b8605Smrg    */
1659b8e80941Smrg   prog = _mesa_search_program_cache(ctx->VertexProgram.Cache, &key,
1660b8e80941Smrg                                     sizeof(key));
1661848b8605Smrg
1662848b8605Smrg   if (!prog) {
1663848b8605Smrg      /* OK, we'll have to build a new one */
1664848b8605Smrg      if (0)
1665848b8605Smrg         printf("Build new TNL program\n");
1666848b8605Smrg
1667b8e80941Smrg      prog = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0, true);
1668848b8605Smrg      if (!prog)
1669848b8605Smrg         return NULL;
1670848b8605Smrg
1671848b8605Smrg      create_new_program( &key, prog,
1672848b8605Smrg                          ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS,
1673848b8605Smrg                          ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps );
1674848b8605Smrg
1675848b8605Smrg      if (ctx->Driver.ProgramStringNotify)
1676b8e80941Smrg         ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, prog);
1677b8e80941Smrg
1678b8e80941Smrg      _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, &key,
1679b8e80941Smrg                                 sizeof(key), prog);
1680848b8605Smrg   }
1681848b8605Smrg
1682848b8605Smrg   return prog;
1683848b8605Smrg}
1684