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