OSDN Git Service

Merge remote-tracking branch 'mesa/12.0' into marshmallow-x86
[android-x86/external-mesa.git] / src / mesa / main / ffvertex_prog.c
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27
28 /**
29  * \file ffvertex_prog.c
30  *
31  * Create a vertex program to execute the current fixed function T&L pipeline.
32  * \author Keith Whitwell
33  */
34
35
36 #include "main/glheader.h"
37 #include "main/mtypes.h"
38 #include "main/macros.h"
39 #include "main/enums.h"
40 #include "main/ffvertex_prog.h"
41 #include "program/program.h"
42 #include "program/prog_cache.h"
43 #include "program/prog_instruction.h"
44 #include "program/prog_parameter.h"
45 #include "program/prog_print.h"
46 #include "program/prog_statevars.h"
47
48
49 /** Max of number of lights and texture coord units */
50 #define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS)
51
52 struct state_key {
53    unsigned light_color_material_mask:12;
54    unsigned light_global_enabled:1;
55    unsigned light_local_viewer:1;
56    unsigned light_twoside:1;
57    unsigned material_shininess_is_zero:1;
58    unsigned need_eye_coords:1;
59    unsigned normalize:1;
60    unsigned rescale_normals:1;
61
62    unsigned fog_source_is_depth:1;
63    unsigned fog_distance_mode:2;
64    unsigned separate_specular:1;
65    unsigned point_attenuated:1;
66    unsigned point_array:1;
67    unsigned texture_enabled_global:1;
68    unsigned fragprog_inputs_read:12;
69
70    GLbitfield64 varying_vp_inputs;
71
72    struct {
73       unsigned light_enabled:1;
74       unsigned light_eyepos3_is_zero:1;
75       unsigned light_spotcutoff_is_180:1;
76       unsigned light_attenuated:1;
77       unsigned texunit_really_enabled:1;
78       unsigned texmat_enabled:1;
79       unsigned coord_replace:1;
80       unsigned texgen_enabled:4;
81       unsigned texgen_mode0:4;
82       unsigned texgen_mode1:4;
83       unsigned texgen_mode2:4;
84       unsigned texgen_mode3:4;
85    } unit[NUM_UNITS];
86 };
87
88
89 #define TXG_NONE           0
90 #define TXG_OBJ_LINEAR     1
91 #define TXG_EYE_LINEAR     2
92 #define TXG_SPHERE_MAP     3
93 #define TXG_REFLECTION_MAP 4
94 #define TXG_NORMAL_MAP     5
95
96 static GLuint translate_texgen( GLboolean enabled, GLenum mode )
97 {
98    if (!enabled)
99       return TXG_NONE;
100
101    switch (mode) {
102    case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR;
103    case GL_EYE_LINEAR: return TXG_EYE_LINEAR;
104    case GL_SPHERE_MAP: return TXG_SPHERE_MAP;
105    case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP;
106    case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP;
107    default: return TXG_NONE;
108    }
109 }
110
111 #define FDM_EYE_RADIAL    0
112 #define FDM_EYE_PLANE     1
113 #define FDM_EYE_PLANE_ABS 2
114
115 static GLuint translate_fog_distance_mode( GLenum mode )
116 {
117    switch (mode) {
118    case GL_EYE_RADIAL_NV:
119       return FDM_EYE_RADIAL;
120    case GL_EYE_PLANE:
121       return FDM_EYE_PLANE;
122    default: /* shouldn't happen; fall through to a sensible default */
123    case GL_EYE_PLANE_ABSOLUTE_NV:
124       return FDM_EYE_PLANE_ABS;
125    }
126 }
127
128 static GLboolean check_active_shininess( struct gl_context *ctx,
129                                          const struct state_key *key,
130                                          GLuint side )
131 {
132    GLuint attr = MAT_ATTRIB_FRONT_SHININESS + side;
133
134    if ((key->varying_vp_inputs & VERT_BIT_COLOR0) &&
135        (key->light_color_material_mask & (1 << attr)))
136       return GL_TRUE;
137
138    if (key->varying_vp_inputs & VERT_BIT_GENERIC(attr))
139       return GL_TRUE;
140
141    if (ctx->Light.Material.Attrib[attr][0] != 0.0F)
142       return GL_TRUE;
143
144    return GL_FALSE;
145 }
146
147
148 static void make_state_key( struct gl_context *ctx, struct state_key *key )
149 {
150    const struct gl_fragment_program *fp;
151    GLuint i;
152
153    memset(key, 0, sizeof(struct state_key));
154    fp = ctx->FragmentProgram._Current;
155
156    /* This now relies on texenvprogram.c being active:
157     */
158    assert(fp);
159
160    key->need_eye_coords = ctx->_NeedEyeCoords;
161
162    key->fragprog_inputs_read = fp->Base.InputsRead;
163    key->varying_vp_inputs = ctx->varying_vp_inputs;
164
165    if (ctx->RenderMode == GL_FEEDBACK) {
166       /* make sure the vertprog emits color and tex0 */
167       key->fragprog_inputs_read |= (VARYING_BIT_COL0 | VARYING_BIT_TEX0);
168    }
169
170    key->separate_specular = (ctx->Light.Model.ColorControl ==
171                              GL_SEPARATE_SPECULAR_COLOR);
172
173    if (ctx->Light.Enabled) {
174       key->light_global_enabled = 1;
175
176       if (ctx->Light.Model.LocalViewer)
177          key->light_local_viewer = 1;
178
179       if (ctx->Light.Model.TwoSide)
180          key->light_twoside = 1;
181
182       if (ctx->Light.ColorMaterialEnabled) {
183          key->light_color_material_mask = ctx->Light._ColorMaterialBitmask;
184       }
185
186       for (i = 0; i < MAX_LIGHTS; i++) {
187          struct gl_light *light = &ctx->Light.Light[i];
188
189          if (light->Enabled) {
190             key->unit[i].light_enabled = 1;
191
192             if (light->EyePosition[3] == 0.0F)
193                key->unit[i].light_eyepos3_is_zero = 1;
194
195             if (light->SpotCutoff == 180.0F)
196                key->unit[i].light_spotcutoff_is_180 = 1;
197
198             if (light->ConstantAttenuation != 1.0F ||
199                 light->LinearAttenuation != 0.0F ||
200                 light->QuadraticAttenuation != 0.0F)
201                key->unit[i].light_attenuated = 1;
202          }
203       }
204
205       if (check_active_shininess(ctx, key, 0)) {
206          key->material_shininess_is_zero = 0;
207       }
208       else if (key->light_twoside &&
209                check_active_shininess(ctx, key, 1)) {
210          key->material_shininess_is_zero = 0;
211       }
212       else {
213          key->material_shininess_is_zero = 1;
214       }
215    }
216
217    if (ctx->Transform.Normalize)
218       key->normalize = 1;
219
220    if (ctx->Transform.RescaleNormals)
221       key->rescale_normals = 1;
222
223    if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
224       key->fog_source_is_depth = 1;
225       key->fog_distance_mode = translate_fog_distance_mode(ctx->Fog.FogDistanceMode);
226    }
227
228    if (ctx->Point._Attenuated)
229       key->point_attenuated = 1;
230
231    if (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Enabled)
232       key->point_array = 1;
233
234    if (ctx->Texture._TexGenEnabled ||
235        ctx->Texture._TexMatEnabled ||
236        ctx->Texture._MaxEnabledTexImageUnit != -1)
237       key->texture_enabled_global = 1;
238
239    for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
240       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
241
242       if (texUnit->_Current)
243          key->unit[i].texunit_really_enabled = 1;
244
245       if (ctx->Point.PointSprite)
246          if (ctx->Point.CoordReplace[i])
247             key->unit[i].coord_replace = 1;
248
249       if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i))
250          key->unit[i].texmat_enabled = 1;
251
252       if (texUnit->TexGenEnabled) {
253          key->unit[i].texgen_enabled = 1;
254
255          key->unit[i].texgen_mode0 =
256             translate_texgen( texUnit->TexGenEnabled & (1<<0),
257                               texUnit->GenS.Mode );
258          key->unit[i].texgen_mode1 =
259             translate_texgen( texUnit->TexGenEnabled & (1<<1),
260                               texUnit->GenT.Mode );
261          key->unit[i].texgen_mode2 =
262             translate_texgen( texUnit->TexGenEnabled & (1<<2),
263                               texUnit->GenR.Mode );
264          key->unit[i].texgen_mode3 =
265             translate_texgen( texUnit->TexGenEnabled & (1<<3),
266                               texUnit->GenQ.Mode );
267       }
268    }
269 }
270
271
272
273 /* Very useful debugging tool - produces annotated listing of
274  * generated program with line/function references for each
275  * instruction back into this file:
276  */
277 #define DISASSEM 0
278
279
280 /* Use uregs to represent registers internally, translate to Mesa's
281  * expected formats on emit.
282  *
283  * NOTE: These are passed by value extensively in this file rather
284  * than as usual by pointer reference.  If this disturbs you, try
285  * remembering they are just 32bits in size.
286  *
287  * GCC is smart enough to deal with these dword-sized structures in
288  * much the same way as if I had defined them as dwords and was using
289  * macros to access and set the fields.  This is much nicer and easier
290  * to evolve.
291  */
292 struct ureg {
293    GLuint file:4;
294    GLint idx:9;      /* relative addressing may be negative */
295                      /* sizeof(idx) should == sizeof(prog_src_reg::Index) */
296    GLuint negate:1;
297    GLuint swz:12;
298    GLuint pad:6;
299 };
300
301
302 struct tnl_program {
303    const struct state_key *state;
304    struct gl_vertex_program *program;
305    GLuint max_inst;  /** number of instructions allocated for program */
306    GLboolean mvp_with_dp4;
307
308    GLuint temp_in_use;
309    GLuint temp_reserved;
310
311    struct ureg eye_position;
312    struct ureg eye_position_z;
313    struct ureg eye_position_normalized;
314    struct ureg transformed_normal;
315    struct ureg identity;
316
317    GLuint materials;
318    GLuint color_materials;
319 };
320
321
322 static const struct ureg undef = {
323    PROGRAM_UNDEFINED,
324    0,
325    0,
326    0,
327    0
328 };
329
330 /* Local shorthand:
331  */
332 #define X    SWIZZLE_X
333 #define Y    SWIZZLE_Y
334 #define Z    SWIZZLE_Z
335 #define W    SWIZZLE_W
336
337
338 /* Construct a ureg:
339  */
340 static struct ureg make_ureg(GLuint file, GLint idx)
341 {
342    struct ureg reg;
343    reg.file = file;
344    reg.idx = idx;
345    reg.negate = 0;
346    reg.swz = SWIZZLE_NOOP;
347    reg.pad = 0;
348    return reg;
349 }
350
351
352 static struct ureg negate( struct ureg reg )
353 {
354    reg.negate ^= 1;
355    return reg;
356 }
357
358
359 static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
360 {
361    reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
362                            GET_SWZ(reg.swz, y),
363                            GET_SWZ(reg.swz, z),
364                            GET_SWZ(reg.swz, w));
365    return reg;
366 }
367
368
369 static struct ureg swizzle1( struct ureg reg, int x )
370 {
371    return swizzle(reg, x, x, x, x);
372 }
373
374
375 static struct ureg get_temp( struct tnl_program *p )
376 {
377    int bit = ffs( ~p->temp_in_use );
378    if (!bit) {
379       _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
380       exit(1);
381    }
382
383    if ((GLuint) bit > p->program->Base.NumTemporaries)
384       p->program->Base.NumTemporaries = bit;
385
386    p->temp_in_use |= 1<<(bit-1);
387    return make_ureg(PROGRAM_TEMPORARY, bit-1);
388 }
389
390
391 static struct ureg reserve_temp( struct tnl_program *p )
392 {
393    struct ureg temp = get_temp( p );
394    p->temp_reserved |= 1<<temp.idx;
395    return temp;
396 }
397
398
399 static void release_temp( struct tnl_program *p, struct ureg reg )
400 {
401    if (reg.file == PROGRAM_TEMPORARY) {
402       p->temp_in_use &= ~(1<<reg.idx);
403       p->temp_in_use |= p->temp_reserved; /* can't release reserved temps */
404    }
405 }
406
407 static void release_temps( struct tnl_program *p )
408 {
409    p->temp_in_use = p->temp_reserved;
410 }
411
412
413 static struct ureg register_param5(struct tnl_program *p,
414                                    GLint s0,
415                                    GLint s1,
416                                    GLint s2,
417                                    GLint s3,
418                                    GLint s4)
419 {
420    gl_state_index tokens[STATE_LENGTH];
421    GLint idx;
422    tokens[0] = s0;
423    tokens[1] = s1;
424    tokens[2] = s2;
425    tokens[3] = s3;
426    tokens[4] = s4;
427    idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens );
428    return make_ureg(PROGRAM_STATE_VAR, idx);
429 }
430
431
432 #define register_param1(p,s0)          register_param5(p,s0,0,0,0,0)
433 #define register_param2(p,s0,s1)       register_param5(p,s0,s1,0,0,0)
434 #define register_param3(p,s0,s1,s2)    register_param5(p,s0,s1,s2,0,0)
435 #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
436
437
438
439 /**
440  * \param input  one of VERT_ATTRIB_x tokens.
441  */
442 static struct ureg register_input( struct tnl_program *p, GLuint input )
443 {
444    assert(input < VERT_ATTRIB_MAX);
445
446    if (p->state->varying_vp_inputs & VERT_BIT(input)) {
447       p->program->Base.InputsRead |= VERT_BIT(input);
448       return make_ureg(PROGRAM_INPUT, input);
449    }
450    else {
451       return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, input );
452    }
453 }
454
455
456 /**
457  * \param input  one of VARYING_SLOT_x tokens.
458  */
459 static struct ureg register_output( struct tnl_program *p, GLuint output )
460 {
461    p->program->Base.OutputsWritten |= BITFIELD64_BIT(output);
462    return make_ureg(PROGRAM_OUTPUT, output);
463 }
464
465
466 static struct ureg register_const4f( struct tnl_program *p,
467                               GLfloat s0,
468                               GLfloat s1,
469                               GLfloat s2,
470                               GLfloat s3)
471 {
472    gl_constant_value values[4];
473    GLint idx;
474    GLuint swizzle;
475    values[0].f = s0;
476    values[1].f = s1;
477    values[2].f = s2;
478    values[3].f = s3;
479    idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
480                                      &swizzle );
481    assert(swizzle == SWIZZLE_NOOP);
482    return make_ureg(PROGRAM_CONSTANT, idx);
483 }
484
485 #define register_const1f(p, s0)         register_const4f(p, s0, 0, 0, 1)
486 #define register_scalar_const(p, s0)    register_const4f(p, s0, s0, s0, s0)
487 #define register_const2f(p, s0, s1)     register_const4f(p, s0, s1, 0, 1)
488 #define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
489
490 static GLboolean is_undef( struct ureg reg )
491 {
492    return reg.file == PROGRAM_UNDEFINED;
493 }
494
495
496 static struct ureg get_identity_param( struct tnl_program *p )
497 {
498    if (is_undef(p->identity))
499       p->identity = register_const4f(p, 0,0,0,1);
500
501    return p->identity;
502 }
503
504 static void register_matrix_param5( struct tnl_program *p,
505                                     GLint s0, /* modelview, projection, etc */
506                                     GLint s1, /* texture matrix number */
507                                     GLint s2, /* first row */
508                                     GLint s3, /* last row */
509                                     GLint s4, /* inverse, transpose, etc */
510                                     struct ureg *matrix )
511 {
512    GLint i;
513
514    /* This is a bit sad as the support is there to pull the whole
515     * matrix out in one go:
516     */
517    for (i = 0; i <= s3 - s2; i++)
518       matrix[i] = register_param5( p, s0, s1, i, i, s4 );
519 }
520
521
522 static void emit_arg( struct prog_src_register *src,
523                       struct ureg reg )
524 {
525    src->File = reg.file;
526    src->Index = reg.idx;
527    src->Swizzle = reg.swz;
528    src->Negate = reg.negate ? NEGATE_XYZW : NEGATE_NONE;
529    src->RelAddr = 0;
530    /* Check that bitfield sizes aren't exceeded */
531    assert(src->Index == reg.idx);
532 }
533
534
535 static void emit_dst( struct prog_dst_register *dst,
536                       struct ureg reg, GLuint mask )
537 {
538    dst->File = reg.file;
539    dst->Index = reg.idx;
540    /* allow zero as a shorthand for xyzw */
541    dst->WriteMask = mask ? mask : WRITEMASK_XYZW;
542    /* Check that bitfield sizes aren't exceeded */
543    assert(dst->Index == reg.idx);
544 }
545
546
547 static void debug_insn( struct prog_instruction *inst, const char *fn,
548                         GLuint line )
549 {
550    if (DISASSEM) {
551       static const char *last_fn;
552
553       if (fn != last_fn) {
554          last_fn = fn;
555          printf("%s:\n", fn);
556       }
557
558       printf("%d:\t", line);
559       _mesa_print_instruction(inst);
560    }
561 }
562
563
564 static void emit_op3fn(struct tnl_program *p,
565                        enum prog_opcode op,
566                        struct ureg dest,
567                        GLuint mask,
568                        struct ureg src0,
569                        struct ureg src1,
570                        struct ureg src2,
571                        const char *fn,
572                        GLuint line)
573 {
574    GLuint nr;
575    struct prog_instruction *inst;
576
577    assert(p->program->Base.NumInstructions <= p->max_inst);
578
579    if (p->program->Base.NumInstructions == p->max_inst) {
580       /* need to extend the program's instruction array */
581       struct prog_instruction *newInst;
582
583       /* double the size */
584       p->max_inst *= 2;
585
586       newInst = _mesa_alloc_instructions(p->max_inst);
587       if (!newInst) {
588          _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build");
589          return;
590       }
591
592       _mesa_copy_instructions(newInst,
593                               p->program->Base.Instructions,
594                               p->program->Base.NumInstructions);
595
596       _mesa_free_instructions(p->program->Base.Instructions,
597                               p->program->Base.NumInstructions);
598
599       p->program->Base.Instructions = newInst;
600    }
601
602    nr = p->program->Base.NumInstructions++;
603
604    inst = &p->program->Base.Instructions[nr];
605    inst->Opcode = (enum prog_opcode) op;
606
607    emit_arg( &inst->SrcReg[0], src0 );
608    emit_arg( &inst->SrcReg[1], src1 );
609    emit_arg( &inst->SrcReg[2], src2 );
610
611    emit_dst( &inst->DstReg, dest, mask );
612
613    debug_insn(inst, fn, line);
614 }
615
616
617 #define emit_op3(p, op, dst, mask, src0, src1, src2) \
618    emit_op3fn(p, op, dst, mask, src0, src1, src2, __func__, __LINE__)
619
620 #define emit_op2(p, op, dst, mask, src0, src1) \
621     emit_op3fn(p, op, dst, mask, src0, src1, undef, __func__, __LINE__)
622
623 #define emit_op1(p, op, dst, mask, src0) \
624     emit_op3fn(p, op, dst, mask, src0, undef, undef, __func__, __LINE__)
625
626
627 static struct ureg make_temp( struct tnl_program *p, struct ureg reg )
628 {
629    if (reg.file == PROGRAM_TEMPORARY &&
630        !(p->temp_reserved & (1<<reg.idx)))
631       return reg;
632    else {
633       struct ureg temp = get_temp(p);
634       emit_op1(p, OPCODE_MOV, temp, 0, reg);
635       return temp;
636    }
637 }
638
639
640 /* Currently no tracking performed of input/output/register size or
641  * active elements.  Could be used to reduce these operations, as
642  * could the matrix type.
643  */
644 static void emit_matrix_transform_vec4( struct tnl_program *p,
645                                         struct ureg dest,
646                                         const struct ureg *mat,
647                                         struct ureg src)
648 {
649    emit_op2(p, OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]);
650    emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]);
651    emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]);
652    emit_op2(p, OPCODE_DP4, dest, WRITEMASK_W, src, mat[3]);
653 }
654
655
656 /* This version is much easier to implement if writemasks are not
657  * supported natively on the target or (like SSE), the target doesn't
658  * have a clean/obvious dotproduct implementation.
659  */
660 static void emit_transpose_matrix_transform_vec4( struct tnl_program *p,
661                                                   struct ureg dest,
662                                                   const struct ureg *mat,
663                                                   struct ureg src)
664 {
665    struct ureg tmp;
666
667    if (dest.file != PROGRAM_TEMPORARY)
668       tmp = get_temp(p);
669    else
670       tmp = dest;
671
672    emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
673    emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
674    emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
675    emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
676
677    if (dest.file != PROGRAM_TEMPORARY)
678       release_temp(p, tmp);
679 }
680
681
682 static void emit_matrix_transform_vec3( struct tnl_program *p,
683                                         struct ureg dest,
684                                         const struct ureg *mat,
685                                         struct ureg src)
686 {
687    emit_op2(p, OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]);
688    emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]);
689    emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Z, src, mat[2]);
690 }
691
692
693 static void emit_normalize_vec3( struct tnl_program *p,
694                                  struct ureg dest,
695                                  struct ureg src )
696 {
697    struct ureg tmp = get_temp(p);
698    emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, src, src);
699    emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp);
700    emit_op2(p, OPCODE_MUL, dest, 0, src, swizzle1(tmp, X));
701    release_temp(p, tmp);
702 }
703
704
705 static void emit_passthrough( struct tnl_program *p,
706                               GLuint input,
707                               GLuint output )
708 {
709    struct ureg out = register_output(p, output);
710    emit_op1(p, OPCODE_MOV, out, 0, register_input(p, input));
711 }
712
713
714 static struct ureg get_eye_position( struct tnl_program *p )
715 {
716    if (is_undef(p->eye_position)) {
717       struct ureg pos = register_input( p, VERT_ATTRIB_POS );
718       struct ureg modelview[4];
719
720       p->eye_position = reserve_temp(p);
721
722       if (p->mvp_with_dp4) {
723          register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
724                                  0, modelview );
725
726          emit_matrix_transform_vec4(p, p->eye_position, modelview, pos);
727       }
728       else {
729          register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
730                                  STATE_MATRIX_TRANSPOSE, modelview );
731
732          emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos);
733       }
734    }
735
736    return p->eye_position;
737 }
738
739
740 static struct ureg get_eye_position_z( struct tnl_program *p )
741 {
742    if (!is_undef(p->eye_position))
743       return swizzle1(p->eye_position, Z);
744
745    if (is_undef(p->eye_position_z)) {
746       struct ureg pos = register_input( p, VERT_ATTRIB_POS );
747       struct ureg modelview[4];
748
749       p->eye_position_z = reserve_temp(p);
750
751       register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
752                               0, modelview );
753
754       emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]);
755    }
756
757    return p->eye_position_z;
758 }
759
760
761 static struct ureg get_eye_position_normalized( struct tnl_program *p )
762 {
763    if (is_undef(p->eye_position_normalized)) {
764       struct ureg eye = get_eye_position(p);
765       p->eye_position_normalized = reserve_temp(p);
766       emit_normalize_vec3(p, p->eye_position_normalized, eye);
767    }
768
769    return p->eye_position_normalized;
770 }
771
772
773 static struct ureg get_transformed_normal( struct tnl_program *p )
774 {
775    if (is_undef(p->transformed_normal) &&
776        !p->state->need_eye_coords &&
777        !p->state->normalize &&
778        !(p->state->need_eye_coords == p->state->rescale_normals))
779    {
780       p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL );
781    }
782    else if (is_undef(p->transformed_normal))
783    {
784       struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL );
785       struct ureg mvinv[3];
786       struct ureg transformed_normal = reserve_temp(p);
787
788       if (p->state->need_eye_coords) {
789          register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2,
790                                  STATE_MATRIX_INVTRANS, mvinv );
791
792          /* Transform to eye space:
793           */
794          emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal );
795          normal = transformed_normal;
796       }
797
798       /* Normalize/Rescale:
799        */
800       if (p->state->normalize) {
801          emit_normalize_vec3( p, transformed_normal, normal );
802          normal = transformed_normal;
803       }
804       else if (p->state->need_eye_coords == p->state->rescale_normals) {
805          /* This is already adjusted for eye/non-eye rendering:
806           */
807          struct ureg rescale = register_param2(p, STATE_INTERNAL,
808                                                STATE_NORMAL_SCALE);
809
810          emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale );
811          normal = transformed_normal;
812       }
813
814       assert(normal.file == PROGRAM_TEMPORARY);
815       p->transformed_normal = normal;
816    }
817
818    return p->transformed_normal;
819 }
820
821
822 static void build_hpos( struct tnl_program *p )
823 {
824    struct ureg pos = register_input( p, VERT_ATTRIB_POS );
825    struct ureg hpos = register_output( p, VARYING_SLOT_POS );
826    struct ureg mvp[4];
827
828    if (p->mvp_with_dp4) {
829       register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
830                               0, mvp );
831       emit_matrix_transform_vec4( p, hpos, mvp, pos );
832    }
833    else {
834       register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
835                               STATE_MATRIX_TRANSPOSE, mvp );
836       emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos );
837    }
838 }
839
840
841 static GLuint material_attrib( GLuint side, GLuint property )
842 {
843    return (property - STATE_AMBIENT) * 2 + side;
844 }
845
846
847 /**
848  * Get a bitmask of which material values vary on a per-vertex basis.
849  */
850 static void set_material_flags( struct tnl_program *p )
851 {
852    p->color_materials = 0;
853    p->materials = 0;
854
855    if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) {
856       p->materials =
857          p->color_materials = p->state->light_color_material_mask;
858    }
859
860    p->materials |= (p->state->varying_vp_inputs >> VERT_ATTRIB_GENERIC0);
861 }
862
863
864 static struct ureg get_material( struct tnl_program *p, GLuint side,
865                                  GLuint property )
866 {
867    GLuint attrib = material_attrib(side, property);
868
869    if (p->color_materials & (1<<attrib))
870       return register_input(p, VERT_ATTRIB_COLOR0);
871    else if (p->materials & (1<<attrib)) {
872       /* Put material values in the GENERIC slots -- they are not used
873        * for anything in fixed function mode.
874        */
875       return register_input( p, attrib + VERT_ATTRIB_GENERIC0 );
876    }
877    else
878       return register_param3( p, STATE_MATERIAL, side, property );
879 }
880
881 #define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \
882                                    MAT_BIT_FRONT_AMBIENT | \
883                                    MAT_BIT_FRONT_DIFFUSE) << (side))
884
885
886 /**
887  * Either return a precalculated constant value or emit code to
888  * calculate these values dynamically in the case where material calls
889  * are present between begin/end pairs.
890  *
891  * Probably want to shift this to the program compilation phase - if
892  * we always emitted the calculation here, a smart compiler could
893  * detect that it was constant (given a certain set of inputs), and
894  * lift it out of the main loop.  That way the programs created here
895  * would be independent of the vertex_buffer details.
896  */
897 static struct ureg get_scenecolor( struct tnl_program *p, GLuint side )
898 {
899    if (p->materials & SCENE_COLOR_BITS(side)) {
900       struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT);
901       struct ureg material_emission = get_material(p, side, STATE_EMISSION);
902       struct ureg material_ambient = get_material(p, side, STATE_AMBIENT);
903       struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE);
904       struct ureg tmp = make_temp(p, material_diffuse);
905       emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient,
906                material_ambient, material_emission);
907       return tmp;
908    }
909    else
910       return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side );
911 }
912
913
914 static struct ureg get_lightprod( struct tnl_program *p, GLuint light,
915                                   GLuint side, GLuint property )
916 {
917    GLuint attrib = material_attrib(side, property);
918    if (p->materials & (1<<attrib)) {
919       struct ureg light_value =
920          register_param3(p, STATE_LIGHT, light, property);
921       struct ureg material_value = get_material(p, side, property);
922       struct ureg tmp = get_temp(p);
923       emit_op2(p, OPCODE_MUL, tmp, 0, light_value, material_value);
924       return tmp;
925    }
926    else
927       return register_param4(p, STATE_LIGHTPROD, light, side, property);
928 }
929
930
931 static struct ureg calculate_light_attenuation( struct tnl_program *p,
932                                                 GLuint i,
933                                                 struct ureg VPpli,
934                                                 struct ureg dist )
935 {
936    struct ureg attenuation = register_param3(p, STATE_LIGHT, i,
937                                              STATE_ATTENUATION);
938    struct ureg att = undef;
939
940    /* Calculate spot attenuation:
941     */
942    if (!p->state->unit[i].light_spotcutoff_is_180) {
943       struct ureg spot_dir_norm = register_param3(p, STATE_INTERNAL,
944                                                   STATE_LIGHT_SPOT_DIR_NORMALIZED, i);
945       struct ureg spot = get_temp(p);
946       struct ureg slt = get_temp(p);
947
948       att = get_temp(p);
949
950       emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm);
951       emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot);
952       emit_op1(p, OPCODE_ABS, spot, 0, spot);
953       emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W));
954       emit_op2(p, OPCODE_MUL, att, 0, slt, spot);
955
956       release_temp(p, spot);
957       release_temp(p, slt);
958    }
959
960    /* Calculate distance attenuation(See formula (2.4) at glspec 2.1 page 62):
961     *
962     * Skip the calucation when _dist_ is undefined(light_eyepos3_is_zero)
963     */
964    if (p->state->unit[i].light_attenuated && !is_undef(dist)) {
965       if (is_undef(att))
966          att = get_temp(p);
967       /* 1/d,d,d,1/d */
968       emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist);
969       /* 1,d,d*d,1/d */
970       emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y));
971       /* 1/dist-atten */
972       emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist);
973
974       if (!p->state->unit[i].light_spotcutoff_is_180) {
975          /* dist-atten */
976          emit_op1(p, OPCODE_RCP, dist, 0, dist);
977          /* spot-atten * dist-atten */
978          emit_op2(p, OPCODE_MUL, att, 0, dist, att);
979       }
980       else {
981          /* dist-atten */
982          emit_op1(p, OPCODE_RCP, att, 0, dist);
983       }
984    }
985
986    return att;
987 }
988
989
990 /**
991  * Compute:
992  *   lit.y = MAX(0, dots.x)
993  *   lit.z = SLT(0, dots.x)
994  */
995 static void emit_degenerate_lit( struct tnl_program *p,
996                                  struct ureg lit,
997                                  struct ureg dots )
998 {
999    struct ureg id = get_identity_param(p);  /* id = {0,0,0,1} */
1000
1001    /* Note that lit.x & lit.w will not be examined.  Note also that
1002     * dots.xyzw == dots.xxxx.
1003     */
1004
1005    /* MAX lit, id, dots;
1006     */
1007    emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots);
1008
1009    /* result[2] = (in > 0 ? 1 : 0)
1010     * SLT lit.z, id.z, dots;   # lit.z = (0 < dots.z) ? 1 : 0
1011     */
1012    emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots);
1013 }
1014
1015
1016 /* Need to add some addtional parameters to allow lighting in object
1017  * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye
1018  * space lighting.
1019  */
1020 static void build_lighting( struct tnl_program *p )
1021 {
1022    const GLboolean twoside = p->state->light_twoside;
1023    const GLboolean separate = p->state->separate_specular;
1024    GLuint nr_lights = 0, count = 0;
1025    struct ureg normal = get_transformed_normal(p);
1026    struct ureg lit = get_temp(p);
1027    struct ureg dots = get_temp(p);
1028    struct ureg _col0 = undef, _col1 = undef;
1029    struct ureg _bfc0 = undef, _bfc1 = undef;
1030    GLuint i;
1031
1032    /*
1033     * NOTE:
1034     * dots.x = dot(normal, VPpli)
1035     * dots.y = dot(normal, halfAngle)
1036     * dots.z = back.shininess
1037     * dots.w = front.shininess
1038     */
1039
1040    for (i = 0; i < MAX_LIGHTS; i++)
1041       if (p->state->unit[i].light_enabled)
1042          nr_lights++;
1043
1044    set_material_flags(p);
1045
1046    {
1047       if (!p->state->material_shininess_is_zero) {
1048          struct ureg shininess = get_material(p, 0, STATE_SHININESS);
1049          emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X));
1050          release_temp(p, shininess);
1051       }
1052
1053       _col0 = make_temp(p, get_scenecolor(p, 0));
1054       if (separate)
1055          _col1 = make_temp(p, get_identity_param(p));
1056       else
1057          _col1 = _col0;
1058    }
1059
1060    if (twoside) {
1061       if (!p->state->material_shininess_is_zero) {
1062          /* Note that we negate the back-face specular exponent here.
1063           * The negation will be un-done later in the back-face code below.
1064           */
1065          struct ureg shininess = get_material(p, 1, STATE_SHININESS);
1066          emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z,
1067                   negate(swizzle1(shininess,X)));
1068          release_temp(p, shininess);
1069       }
1070
1071       _bfc0 = make_temp(p, get_scenecolor(p, 1));
1072       if (separate)
1073          _bfc1 = make_temp(p, get_identity_param(p));
1074       else
1075          _bfc1 = _bfc0;
1076    }
1077
1078    /* If no lights, still need to emit the scenecolor.
1079     */
1080    {
1081       struct ureg res0 = register_output( p, VARYING_SLOT_COL0 );
1082       emit_op1(p, OPCODE_MOV, res0, 0, _col0);
1083    }
1084
1085    if (separate) {
1086       struct ureg res1 = register_output( p, VARYING_SLOT_COL1 );
1087       emit_op1(p, OPCODE_MOV, res1, 0, _col1);
1088    }
1089
1090    if (twoside) {
1091       struct ureg res0 = register_output( p, VARYING_SLOT_BFC0 );
1092       emit_op1(p, OPCODE_MOV, res0, 0, _bfc0);
1093    }
1094
1095    if (twoside && separate) {
1096       struct ureg res1 = register_output( p, VARYING_SLOT_BFC1 );
1097       emit_op1(p, OPCODE_MOV, res1, 0, _bfc1);
1098    }
1099
1100    if (nr_lights == 0) {
1101       release_temps(p);
1102       return;
1103    }
1104
1105    for (i = 0; i < MAX_LIGHTS; i++) {
1106       if (p->state->unit[i].light_enabled) {
1107          struct ureg half = undef;
1108          struct ureg att = undef, VPpli = undef;
1109          struct ureg dist = undef;
1110
1111          count++;
1112          if (p->state->unit[i].light_eyepos3_is_zero) {
1113              VPpli = register_param3(p, STATE_INTERNAL,
1114                                      STATE_LIGHT_POSITION_NORMALIZED, i);
1115          } else {
1116             struct ureg Ppli = register_param3(p, STATE_INTERNAL,
1117                                                STATE_LIGHT_POSITION, i);
1118             struct ureg V = get_eye_position(p);
1119
1120             VPpli = get_temp(p);
1121             dist = get_temp(p);
1122
1123             /* Calculate VPpli vector
1124              */
1125             emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V);
1126
1127             /* Normalize VPpli.  The dist value also used in
1128              * attenuation below.
1129              */
1130             emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli);
1131             emit_op1(p, OPCODE_RSQ, dist, 0, dist);
1132             emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist);
1133          }
1134
1135          /* Calculate attenuation:
1136           */
1137          att = calculate_light_attenuation(p, i, VPpli, dist);
1138          release_temp(p, dist);
1139
1140          /* Calculate viewer direction, or use infinite viewer:
1141           */
1142          if (!p->state->material_shininess_is_zero) {
1143             if (p->state->light_local_viewer) {
1144                struct ureg eye_hat = get_eye_position_normalized(p);
1145                half = get_temp(p);
1146                emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat);
1147                emit_normalize_vec3(p, half, half);
1148             } else if (p->state->unit[i].light_eyepos3_is_zero) {
1149                half = register_param3(p, STATE_INTERNAL,
1150                                       STATE_LIGHT_HALF_VECTOR, i);
1151             } else {
1152                struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z);
1153                half = get_temp(p);
1154                emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir);
1155                emit_normalize_vec3(p, half, half);
1156             }
1157          }
1158
1159          /* Calculate dot products:
1160           */
1161          if (p->state->material_shininess_is_zero) {
1162             emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli);
1163          }
1164          else {
1165             emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli);
1166             emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half);
1167          }
1168
1169          /* Front face lighting:
1170           */
1171          {
1172             struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT);
1173             struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE);
1174             struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR);
1175             struct ureg res0, res1;
1176             GLuint mask0, mask1;
1177
1178             if (count == nr_lights) {
1179                if (separate) {
1180                   mask0 = WRITEMASK_XYZ;
1181                   mask1 = WRITEMASK_XYZ;
1182                   res0 = register_output( p, VARYING_SLOT_COL0 );
1183                   res1 = register_output( p, VARYING_SLOT_COL1 );
1184                }
1185                else {
1186                   mask0 = 0;
1187                   mask1 = WRITEMASK_XYZ;
1188                   res0 = _col0;
1189                   res1 = register_output( p, VARYING_SLOT_COL0 );
1190                }
1191             }
1192             else {
1193                mask0 = 0;
1194                mask1 = 0;
1195                res0 = _col0;
1196                res1 = _col1;
1197             }
1198
1199             if (!is_undef(att)) {
1200                /* light is attenuated by distance */
1201                emit_op1(p, OPCODE_LIT, lit, 0, dots);
1202                emit_op2(p, OPCODE_MUL, lit, 0, lit, att);
1203                emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0);
1204             }
1205             else if (!p->state->material_shininess_is_zero) {
1206                /* there's a non-zero specular term */
1207                emit_op1(p, OPCODE_LIT, lit, 0, dots);
1208                emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0);
1209             }
1210             else {
1211                /* no attenutation, no specular */
1212                emit_degenerate_lit(p, lit, dots);
1213                emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0);
1214             }
1215
1216             emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0);
1217             emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1);
1218
1219             release_temp(p, ambient);
1220             release_temp(p, diffuse);
1221             release_temp(p, specular);
1222          }
1223
1224          /* Back face lighting:
1225           */
1226          if (twoside) {
1227             struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT);
1228             struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE);
1229             struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR);
1230             struct ureg res0, res1;
1231             GLuint mask0, mask1;
1232
1233             if (count == nr_lights) {
1234                if (separate) {
1235                   mask0 = WRITEMASK_XYZ;
1236                   mask1 = WRITEMASK_XYZ;
1237                   res0 = register_output( p, VARYING_SLOT_BFC0 );
1238                   res1 = register_output( p, VARYING_SLOT_BFC1 );
1239                }
1240                else {
1241                   mask0 = 0;
1242                   mask1 = WRITEMASK_XYZ;
1243                   res0 = _bfc0;
1244                   res1 = register_output( p, VARYING_SLOT_BFC0 );
1245                }
1246             }
1247             else {
1248                res0 = _bfc0;
1249                res1 = _bfc1;
1250                mask0 = 0;
1251                mask1 = 0;
1252             }
1253
1254             /* For the back face we need to negate the X and Y component
1255              * dot products.  dots.Z has the negated back-face specular
1256              * exponent.  We swizzle that into the W position.  This
1257              * negation makes the back-face specular term positive again.
1258              */
1259             dots = negate(swizzle(dots,X,Y,W,Z));
1260
1261             if (!is_undef(att)) {
1262                emit_op1(p, OPCODE_LIT, lit, 0, dots);
1263                emit_op2(p, OPCODE_MUL, lit, 0, lit, att);
1264                emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0);
1265             }
1266             else if (!p->state->material_shininess_is_zero) {
1267                emit_op1(p, OPCODE_LIT, lit, 0, dots);
1268                emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); /**/
1269             }
1270             else {
1271                emit_degenerate_lit(p, lit, dots);
1272                emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0);
1273             }
1274
1275             emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0);
1276             emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1);
1277             /* restore dots to its original state for subsequent lights
1278              * by negating and swizzling again.
1279              */
1280             dots = negate(swizzle(dots,X,Y,W,Z));
1281
1282             release_temp(p, ambient);
1283             release_temp(p, diffuse);
1284             release_temp(p, specular);
1285          }
1286
1287          release_temp(p, half);
1288          release_temp(p, VPpli);
1289          release_temp(p, att);
1290       }
1291    }
1292
1293    release_temps( p );
1294 }
1295
1296
1297 static void build_fog( struct tnl_program *p )
1298 {
1299    struct ureg fog = register_output(p, VARYING_SLOT_FOGC);
1300    struct ureg input;
1301
1302    if (p->state->fog_source_is_depth) {
1303
1304       switch (p->state->fog_distance_mode) {
1305       case FDM_EYE_RADIAL: /* Z = sqrt(Xe*Xe + Ye*Ye + Ze*Ze) */
1306          input = get_eye_position(p);
1307          emit_op2(p, OPCODE_DP3, fog, WRITEMASK_X, input, input);
1308          emit_op1(p, OPCODE_RSQ, fog, WRITEMASK_X, fog);
1309          emit_op1(p, OPCODE_RCP, fog, WRITEMASK_X, fog);
1310          break;
1311       case FDM_EYE_PLANE: /* Z = Ze */
1312          input = get_eye_position_z(p);
1313          emit_op1(p, OPCODE_MOV, fog, WRITEMASK_X, input);
1314          break;
1315       case FDM_EYE_PLANE_ABS: /* Z = abs(Ze) */
1316          input = get_eye_position_z(p);
1317          emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input);
1318          break;
1319       default:
1320          assert(!"Bad fog mode in build_fog()");
1321          break;
1322       }
1323
1324    }
1325    else {
1326       input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X);
1327       emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input);
1328    }
1329
1330    emit_op1(p, OPCODE_MOV, fog, WRITEMASK_YZW, get_identity_param(p));
1331 }
1332
1333
1334 static void build_reflect_texgen( struct tnl_program *p,
1335                                   struct ureg dest,
1336                                   GLuint writemask )
1337 {
1338    struct ureg normal = get_transformed_normal(p);
1339    struct ureg eye_hat = get_eye_position_normalized(p);
1340    struct ureg tmp = get_temp(p);
1341
1342    /* n.u */
1343    emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat);
1344    /* 2n.u */
1345    emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp);
1346    /* (-2n.u)n + u */
1347    emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat);
1348
1349    release_temp(p, tmp);
1350 }
1351
1352
1353 static void build_sphere_texgen( struct tnl_program *p,
1354                                  struct ureg dest,
1355                                  GLuint writemask )
1356 {
1357    struct ureg normal = get_transformed_normal(p);
1358    struct ureg eye_hat = get_eye_position_normalized(p);
1359    struct ureg tmp = get_temp(p);
1360    struct ureg half = register_scalar_const(p, .5);
1361    struct ureg r = get_temp(p);
1362    struct ureg inv_m = get_temp(p);
1363    struct ureg id = get_identity_param(p);
1364
1365    /* Could share the above calculations, but it would be
1366     * a fairly odd state for someone to set (both sphere and
1367     * reflection active for different texture coordinate
1368     * components.  Of course - if two texture units enable
1369     * reflect and/or sphere, things start to tilt in favour
1370     * of seperating this out:
1371     */
1372
1373    /* n.u */
1374    emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat);
1375    /* 2n.u */
1376    emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp);
1377    /* (-2n.u)n + u */
1378    emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat);
1379    /* r + 0,0,1 */
1380    emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z));
1381    /* rx^2 + ry^2 + (rz+1)^2 */
1382    emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp);
1383    /* 2/m */
1384    emit_op1(p, OPCODE_RSQ, tmp, 0, tmp);
1385    /* 1/m */
1386    emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half);
1387    /* r/m + 1/2 */
1388    emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half);
1389
1390    release_temp(p, tmp);
1391    release_temp(p, r);
1392    release_temp(p, inv_m);
1393 }
1394
1395
1396 static void build_texture_transform( struct tnl_program *p )
1397 {
1398    GLuint i, j;
1399
1400    for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
1401
1402       if (!(p->state->fragprog_inputs_read & VARYING_BIT_TEX(i)))
1403          continue;
1404
1405       if (p->state->unit[i].coord_replace)
1406          continue;
1407
1408       if (p->state->unit[i].texgen_enabled ||
1409           p->state->unit[i].texmat_enabled) {
1410
1411          GLuint texmat_enabled = p->state->unit[i].texmat_enabled;
1412          struct ureg out = register_output(p, VARYING_SLOT_TEX0 + i);
1413          struct ureg out_texgen = undef;
1414
1415          if (p->state->unit[i].texgen_enabled) {
1416             GLuint copy_mask = 0;
1417             GLuint sphere_mask = 0;
1418             GLuint reflect_mask = 0;
1419             GLuint normal_mask = 0;
1420             GLuint modes[4];
1421
1422             if (texmat_enabled)
1423                out_texgen = get_temp(p);
1424             else
1425                out_texgen = out;
1426
1427             modes[0] = p->state->unit[i].texgen_mode0;
1428             modes[1] = p->state->unit[i].texgen_mode1;
1429             modes[2] = p->state->unit[i].texgen_mode2;
1430             modes[3] = p->state->unit[i].texgen_mode3;
1431
1432             for (j = 0; j < 4; j++) {
1433                switch (modes[j]) {
1434                case TXG_OBJ_LINEAR: {
1435                   struct ureg obj = register_input(p, VERT_ATTRIB_POS);
1436                   struct ureg plane =
1437                      register_param3(p, STATE_TEXGEN, i,
1438                                      STATE_TEXGEN_OBJECT_S + j);
1439
1440                   emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j,
1441                            obj, plane );
1442                   break;
1443                }
1444                case TXG_EYE_LINEAR: {
1445                   struct ureg eye = get_eye_position(p);
1446                   struct ureg plane =
1447                      register_param3(p, STATE_TEXGEN, i,
1448                                      STATE_TEXGEN_EYE_S + j);
1449
1450                   emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j,
1451                            eye, plane );
1452                   break;
1453                }
1454                case TXG_SPHERE_MAP:
1455                   sphere_mask |= WRITEMASK_X << j;
1456                   break;
1457                case TXG_REFLECTION_MAP:
1458                   reflect_mask |= WRITEMASK_X << j;
1459                   break;
1460                case TXG_NORMAL_MAP:
1461                   normal_mask |= WRITEMASK_X << j;
1462                   break;
1463                case TXG_NONE:
1464                   copy_mask |= WRITEMASK_X << j;
1465                }
1466             }
1467
1468             if (sphere_mask) {
1469                build_sphere_texgen(p, out_texgen, sphere_mask);
1470             }
1471
1472             if (reflect_mask) {
1473                build_reflect_texgen(p, out_texgen, reflect_mask);
1474             }
1475
1476             if (normal_mask) {
1477                struct ureg normal = get_transformed_normal(p);
1478                emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal );
1479             }
1480
1481             if (copy_mask) {
1482                struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i);
1483                emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in );
1484             }
1485          }
1486
1487          if (texmat_enabled) {
1488             struct ureg texmat[4];
1489             struct ureg in = (!is_undef(out_texgen) ?
1490                               out_texgen :
1491                               register_input(p, VERT_ATTRIB_TEX0+i));
1492             if (p->mvp_with_dp4) {
1493                register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
1494                                        0, texmat );
1495                emit_matrix_transform_vec4( p, out, texmat, in );
1496             }
1497             else {
1498                register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
1499                                        STATE_MATRIX_TRANSPOSE, texmat );
1500                emit_transpose_matrix_transform_vec4( p, out, texmat, in );
1501             }
1502          }
1503
1504          release_temps(p);
1505       }
1506       else {
1507          emit_passthrough(p, VERT_ATTRIB_TEX0+i, VARYING_SLOT_TEX0+i);
1508       }
1509    }
1510 }
1511
1512
1513 /**
1514  * Point size attenuation computation.
1515  */
1516 static void build_atten_pointsize( struct tnl_program *p )
1517 {
1518    struct ureg eye = get_eye_position_z(p);
1519    struct ureg state_size = register_param2(p, STATE_INTERNAL, STATE_POINT_SIZE_CLAMPED);
1520    struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION);
1521    struct ureg out = register_output(p, VARYING_SLOT_PSIZ);
1522    struct ureg ut = get_temp(p);
1523
1524    /* dist = |eyez| */
1525    emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z));
1526    /* p1 + dist * (p2 + dist * p3); */
1527    emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y),
1528                 swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y));
1529    emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y),
1530                 ut, swizzle1(state_attenuation, X));
1531
1532    /* 1 / sqrt(factor) */
1533    emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut );
1534
1535 #if 0
1536    /* out = pointSize / sqrt(factor) */
1537    emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size);
1538 #else
1539    /* this is a good place to clamp the point size since there's likely
1540     * no hardware registers to clamp point size at rasterization time.
1541     */
1542    emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size);
1543    emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y));
1544    emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z));
1545 #endif
1546
1547    release_temp(p, ut);
1548 }
1549
1550
1551 /**
1552  * Pass-though per-vertex point size, from user's point size array.
1553  */
1554 static void build_array_pointsize( struct tnl_program *p )
1555 {
1556    struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE);
1557    struct ureg out = register_output(p, VARYING_SLOT_PSIZ);
1558    emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in);
1559 }
1560
1561
1562 static void build_tnl_program( struct tnl_program *p )
1563 {
1564    /* Emit the program, starting with the modelview, projection transforms:
1565     */
1566    build_hpos(p);
1567
1568    /* Lighting calculations:
1569     */
1570    if (p->state->fragprog_inputs_read & (VARYING_BIT_COL0|VARYING_BIT_COL1)) {
1571       if (p->state->light_global_enabled)
1572          build_lighting(p);
1573       else {
1574          if (p->state->fragprog_inputs_read & VARYING_BIT_COL0)
1575             emit_passthrough(p, VERT_ATTRIB_COLOR0, VARYING_SLOT_COL0);
1576
1577          if (p->state->fragprog_inputs_read & VARYING_BIT_COL1)
1578             emit_passthrough(p, VERT_ATTRIB_COLOR1, VARYING_SLOT_COL1);
1579       }
1580    }
1581
1582    if (p->state->fragprog_inputs_read & VARYING_BIT_FOGC)
1583       build_fog(p);
1584
1585    if (p->state->fragprog_inputs_read & VARYING_BITS_TEX_ANY)
1586       build_texture_transform(p);
1587
1588    if (p->state->point_attenuated)
1589       build_atten_pointsize(p);
1590    else if (p->state->point_array)
1591       build_array_pointsize(p);
1592
1593    /* Finish up:
1594     */
1595    emit_op1(p, OPCODE_END, undef, 0, undef);
1596
1597    /* Disassemble:
1598     */
1599    if (DISASSEM) {
1600       printf ("\n");
1601    }
1602 }
1603
1604
1605 static void
1606 create_new_program( const struct state_key *key,
1607                     struct gl_vertex_program *program,
1608                     GLboolean mvp_with_dp4,
1609                     GLuint max_temps)
1610 {
1611    struct tnl_program p;
1612
1613    memset(&p, 0, sizeof(p));
1614    p.state = key;
1615    p.program = program;
1616    p.eye_position = undef;
1617    p.eye_position_z = undef;
1618    p.eye_position_normalized = undef;
1619    p.transformed_normal = undef;
1620    p.identity = undef;
1621    p.temp_in_use = 0;
1622    p.mvp_with_dp4 = mvp_with_dp4;
1623
1624    if (max_temps >= sizeof(int) * 8)
1625       p.temp_reserved = 0;
1626    else
1627       p.temp_reserved = ~((1<<max_temps)-1);
1628
1629    /* Start by allocating 32 instructions.
1630     * If we need more, we'll grow the instruction array as needed.
1631     */
1632    p.max_inst = 32;
1633    p.program->Base.Instructions = _mesa_alloc_instructions(p.max_inst);
1634    p.program->Base.String = NULL;
1635    p.program->Base.NumInstructions =
1636    p.program->Base.NumTemporaries =
1637    p.program->Base.NumParameters =
1638    p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0;
1639    p.program->Base.Parameters = _mesa_new_parameter_list();
1640    p.program->Base.InputsRead = 0;
1641    p.program->Base.OutputsWritten = 0;
1642
1643    build_tnl_program( &p );
1644 }
1645
1646
1647 /**
1648  * Return a vertex program which implements the current fixed-function
1649  * transform/lighting/texgen operations.
1650  */
1651 struct gl_vertex_program *
1652 _mesa_get_fixed_func_vertex_program(struct gl_context *ctx)
1653 {
1654    struct gl_vertex_program *prog;
1655    struct state_key key;
1656
1657    /* Grab all the relevant state and put it in a single structure:
1658     */
1659    make_state_key(ctx, &key);
1660
1661    /* Look for an already-prepared program for this state:
1662     */
1663    prog = gl_vertex_program(
1664       _mesa_search_program_cache(ctx->VertexProgram.Cache, &key, sizeof(key)));
1665
1666    if (!prog) {
1667       /* OK, we'll have to build a new one */
1668       if (0)
1669          printf("Build new TNL program\n");
1670
1671       prog = gl_vertex_program(ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0));
1672       if (!prog)
1673          return NULL;
1674
1675       create_new_program( &key, prog,
1676                           ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS,
1677                           ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps );
1678
1679       if (ctx->Driver.ProgramStringNotify)
1680          ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB,
1681                                           &prog->Base );
1682
1683       _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache,
1684                                  &key, sizeof(key), &prog->Base);
1685    }
1686
1687    return prog;
1688 }