~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/mesa/main/ffvertex_prog.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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