1c1f859d4Smrg/************************************************************************** 24a49301eSmrg * 3af69d88dSmrg * Copyright 2007 VMware, Inc. 4c1f859d4Smrg * All Rights Reserved. 54a49301eSmrg * 6c1f859d4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7c1f859d4Smrg * copy of this software and associated documentation files (the 8c1f859d4Smrg * "Software"), to deal in the Software without restriction, including 9c1f859d4Smrg * without limitation the rights to use, copy, modify, merge, publish, 10c1f859d4Smrg * distribute, sub license, and/or sell copies of the Software, and to 11c1f859d4Smrg * permit persons to whom the Software is furnished to do so, subject to 12c1f859d4Smrg * the following conditions: 134a49301eSmrg * 14c1f859d4Smrg * The above copyright notice and this permission notice (including the 15c1f859d4Smrg * next paragraph) shall be included in all copies or substantial portions 16c1f859d4Smrg * of the Software. 174a49301eSmrg * 18c1f859d4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19c1f859d4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20c1f859d4Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22c1f859d4Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23c1f859d4Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24c1f859d4Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 254a49301eSmrg * 26c1f859d4Smrg **************************************************************************/ 27c1f859d4Smrg 28c1f859d4Smrg/** 29c1f859d4Smrg * \file ffvertex_prog.c 30c1f859d4Smrg * 31c1f859d4Smrg * Create a vertex program to execute the current fixed function T&L pipeline. 32c1f859d4Smrg * \author Keith Whitwell 33c1f859d4Smrg */ 34c1f859d4Smrg 35c1f859d4Smrg 3601e04c3fSmrg#include "main/errors.h" 37c1f859d4Smrg#include "main/glheader.h" 38c1f859d4Smrg#include "main/mtypes.h" 39c1f859d4Smrg#include "main/macros.h" 40c1f859d4Smrg#include "main/enums.h" 41c1f859d4Smrg#include "main/ffvertex_prog.h" 423464ebd5Sriastradh#include "program/program.h" 433464ebd5Sriastradh#include "program/prog_cache.h" 443464ebd5Sriastradh#include "program/prog_instruction.h" 453464ebd5Sriastradh#include "program/prog_parameter.h" 463464ebd5Sriastradh#include "program/prog_print.h" 473464ebd5Sriastradh#include "program/prog_statevars.h" 4801e04c3fSmrg#include "util/bitscan.h" 49c1f859d4Smrg 50c1f859d4Smrg 514a49301eSmrg/** Max of number of lights and texture coord units */ 524a49301eSmrg#define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS) 534a49301eSmrg 54c1f859d4Smrgstruct state_key { 5501e04c3fSmrg GLbitfield varying_vp_inputs; 5601e04c3fSmrg 5701e04c3fSmrg unsigned fragprog_inputs_read:12; 5801e04c3fSmrg 594a49301eSmrg unsigned light_color_material_mask:12; 60c1f859d4Smrg unsigned light_global_enabled:1; 61c1f859d4Smrg unsigned light_local_viewer:1; 62c1f859d4Smrg unsigned light_twoside:1; 63c1f859d4Smrg unsigned material_shininess_is_zero:1; 64c1f859d4Smrg unsigned need_eye_coords:1; 65c1f859d4Smrg unsigned normalize:1; 66c1f859d4Smrg unsigned rescale_normals:1; 674a49301eSmrg 68af69d88dSmrg unsigned fog_distance_mode:2; 69c1f859d4Smrg unsigned separate_specular:1; 70c1f859d4Smrg unsigned point_attenuated:1; 714a49301eSmrg 72c1f859d4Smrg struct { 7301e04c3fSmrg unsigned char light_enabled:1; 7401e04c3fSmrg unsigned char light_eyepos3_is_zero:1; 7501e04c3fSmrg unsigned char light_spotcutoff_is_180:1; 7601e04c3fSmrg unsigned char light_attenuated:1; 7701e04c3fSmrg unsigned char texmat_enabled:1; 7801e04c3fSmrg unsigned char coord_replace:1; 7901e04c3fSmrg unsigned char texgen_enabled:1; 8001e04c3fSmrg unsigned char texgen_mode0:4; 8101e04c3fSmrg unsigned char texgen_mode1:4; 8201e04c3fSmrg unsigned char texgen_mode2:4; 8301e04c3fSmrg unsigned char texgen_mode3:4; 844a49301eSmrg } unit[NUM_UNITS]; 85c1f859d4Smrg}; 86c1f859d4Smrg 87c1f859d4Smrg 88c1f859d4Smrg#define TXG_NONE 0 89c1f859d4Smrg#define TXG_OBJ_LINEAR 1 90c1f859d4Smrg#define TXG_EYE_LINEAR 2 91c1f859d4Smrg#define TXG_SPHERE_MAP 3 92c1f859d4Smrg#define TXG_REFLECTION_MAP 4 93c1f859d4Smrg#define TXG_NORMAL_MAP 5 94c1f859d4Smrg 95c1f859d4Smrgstatic GLuint translate_texgen( GLboolean enabled, GLenum mode ) 96c1f859d4Smrg{ 97c1f859d4Smrg if (!enabled) 98c1f859d4Smrg return TXG_NONE; 99c1f859d4Smrg 100c1f859d4Smrg switch (mode) { 101c1f859d4Smrg case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR; 102c1f859d4Smrg case GL_EYE_LINEAR: return TXG_EYE_LINEAR; 103c1f859d4Smrg case GL_SPHERE_MAP: return TXG_SPHERE_MAP; 104c1f859d4Smrg case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP; 105c1f859d4Smrg case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP; 106c1f859d4Smrg default: return TXG_NONE; 107c1f859d4Smrg } 108c1f859d4Smrg} 109c1f859d4Smrg 110af69d88dSmrg#define FDM_EYE_RADIAL 0 111af69d88dSmrg#define FDM_EYE_PLANE 1 112af69d88dSmrg#define FDM_EYE_PLANE_ABS 2 11301e04c3fSmrg#define FDM_FROM_ARRAY 3 114c1f859d4Smrg 11501e04c3fSmrgstatic GLuint translate_fog_distance_mode(GLenum source, GLenum mode) 116af69d88dSmrg{ 11701e04c3fSmrg if (source == GL_FRAGMENT_DEPTH_EXT) { 11801e04c3fSmrg switch (mode) { 11901e04c3fSmrg case GL_EYE_RADIAL_NV: 12001e04c3fSmrg return FDM_EYE_RADIAL; 12101e04c3fSmrg case GL_EYE_PLANE: 12201e04c3fSmrg return FDM_EYE_PLANE; 12301e04c3fSmrg default: /* shouldn't happen; fall through to a sensible default */ 12401e04c3fSmrg case GL_EYE_PLANE_ABSOLUTE_NV: 12501e04c3fSmrg return FDM_EYE_PLANE_ABS; 12601e04c3fSmrg } 12701e04c3fSmrg } else { 12801e04c3fSmrg return FDM_FROM_ARRAY; 129af69d88dSmrg } 130af69d88dSmrg} 131c1f859d4Smrg 1323464ebd5Sriastradhstatic GLboolean check_active_shininess( struct gl_context *ctx, 133c1f859d4Smrg const struct state_key *key, 134c1f859d4Smrg GLuint side ) 135c1f859d4Smrg{ 136af69d88dSmrg GLuint attr = MAT_ATTRIB_FRONT_SHININESS + side; 137c1f859d4Smrg 1384a49301eSmrg if ((key->varying_vp_inputs & VERT_BIT_COLOR0) && 139af69d88dSmrg (key->light_color_material_mask & (1 << attr))) 140c1f859d4Smrg return GL_TRUE; 141c1f859d4Smrg 14201e04c3fSmrg if (key->varying_vp_inputs & VERT_BIT_MAT(attr)) 143c1f859d4Smrg return GL_TRUE; 144c1f859d4Smrg 145af69d88dSmrg if (ctx->Light.Material.Attrib[attr][0] != 0.0F) 146c1f859d4Smrg return GL_TRUE; 147c1f859d4Smrg 148c1f859d4Smrg return GL_FALSE; 149c1f859d4Smrg} 150c1f859d4Smrg 151c1f859d4Smrg 1523464ebd5Sriastradhstatic void make_state_key( struct gl_context *ctx, struct state_key *key ) 153c1f859d4Smrg{ 15401e04c3fSmrg const struct gl_program *fp = ctx->FragmentProgram._Current; 15501e04c3fSmrg GLbitfield mask; 156c1f859d4Smrg 157c1f859d4Smrg memset(key, 0, sizeof(struct state_key)); 158c1f859d4Smrg 159c1f859d4Smrg /* This now relies on texenvprogram.c being active: 160c1f859d4Smrg */ 161c1f859d4Smrg assert(fp); 162c1f859d4Smrg 163c1f859d4Smrg key->need_eye_coords = ctx->_NeedEyeCoords; 164c1f859d4Smrg 16501e04c3fSmrg key->fragprog_inputs_read = fp->info.inputs_read; 1667ec681f3Smrg key->varying_vp_inputs = ctx->VertexProgram._VaryingInputs; 167c1f859d4Smrg 168c1f859d4Smrg if (ctx->RenderMode == GL_FEEDBACK) { 169c1f859d4Smrg /* make sure the vertprog emits color and tex0 */ 170af69d88dSmrg key->fragprog_inputs_read |= (VARYING_BIT_COL0 | VARYING_BIT_TEX0); 171c1f859d4Smrg } 172c1f859d4Smrg 173c1f859d4Smrg if (ctx->Light.Enabled) { 174c1f859d4Smrg key->light_global_enabled = 1; 175c1f859d4Smrg 176c1f859d4Smrg if (ctx->Light.Model.LocalViewer) 177c1f859d4Smrg key->light_local_viewer = 1; 178c1f859d4Smrg 179c1f859d4Smrg if (ctx->Light.Model.TwoSide) 180c1f859d4Smrg key->light_twoside = 1; 181c1f859d4Smrg 18201e04c3fSmrg if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) 18301e04c3fSmrg key->separate_specular = 1; 18401e04c3fSmrg 185c1f859d4Smrg if (ctx->Light.ColorMaterialEnabled) { 186af69d88dSmrg key->light_color_material_mask = ctx->Light._ColorMaterialBitmask; 187c1f859d4Smrg } 188c1f859d4Smrg 18901e04c3fSmrg mask = ctx->Light._EnabledLights; 19001e04c3fSmrg while (mask) { 19101e04c3fSmrg const int i = u_bit_scan(&mask); 1927ec681f3Smrg struct gl_light_uniforms *lu = &ctx->Light.LightSource[i]; 193c1f859d4Smrg 19401e04c3fSmrg key->unit[i].light_enabled = 1; 195c1f859d4Smrg 1967ec681f3Smrg if (lu->EyePosition[3] == 0.0F) 19701e04c3fSmrg key->unit[i].light_eyepos3_is_zero = 1; 1984a49301eSmrg 1997ec681f3Smrg if (lu->SpotCutoff == 180.0F) 20001e04c3fSmrg key->unit[i].light_spotcutoff_is_180 = 1; 201c1f859d4Smrg 2027ec681f3Smrg if (lu->ConstantAttenuation != 1.0F || 2037ec681f3Smrg lu->LinearAttenuation != 0.0F || 2047ec681f3Smrg lu->QuadraticAttenuation != 0.0F) 20501e04c3fSmrg key->unit[i].light_attenuated = 1; 206c1f859d4Smrg } 207c1f859d4Smrg 208c1f859d4Smrg if (check_active_shininess(ctx, key, 0)) { 209c1f859d4Smrg key->material_shininess_is_zero = 0; 210c1f859d4Smrg } 211c1f859d4Smrg else if (key->light_twoside && 212c1f859d4Smrg check_active_shininess(ctx, key, 1)) { 213c1f859d4Smrg key->material_shininess_is_zero = 0; 214c1f859d4Smrg } 215c1f859d4Smrg else { 216c1f859d4Smrg key->material_shininess_is_zero = 1; 217c1f859d4Smrg } 218c1f859d4Smrg } 219c1f859d4Smrg 220c1f859d4Smrg if (ctx->Transform.Normalize) 221c1f859d4Smrg key->normalize = 1; 222c1f859d4Smrg 223c1f859d4Smrg if (ctx->Transform.RescaleNormals) 224c1f859d4Smrg key->rescale_normals = 1; 225c1f859d4Smrg 22601e04c3fSmrg /* Only distinguish fog parameters if we actually need */ 22701e04c3fSmrg if (key->fragprog_inputs_read & VARYING_BIT_FOGC) 22801e04c3fSmrg key->fog_distance_mode = 22901e04c3fSmrg translate_fog_distance_mode(ctx->Fog.FogCoordinateSource, 23001e04c3fSmrg ctx->Fog.FogDistanceMode); 231c1f859d4Smrg 232c1f859d4Smrg if (ctx->Point._Attenuated) 233c1f859d4Smrg key->point_attenuated = 1; 234c1f859d4Smrg 23501e04c3fSmrg mask = ctx->Texture._EnabledCoordUnits | ctx->Texture._TexGenEnabled 23601e04c3fSmrg | ctx->Texture._TexMatEnabled | ctx->Point.CoordReplace; 23701e04c3fSmrg while (mask) { 23801e04c3fSmrg const int i = u_bit_scan(&mask); 23901e04c3fSmrg struct gl_fixedfunc_texture_unit *texUnit = 24001e04c3fSmrg &ctx->Texture.FixedFuncUnit[i]; 241c1f859d4Smrg 2423464ebd5Sriastradh if (ctx->Point.PointSprite) 24301e04c3fSmrg if (ctx->Point.CoordReplace & (1u << i)) 2443464ebd5Sriastradh key->unit[i].coord_replace = 1; 2453464ebd5Sriastradh 2464a49301eSmrg if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) 247c1f859d4Smrg key->unit[i].texmat_enabled = 1; 2484a49301eSmrg 249c1f859d4Smrg if (texUnit->TexGenEnabled) { 250c1f859d4Smrg key->unit[i].texgen_enabled = 1; 2514a49301eSmrg 2524a49301eSmrg key->unit[i].texgen_mode0 = 253c1f859d4Smrg translate_texgen( texUnit->TexGenEnabled & (1<<0), 2544a49301eSmrg texUnit->GenS.Mode ); 2554a49301eSmrg key->unit[i].texgen_mode1 = 256c1f859d4Smrg translate_texgen( texUnit->TexGenEnabled & (1<<1), 2574a49301eSmrg texUnit->GenT.Mode ); 2584a49301eSmrg key->unit[i].texgen_mode2 = 259c1f859d4Smrg translate_texgen( texUnit->TexGenEnabled & (1<<2), 2604a49301eSmrg texUnit->GenR.Mode ); 2614a49301eSmrg key->unit[i].texgen_mode3 = 262c1f859d4Smrg translate_texgen( texUnit->TexGenEnabled & (1<<3), 2634a49301eSmrg texUnit->GenQ.Mode ); 264c1f859d4Smrg } 265c1f859d4Smrg } 266c1f859d4Smrg} 267c1f859d4Smrg 268c1f859d4Smrg 2694a49301eSmrg 270c1f859d4Smrg/* Very useful debugging tool - produces annotated listing of 271c1f859d4Smrg * generated program with line/function references for each 272c1f859d4Smrg * instruction back into this file: 273c1f859d4Smrg */ 274c1f859d4Smrg#define DISASSEM 0 275c1f859d4Smrg 276c1f859d4Smrg 277c1f859d4Smrg/* Use uregs to represent registers internally, translate to Mesa's 2784a49301eSmrg * expected formats on emit. 279c1f859d4Smrg * 280c1f859d4Smrg * NOTE: These are passed by value extensively in this file rather 281c1f859d4Smrg * than as usual by pointer reference. If this disturbs you, try 282c1f859d4Smrg * remembering they are just 32bits in size. 283c1f859d4Smrg * 284c1f859d4Smrg * GCC is smart enough to deal with these dword-sized structures in 285c1f859d4Smrg * much the same way as if I had defined them as dwords and was using 286c1f859d4Smrg * macros to access and set the fields. This is much nicer and easier 287c1f859d4Smrg * to evolve. 288c1f859d4Smrg */ 289c1f859d4Smrgstruct ureg { 290c1f859d4Smrg GLuint file:4; 291c1f859d4Smrg GLint idx:9; /* relative addressing may be negative */ 292c1f859d4Smrg /* sizeof(idx) should == sizeof(prog_src_reg::Index) */ 293c1f859d4Smrg GLuint negate:1; 294c1f859d4Smrg GLuint swz:12; 295c1f859d4Smrg GLuint pad:6; 296c1f859d4Smrg}; 297c1f859d4Smrg 298c1f859d4Smrg 299c1f859d4Smrgstruct tnl_program { 300c1f859d4Smrg const struct state_key *state; 30101e04c3fSmrg struct gl_program *program; 3027ec681f3Smrg struct gl_program_parameter_list *state_params; 30301e04c3fSmrg GLuint max_inst; /** number of instructions allocated for program */ 3044a49301eSmrg GLboolean mvp_with_dp4; 3054a49301eSmrg 306c1f859d4Smrg GLuint temp_in_use; 307c1f859d4Smrg GLuint temp_reserved; 3084a49301eSmrg 309c1f859d4Smrg struct ureg eye_position; 310c1f859d4Smrg struct ureg eye_position_z; 311c1f859d4Smrg struct ureg eye_position_normalized; 312c1f859d4Smrg struct ureg transformed_normal; 313c1f859d4Smrg struct ureg identity; 314c1f859d4Smrg 315c1f859d4Smrg GLuint materials; 316c1f859d4Smrg GLuint color_materials; 317c1f859d4Smrg}; 318c1f859d4Smrg 319c1f859d4Smrg 3204a49301eSmrgstatic const struct ureg undef = { 321c1f859d4Smrg PROGRAM_UNDEFINED, 322c1f859d4Smrg 0, 323c1f859d4Smrg 0, 324c1f859d4Smrg 0, 325c1f859d4Smrg 0 326c1f859d4Smrg}; 327c1f859d4Smrg 328c1f859d4Smrg/* Local shorthand: 329c1f859d4Smrg */ 330c1f859d4Smrg#define X SWIZZLE_X 331c1f859d4Smrg#define Y SWIZZLE_Y 332c1f859d4Smrg#define Z SWIZZLE_Z 333c1f859d4Smrg#define W SWIZZLE_W 334c1f859d4Smrg 335c1f859d4Smrg 336c1f859d4Smrg/* Construct a ureg: 337c1f859d4Smrg */ 338c1f859d4Smrgstatic struct ureg make_ureg(GLuint file, GLint idx) 339c1f859d4Smrg{ 340c1f859d4Smrg struct ureg reg; 341c1f859d4Smrg reg.file = file; 342c1f859d4Smrg reg.idx = idx; 343c1f859d4Smrg reg.negate = 0; 344c1f859d4Smrg reg.swz = SWIZZLE_NOOP; 345c1f859d4Smrg reg.pad = 0; 346c1f859d4Smrg return reg; 347c1f859d4Smrg} 348c1f859d4Smrg 349c1f859d4Smrg 350c1f859d4Smrgstatic struct ureg negate( struct ureg reg ) 351c1f859d4Smrg{ 352c1f859d4Smrg reg.negate ^= 1; 353c1f859d4Smrg return reg; 3544a49301eSmrg} 355c1f859d4Smrg 356c1f859d4Smrg 357c1f859d4Smrgstatic struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) 358c1f859d4Smrg{ 359c1f859d4Smrg reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), 360c1f859d4Smrg GET_SWZ(reg.swz, y), 361c1f859d4Smrg GET_SWZ(reg.swz, z), 362c1f859d4Smrg GET_SWZ(reg.swz, w)); 363c1f859d4Smrg return reg; 364c1f859d4Smrg} 365c1f859d4Smrg 366c1f859d4Smrg 367c1f859d4Smrgstatic struct ureg swizzle1( struct ureg reg, int x ) 368c1f859d4Smrg{ 369c1f859d4Smrg return swizzle(reg, x, x, x, x); 370c1f859d4Smrg} 371c1f859d4Smrg 372c1f859d4Smrg 373c1f859d4Smrgstatic struct ureg get_temp( struct tnl_program *p ) 374c1f859d4Smrg{ 375af69d88dSmrg int bit = ffs( ~p->temp_in_use ); 376c1f859d4Smrg if (!bit) { 377c1f859d4Smrg _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); 378cdc920a0Smrg exit(1); 379c1f859d4Smrg } 380c1f859d4Smrg 38101e04c3fSmrg if ((GLuint) bit > p->program->arb.NumTemporaries) 38201e04c3fSmrg p->program->arb.NumTemporaries = bit; 383c1f859d4Smrg 384c1f859d4Smrg p->temp_in_use |= 1<<(bit-1); 385c1f859d4Smrg return make_ureg(PROGRAM_TEMPORARY, bit-1); 386c1f859d4Smrg} 387c1f859d4Smrg 388c1f859d4Smrg 389c1f859d4Smrgstatic struct ureg reserve_temp( struct tnl_program *p ) 390c1f859d4Smrg{ 391c1f859d4Smrg struct ureg temp = get_temp( p ); 392c1f859d4Smrg p->temp_reserved |= 1<<temp.idx; 393c1f859d4Smrg return temp; 394c1f859d4Smrg} 395c1f859d4Smrg 396c1f859d4Smrg 397c1f859d4Smrgstatic void release_temp( struct tnl_program *p, struct ureg reg ) 398c1f859d4Smrg{ 399c1f859d4Smrg if (reg.file == PROGRAM_TEMPORARY) { 400c1f859d4Smrg p->temp_in_use &= ~(1<<reg.idx); 401c1f859d4Smrg p->temp_in_use |= p->temp_reserved; /* can't release reserved temps */ 402c1f859d4Smrg } 403c1f859d4Smrg} 404c1f859d4Smrg 405c1f859d4Smrgstatic void release_temps( struct tnl_program *p ) 406c1f859d4Smrg{ 407c1f859d4Smrg p->temp_in_use = p->temp_reserved; 408c1f859d4Smrg} 409c1f859d4Smrg 410c1f859d4Smrg 4117ec681f3Smrgstatic struct ureg register_param4(struct tnl_program *p, 4124a49301eSmrg GLint s0, 4134a49301eSmrg GLint s1, 4144a49301eSmrg GLint s2, 4157ec681f3Smrg GLint s3) 4164a49301eSmrg{ 41701e04c3fSmrg gl_state_index16 tokens[STATE_LENGTH]; 4184a49301eSmrg GLint idx; 4194a49301eSmrg tokens[0] = s0; 4204a49301eSmrg tokens[1] = s1; 4214a49301eSmrg tokens[2] = s2; 4224a49301eSmrg tokens[3] = s3; 4237ec681f3Smrg idx = _mesa_add_state_reference(p->state_params, tokens); 4244a49301eSmrg return make_ureg(PROGRAM_STATE_VAR, idx); 4254a49301eSmrg} 4264a49301eSmrg 4274a49301eSmrg 4287ec681f3Smrg#define register_param1(p,s0) register_param4(p,s0,0,0,0) 4297ec681f3Smrg#define register_param2(p,s0,s1) register_param4(p,s0,s1,0,0) 4307ec681f3Smrg#define register_param3(p,s0,s1,s2) register_param4(p,s0,s1,s2,0) 4314a49301eSmrg 4324a49301eSmrg 4334a49301eSmrg 434c1f859d4Smrg/** 435c1f859d4Smrg * \param input one of VERT_ATTRIB_x tokens. 436c1f859d4Smrg */ 437c1f859d4Smrgstatic struct ureg register_input( struct tnl_program *p, GLuint input ) 438c1f859d4Smrg{ 439af69d88dSmrg assert(input < VERT_ATTRIB_MAX); 4404a49301eSmrg 441af69d88dSmrg if (p->state->varying_vp_inputs & VERT_BIT(input)) { 4427ec681f3Smrg p->program->info.inputs_read |= (uint64_t)VERT_BIT(input); 4434a49301eSmrg return make_ureg(PROGRAM_INPUT, input); 4444a49301eSmrg } 4454a49301eSmrg else { 4467ec681f3Smrg return register_param2(p, STATE_CURRENT_ATTRIB, input); 4474a49301eSmrg } 448c1f859d4Smrg} 449c1f859d4Smrg 450c1f859d4Smrg 451c1f859d4Smrg/** 452af69d88dSmrg * \param input one of VARYING_SLOT_x tokens. 453c1f859d4Smrg */ 454c1f859d4Smrgstatic struct ureg register_output( struct tnl_program *p, GLuint output ) 455c1f859d4Smrg{ 45601e04c3fSmrg p->program->info.outputs_written |= BITFIELD64_BIT(output); 457c1f859d4Smrg return make_ureg(PROGRAM_OUTPUT, output); 458c1f859d4Smrg} 459c1f859d4Smrg 460c1f859d4Smrg 4614a49301eSmrgstatic struct ureg register_const4f( struct tnl_program *p, 462c1f859d4Smrg GLfloat s0, 463c1f859d4Smrg GLfloat s1, 464c1f859d4Smrg GLfloat s2, 465c1f859d4Smrg GLfloat s3) 466c1f859d4Smrg{ 467af69d88dSmrg gl_constant_value values[4]; 468c1f859d4Smrg GLint idx; 469c1f859d4Smrg GLuint swizzle; 470af69d88dSmrg values[0].f = s0; 471af69d88dSmrg values[1].f = s1; 472af69d88dSmrg values[2].f = s2; 473af69d88dSmrg values[3].f = s3; 47401e04c3fSmrg idx = _mesa_add_unnamed_constant(p->program->Parameters, values, 4, 47501e04c3fSmrg &swizzle ); 47601e04c3fSmrg assert(swizzle == SWIZZLE_NOOP); 477c1f859d4Smrg return make_ureg(PROGRAM_CONSTANT, idx); 478c1f859d4Smrg} 479c1f859d4Smrg 480c1f859d4Smrg#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) 481c1f859d4Smrg#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) 482c1f859d4Smrg#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) 483c1f859d4Smrg#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) 484c1f859d4Smrg 485c1f859d4Smrgstatic GLboolean is_undef( struct ureg reg ) 486c1f859d4Smrg{ 487c1f859d4Smrg return reg.file == PROGRAM_UNDEFINED; 488c1f859d4Smrg} 489c1f859d4Smrg 490c1f859d4Smrg 491c1f859d4Smrgstatic struct ureg get_identity_param( struct tnl_program *p ) 492c1f859d4Smrg{ 4934a49301eSmrg if (is_undef(p->identity)) 494c1f859d4Smrg p->identity = register_const4f(p, 0,0,0,1); 495c1f859d4Smrg 496c1f859d4Smrg return p->identity; 497c1f859d4Smrg} 498c1f859d4Smrg 499c1f859d4Smrgstatic void register_matrix_param5( struct tnl_program *p, 500c1f859d4Smrg GLint s0, /* modelview, projection, etc */ 501c1f859d4Smrg GLint s1, /* texture matrix number */ 502c1f859d4Smrg GLint s2, /* first row */ 503c1f859d4Smrg GLint s3, /* last row */ 504c1f859d4Smrg struct ureg *matrix ) 505c1f859d4Smrg{ 506c1f859d4Smrg GLint i; 507c1f859d4Smrg 508c1f859d4Smrg /* This is a bit sad as the support is there to pull the whole 509c1f859d4Smrg * matrix out in one go: 510c1f859d4Smrg */ 5114a49301eSmrg for (i = 0; i <= s3 - s2; i++) 5127ec681f3Smrg matrix[i] = register_param4(p, s0, s1, i, i); 513c1f859d4Smrg} 514c1f859d4Smrg 515c1f859d4Smrg 516c1f859d4Smrgstatic void emit_arg( struct prog_src_register *src, 517c1f859d4Smrg struct ureg reg ) 518c1f859d4Smrg{ 519c1f859d4Smrg src->File = reg.file; 520c1f859d4Smrg src->Index = reg.idx; 521c1f859d4Smrg src->Swizzle = reg.swz; 5224a49301eSmrg src->Negate = reg.negate ? NEGATE_XYZW : NEGATE_NONE; 523c1f859d4Smrg src->RelAddr = 0; 524c1f859d4Smrg /* Check that bitfield sizes aren't exceeded */ 52501e04c3fSmrg assert(src->Index == reg.idx); 526c1f859d4Smrg} 527c1f859d4Smrg 528c1f859d4Smrg 529c1f859d4Smrgstatic void emit_dst( struct prog_dst_register *dst, 530c1f859d4Smrg struct ureg reg, GLuint mask ) 531c1f859d4Smrg{ 532c1f859d4Smrg dst->File = reg.file; 533c1f859d4Smrg dst->Index = reg.idx; 534c1f859d4Smrg /* allow zero as a shorthand for xyzw */ 5354a49301eSmrg dst->WriteMask = mask ? mask : WRITEMASK_XYZW; 536c1f859d4Smrg /* Check that bitfield sizes aren't exceeded */ 53701e04c3fSmrg assert(dst->Index == reg.idx); 538c1f859d4Smrg} 539c1f859d4Smrg 540c1f859d4Smrg 541c1f859d4Smrgstatic void debug_insn( struct prog_instruction *inst, const char *fn, 542c1f859d4Smrg GLuint line ) 543c1f859d4Smrg{ 544c1f859d4Smrg if (DISASSEM) { 545c1f859d4Smrg static const char *last_fn; 5464a49301eSmrg 547c1f859d4Smrg if (fn != last_fn) { 548c1f859d4Smrg last_fn = fn; 549cdc920a0Smrg printf("%s:\n", fn); 550c1f859d4Smrg } 5514a49301eSmrg 552cdc920a0Smrg printf("%d:\t", line); 553c1f859d4Smrg _mesa_print_instruction(inst); 554c1f859d4Smrg } 555c1f859d4Smrg} 556c1f859d4Smrg 557c1f859d4Smrg 558c1f859d4Smrgstatic void emit_op3fn(struct tnl_program *p, 559c1f859d4Smrg enum prog_opcode op, 560c1f859d4Smrg struct ureg dest, 561c1f859d4Smrg GLuint mask, 562c1f859d4Smrg struct ureg src0, 563c1f859d4Smrg struct ureg src1, 564c1f859d4Smrg struct ureg src2, 565c1f859d4Smrg const char *fn, 566c1f859d4Smrg GLuint line) 567c1f859d4Smrg{ 568c1f859d4Smrg GLuint nr; 569c1f859d4Smrg struct prog_instruction *inst; 5704a49301eSmrg 57101e04c3fSmrg assert(p->program->arb.NumInstructions <= p->max_inst); 572c1f859d4Smrg 57301e04c3fSmrg if (p->program->arb.NumInstructions == p->max_inst) { 574c1f859d4Smrg /* need to extend the program's instruction array */ 575c1f859d4Smrg struct prog_instruction *newInst; 576c1f859d4Smrg 577c1f859d4Smrg /* double the size */ 578c1f859d4Smrg p->max_inst *= 2; 579c1f859d4Smrg 58001e04c3fSmrg newInst = 58101e04c3fSmrg rzalloc_array(p->program, struct prog_instruction, p->max_inst); 582c1f859d4Smrg if (!newInst) { 583c1f859d4Smrg _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build"); 584c1f859d4Smrg return; 585c1f859d4Smrg } 586c1f859d4Smrg 58701e04c3fSmrg _mesa_copy_instructions(newInst, p->program->arb.Instructions, 58801e04c3fSmrg p->program->arb.NumInstructions); 589c1f859d4Smrg 59001e04c3fSmrg ralloc_free(p->program->arb.Instructions); 591c1f859d4Smrg 59201e04c3fSmrg p->program->arb.Instructions = newInst; 593c1f859d4Smrg } 5944a49301eSmrg 59501e04c3fSmrg nr = p->program->arb.NumInstructions++; 596c1f859d4Smrg 59701e04c3fSmrg inst = &p->program->arb.Instructions[nr]; 5984a49301eSmrg inst->Opcode = (enum prog_opcode) op; 5994a49301eSmrg 600c1f859d4Smrg emit_arg( &inst->SrcReg[0], src0 ); 601c1f859d4Smrg emit_arg( &inst->SrcReg[1], src1 ); 6024a49301eSmrg emit_arg( &inst->SrcReg[2], src2 ); 603c1f859d4Smrg 604c1f859d4Smrg emit_dst( &inst->DstReg, dest, mask ); 605c1f859d4Smrg 606c1f859d4Smrg debug_insn(inst, fn, line); 607c1f859d4Smrg} 608c1f859d4Smrg 609c1f859d4Smrg 610c1f859d4Smrg#define emit_op3(p, op, dst, mask, src0, src1, src2) \ 61101e04c3fSmrg emit_op3fn(p, op, dst, mask, src0, src1, src2, __func__, __LINE__) 612c1f859d4Smrg 613c1f859d4Smrg#define emit_op2(p, op, dst, mask, src0, src1) \ 61401e04c3fSmrg emit_op3fn(p, op, dst, mask, src0, src1, undef, __func__, __LINE__) 615c1f859d4Smrg 616c1f859d4Smrg#define emit_op1(p, op, dst, mask, src0) \ 61701e04c3fSmrg emit_op3fn(p, op, dst, mask, src0, undef, undef, __func__, __LINE__) 618c1f859d4Smrg 619c1f859d4Smrg 620c1f859d4Smrgstatic struct ureg make_temp( struct tnl_program *p, struct ureg reg ) 621c1f859d4Smrg{ 6224a49301eSmrg if (reg.file == PROGRAM_TEMPORARY && 623c1f859d4Smrg !(p->temp_reserved & (1<<reg.idx))) 624c1f859d4Smrg return reg; 625c1f859d4Smrg else { 626c1f859d4Smrg struct ureg temp = get_temp(p); 627c1f859d4Smrg emit_op1(p, OPCODE_MOV, temp, 0, reg); 628c1f859d4Smrg return temp; 629c1f859d4Smrg } 630c1f859d4Smrg} 631c1f859d4Smrg 632c1f859d4Smrg 633c1f859d4Smrg/* Currently no tracking performed of input/output/register size or 634c1f859d4Smrg * active elements. Could be used to reduce these operations, as 635c1f859d4Smrg * could the matrix type. 636c1f859d4Smrg */ 637c1f859d4Smrgstatic void emit_matrix_transform_vec4( struct tnl_program *p, 638c1f859d4Smrg struct ureg dest, 639c1f859d4Smrg const struct ureg *mat, 640c1f859d4Smrg struct ureg src) 641c1f859d4Smrg{ 642c1f859d4Smrg emit_op2(p, OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]); 643c1f859d4Smrg emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]); 644c1f859d4Smrg emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]); 645c1f859d4Smrg emit_op2(p, OPCODE_DP4, dest, WRITEMASK_W, src, mat[3]); 646c1f859d4Smrg} 647c1f859d4Smrg 648c1f859d4Smrg 649c1f859d4Smrg/* This version is much easier to implement if writemasks are not 650c1f859d4Smrg * supported natively on the target or (like SSE), the target doesn't 651c1f859d4Smrg * have a clean/obvious dotproduct implementation. 652c1f859d4Smrg */ 653c1f859d4Smrgstatic void emit_transpose_matrix_transform_vec4( struct tnl_program *p, 654c1f859d4Smrg struct ureg dest, 655c1f859d4Smrg const struct ureg *mat, 656c1f859d4Smrg struct ureg src) 657c1f859d4Smrg{ 658c1f859d4Smrg struct ureg tmp; 659c1f859d4Smrg 660c1f859d4Smrg if (dest.file != PROGRAM_TEMPORARY) 661c1f859d4Smrg tmp = get_temp(p); 662c1f859d4Smrg else 663c1f859d4Smrg tmp = dest; 664c1f859d4Smrg 665c1f859d4Smrg emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 666c1f859d4Smrg emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 667c1f859d4Smrg emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 668c1f859d4Smrg emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 669c1f859d4Smrg 670c1f859d4Smrg if (dest.file != PROGRAM_TEMPORARY) 671c1f859d4Smrg release_temp(p, tmp); 672c1f859d4Smrg} 673c1f859d4Smrg 674c1f859d4Smrg 675c1f859d4Smrgstatic void emit_matrix_transform_vec3( struct tnl_program *p, 676c1f859d4Smrg struct ureg dest, 677c1f859d4Smrg const struct ureg *mat, 678c1f859d4Smrg struct ureg src) 679c1f859d4Smrg{ 680c1f859d4Smrg emit_op2(p, OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]); 681c1f859d4Smrg emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]); 682c1f859d4Smrg emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Z, src, mat[2]); 683c1f859d4Smrg} 684c1f859d4Smrg 685c1f859d4Smrg 686c1f859d4Smrgstatic void emit_normalize_vec3( struct tnl_program *p, 687c1f859d4Smrg struct ureg dest, 688c1f859d4Smrg struct ureg src ) 689c1f859d4Smrg{ 690c1f859d4Smrg struct ureg tmp = get_temp(p); 691c1f859d4Smrg emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, src, src); 692c1f859d4Smrg emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp); 693c1f859d4Smrg emit_op2(p, OPCODE_MUL, dest, 0, src, swizzle1(tmp, X)); 694c1f859d4Smrg release_temp(p, tmp); 695c1f859d4Smrg} 696c1f859d4Smrg 697c1f859d4Smrg 6984a49301eSmrgstatic void emit_passthrough( struct tnl_program *p, 699c1f859d4Smrg GLuint input, 700c1f859d4Smrg GLuint output ) 701c1f859d4Smrg{ 702c1f859d4Smrg struct ureg out = register_output(p, output); 7034a49301eSmrg emit_op1(p, OPCODE_MOV, out, 0, register_input(p, input)); 704c1f859d4Smrg} 705c1f859d4Smrg 706c1f859d4Smrg 707c1f859d4Smrgstatic struct ureg get_eye_position( struct tnl_program *p ) 708c1f859d4Smrg{ 709c1f859d4Smrg if (is_undef(p->eye_position)) { 7104a49301eSmrg struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 711c1f859d4Smrg struct ureg modelview[4]; 712c1f859d4Smrg 713c1f859d4Smrg p->eye_position = reserve_temp(p); 714c1f859d4Smrg 7154a49301eSmrg if (p->mvp_with_dp4) { 716c1f859d4Smrg register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 7177ec681f3Smrg modelview ); 718c1f859d4Smrg 719c1f859d4Smrg emit_matrix_transform_vec4(p, p->eye_position, modelview, pos); 720c1f859d4Smrg } 721c1f859d4Smrg else { 7227ec681f3Smrg register_matrix_param5( p, STATE_MODELVIEW_MATRIX_TRANSPOSE, 0, 0, 3, 7237ec681f3Smrg modelview ); 724c1f859d4Smrg 725c1f859d4Smrg emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos); 726c1f859d4Smrg } 727c1f859d4Smrg } 7284a49301eSmrg 729c1f859d4Smrg return p->eye_position; 730c1f859d4Smrg} 731c1f859d4Smrg 732c1f859d4Smrg 733c1f859d4Smrgstatic struct ureg get_eye_position_z( struct tnl_program *p ) 734c1f859d4Smrg{ 7354a49301eSmrg if (!is_undef(p->eye_position)) 736c1f859d4Smrg return swizzle1(p->eye_position, Z); 737c1f859d4Smrg 738c1f859d4Smrg if (is_undef(p->eye_position_z)) { 7394a49301eSmrg struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 740c1f859d4Smrg struct ureg modelview[4]; 741c1f859d4Smrg 742c1f859d4Smrg p->eye_position_z = reserve_temp(p); 743c1f859d4Smrg 744c1f859d4Smrg register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 7457ec681f3Smrg modelview ); 746c1f859d4Smrg 747c1f859d4Smrg emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]); 748c1f859d4Smrg } 7494a49301eSmrg 750c1f859d4Smrg return p->eye_position_z; 751c1f859d4Smrg} 7524a49301eSmrg 753c1f859d4Smrg 754c1f859d4Smrgstatic struct ureg get_eye_position_normalized( struct tnl_program *p ) 755c1f859d4Smrg{ 756c1f859d4Smrg if (is_undef(p->eye_position_normalized)) { 757c1f859d4Smrg struct ureg eye = get_eye_position(p); 758c1f859d4Smrg p->eye_position_normalized = reserve_temp(p); 759c1f859d4Smrg emit_normalize_vec3(p, p->eye_position_normalized, eye); 760c1f859d4Smrg } 7614a49301eSmrg 762c1f859d4Smrg return p->eye_position_normalized; 763c1f859d4Smrg} 764c1f859d4Smrg 765c1f859d4Smrg 766c1f859d4Smrgstatic struct ureg get_transformed_normal( struct tnl_program *p ) 767c1f859d4Smrg{ 768c1f859d4Smrg if (is_undef(p->transformed_normal) && 769c1f859d4Smrg !p->state->need_eye_coords && 770c1f859d4Smrg !p->state->normalize && 771c1f859d4Smrg !(p->state->need_eye_coords == p->state->rescale_normals)) 772c1f859d4Smrg { 773c1f859d4Smrg p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL ); 774c1f859d4Smrg } 7754a49301eSmrg else if (is_undef(p->transformed_normal)) 776c1f859d4Smrg { 777c1f859d4Smrg struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL ); 778c1f859d4Smrg struct ureg mvinv[3]; 779c1f859d4Smrg struct ureg transformed_normal = reserve_temp(p); 780c1f859d4Smrg 781c1f859d4Smrg if (p->state->need_eye_coords) { 7827ec681f3Smrg register_matrix_param5( p, STATE_MODELVIEW_MATRIX_INVTRANS, 0, 0, 2, 7837ec681f3Smrg mvinv ); 784c1f859d4Smrg 785c1f859d4Smrg /* Transform to eye space: 786c1f859d4Smrg */ 787c1f859d4Smrg emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal ); 788c1f859d4Smrg normal = transformed_normal; 789c1f859d4Smrg } 790c1f859d4Smrg 791c1f859d4Smrg /* Normalize/Rescale: 792c1f859d4Smrg */ 793c1f859d4Smrg if (p->state->normalize) { 794c1f859d4Smrg emit_normalize_vec3( p, transformed_normal, normal ); 795c1f859d4Smrg normal = transformed_normal; 796c1f859d4Smrg } 797c1f859d4Smrg else if (p->state->need_eye_coords == p->state->rescale_normals) { 798c1f859d4Smrg /* This is already adjusted for eye/non-eye rendering: 799c1f859d4Smrg */ 8007ec681f3Smrg struct ureg rescale = register_param1(p, STATE_NORMAL_SCALE); 801c1f859d4Smrg 802c1f859d4Smrg emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale ); 803c1f859d4Smrg normal = transformed_normal; 804c1f859d4Smrg } 8054a49301eSmrg 806c1f859d4Smrg assert(normal.file == PROGRAM_TEMPORARY); 807c1f859d4Smrg p->transformed_normal = normal; 808c1f859d4Smrg } 809c1f859d4Smrg 810c1f859d4Smrg return p->transformed_normal; 811c1f859d4Smrg} 812c1f859d4Smrg 813c1f859d4Smrg 814c1f859d4Smrgstatic void build_hpos( struct tnl_program *p ) 815c1f859d4Smrg{ 8164a49301eSmrg struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 817af69d88dSmrg struct ureg hpos = register_output( p, VARYING_SLOT_POS ); 818c1f859d4Smrg struct ureg mvp[4]; 819c1f859d4Smrg 8204a49301eSmrg if (p->mvp_with_dp4) { 8214a49301eSmrg register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, 8227ec681f3Smrg mvp ); 823c1f859d4Smrg emit_matrix_transform_vec4( p, hpos, mvp, pos ); 824c1f859d4Smrg } 825c1f859d4Smrg else { 8267ec681f3Smrg register_matrix_param5( p, STATE_MVP_MATRIX_TRANSPOSE, 0, 0, 3, 8277ec681f3Smrg mvp ); 828c1f859d4Smrg emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos ); 829c1f859d4Smrg } 830c1f859d4Smrg} 831c1f859d4Smrg 832c1f859d4Smrg 833c1f859d4Smrgstatic GLuint material_attrib( GLuint side, GLuint property ) 834c1f859d4Smrg{ 8357ec681f3Smrg switch (property) { 8367ec681f3Smrg case STATE_AMBIENT: 8377ec681f3Smrg return MAT_ATTRIB_FRONT_AMBIENT + side; 8387ec681f3Smrg case STATE_DIFFUSE: 8397ec681f3Smrg return MAT_ATTRIB_FRONT_DIFFUSE + side; 8407ec681f3Smrg case STATE_SPECULAR: 8417ec681f3Smrg return MAT_ATTRIB_FRONT_SPECULAR + side; 8427ec681f3Smrg case STATE_EMISSION: 8437ec681f3Smrg return MAT_ATTRIB_FRONT_EMISSION + side; 8447ec681f3Smrg case STATE_SHININESS: 8457ec681f3Smrg return MAT_ATTRIB_FRONT_SHININESS + side; 8467ec681f3Smrg default: 8477ec681f3Smrg unreachable("invalid value"); 8487ec681f3Smrg } 849c1f859d4Smrg} 850c1f859d4Smrg 851c1f859d4Smrg 852c1f859d4Smrg/** 853c1f859d4Smrg * Get a bitmask of which material values vary on a per-vertex basis. 854c1f859d4Smrg */ 855c1f859d4Smrgstatic void set_material_flags( struct tnl_program *p ) 856c1f859d4Smrg{ 857c1f859d4Smrg p->color_materials = 0; 858c1f859d4Smrg p->materials = 0; 859c1f859d4Smrg 8604a49301eSmrg if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) { 8614a49301eSmrg p->materials = 862c1f859d4Smrg p->color_materials = p->state->light_color_material_mask; 863c1f859d4Smrg } 864c1f859d4Smrg 86501e04c3fSmrg p->materials |= ((p->state->varying_vp_inputs & VERT_BIT_MAT_ALL) 86601e04c3fSmrg >> VERT_ATTRIB_MAT(0)); 867c1f859d4Smrg} 868c1f859d4Smrg 869c1f859d4Smrg 8704a49301eSmrgstatic struct ureg get_material( struct tnl_program *p, GLuint side, 871c1f859d4Smrg GLuint property ) 872c1f859d4Smrg{ 873c1f859d4Smrg GLuint attrib = material_attrib(side, property); 874c1f859d4Smrg 875c1f859d4Smrg if (p->color_materials & (1<<attrib)) 876c1f859d4Smrg return register_input(p, VERT_ATTRIB_COLOR0); 8774a49301eSmrg else if (p->materials & (1<<attrib)) { 8784a49301eSmrg /* Put material values in the GENERIC slots -- they are not used 8794a49301eSmrg * for anything in fixed function mode. 8804a49301eSmrg */ 88101e04c3fSmrg return register_input( p, VERT_ATTRIB_MAT(attrib) ); 8824a49301eSmrg } 883c1f859d4Smrg else 8847ec681f3Smrg return register_param2(p, STATE_MATERIAL, attrib); 885c1f859d4Smrg} 886c1f859d4Smrg 887c1f859d4Smrg#define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \ 888c1f859d4Smrg MAT_BIT_FRONT_AMBIENT | \ 889c1f859d4Smrg MAT_BIT_FRONT_DIFFUSE) << (side)) 890c1f859d4Smrg 891c1f859d4Smrg 892c1f859d4Smrg/** 893c1f859d4Smrg * Either return a precalculated constant value or emit code to 894c1f859d4Smrg * calculate these values dynamically in the case where material calls 895c1f859d4Smrg * are present between begin/end pairs. 896c1f859d4Smrg * 897c1f859d4Smrg * Probably want to shift this to the program compilation phase - if 898c1f859d4Smrg * we always emitted the calculation here, a smart compiler could 899c1f859d4Smrg * detect that it was constant (given a certain set of inputs), and 900c1f859d4Smrg * lift it out of the main loop. That way the programs created here 901c1f859d4Smrg * would be independent of the vertex_buffer details. 902c1f859d4Smrg */ 903c1f859d4Smrgstatic struct ureg get_scenecolor( struct tnl_program *p, GLuint side ) 904c1f859d4Smrg{ 905c1f859d4Smrg if (p->materials & SCENE_COLOR_BITS(side)) { 906c1f859d4Smrg struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT); 907c1f859d4Smrg struct ureg material_emission = get_material(p, side, STATE_EMISSION); 908c1f859d4Smrg struct ureg material_ambient = get_material(p, side, STATE_AMBIENT); 909c1f859d4Smrg struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE); 910c1f859d4Smrg struct ureg tmp = make_temp(p, material_diffuse); 9114a49301eSmrg emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient, 912c1f859d4Smrg material_ambient, material_emission); 913c1f859d4Smrg return tmp; 914c1f859d4Smrg } 915c1f859d4Smrg else 916c1f859d4Smrg return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side ); 917c1f859d4Smrg} 918c1f859d4Smrg 919c1f859d4Smrg 9204a49301eSmrgstatic struct ureg get_lightprod( struct tnl_program *p, GLuint light, 9217ec681f3Smrg GLuint side, GLuint property, bool *is_state_light ) 922c1f859d4Smrg{ 923c1f859d4Smrg GLuint attrib = material_attrib(side, property); 924c1f859d4Smrg if (p->materials & (1<<attrib)) { 9254a49301eSmrg struct ureg light_value = 926c1f859d4Smrg register_param3(p, STATE_LIGHT, light, property); 9277ec681f3Smrg *is_state_light = true; 9287ec681f3Smrg return light_value; 9297ec681f3Smrg } 9307ec681f3Smrg else { 9317ec681f3Smrg *is_state_light = false; 9327ec681f3Smrg return register_param3(p, STATE_LIGHTPROD, light, attrib); 933c1f859d4Smrg } 934c1f859d4Smrg} 935c1f859d4Smrg 936c1f859d4Smrg 937c1f859d4Smrgstatic struct ureg calculate_light_attenuation( struct tnl_program *p, 9384a49301eSmrg GLuint i, 939c1f859d4Smrg struct ureg VPpli, 940c1f859d4Smrg struct ureg dist ) 941c1f859d4Smrg{ 942c1f859d4Smrg struct ureg attenuation = register_param3(p, STATE_LIGHT, i, 943c1f859d4Smrg STATE_ATTENUATION); 944af69d88dSmrg struct ureg att = undef; 945c1f859d4Smrg 946c1f859d4Smrg /* Calculate spot attenuation: 947c1f859d4Smrg */ 948c1f859d4Smrg if (!p->state->unit[i].light_spotcutoff_is_180) { 9497ec681f3Smrg struct ureg spot_dir_norm = register_param2(p, STATE_LIGHT_SPOT_DIR_NORMALIZED, i); 950c1f859d4Smrg struct ureg spot = get_temp(p); 951c1f859d4Smrg struct ureg slt = get_temp(p); 952c1f859d4Smrg 953af69d88dSmrg att = get_temp(p); 954af69d88dSmrg 955c1f859d4Smrg emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm); 956c1f859d4Smrg emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot); 95701e04c3fSmrg emit_op1(p, OPCODE_ABS, spot, 0, spot); 958c1f859d4Smrg emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W)); 959c1f859d4Smrg emit_op2(p, OPCODE_MUL, att, 0, slt, spot); 960c1f859d4Smrg 961c1f859d4Smrg release_temp(p, spot); 962c1f859d4Smrg release_temp(p, slt); 963c1f859d4Smrg } 964c1f859d4Smrg 965af69d88dSmrg /* Calculate distance attenuation(See formula (2.4) at glspec 2.1 page 62): 966af69d88dSmrg * 967af69d88dSmrg * Skip the calucation when _dist_ is undefined(light_eyepos3_is_zero) 968c1f859d4Smrg */ 969af69d88dSmrg if (p->state->unit[i].light_attenuated && !is_undef(dist)) { 970af69d88dSmrg if (is_undef(att)) 971af69d88dSmrg att = get_temp(p); 972c1f859d4Smrg /* 1/d,d,d,1/d */ 9734a49301eSmrg emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist); 974c1f859d4Smrg /* 1,d,d*d,1/d */ 9754a49301eSmrg emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y)); 976c1f859d4Smrg /* 1/dist-atten */ 9774a49301eSmrg emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist); 978c1f859d4Smrg 979c1f859d4Smrg if (!p->state->unit[i].light_spotcutoff_is_180) { 980c1f859d4Smrg /* dist-atten */ 9814a49301eSmrg emit_op1(p, OPCODE_RCP, dist, 0, dist); 982c1f859d4Smrg /* spot-atten * dist-atten */ 9834a49301eSmrg emit_op2(p, OPCODE_MUL, att, 0, dist, att); 9844a49301eSmrg } 9854a49301eSmrg else { 986c1f859d4Smrg /* dist-atten */ 9874a49301eSmrg emit_op1(p, OPCODE_RCP, att, 0, dist); 988c1f859d4Smrg } 989c1f859d4Smrg } 990c1f859d4Smrg 991c1f859d4Smrg return att; 992c1f859d4Smrg} 9934a49301eSmrg 994c1f859d4Smrg 995c1f859d4Smrg/** 996c1f859d4Smrg * Compute: 997c1f859d4Smrg * lit.y = MAX(0, dots.x) 998c1f859d4Smrg * lit.z = SLT(0, dots.x) 999c1f859d4Smrg */ 1000c1f859d4Smrgstatic void emit_degenerate_lit( struct tnl_program *p, 1001c1f859d4Smrg struct ureg lit, 1002c1f859d4Smrg struct ureg dots ) 1003c1f859d4Smrg{ 1004c1f859d4Smrg struct ureg id = get_identity_param(p); /* id = {0,0,0,1} */ 1005c1f859d4Smrg 1006c1f859d4Smrg /* Note that lit.x & lit.w will not be examined. Note also that 1007c1f859d4Smrg * dots.xyzw == dots.xxxx. 1008c1f859d4Smrg */ 1009c1f859d4Smrg 1010c1f859d4Smrg /* MAX lit, id, dots; 1011c1f859d4Smrg */ 10124a49301eSmrg emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots); 1013c1f859d4Smrg 1014c1f859d4Smrg /* result[2] = (in > 0 ? 1 : 0) 1015c1f859d4Smrg * SLT lit.z, id.z, dots; # lit.z = (0 < dots.z) ? 1 : 0 1016c1f859d4Smrg */ 1017c1f859d4Smrg emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots); 1018c1f859d4Smrg} 1019c1f859d4Smrg 1020c1f859d4Smrg 1021c1f859d4Smrg/* Need to add some addtional parameters to allow lighting in object 1022c1f859d4Smrg * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye 1023c1f859d4Smrg * space lighting. 1024c1f859d4Smrg */ 1025c1f859d4Smrgstatic void build_lighting( struct tnl_program *p ) 1026c1f859d4Smrg{ 1027c1f859d4Smrg const GLboolean twoside = p->state->light_twoside; 1028c1f859d4Smrg const GLboolean separate = p->state->separate_specular; 1029c1f859d4Smrg GLuint nr_lights = 0, count = 0; 1030c1f859d4Smrg struct ureg normal = get_transformed_normal(p); 1031c1f859d4Smrg struct ureg lit = get_temp(p); 1032c1f859d4Smrg struct ureg dots = get_temp(p); 1033c1f859d4Smrg struct ureg _col0 = undef, _col1 = undef; 1034c1f859d4Smrg struct ureg _bfc0 = undef, _bfc1 = undef; 1035c1f859d4Smrg GLuint i; 1036c1f859d4Smrg 1037c1f859d4Smrg /* 1038c1f859d4Smrg * NOTE: 10394a49301eSmrg * dots.x = dot(normal, VPpli) 10404a49301eSmrg * dots.y = dot(normal, halfAngle) 10414a49301eSmrg * dots.z = back.shininess 10424a49301eSmrg * dots.w = front.shininess 1043c1f859d4Smrg */ 1044c1f859d4Smrg 10454a49301eSmrg for (i = 0; i < MAX_LIGHTS; i++) 1046c1f859d4Smrg if (p->state->unit[i].light_enabled) 1047c1f859d4Smrg nr_lights++; 10484a49301eSmrg 1049c1f859d4Smrg set_material_flags(p); 1050c1f859d4Smrg 1051c1f859d4Smrg { 1052c1f859d4Smrg if (!p->state->material_shininess_is_zero) { 1053c1f859d4Smrg struct ureg shininess = get_material(p, 0, STATE_SHININESS); 10544a49301eSmrg emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X)); 1055c1f859d4Smrg release_temp(p, shininess); 1056c1f859d4Smrg } 1057c1f859d4Smrg 1058c1f859d4Smrg _col0 = make_temp(p, get_scenecolor(p, 0)); 1059c1f859d4Smrg if (separate) 1060c1f859d4Smrg _col1 = make_temp(p, get_identity_param(p)); 1061c1f859d4Smrg else 1062c1f859d4Smrg _col1 = _col0; 1063c1f859d4Smrg } 1064c1f859d4Smrg 1065c1f859d4Smrg if (twoside) { 1066c1f859d4Smrg if (!p->state->material_shininess_is_zero) { 1067c1f859d4Smrg /* Note that we negate the back-face specular exponent here. 1068c1f859d4Smrg * The negation will be un-done later in the back-face code below. 1069c1f859d4Smrg */ 1070c1f859d4Smrg struct ureg shininess = get_material(p, 1, STATE_SHININESS); 10714a49301eSmrg emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z, 1072c1f859d4Smrg negate(swizzle1(shininess,X))); 1073c1f859d4Smrg release_temp(p, shininess); 1074c1f859d4Smrg } 1075c1f859d4Smrg 1076c1f859d4Smrg _bfc0 = make_temp(p, get_scenecolor(p, 1)); 1077c1f859d4Smrg if (separate) 1078c1f859d4Smrg _bfc1 = make_temp(p, get_identity_param(p)); 1079c1f859d4Smrg else 1080c1f859d4Smrg _bfc1 = _bfc0; 1081c1f859d4Smrg } 1082c1f859d4Smrg 1083c1f859d4Smrg /* If no lights, still need to emit the scenecolor. 1084c1f859d4Smrg */ 1085c1f859d4Smrg { 1086af69d88dSmrg struct ureg res0 = register_output( p, VARYING_SLOT_COL0 ); 1087c1f859d4Smrg emit_op1(p, OPCODE_MOV, res0, 0, _col0); 1088c1f859d4Smrg } 1089c1f859d4Smrg 1090c1f859d4Smrg if (separate) { 1091af69d88dSmrg struct ureg res1 = register_output( p, VARYING_SLOT_COL1 ); 1092c1f859d4Smrg emit_op1(p, OPCODE_MOV, res1, 0, _col1); 1093c1f859d4Smrg } 1094c1f859d4Smrg 1095c1f859d4Smrg if (twoside) { 1096af69d88dSmrg struct ureg res0 = register_output( p, VARYING_SLOT_BFC0 ); 1097c1f859d4Smrg emit_op1(p, OPCODE_MOV, res0, 0, _bfc0); 1098c1f859d4Smrg } 10994a49301eSmrg 1100c1f859d4Smrg if (twoside && separate) { 1101af69d88dSmrg struct ureg res1 = register_output( p, VARYING_SLOT_BFC1 ); 1102c1f859d4Smrg emit_op1(p, OPCODE_MOV, res1, 0, _bfc1); 1103c1f859d4Smrg } 11044a49301eSmrg 1105c1f859d4Smrg if (nr_lights == 0) { 1106c1f859d4Smrg release_temps(p); 1107c1f859d4Smrg return; 1108c1f859d4Smrg } 1109c1f859d4Smrg 11107ec681f3Smrg /* Declare light products first to place them sequentially next to each 11117ec681f3Smrg * other for optimal constant uploads. 11127ec681f3Smrg */ 11137ec681f3Smrg struct ureg lightprod_front[MAX_LIGHTS][3]; 11147ec681f3Smrg struct ureg lightprod_back[MAX_LIGHTS][3]; 11157ec681f3Smrg bool lightprod_front_is_state_light[MAX_LIGHTS][3]; 11167ec681f3Smrg bool lightprod_back_is_state_light[MAX_LIGHTS][3]; 11177ec681f3Smrg 11187ec681f3Smrg for (i = 0; i < MAX_LIGHTS; i++) { 11197ec681f3Smrg if (p->state->unit[i].light_enabled) { 11207ec681f3Smrg lightprod_front[i][0] = get_lightprod(p, i, 0, STATE_AMBIENT, 11217ec681f3Smrg &lightprod_front_is_state_light[i][0]); 11227ec681f3Smrg if (twoside) 11237ec681f3Smrg lightprod_back[i][0] = get_lightprod(p, i, 1, STATE_AMBIENT, 11247ec681f3Smrg &lightprod_back_is_state_light[i][0]); 11257ec681f3Smrg 11267ec681f3Smrg lightprod_front[i][1] = get_lightprod(p, i, 0, STATE_DIFFUSE, 11277ec681f3Smrg &lightprod_front_is_state_light[i][1]); 11287ec681f3Smrg if (twoside) 11297ec681f3Smrg lightprod_back[i][1] = get_lightprod(p, i, 1, STATE_DIFFUSE, 11307ec681f3Smrg &lightprod_back_is_state_light[i][1]); 11317ec681f3Smrg 11327ec681f3Smrg lightprod_front[i][2] = get_lightprod(p, i, 0, STATE_SPECULAR, 11337ec681f3Smrg &lightprod_front_is_state_light[i][2]); 11347ec681f3Smrg if (twoside) 11357ec681f3Smrg lightprod_back[i][2] = get_lightprod(p, i, 1, STATE_SPECULAR, 11367ec681f3Smrg &lightprod_back_is_state_light[i][2]); 11377ec681f3Smrg } 11387ec681f3Smrg } 11397ec681f3Smrg 11407ec681f3Smrg /* Add more variables now that we'll use later, so that they are nicely 11417ec681f3Smrg * sorted in the parameter list. 11427ec681f3Smrg */ 11437ec681f3Smrg for (i = 0; i < MAX_LIGHTS; i++) { 11447ec681f3Smrg if (p->state->unit[i].light_enabled) { 11457ec681f3Smrg if (p->state->unit[i].light_eyepos3_is_zero) 11467ec681f3Smrg register_param2(p, STATE_LIGHT_POSITION_NORMALIZED, i); 11477ec681f3Smrg else 11487ec681f3Smrg register_param2(p, STATE_LIGHT_POSITION, i); 11497ec681f3Smrg } 11507ec681f3Smrg } 11517ec681f3Smrg for (i = 0; i < MAX_LIGHTS; i++) { 11527ec681f3Smrg if (p->state->unit[i].light_enabled) 11537ec681f3Smrg register_param3(p, STATE_LIGHT, i, STATE_ATTENUATION); 11547ec681f3Smrg } 11557ec681f3Smrg 1156c1f859d4Smrg for (i = 0; i < MAX_LIGHTS; i++) { 1157c1f859d4Smrg if (p->state->unit[i].light_enabled) { 1158c1f859d4Smrg struct ureg half = undef; 1159c1f859d4Smrg struct ureg att = undef, VPpli = undef; 1160af69d88dSmrg struct ureg dist = undef; 11614a49301eSmrg 1162c1f859d4Smrg count++; 1163af69d88dSmrg if (p->state->unit[i].light_eyepos3_is_zero) { 11647ec681f3Smrg VPpli = register_param2(p, STATE_LIGHT_POSITION_NORMALIZED, i); 1165af69d88dSmrg } else { 11667ec681f3Smrg struct ureg Ppli = register_param2(p, STATE_LIGHT_POSITION, i); 1167af69d88dSmrg struct ureg V = get_eye_position(p); 1168af69d88dSmrg 1169af69d88dSmrg VPpli = get_temp(p); 1170af69d88dSmrg dist = get_temp(p); 1171af69d88dSmrg 1172af69d88dSmrg /* Calculate VPpli vector 1173af69d88dSmrg */ 1174af69d88dSmrg emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V); 1175c1f859d4Smrg 1176af69d88dSmrg /* Normalize VPpli. The dist value also used in 1177af69d88dSmrg * attenuation below. 1178af69d88dSmrg */ 1179af69d88dSmrg emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli); 1180af69d88dSmrg emit_op1(p, OPCODE_RSQ, dist, 0, dist); 1181af69d88dSmrg emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist); 1182af69d88dSmrg } 1183c1f859d4Smrg 1184af69d88dSmrg /* Calculate attenuation: 1185af69d88dSmrg */ 1186af69d88dSmrg att = calculate_light_attenuation(p, i, VPpli, dist); 1187af69d88dSmrg release_temp(p, dist); 1188c1f859d4Smrg 1189af69d88dSmrg /* Calculate viewer direction, or use infinite viewer: 1190af69d88dSmrg */ 1191af69d88dSmrg if (!p->state->material_shininess_is_zero) { 1192af69d88dSmrg if (p->state->light_local_viewer) { 1193af69d88dSmrg struct ureg eye_hat = get_eye_position_normalized(p); 1194af69d88dSmrg half = get_temp(p); 1195af69d88dSmrg emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); 1196af69d88dSmrg emit_normalize_vec3(p, half, half); 1197af69d88dSmrg } else if (p->state->unit[i].light_eyepos3_is_zero) { 11987ec681f3Smrg half = register_param2(p, STATE_LIGHT_HALF_VECTOR, i); 1199af69d88dSmrg } else { 1200af69d88dSmrg struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z); 1201af69d88dSmrg half = get_temp(p); 1202af69d88dSmrg emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir); 1203c1f859d4Smrg emit_normalize_vec3(p, half, half); 1204c1f859d4Smrg } 1205c1f859d4Smrg } 1206c1f859d4Smrg 1207c1f859d4Smrg /* Calculate dot products: 1208c1f859d4Smrg */ 1209c1f859d4Smrg if (p->state->material_shininess_is_zero) { 1210c1f859d4Smrg emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli); 1211c1f859d4Smrg } 1212c1f859d4Smrg else { 1213c1f859d4Smrg emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli); 1214c1f859d4Smrg emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half); 1215c1f859d4Smrg } 1216c1f859d4Smrg 1217c1f859d4Smrg /* Front face lighting: 1218c1f859d4Smrg */ 1219c1f859d4Smrg { 12207ec681f3Smrg /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in 12217ec681f3Smrg * get_lightprod to avoid using too many temps. 12227ec681f3Smrg */ 12237ec681f3Smrg for (int j = 0; j < 3; j++) { 12247ec681f3Smrg if (lightprod_front_is_state_light[i][j]) { 12257ec681f3Smrg struct ureg material_value = get_material(p, 0, STATE_AMBIENT + j); 12267ec681f3Smrg struct ureg tmp = get_temp(p); 12277ec681f3Smrg emit_op2(p, OPCODE_MUL, tmp, 0, lightprod_front[i][j], material_value); 12287ec681f3Smrg lightprod_front[i][j] = tmp; 12297ec681f3Smrg } 12307ec681f3Smrg } 12317ec681f3Smrg 12327ec681f3Smrg struct ureg ambient = lightprod_front[i][0]; 12337ec681f3Smrg struct ureg diffuse = lightprod_front[i][1]; 12347ec681f3Smrg struct ureg specular = lightprod_front[i][2]; 1235c1f859d4Smrg struct ureg res0, res1; 1236c1f859d4Smrg GLuint mask0, mask1; 1237c1f859d4Smrg 1238c1f859d4Smrg if (count == nr_lights) { 1239c1f859d4Smrg if (separate) { 1240c1f859d4Smrg mask0 = WRITEMASK_XYZ; 1241c1f859d4Smrg mask1 = WRITEMASK_XYZ; 1242af69d88dSmrg res0 = register_output( p, VARYING_SLOT_COL0 ); 1243af69d88dSmrg res1 = register_output( p, VARYING_SLOT_COL1 ); 1244c1f859d4Smrg } 1245c1f859d4Smrg else { 1246c1f859d4Smrg mask0 = 0; 1247c1f859d4Smrg mask1 = WRITEMASK_XYZ; 1248c1f859d4Smrg res0 = _col0; 1249af69d88dSmrg res1 = register_output( p, VARYING_SLOT_COL0 ); 1250c1f859d4Smrg } 12514a49301eSmrg } 12524a49301eSmrg else { 1253c1f859d4Smrg mask0 = 0; 1254c1f859d4Smrg mask1 = 0; 1255c1f859d4Smrg res0 = _col0; 1256c1f859d4Smrg res1 = _col1; 1257c1f859d4Smrg } 1258c1f859d4Smrg 1259c1f859d4Smrg if (!is_undef(att)) { 1260c1f859d4Smrg /* light is attenuated by distance */ 1261c1f859d4Smrg emit_op1(p, OPCODE_LIT, lit, 0, dots); 1262c1f859d4Smrg emit_op2(p, OPCODE_MUL, lit, 0, lit, att); 1263c1f859d4Smrg emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0); 12644a49301eSmrg } 1265c1f859d4Smrg else if (!p->state->material_shininess_is_zero) { 1266c1f859d4Smrg /* there's a non-zero specular term */ 1267c1f859d4Smrg emit_op1(p, OPCODE_LIT, lit, 0, dots); 1268c1f859d4Smrg emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); 12694a49301eSmrg } 1270c1f859d4Smrg else { 1271c1f859d4Smrg /* no attenutation, no specular */ 1272c1f859d4Smrg emit_degenerate_lit(p, lit, dots); 1273c1f859d4Smrg emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); 1274c1f859d4Smrg } 1275c1f859d4Smrg 1276c1f859d4Smrg emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0); 1277c1f859d4Smrg emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1); 12784a49301eSmrg 1279c1f859d4Smrg release_temp(p, ambient); 1280c1f859d4Smrg release_temp(p, diffuse); 1281c1f859d4Smrg release_temp(p, specular); 1282c1f859d4Smrg } 1283c1f859d4Smrg 1284c1f859d4Smrg /* Back face lighting: 1285c1f859d4Smrg */ 1286c1f859d4Smrg if (twoside) { 12877ec681f3Smrg /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in 12887ec681f3Smrg * get_lightprod to avoid using too many temps. 12897ec681f3Smrg */ 12907ec681f3Smrg for (int j = 0; j < 3; j++) { 12917ec681f3Smrg if (lightprod_back_is_state_light[i][j]) { 12927ec681f3Smrg struct ureg material_value = get_material(p, 1, STATE_AMBIENT + j); 12937ec681f3Smrg struct ureg tmp = get_temp(p); 12947ec681f3Smrg emit_op2(p, OPCODE_MUL, tmp, 1, lightprod_back[i][j], material_value); 12957ec681f3Smrg lightprod_back[i][j] = tmp; 12967ec681f3Smrg } 12977ec681f3Smrg } 12987ec681f3Smrg 12997ec681f3Smrg struct ureg ambient = lightprod_back[i][0]; 13007ec681f3Smrg struct ureg diffuse = lightprod_back[i][1]; 13017ec681f3Smrg struct ureg specular = lightprod_back[i][2]; 1302c1f859d4Smrg struct ureg res0, res1; 1303c1f859d4Smrg GLuint mask0, mask1; 13044a49301eSmrg 1305c1f859d4Smrg if (count == nr_lights) { 1306c1f859d4Smrg if (separate) { 1307c1f859d4Smrg mask0 = WRITEMASK_XYZ; 1308c1f859d4Smrg mask1 = WRITEMASK_XYZ; 1309af69d88dSmrg res0 = register_output( p, VARYING_SLOT_BFC0 ); 1310af69d88dSmrg res1 = register_output( p, VARYING_SLOT_BFC1 ); 1311c1f859d4Smrg } 1312c1f859d4Smrg else { 1313c1f859d4Smrg mask0 = 0; 1314c1f859d4Smrg mask1 = WRITEMASK_XYZ; 1315c1f859d4Smrg res0 = _bfc0; 1316af69d88dSmrg res1 = register_output( p, VARYING_SLOT_BFC0 ); 1317c1f859d4Smrg } 13184a49301eSmrg } 13194a49301eSmrg else { 1320c1f859d4Smrg res0 = _bfc0; 1321c1f859d4Smrg res1 = _bfc1; 1322c1f859d4Smrg mask0 = 0; 1323c1f859d4Smrg mask1 = 0; 1324c1f859d4Smrg } 1325c1f859d4Smrg 1326c1f859d4Smrg /* For the back face we need to negate the X and Y component 1327c1f859d4Smrg * dot products. dots.Z has the negated back-face specular 1328c1f859d4Smrg * exponent. We swizzle that into the W position. This 1329c1f859d4Smrg * negation makes the back-face specular term positive again. 1330c1f859d4Smrg */ 1331c1f859d4Smrg dots = negate(swizzle(dots,X,Y,W,Z)); 1332c1f859d4Smrg 1333c1f859d4Smrg if (!is_undef(att)) { 1334c1f859d4Smrg emit_op1(p, OPCODE_LIT, lit, 0, dots); 1335c1f859d4Smrg emit_op2(p, OPCODE_MUL, lit, 0, lit, att); 1336c1f859d4Smrg emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0); 1337c1f859d4Smrg } 1338c1f859d4Smrg else if (!p->state->material_shininess_is_zero) { 1339c1f859d4Smrg emit_op1(p, OPCODE_LIT, lit, 0, dots); 13404a49301eSmrg emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); /**/ 13414a49301eSmrg } 1342c1f859d4Smrg else { 1343c1f859d4Smrg emit_degenerate_lit(p, lit, dots); 1344c1f859d4Smrg emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); 1345c1f859d4Smrg } 1346c1f859d4Smrg 1347c1f859d4Smrg emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0); 1348c1f859d4Smrg emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1); 1349c1f859d4Smrg /* restore dots to its original state for subsequent lights 1350c1f859d4Smrg * by negating and swizzling again. 1351c1f859d4Smrg */ 1352c1f859d4Smrg dots = negate(swizzle(dots,X,Y,W,Z)); 1353c1f859d4Smrg 1354c1f859d4Smrg release_temp(p, ambient); 1355c1f859d4Smrg release_temp(p, diffuse); 1356c1f859d4Smrg release_temp(p, specular); 1357c1f859d4Smrg } 1358c1f859d4Smrg 1359c1f859d4Smrg release_temp(p, half); 1360c1f859d4Smrg release_temp(p, VPpli); 1361c1f859d4Smrg release_temp(p, att); 1362c1f859d4Smrg } 1363c1f859d4Smrg } 1364c1f859d4Smrg 1365c1f859d4Smrg release_temps( p ); 1366c1f859d4Smrg} 1367c1f859d4Smrg 1368c1f859d4Smrg 1369c1f859d4Smrgstatic void build_fog( struct tnl_program *p ) 1370c1f859d4Smrg{ 1371af69d88dSmrg struct ureg fog = register_output(p, VARYING_SLOT_FOGC); 1372c1f859d4Smrg struct ureg input; 1373c1f859d4Smrg 137401e04c3fSmrg switch (p->state->fog_distance_mode) { 137501e04c3fSmrg case FDM_EYE_RADIAL: { /* Z = sqrt(Xe*Xe + Ye*Ye + Ze*Ze) */ 137601e04c3fSmrg struct ureg tmp = get_temp(p); 137701e04c3fSmrg input = get_eye_position(p); 137801e04c3fSmrg emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, input, input); 137901e04c3fSmrg emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp); 138001e04c3fSmrg emit_op1(p, OPCODE_RCP, fog, WRITEMASK_X, tmp); 138101e04c3fSmrg break; 1382c1f859d4Smrg } 138301e04c3fSmrg case FDM_EYE_PLANE: /* Z = Ze */ 138401e04c3fSmrg input = get_eye_position_z(p); 138501e04c3fSmrg emit_op1(p, OPCODE_MOV, fog, WRITEMASK_X, input); 138601e04c3fSmrg break; 138701e04c3fSmrg case FDM_EYE_PLANE_ABS: /* Z = abs(Ze) */ 138801e04c3fSmrg input = get_eye_position_z(p); 138901e04c3fSmrg emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input); 139001e04c3fSmrg break; 139101e04c3fSmrg case FDM_FROM_ARRAY: 1392c1f859d4Smrg input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X); 1393af69d88dSmrg emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input); 139401e04c3fSmrg break; 139501e04c3fSmrg default: 139601e04c3fSmrg assert(!"Bad fog mode in build_fog()"); 139701e04c3fSmrg break; 1398c1f859d4Smrg } 1399c1f859d4Smrg 14004a49301eSmrg emit_op1(p, OPCODE_MOV, fog, WRITEMASK_YZW, get_identity_param(p)); 1401c1f859d4Smrg} 1402c1f859d4Smrg 14034a49301eSmrg 1404c1f859d4Smrgstatic void build_reflect_texgen( struct tnl_program *p, 1405c1f859d4Smrg struct ureg dest, 1406c1f859d4Smrg GLuint writemask ) 1407c1f859d4Smrg{ 1408c1f859d4Smrg struct ureg normal = get_transformed_normal(p); 1409c1f859d4Smrg struct ureg eye_hat = get_eye_position_normalized(p); 1410c1f859d4Smrg struct ureg tmp = get_temp(p); 1411c1f859d4Smrg 1412c1f859d4Smrg /* n.u */ 14134a49301eSmrg emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); 1414c1f859d4Smrg /* 2n.u */ 14154a49301eSmrg emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); 1416c1f859d4Smrg /* (-2n.u)n + u */ 1417c1f859d4Smrg emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat); 1418c1f859d4Smrg 1419c1f859d4Smrg release_temp(p, tmp); 1420c1f859d4Smrg} 1421c1f859d4Smrg 1422c1f859d4Smrg 1423c1f859d4Smrgstatic void build_sphere_texgen( struct tnl_program *p, 1424c1f859d4Smrg struct ureg dest, 1425c1f859d4Smrg GLuint writemask ) 1426c1f859d4Smrg{ 1427c1f859d4Smrg struct ureg normal = get_transformed_normal(p); 1428c1f859d4Smrg struct ureg eye_hat = get_eye_position_normalized(p); 1429c1f859d4Smrg struct ureg tmp = get_temp(p); 1430c1f859d4Smrg struct ureg half = register_scalar_const(p, .5); 1431c1f859d4Smrg struct ureg r = get_temp(p); 1432c1f859d4Smrg struct ureg inv_m = get_temp(p); 1433c1f859d4Smrg struct ureg id = get_identity_param(p); 1434c1f859d4Smrg 1435c1f859d4Smrg /* Could share the above calculations, but it would be 1436c1f859d4Smrg * a fairly odd state for someone to set (both sphere and 1437c1f859d4Smrg * reflection active for different texture coordinate 1438c1f859d4Smrg * components. Of course - if two texture units enable 1439c1f859d4Smrg * reflect and/or sphere, things start to tilt in favour 1440c1f859d4Smrg * of seperating this out: 1441c1f859d4Smrg */ 1442c1f859d4Smrg 1443c1f859d4Smrg /* n.u */ 14444a49301eSmrg emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); 1445c1f859d4Smrg /* 2n.u */ 14464a49301eSmrg emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); 1447c1f859d4Smrg /* (-2n.u)n + u */ 14484a49301eSmrg emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); 1449c1f859d4Smrg /* r + 0,0,1 */ 14504a49301eSmrg emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); 1451c1f859d4Smrg /* rx^2 + ry^2 + (rz+1)^2 */ 14524a49301eSmrg emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp); 1453c1f859d4Smrg /* 2/m */ 14544a49301eSmrg emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); 1455c1f859d4Smrg /* 1/m */ 14564a49301eSmrg emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half); 1457c1f859d4Smrg /* r/m + 1/2 */ 14584a49301eSmrg emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half); 14594a49301eSmrg 1460c1f859d4Smrg release_temp(p, tmp); 1461c1f859d4Smrg release_temp(p, r); 1462c1f859d4Smrg release_temp(p, inv_m); 1463c1f859d4Smrg} 1464c1f859d4Smrg 1465c1f859d4Smrg 1466c1f859d4Smrgstatic void build_texture_transform( struct tnl_program *p ) 1467c1f859d4Smrg{ 1468c1f859d4Smrg GLuint i, j; 1469c1f859d4Smrg 1470c1f859d4Smrg for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { 1471c1f859d4Smrg 1472af69d88dSmrg if (!(p->state->fragprog_inputs_read & VARYING_BIT_TEX(i))) 1473c1f859d4Smrg continue; 14744a49301eSmrg 14753464ebd5Sriastradh if (p->state->unit[i].coord_replace) 14763464ebd5Sriastradh continue; 14773464ebd5Sriastradh 14784a49301eSmrg if (p->state->unit[i].texgen_enabled || 1479c1f859d4Smrg p->state->unit[i].texmat_enabled) { 14804a49301eSmrg 1481c1f859d4Smrg GLuint texmat_enabled = p->state->unit[i].texmat_enabled; 1482af69d88dSmrg struct ureg out = register_output(p, VARYING_SLOT_TEX0 + i); 1483c1f859d4Smrg struct ureg out_texgen = undef; 1484c1f859d4Smrg 1485c1f859d4Smrg if (p->state->unit[i].texgen_enabled) { 1486c1f859d4Smrg GLuint copy_mask = 0; 1487c1f859d4Smrg GLuint sphere_mask = 0; 1488c1f859d4Smrg GLuint reflect_mask = 0; 1489c1f859d4Smrg GLuint normal_mask = 0; 1490c1f859d4Smrg GLuint modes[4]; 14914a49301eSmrg 14924a49301eSmrg if (texmat_enabled) 1493c1f859d4Smrg out_texgen = get_temp(p); 1494c1f859d4Smrg else 1495c1f859d4Smrg out_texgen = out; 1496c1f859d4Smrg 1497c1f859d4Smrg modes[0] = p->state->unit[i].texgen_mode0; 1498c1f859d4Smrg modes[1] = p->state->unit[i].texgen_mode1; 1499c1f859d4Smrg modes[2] = p->state->unit[i].texgen_mode2; 1500c1f859d4Smrg modes[3] = p->state->unit[i].texgen_mode3; 1501c1f859d4Smrg 1502c1f859d4Smrg for (j = 0; j < 4; j++) { 1503c1f859d4Smrg switch (modes[j]) { 1504c1f859d4Smrg case TXG_OBJ_LINEAR: { 1505c1f859d4Smrg struct ureg obj = register_input(p, VERT_ATTRIB_POS); 15064a49301eSmrg struct ureg plane = 1507c1f859d4Smrg register_param3(p, STATE_TEXGEN, i, 1508c1f859d4Smrg STATE_TEXGEN_OBJECT_S + j); 1509c1f859d4Smrg 15104a49301eSmrg emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, 1511c1f859d4Smrg obj, plane ); 1512c1f859d4Smrg break; 1513c1f859d4Smrg } 1514c1f859d4Smrg case TXG_EYE_LINEAR: { 1515c1f859d4Smrg struct ureg eye = get_eye_position(p); 15164a49301eSmrg struct ureg plane = 15174a49301eSmrg register_param3(p, STATE_TEXGEN, i, 1518c1f859d4Smrg STATE_TEXGEN_EYE_S + j); 1519c1f859d4Smrg 15204a49301eSmrg emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, 1521c1f859d4Smrg eye, plane ); 1522c1f859d4Smrg break; 1523c1f859d4Smrg } 15244a49301eSmrg case TXG_SPHERE_MAP: 1525c1f859d4Smrg sphere_mask |= WRITEMASK_X << j; 1526c1f859d4Smrg break; 1527c1f859d4Smrg case TXG_REFLECTION_MAP: 1528c1f859d4Smrg reflect_mask |= WRITEMASK_X << j; 1529c1f859d4Smrg break; 15304a49301eSmrg case TXG_NORMAL_MAP: 1531c1f859d4Smrg normal_mask |= WRITEMASK_X << j; 1532c1f859d4Smrg break; 1533c1f859d4Smrg case TXG_NONE: 1534c1f859d4Smrg copy_mask |= WRITEMASK_X << j; 1535c1f859d4Smrg } 1536c1f859d4Smrg } 1537c1f859d4Smrg 1538c1f859d4Smrg if (sphere_mask) { 1539c1f859d4Smrg build_sphere_texgen(p, out_texgen, sphere_mask); 1540c1f859d4Smrg } 1541c1f859d4Smrg 1542c1f859d4Smrg if (reflect_mask) { 1543c1f859d4Smrg build_reflect_texgen(p, out_texgen, reflect_mask); 1544c1f859d4Smrg } 1545c1f859d4Smrg 1546c1f859d4Smrg if (normal_mask) { 1547c1f859d4Smrg struct ureg normal = get_transformed_normal(p); 1548c1f859d4Smrg emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal ); 1549c1f859d4Smrg } 1550c1f859d4Smrg 1551c1f859d4Smrg if (copy_mask) { 1552c1f859d4Smrg struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i); 1553c1f859d4Smrg emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in ); 1554c1f859d4Smrg } 1555c1f859d4Smrg } 1556c1f859d4Smrg 1557c1f859d4Smrg if (texmat_enabled) { 1558c1f859d4Smrg struct ureg texmat[4]; 15594a49301eSmrg struct ureg in = (!is_undef(out_texgen) ? 15604a49301eSmrg out_texgen : 1561c1f859d4Smrg register_input(p, VERT_ATTRIB_TEX0+i)); 15624a49301eSmrg if (p->mvp_with_dp4) { 1563c1f859d4Smrg register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, 15647ec681f3Smrg texmat ); 1565c1f859d4Smrg emit_matrix_transform_vec4( p, out, texmat, in ); 1566c1f859d4Smrg } 1567c1f859d4Smrg else { 15687ec681f3Smrg register_matrix_param5( p, STATE_TEXTURE_MATRIX_TRANSPOSE, i, 0, 3, 15697ec681f3Smrg texmat ); 1570c1f859d4Smrg emit_transpose_matrix_transform_vec4( p, out, texmat, in ); 1571c1f859d4Smrg } 1572c1f859d4Smrg } 1573c1f859d4Smrg 1574c1f859d4Smrg release_temps(p); 15754a49301eSmrg } 1576c1f859d4Smrg else { 1577af69d88dSmrg emit_passthrough(p, VERT_ATTRIB_TEX0+i, VARYING_SLOT_TEX0+i); 1578c1f859d4Smrg } 1579c1f859d4Smrg } 1580c1f859d4Smrg} 1581c1f859d4Smrg 1582c1f859d4Smrg 1583c1f859d4Smrg/** 1584c1f859d4Smrg * Point size attenuation computation. 1585c1f859d4Smrg */ 1586c1f859d4Smrgstatic void build_atten_pointsize( struct tnl_program *p ) 1587c1f859d4Smrg{ 1588c1f859d4Smrg struct ureg eye = get_eye_position_z(p); 15897ec681f3Smrg struct ureg state_size = register_param1(p, STATE_POINT_SIZE_CLAMPED); 1590c1f859d4Smrg struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION); 1591af69d88dSmrg struct ureg out = register_output(p, VARYING_SLOT_PSIZ); 1592c1f859d4Smrg struct ureg ut = get_temp(p); 1593c1f859d4Smrg 1594c1f859d4Smrg /* dist = |eyez| */ 1595c1f859d4Smrg emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z)); 1596c1f859d4Smrg /* p1 + dist * (p2 + dist * p3); */ 1597c1f859d4Smrg emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), 1598c1f859d4Smrg swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y)); 1599c1f859d4Smrg emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), 1600c1f859d4Smrg ut, swizzle1(state_attenuation, X)); 1601c1f859d4Smrg 1602c1f859d4Smrg /* 1 / sqrt(factor) */ 1603c1f859d4Smrg emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut ); 1604c1f859d4Smrg 1605c1f859d4Smrg#if 0 1606c1f859d4Smrg /* out = pointSize / sqrt(factor) */ 1607c1f859d4Smrg emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size); 1608c1f859d4Smrg#else 1609c1f859d4Smrg /* this is a good place to clamp the point size since there's likely 1610c1f859d4Smrg * no hardware registers to clamp point size at rasterization time. 1611c1f859d4Smrg */ 1612c1f859d4Smrg emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size); 1613c1f859d4Smrg emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y)); 1614c1f859d4Smrg emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z)); 1615c1f859d4Smrg#endif 1616c1f859d4Smrg 1617c1f859d4Smrg release_temp(p, ut); 1618c1f859d4Smrg} 1619c1f859d4Smrg 1620c1f859d4Smrg 1621c1f859d4Smrg/** 1622c1f859d4Smrg * Pass-though per-vertex point size, from user's point size array. 1623c1f859d4Smrg */ 1624c1f859d4Smrgstatic void build_array_pointsize( struct tnl_program *p ) 1625c1f859d4Smrg{ 1626c1f859d4Smrg struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE); 1627af69d88dSmrg struct ureg out = register_output(p, VARYING_SLOT_PSIZ); 1628c1f859d4Smrg emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in); 1629c1f859d4Smrg} 1630c1f859d4Smrg 1631c1f859d4Smrg 1632c1f859d4Smrgstatic void build_tnl_program( struct tnl_program *p ) 16334a49301eSmrg{ 1634af69d88dSmrg /* Emit the program, starting with the modelview, projection transforms: 1635c1f859d4Smrg */ 1636c1f859d4Smrg build_hpos(p); 1637c1f859d4Smrg 1638c1f859d4Smrg /* Lighting calculations: 1639c1f859d4Smrg */ 1640af69d88dSmrg if (p->state->fragprog_inputs_read & (VARYING_BIT_COL0|VARYING_BIT_COL1)) { 1641c1f859d4Smrg if (p->state->light_global_enabled) 1642c1f859d4Smrg build_lighting(p); 1643c1f859d4Smrg else { 1644af69d88dSmrg if (p->state->fragprog_inputs_read & VARYING_BIT_COL0) 1645af69d88dSmrg emit_passthrough(p, VERT_ATTRIB_COLOR0, VARYING_SLOT_COL0); 1646c1f859d4Smrg 1647af69d88dSmrg if (p->state->fragprog_inputs_read & VARYING_BIT_COL1) 1648af69d88dSmrg emit_passthrough(p, VERT_ATTRIB_COLOR1, VARYING_SLOT_COL1); 1649c1f859d4Smrg } 1650c1f859d4Smrg } 1651c1f859d4Smrg 1652af69d88dSmrg if (p->state->fragprog_inputs_read & VARYING_BIT_FOGC) 1653c1f859d4Smrg build_fog(p); 1654c1f859d4Smrg 1655af69d88dSmrg if (p->state->fragprog_inputs_read & VARYING_BITS_TEX_ANY) 1656c1f859d4Smrg build_texture_transform(p); 1657c1f859d4Smrg 1658c1f859d4Smrg if (p->state->point_attenuated) 1659c1f859d4Smrg build_atten_pointsize(p); 166001e04c3fSmrg else if (p->state->varying_vp_inputs & VERT_BIT_POINT_SIZE) 1661c1f859d4Smrg build_array_pointsize(p); 1662c1f859d4Smrg 1663c1f859d4Smrg /* Finish up: 1664c1f859d4Smrg */ 1665c1f859d4Smrg emit_op1(p, OPCODE_END, undef, 0, undef); 1666c1f859d4Smrg 1667c1f859d4Smrg /* Disassemble: 1668c1f859d4Smrg */ 1669c1f859d4Smrg if (DISASSEM) { 1670cdc920a0Smrg printf ("\n"); 1671c1f859d4Smrg } 1672c1f859d4Smrg} 1673c1f859d4Smrg 1674c1f859d4Smrg 1675c1f859d4Smrgstatic void 1676c1f859d4Smrgcreate_new_program( const struct state_key *key, 167701e04c3fSmrg struct gl_program *program, 16784a49301eSmrg GLboolean mvp_with_dp4, 1679c1f859d4Smrg GLuint max_temps) 1680c1f859d4Smrg{ 1681c1f859d4Smrg struct tnl_program p; 1682c1f859d4Smrg 1683cdc920a0Smrg memset(&p, 0, sizeof(p)); 1684c1f859d4Smrg p.state = key; 1685c1f859d4Smrg p.program = program; 1686c1f859d4Smrg p.eye_position = undef; 1687c1f859d4Smrg p.eye_position_z = undef; 1688c1f859d4Smrg p.eye_position_normalized = undef; 1689c1f859d4Smrg p.transformed_normal = undef; 1690c1f859d4Smrg p.identity = undef; 1691c1f859d4Smrg p.temp_in_use = 0; 16924a49301eSmrg p.mvp_with_dp4 = mvp_with_dp4; 16934a49301eSmrg 1694c1f859d4Smrg if (max_temps >= sizeof(int) * 8) 1695c1f859d4Smrg p.temp_reserved = 0; 1696c1f859d4Smrg else 1697c1f859d4Smrg p.temp_reserved = ~((1<<max_temps)-1); 1698c1f859d4Smrg 1699c1f859d4Smrg /* Start by allocating 32 instructions. 1700c1f859d4Smrg * If we need more, we'll grow the instruction array as needed. 1701c1f859d4Smrg */ 1702c1f859d4Smrg p.max_inst = 32; 170301e04c3fSmrg p.program->arb.Instructions = 170401e04c3fSmrg rzalloc_array(program, struct prog_instruction, p.max_inst); 170501e04c3fSmrg p.program->String = NULL; 170601e04c3fSmrg p.program->arb.NumInstructions = 170701e04c3fSmrg p.program->arb.NumTemporaries = 170801e04c3fSmrg p.program->arb.NumParameters = 170901e04c3fSmrg p.program->arb.NumAttributes = p.program->arb.NumAddressRegs = 0; 171001e04c3fSmrg p.program->Parameters = _mesa_new_parameter_list(); 171101e04c3fSmrg p.program->info.inputs_read = 0; 171201e04c3fSmrg p.program->info.outputs_written = 0; 17137ec681f3Smrg p.state_params = _mesa_new_parameter_list(); 1714c1f859d4Smrg 1715c1f859d4Smrg build_tnl_program( &p ); 17167ec681f3Smrg 17177ec681f3Smrg _mesa_add_separate_state_parameters(p.program, p.state_params); 17187ec681f3Smrg _mesa_free_parameter_list(p.state_params); 1719c1f859d4Smrg} 1720c1f859d4Smrg 1721c1f859d4Smrg 1722c1f859d4Smrg/** 1723c1f859d4Smrg * Return a vertex program which implements the current fixed-function 1724c1f859d4Smrg * transform/lighting/texgen operations. 1725c1f859d4Smrg */ 172601e04c3fSmrgstruct gl_program * 17273464ebd5Sriastradh_mesa_get_fixed_func_vertex_program(struct gl_context *ctx) 1728c1f859d4Smrg{ 172901e04c3fSmrg struct gl_program *prog; 1730c1f859d4Smrg struct state_key key; 1731c1f859d4Smrg 17327ec681f3Smrg /* We only update ctx->VertexProgram._VaryingInputs when in VP_MODE_FF _VPMode */ 17337ec681f3Smrg assert(VP_MODE_FF == ctx->VertexProgram._VPMode); 17347ec681f3Smrg 173501e04c3fSmrg /* Grab all the relevant state and put it in a single structure: 1736c1f859d4Smrg */ 1737c1f859d4Smrg make_state_key(ctx, &key); 1738c1f859d4Smrg 1739c1f859d4Smrg /* Look for an already-prepared program for this state: 1740c1f859d4Smrg */ 174101e04c3fSmrg prog = _mesa_search_program_cache(ctx->VertexProgram.Cache, &key, 174201e04c3fSmrg sizeof(key)); 17434a49301eSmrg 1744c1f859d4Smrg if (!prog) { 1745c1f859d4Smrg /* OK, we'll have to build a new one */ 1746c1f859d4Smrg if (0) 1747cdc920a0Smrg printf("Build new TNL program\n"); 17484a49301eSmrg 17497ec681f3Smrg prog = ctx->Driver.NewProgram(ctx, MESA_SHADER_VERTEX, 0, true); 1750c1f859d4Smrg if (!prog) 1751c1f859d4Smrg return NULL; 1752c1f859d4Smrg 1753c1f859d4Smrg create_new_program( &key, prog, 1754af69d88dSmrg ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS, 1755af69d88dSmrg ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps ); 1756c1f859d4Smrg 1757c1f859d4Smrg if (ctx->Driver.ProgramStringNotify) 175801e04c3fSmrg ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, prog); 175901e04c3fSmrg 176001e04c3fSmrg _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, &key, 176101e04c3fSmrg sizeof(key), prog); 1762c1f859d4Smrg } 1763c1f859d4Smrg 1764c1f859d4Smrg return prog; 1765c1f859d4Smrg} 1766