From d105412503ea250e07d3cb008f10f60e6e48bf8a Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 5 Aug 2011 08:12:52 +0200 Subject: mesa pixman git update 5 aug 2011 --- mesalib/src/mesa/main/compiler.h | 24 +- mesalib/src/mesa/main/enable.c | 11 +- mesalib/src/mesa/main/ff_fragment_shader.cpp | 3 +- mesalib/src/mesa/main/ffvertex_prog.c | 3360 +++++++++++++------------- mesalib/src/mesa/main/nvprogram.c | 1840 +++++++------- mesalib/src/mesa/main/texcompress_rgtc_tmp.h | 2 +- mesalib/src/mesa/main/texobj.c | 6 +- mesalib/src/mesa/main/texparam.c | 304 +-- mesalib/src/mesa/main/uniforms.c | 46 +- 9 files changed, 2748 insertions(+), 2848 deletions(-) (limited to 'mesalib/src/mesa/main') diff --git a/mesalib/src/mesa/main/compiler.h b/mesalib/src/mesa/main/compiler.h index d736fdfc5..ee7d0b2f8 100644 --- a/mesalib/src/mesa/main/compiler.h +++ b/mesalib/src/mesa/main/compiler.h @@ -60,29 +60,7 @@ extern "C" { /** * Get standard integer types */ -#if defined(_MSC_VER) - typedef __int8 int8_t; - typedef unsigned __int8 uint8_t; - typedef __int16 int16_t; - typedef unsigned __int16 uint16_t; - typedef __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; - -# if defined(_WIN64) - typedef __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -# else - typedef __int32 intptr_t; - typedef unsigned __int32 uintptr_t; -# endif - -# define INT64_C(__val) __val##i64 -# define UINT64_C(__val) __val##ui64 -#else -# include -#endif +#include /** diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index aac8b9c5e..3ba4df634 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -5,7 +5,6 @@ /* * Mesa 3-D graphics library - * Version: 7.0.3 * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * @@ -560,7 +559,6 @@ _mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) ctx->Polygon.OffsetLine = state; break; case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ if (ctx->Polygon.OffsetFill == state) return; FLUSH_VERTICES(ctx, _NEW_POLYGON); @@ -643,9 +641,7 @@ _mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) break; #endif - /* - * CLIENT STATE!!! - */ + /* client-side state */ case GL_VERTEX_ARRAY: case GL_NORMAL_ARRAY: case GL_COLOR_ARRAY: @@ -1174,7 +1170,6 @@ _mesa_IsEnabled( GLenum cap ) case GL_POLYGON_OFFSET_LINE: return ctx->Polygon.OffsetLine; case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ return ctx->Polygon.OffsetFill; case GL_RESCALE_NORMAL_EXT: return ctx->Transform.RescaleNormals; @@ -1213,9 +1208,7 @@ _mesa_IsEnabled( GLenum cap ) } #endif - /* - * CLIENT STATE!!! - */ + /* client-side state */ case GL_VERTEX_ARRAY: return (ctx->Array.ArrayObj->Vertex.Enabled != 0); case GL_NORMAL_ARRAY: diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp index dbfa6b57d..7cc172168 100644 --- a/mesalib/src/mesa/main/ff_fragment_shader.cpp +++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp @@ -874,7 +874,8 @@ static struct ureg register_const4f( struct texenv_fragment_program *p, values[1] = s1; values[2] = s2; values[3] = s3; - idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, + idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, + (gl_constant_value *) values, 4, &swizzle ); r = make_ureg(PROGRAM_CONSTANT, idx); r.swz = swizzle; diff --git a/mesalib/src/mesa/main/ffvertex_prog.c b/mesalib/src/mesa/main/ffvertex_prog.c index 281229e34..2d2485c9e 100644 --- a/mesalib/src/mesa/main/ffvertex_prog.c +++ b/mesalib/src/mesa/main/ffvertex_prog.c @@ -1,1680 +1,1680 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -/** - * \file ffvertex_prog.c - * - * Create a vertex program to execute the current fixed function T&L pipeline. - * \author Keith Whitwell - */ - - -#include "main/glheader.h" -#include "main/mtypes.h" -#include "main/macros.h" -#include "main/mfeatures.h" -#include "main/enums.h" -#include "main/ffvertex_prog.h" -#include "program/program.h" -#include "program/prog_cache.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/prog_statevars.h" - - -/** Max of number of lights and texture coord units */ -#define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS) - -struct state_key { - unsigned light_color_material_mask:12; - unsigned light_global_enabled:1; - unsigned light_local_viewer:1; - unsigned light_twoside:1; - unsigned material_shininess_is_zero:1; - unsigned need_eye_coords:1; - unsigned normalize:1; - unsigned rescale_normals:1; - - unsigned fog_source_is_depth:1; - unsigned separate_specular:1; - unsigned point_attenuated:1; - unsigned point_array:1; - unsigned texture_enabled_global:1; - unsigned fragprog_inputs_read:12; - - unsigned varying_vp_inputs; - - struct { - unsigned light_enabled:1; - unsigned light_eyepos3_is_zero:1; - unsigned light_spotcutoff_is_180:1; - unsigned light_attenuated:1; - unsigned texunit_really_enabled:1; - unsigned texmat_enabled:1; - unsigned coord_replace:1; - unsigned texgen_enabled:4; - unsigned texgen_mode0:4; - unsigned texgen_mode1:4; - unsigned texgen_mode2:4; - unsigned texgen_mode3:4; - } unit[NUM_UNITS]; -}; - - -#define TXG_NONE 0 -#define TXG_OBJ_LINEAR 1 -#define TXG_EYE_LINEAR 2 -#define TXG_SPHERE_MAP 3 -#define TXG_REFLECTION_MAP 4 -#define TXG_NORMAL_MAP 5 - -static GLuint translate_texgen( GLboolean enabled, GLenum mode ) -{ - if (!enabled) - return TXG_NONE; - - switch (mode) { - case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR; - case GL_EYE_LINEAR: return TXG_EYE_LINEAR; - case GL_SPHERE_MAP: return TXG_SPHERE_MAP; - case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP; - case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP; - default: return TXG_NONE; - } -} - - - -static GLboolean check_active_shininess( struct gl_context *ctx, - const struct state_key *key, - GLuint side ) -{ - GLuint bit = 1 << (MAT_ATTRIB_FRONT_SHININESS + side); - - if ((key->varying_vp_inputs & VERT_BIT_COLOR0) && - (key->light_color_material_mask & bit)) - return GL_TRUE; - - if (key->varying_vp_inputs & (bit << 16)) - return GL_TRUE; - - if (ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS + side][0] != 0.0F) - return GL_TRUE; - - return GL_FALSE; -} - - -static void make_state_key( struct gl_context *ctx, struct state_key *key ) -{ - const struct gl_fragment_program *fp; - GLuint i; - - memset(key, 0, sizeof(struct state_key)); - fp = ctx->FragmentProgram._Current; - - /* This now relies on texenvprogram.c being active: - */ - assert(fp); - - key->need_eye_coords = ctx->_NeedEyeCoords; - - key->fragprog_inputs_read = fp->Base.InputsRead; - key->varying_vp_inputs = ctx->varying_vp_inputs; - - if (ctx->RenderMode == GL_FEEDBACK) { - /* make sure the vertprog emits color and tex0 */ - key->fragprog_inputs_read |= (FRAG_BIT_COL0 | FRAG_BIT_TEX0); - } - - key->separate_specular = (ctx->Light.Model.ColorControl == - GL_SEPARATE_SPECULAR_COLOR); - - if (ctx->Light.Enabled) { - key->light_global_enabled = 1; - - if (ctx->Light.Model.LocalViewer) - key->light_local_viewer = 1; - - if (ctx->Light.Model.TwoSide) - key->light_twoside = 1; - - if (ctx->Light.ColorMaterialEnabled) { - key->light_color_material_mask = ctx->Light.ColorMaterialBitmask; - } - - for (i = 0; i < MAX_LIGHTS; i++) { - struct gl_light *light = &ctx->Light.Light[i]; - - if (light->Enabled) { - key->unit[i].light_enabled = 1; - - if (light->EyePosition[3] == 0.0) - key->unit[i].light_eyepos3_is_zero = 1; - - if (light->SpotCutoff == 180.0) - key->unit[i].light_spotcutoff_is_180 = 1; - - if (light->ConstantAttenuation != 1.0 || - light->LinearAttenuation != 0.0 || - light->QuadraticAttenuation != 0.0) - key->unit[i].light_attenuated = 1; - } - } - - if (check_active_shininess(ctx, key, 0)) { - key->material_shininess_is_zero = 0; - } - else if (key->light_twoside && - check_active_shininess(ctx, key, 1)) { - key->material_shininess_is_zero = 0; - } - else { - key->material_shininess_is_zero = 1; - } - } - - if (ctx->Transform.Normalize) - key->normalize = 1; - - if (ctx->Transform.RescaleNormals) - key->rescale_normals = 1; - - if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) - key->fog_source_is_depth = 1; - - if (ctx->Point._Attenuated) - key->point_attenuated = 1; - -#if FEATURE_point_size_array - if (ctx->Array.ArrayObj->PointSize.Enabled) - key->point_array = 1; -#endif - - if (ctx->Texture._TexGenEnabled || - ctx->Texture._TexMatEnabled || - ctx->Texture._EnabledUnits) - key->texture_enabled_global = 1; - - for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; - - if (texUnit->_ReallyEnabled) - key->unit[i].texunit_really_enabled = 1; - - if (ctx->Point.PointSprite) - if (ctx->Point.CoordReplace[i]) - key->unit[i].coord_replace = 1; - - if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) - key->unit[i].texmat_enabled = 1; - - if (texUnit->TexGenEnabled) { - key->unit[i].texgen_enabled = 1; - - key->unit[i].texgen_mode0 = - translate_texgen( texUnit->TexGenEnabled & (1<<0), - texUnit->GenS.Mode ); - key->unit[i].texgen_mode1 = - translate_texgen( texUnit->TexGenEnabled & (1<<1), - texUnit->GenT.Mode ); - key->unit[i].texgen_mode2 = - translate_texgen( texUnit->TexGenEnabled & (1<<2), - texUnit->GenR.Mode ); - key->unit[i].texgen_mode3 = - translate_texgen( texUnit->TexGenEnabled & (1<<3), - texUnit->GenQ.Mode ); - } - } -} - - - -/* Very useful debugging tool - produces annotated listing of - * generated program with line/function references for each - * instruction back into this file: - */ -#define DISASSEM 0 - - -/* Use uregs to represent registers internally, translate to Mesa's - * expected formats on emit. - * - * NOTE: These are passed by value extensively in this file rather - * than as usual by pointer reference. If this disturbs you, try - * remembering they are just 32bits in size. - * - * GCC is smart enough to deal with these dword-sized structures in - * much the same way as if I had defined them as dwords and was using - * macros to access and set the fields. This is much nicer and easier - * to evolve. - */ -struct ureg { - GLuint file:4; - GLint idx:9; /* relative addressing may be negative */ - /* sizeof(idx) should == sizeof(prog_src_reg::Index) */ - GLuint negate:1; - GLuint swz:12; - GLuint pad:6; -}; - - -struct tnl_program { - const struct state_key *state; - struct gl_vertex_program *program; - GLint max_inst; /** number of instructions allocated for program */ - GLboolean mvp_with_dp4; - - GLuint temp_in_use; - GLuint temp_reserved; - - struct ureg eye_position; - struct ureg eye_position_z; - struct ureg eye_position_normalized; - struct ureg transformed_normal; - struct ureg identity; - - GLuint materials; - GLuint color_materials; -}; - - -static const struct ureg undef = { - PROGRAM_UNDEFINED, - 0, - 0, - 0, - 0 -}; - -/* Local shorthand: - */ -#define X SWIZZLE_X -#define Y SWIZZLE_Y -#define Z SWIZZLE_Z -#define W SWIZZLE_W - - -/* Construct a ureg: - */ -static struct ureg make_ureg(GLuint file, GLint idx) -{ - struct ureg reg; - reg.file = file; - reg.idx = idx; - reg.negate = 0; - reg.swz = SWIZZLE_NOOP; - reg.pad = 0; - return reg; -} - - - -static struct ureg negate( struct ureg reg ) -{ - reg.negate ^= 1; - return reg; -} - - -static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) -{ - reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), - GET_SWZ(reg.swz, y), - GET_SWZ(reg.swz, z), - GET_SWZ(reg.swz, w)); - return reg; -} - - -static struct ureg swizzle1( struct ureg reg, int x ) -{ - return swizzle(reg, x, x, x, x); -} - - -static struct ureg get_temp( struct tnl_program *p ) -{ - int bit = _mesa_ffs( ~p->temp_in_use ); - if (!bit) { - _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); - exit(1); - } - - if ((GLuint) bit > p->program->Base.NumTemporaries) - p->program->Base.NumTemporaries = bit; - - p->temp_in_use |= 1<<(bit-1); - return make_ureg(PROGRAM_TEMPORARY, bit-1); -} - - -static struct ureg reserve_temp( struct tnl_program *p ) -{ - struct ureg temp = get_temp( p ); - p->temp_reserved |= 1<temp_in_use &= ~(1<temp_in_use |= p->temp_reserved; /* can't release reserved temps */ - } -} - -static void release_temps( struct tnl_program *p ) -{ - p->temp_in_use = p->temp_reserved; -} - - -static struct ureg register_param5(struct tnl_program *p, - GLint s0, - GLint s1, - GLint s2, - GLint s3, - GLint s4) -{ - gl_state_index tokens[STATE_LENGTH]; - GLint idx; - tokens[0] = s0; - tokens[1] = s1; - tokens[2] = s2; - tokens[3] = s3; - tokens[4] = s4; - idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); - return make_ureg(PROGRAM_STATE_VAR, idx); -} - - -#define register_param1(p,s0) register_param5(p,s0,0,0,0,0) -#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) -#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) -#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) - - - -/** - * \param input one of VERT_ATTRIB_x tokens. - */ -static struct ureg register_input( struct tnl_program *p, GLuint input ) -{ - assert(input < 32); - - if (p->state->varying_vp_inputs & (1<program->Base.InputsRead |= (1<program->Base.OutputsWritten |= BITFIELD64_BIT(output); - return make_ureg(PROGRAM_OUTPUT, output); -} - - -static struct ureg register_const4f( struct tnl_program *p, - GLfloat s0, - GLfloat s1, - GLfloat s2, - GLfloat s3) -{ - GLfloat values[4]; - GLint idx; - GLuint swizzle; - values[0] = s0; - values[1] = s1; - values[2] = s2; - values[3] = s3; - idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, - &swizzle ); - ASSERT(swizzle == SWIZZLE_NOOP); - return make_ureg(PROGRAM_CONSTANT, idx); -} - -#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) -#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) -#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) -#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) - -static GLboolean is_undef( struct ureg reg ) -{ - return reg.file == PROGRAM_UNDEFINED; -} - - -static struct ureg get_identity_param( struct tnl_program *p ) -{ - if (is_undef(p->identity)) - p->identity = register_const4f(p, 0,0,0,1); - - return p->identity; -} - -static void register_matrix_param5( struct tnl_program *p, - GLint s0, /* modelview, projection, etc */ - GLint s1, /* texture matrix number */ - GLint s2, /* first row */ - GLint s3, /* last row */ - GLint s4, /* inverse, transpose, etc */ - struct ureg *matrix ) -{ - GLint i; - - /* This is a bit sad as the support is there to pull the whole - * matrix out in one go: - */ - for (i = 0; i <= s3 - s2; i++) - matrix[i] = register_param5( p, s0, s1, i, i, s4 ); -} - - -static void emit_arg( struct prog_src_register *src, - struct ureg reg ) -{ - src->File = reg.file; - src->Index = reg.idx; - src->Swizzle = reg.swz; - src->Negate = reg.negate ? NEGATE_XYZW : NEGATE_NONE; - src->Abs = 0; - src->RelAddr = 0; - /* Check that bitfield sizes aren't exceeded */ - ASSERT(src->Index == reg.idx); -} - - -static void emit_dst( struct prog_dst_register *dst, - struct ureg reg, GLuint mask ) -{ - dst->File = reg.file; - dst->Index = reg.idx; - /* allow zero as a shorthand for xyzw */ - dst->WriteMask = mask ? mask : WRITEMASK_XYZW; - dst->CondMask = COND_TR; /* always pass cond test */ - dst->CondSwizzle = SWIZZLE_NOOP; - dst->CondSrc = 0; - /* Check that bitfield sizes aren't exceeded */ - ASSERT(dst->Index == reg.idx); -} - - -static void debug_insn( struct prog_instruction *inst, const char *fn, - GLuint line ) -{ - if (DISASSEM) { - static const char *last_fn; - - if (fn != last_fn) { - last_fn = fn; - printf("%s:\n", fn); - } - - printf("%d:\t", line); - _mesa_print_instruction(inst); - } -} - - -static void emit_op3fn(struct tnl_program *p, - enum prog_opcode op, - struct ureg dest, - GLuint mask, - struct ureg src0, - struct ureg src1, - struct ureg src2, - const char *fn, - GLuint line) -{ - GLuint nr; - struct prog_instruction *inst; - - assert((GLint) p->program->Base.NumInstructions <= p->max_inst); - - if (p->program->Base.NumInstructions == p->max_inst) { - /* need to extend the program's instruction array */ - struct prog_instruction *newInst; - - /* double the size */ - p->max_inst *= 2; - - newInst = _mesa_alloc_instructions(p->max_inst); - if (!newInst) { - _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build"); - return; - } - - _mesa_copy_instructions(newInst, - p->program->Base.Instructions, - p->program->Base.NumInstructions); - - _mesa_free_instructions(p->program->Base.Instructions, - p->program->Base.NumInstructions); - - p->program->Base.Instructions = newInst; - } - - nr = p->program->Base.NumInstructions++; - - inst = &p->program->Base.Instructions[nr]; - inst->Opcode = (enum prog_opcode) op; - inst->Data = 0; - - emit_arg( &inst->SrcReg[0], src0 ); - emit_arg( &inst->SrcReg[1], src1 ); - emit_arg( &inst->SrcReg[2], src2 ); - - emit_dst( &inst->DstReg, dest, mask ); - - debug_insn(inst, fn, line); -} - - -#define emit_op3(p, op, dst, mask, src0, src1, src2) \ - emit_op3fn(p, op, dst, mask, src0, src1, src2, __FUNCTION__, __LINE__) - -#define emit_op2(p, op, dst, mask, src0, src1) \ - emit_op3fn(p, op, dst, mask, src0, src1, undef, __FUNCTION__, __LINE__) - -#define emit_op1(p, op, dst, mask, src0) \ - emit_op3fn(p, op, dst, mask, src0, undef, undef, __FUNCTION__, __LINE__) - - -static struct ureg make_temp( struct tnl_program *p, struct ureg reg ) -{ - if (reg.file == PROGRAM_TEMPORARY && - !(p->temp_reserved & (1<eye_position)) { - struct ureg pos = register_input( p, VERT_ATTRIB_POS ); - struct ureg modelview[4]; - - p->eye_position = reserve_temp(p); - - if (p->mvp_with_dp4) { - register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, - 0, modelview ); - - emit_matrix_transform_vec4(p, p->eye_position, modelview, pos); - } - else { - register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, - STATE_MATRIX_TRANSPOSE, modelview ); - - emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos); - } - } - - return p->eye_position; -} - - -static struct ureg get_eye_position_z( struct tnl_program *p ) -{ - if (!is_undef(p->eye_position)) - return swizzle1(p->eye_position, Z); - - if (is_undef(p->eye_position_z)) { - struct ureg pos = register_input( p, VERT_ATTRIB_POS ); - struct ureg modelview[4]; - - p->eye_position_z = reserve_temp(p); - - register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, - 0, modelview ); - - emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]); - } - - return p->eye_position_z; -} - - -static struct ureg get_eye_position_normalized( struct tnl_program *p ) -{ - if (is_undef(p->eye_position_normalized)) { - struct ureg eye = get_eye_position(p); - p->eye_position_normalized = reserve_temp(p); - emit_normalize_vec3(p, p->eye_position_normalized, eye); - } - - return p->eye_position_normalized; -} - - -static struct ureg get_transformed_normal( struct tnl_program *p ) -{ - if (is_undef(p->transformed_normal) && - !p->state->need_eye_coords && - !p->state->normalize && - !(p->state->need_eye_coords == p->state->rescale_normals)) - { - p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL ); - } - else if (is_undef(p->transformed_normal)) - { - struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL ); - struct ureg mvinv[3]; - struct ureg transformed_normal = reserve_temp(p); - - if (p->state->need_eye_coords) { - register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2, - STATE_MATRIX_INVTRANS, mvinv ); - - /* Transform to eye space: - */ - emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal ); - normal = transformed_normal; - } - - /* Normalize/Rescale: - */ - if (p->state->normalize) { - emit_normalize_vec3( p, transformed_normal, normal ); - normal = transformed_normal; - } - else if (p->state->need_eye_coords == p->state->rescale_normals) { - /* This is already adjusted for eye/non-eye rendering: - */ - struct ureg rescale = register_param2(p, STATE_INTERNAL, - STATE_NORMAL_SCALE); - - emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale ); - normal = transformed_normal; - } - - assert(normal.file == PROGRAM_TEMPORARY); - p->transformed_normal = normal; - } - - return p->transformed_normal; -} - - -static void build_hpos( struct tnl_program *p ) -{ - struct ureg pos = register_input( p, VERT_ATTRIB_POS ); - struct ureg hpos = register_output( p, VERT_RESULT_HPOS ); - struct ureg mvp[4]; - - if (p->mvp_with_dp4) { - register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, - 0, mvp ); - emit_matrix_transform_vec4( p, hpos, mvp, pos ); - } - else { - register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, - STATE_MATRIX_TRANSPOSE, mvp ); - emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos ); - } -} - - -static GLuint material_attrib( GLuint side, GLuint property ) -{ - return (property - STATE_AMBIENT) * 2 + side; -} - - -/** - * Get a bitmask of which material values vary on a per-vertex basis. - */ -static void set_material_flags( struct tnl_program *p ) -{ - p->color_materials = 0; - p->materials = 0; - - if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) { - p->materials = - p->color_materials = p->state->light_color_material_mask; - } - - p->materials |= (p->state->varying_vp_inputs >> 16); -} - - -static struct ureg get_material( struct tnl_program *p, GLuint side, - GLuint property ) -{ - GLuint attrib = material_attrib(side, property); - - if (p->color_materials & (1<materials & (1<materials & SCENE_COLOR_BITS(side)) { - struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT); - struct ureg material_emission = get_material(p, side, STATE_EMISSION); - struct ureg material_ambient = get_material(p, side, STATE_AMBIENT); - struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE); - struct ureg tmp = make_temp(p, material_diffuse); - emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient, - material_ambient, material_emission); - return tmp; - } - else - return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side ); -} - - -static struct ureg get_lightprod( struct tnl_program *p, GLuint light, - GLuint side, GLuint property ) -{ - GLuint attrib = material_attrib(side, property); - if (p->materials & (1<state->unit[i].light_spotcutoff_is_180) { - struct ureg spot_dir_norm = register_param3(p, STATE_INTERNAL, - STATE_LIGHT_SPOT_DIR_NORMALIZED, i); - struct ureg spot = get_temp(p); - struct ureg slt = get_temp(p); - - emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm); - emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot); - emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W)); - emit_op2(p, OPCODE_MUL, att, 0, slt, spot); - - release_temp(p, spot); - release_temp(p, slt); - } - - /* Calculate distance attenuation: - */ - if (p->state->unit[i].light_attenuated) { - /* 1/d,d,d,1/d */ - emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist); - /* 1,d,d*d,1/d */ - emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y)); - /* 1/dist-atten */ - emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist); - - if (!p->state->unit[i].light_spotcutoff_is_180) { - /* dist-atten */ - emit_op1(p, OPCODE_RCP, dist, 0, dist); - /* spot-atten * dist-atten */ - emit_op2(p, OPCODE_MUL, att, 0, dist, att); - } - else { - /* dist-atten */ - emit_op1(p, OPCODE_RCP, att, 0, dist); - } - } - - return att; -} - - -/** - * Compute: - * lit.y = MAX(0, dots.x) - * lit.z = SLT(0, dots.x) - */ -static void emit_degenerate_lit( struct tnl_program *p, - struct ureg lit, - struct ureg dots ) -{ - struct ureg id = get_identity_param(p); /* id = {0,0,0,1} */ - - /* Note that lit.x & lit.w will not be examined. Note also that - * dots.xyzw == dots.xxxx. - */ - - /* MAX lit, id, dots; - */ - emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots); - - /* result[2] = (in > 0 ? 1 : 0) - * SLT lit.z, id.z, dots; # lit.z = (0 < dots.z) ? 1 : 0 - */ - emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots); -} - - -/* Need to add some addtional parameters to allow lighting in object - * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye - * space lighting. - */ -static void build_lighting( struct tnl_program *p ) -{ - const GLboolean twoside = p->state->light_twoside; - const GLboolean separate = p->state->separate_specular; - GLuint nr_lights = 0, count = 0; - struct ureg normal = get_transformed_normal(p); - struct ureg lit = get_temp(p); - struct ureg dots = get_temp(p); - struct ureg _col0 = undef, _col1 = undef; - struct ureg _bfc0 = undef, _bfc1 = undef; - GLuint i; - - /* - * NOTE: - * dots.x = dot(normal, VPpli) - * dots.y = dot(normal, halfAngle) - * dots.z = back.shininess - * dots.w = front.shininess - */ - - for (i = 0; i < MAX_LIGHTS; i++) - if (p->state->unit[i].light_enabled) - nr_lights++; - - set_material_flags(p); - - { - if (!p->state->material_shininess_is_zero) { - struct ureg shininess = get_material(p, 0, STATE_SHININESS); - emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X)); - release_temp(p, shininess); - } - - _col0 = make_temp(p, get_scenecolor(p, 0)); - if (separate) - _col1 = make_temp(p, get_identity_param(p)); - else - _col1 = _col0; - } - - if (twoside) { - if (!p->state->material_shininess_is_zero) { - /* Note that we negate the back-face specular exponent here. - * The negation will be un-done later in the back-face code below. - */ - struct ureg shininess = get_material(p, 1, STATE_SHININESS); - emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z, - negate(swizzle1(shininess,X))); - release_temp(p, shininess); - } - - _bfc0 = make_temp(p, get_scenecolor(p, 1)); - if (separate) - _bfc1 = make_temp(p, get_identity_param(p)); - else - _bfc1 = _bfc0; - } - - /* If no lights, still need to emit the scenecolor. - */ - { - struct ureg res0 = register_output( p, VERT_RESULT_COL0 ); - emit_op1(p, OPCODE_MOV, res0, 0, _col0); - } - - if (separate) { - struct ureg res1 = register_output( p, VERT_RESULT_COL1 ); - emit_op1(p, OPCODE_MOV, res1, 0, _col1); - } - - if (twoside) { - struct ureg res0 = register_output( p, VERT_RESULT_BFC0 ); - emit_op1(p, OPCODE_MOV, res0, 0, _bfc0); - } - - if (twoside && separate) { - struct ureg res1 = register_output( p, VERT_RESULT_BFC1 ); - emit_op1(p, OPCODE_MOV, res1, 0, _bfc1); - } - - if (nr_lights == 0) { - release_temps(p); - return; - } - - for (i = 0; i < MAX_LIGHTS; i++) { - if (p->state->unit[i].light_enabled) { - struct ureg half = undef; - struct ureg att = undef, VPpli = undef; - - count++; - - if (p->state->unit[i].light_eyepos3_is_zero) { - /* Can used precomputed constants in this case. - * Attenuation never applies to infinite lights. - */ - VPpli = register_param3(p, STATE_INTERNAL, - STATE_LIGHT_POSITION_NORMALIZED, i); - - if (!p->state->material_shininess_is_zero) { - if (p->state->light_local_viewer) { - struct ureg eye_hat = get_eye_position_normalized(p); - half = get_temp(p); - emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); - emit_normalize_vec3(p, half, half); - } - else { - half = register_param3(p, STATE_INTERNAL, - STATE_LIGHT_HALF_VECTOR, i); - } - } - } - else { - struct ureg Ppli = register_param3(p, STATE_INTERNAL, - STATE_LIGHT_POSITION, i); - struct ureg V = get_eye_position(p); - struct ureg dist = get_temp(p); - - VPpli = get_temp(p); - - /* Calculate VPpli vector - */ - emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V); - - /* Normalize VPpli. The dist value also used in - * attenuation below. - */ - emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli); - emit_op1(p, OPCODE_RSQ, dist, 0, dist); - emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist); - - /* Calculate attenuation: - */ - if (!p->state->unit[i].light_spotcutoff_is_180 || - p->state->unit[i].light_attenuated) { - att = calculate_light_attenuation(p, i, VPpli, dist); - } - - /* Calculate viewer direction, or use infinite viewer: - */ - if (!p->state->material_shininess_is_zero) { - half = get_temp(p); - - if (p->state->light_local_viewer) { - struct ureg eye_hat = get_eye_position_normalized(p); - emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); - } - else { - struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z); - emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir); - } - - emit_normalize_vec3(p, half, half); - } - - release_temp(p, dist); - } - - /* Calculate dot products: - */ - if (p->state->material_shininess_is_zero) { - emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli); - } - else { - emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli); - emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half); - } - - /* Front face lighting: - */ - { - struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT); - struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE); - struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR); - struct ureg res0, res1; - GLuint mask0, mask1; - - if (count == nr_lights) { - if (separate) { - mask0 = WRITEMASK_XYZ; - mask1 = WRITEMASK_XYZ; - res0 = register_output( p, VERT_RESULT_COL0 ); - res1 = register_output( p, VERT_RESULT_COL1 ); - } - else { - mask0 = 0; - mask1 = WRITEMASK_XYZ; - res0 = _col0; - res1 = register_output( p, VERT_RESULT_COL0 ); - } - } - else { - mask0 = 0; - mask1 = 0; - res0 = _col0; - res1 = _col1; - } - - if (!is_undef(att)) { - /* light is attenuated by distance */ - emit_op1(p, OPCODE_LIT, lit, 0, dots); - emit_op2(p, OPCODE_MUL, lit, 0, lit, att); - emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0); - } - else if (!p->state->material_shininess_is_zero) { - /* there's a non-zero specular term */ - emit_op1(p, OPCODE_LIT, lit, 0, dots); - emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); - } - else { - /* no attenutation, no specular */ - emit_degenerate_lit(p, lit, dots); - emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); - } - - emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0); - emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1); - - release_temp(p, ambient); - release_temp(p, diffuse); - release_temp(p, specular); - } - - /* Back face lighting: - */ - if (twoside) { - struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT); - struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE); - struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR); - struct ureg res0, res1; - GLuint mask0, mask1; - - if (count == nr_lights) { - if (separate) { - mask0 = WRITEMASK_XYZ; - mask1 = WRITEMASK_XYZ; - res0 = register_output( p, VERT_RESULT_BFC0 ); - res1 = register_output( p, VERT_RESULT_BFC1 ); - } - else { - mask0 = 0; - mask1 = WRITEMASK_XYZ; - res0 = _bfc0; - res1 = register_output( p, VERT_RESULT_BFC0 ); - } - } - else { - res0 = _bfc0; - res1 = _bfc1; - mask0 = 0; - mask1 = 0; - } - - /* For the back face we need to negate the X and Y component - * dot products. dots.Z has the negated back-face specular - * exponent. We swizzle that into the W position. This - * negation makes the back-face specular term positive again. - */ - dots = negate(swizzle(dots,X,Y,W,Z)); - - if (!is_undef(att)) { - emit_op1(p, OPCODE_LIT, lit, 0, dots); - emit_op2(p, OPCODE_MUL, lit, 0, lit, att); - emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0); - } - else if (!p->state->material_shininess_is_zero) { - emit_op1(p, OPCODE_LIT, lit, 0, dots); - emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); /**/ - } - else { - emit_degenerate_lit(p, lit, dots); - emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); - } - - emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0); - emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1); - /* restore dots to its original state for subsequent lights - * by negating and swizzling again. - */ - dots = negate(swizzle(dots,X,Y,W,Z)); - - release_temp(p, ambient); - release_temp(p, diffuse); - release_temp(p, specular); - } - - release_temp(p, half); - release_temp(p, VPpli); - release_temp(p, att); - } - } - - release_temps( p ); -} - - -static void build_fog( struct tnl_program *p ) -{ - struct ureg fog = register_output(p, VERT_RESULT_FOGC); - struct ureg input; - - if (p->state->fog_source_is_depth) { - input = get_eye_position_z(p); - } - else { - input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X); - } - - /* result.fog = {abs(f),0,0,1}; */ - emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input); - emit_op1(p, OPCODE_MOV, fog, WRITEMASK_YZW, get_identity_param(p)); -} - - -static void build_reflect_texgen( struct tnl_program *p, - struct ureg dest, - GLuint writemask ) -{ - struct ureg normal = get_transformed_normal(p); - struct ureg eye_hat = get_eye_position_normalized(p); - struct ureg tmp = get_temp(p); - - /* n.u */ - emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); - /* 2n.u */ - emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); - /* (-2n.u)n + u */ - emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat); - - release_temp(p, tmp); -} - - -static void build_sphere_texgen( struct tnl_program *p, - struct ureg dest, - GLuint writemask ) -{ - struct ureg normal = get_transformed_normal(p); - struct ureg eye_hat = get_eye_position_normalized(p); - struct ureg tmp = get_temp(p); - struct ureg half = register_scalar_const(p, .5); - struct ureg r = get_temp(p); - struct ureg inv_m = get_temp(p); - struct ureg id = get_identity_param(p); - - /* Could share the above calculations, but it would be - * a fairly odd state for someone to set (both sphere and - * reflection active for different texture coordinate - * components. Of course - if two texture units enable - * reflect and/or sphere, things start to tilt in favour - * of seperating this out: - */ - - /* n.u */ - emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); - /* 2n.u */ - emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); - /* (-2n.u)n + u */ - emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); - /* r + 0,0,1 */ - emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); - /* rx^2 + ry^2 + (rz+1)^2 */ - emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp); - /* 2/m */ - emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); - /* 1/m */ - emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half); - /* r/m + 1/2 */ - emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half); - - release_temp(p, tmp); - release_temp(p, r); - release_temp(p, inv_m); -} - - -static void build_texture_transform( struct tnl_program *p ) -{ - GLuint i, j; - - for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { - - if (!(p->state->fragprog_inputs_read & FRAG_BIT_TEX(i))) - continue; - - if (p->state->unit[i].coord_replace) - continue; - - if (p->state->unit[i].texgen_enabled || - p->state->unit[i].texmat_enabled) { - - GLuint texmat_enabled = p->state->unit[i].texmat_enabled; - struct ureg out = register_output(p, VERT_RESULT_TEX0 + i); - struct ureg out_texgen = undef; - - if (p->state->unit[i].texgen_enabled) { - GLuint copy_mask = 0; - GLuint sphere_mask = 0; - GLuint reflect_mask = 0; - GLuint normal_mask = 0; - GLuint modes[4]; - - if (texmat_enabled) - out_texgen = get_temp(p); - else - out_texgen = out; - - modes[0] = p->state->unit[i].texgen_mode0; - modes[1] = p->state->unit[i].texgen_mode1; - modes[2] = p->state->unit[i].texgen_mode2; - modes[3] = p->state->unit[i].texgen_mode3; - - for (j = 0; j < 4; j++) { - switch (modes[j]) { - case TXG_OBJ_LINEAR: { - struct ureg obj = register_input(p, VERT_ATTRIB_POS); - struct ureg plane = - register_param3(p, STATE_TEXGEN, i, - STATE_TEXGEN_OBJECT_S + j); - - emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, - obj, plane ); - break; - } - case TXG_EYE_LINEAR: { - struct ureg eye = get_eye_position(p); - struct ureg plane = - register_param3(p, STATE_TEXGEN, i, - STATE_TEXGEN_EYE_S + j); - - emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, - eye, plane ); - break; - } - case TXG_SPHERE_MAP: - sphere_mask |= WRITEMASK_X << j; - break; - case TXG_REFLECTION_MAP: - reflect_mask |= WRITEMASK_X << j; - break; - case TXG_NORMAL_MAP: - normal_mask |= WRITEMASK_X << j; - break; - case TXG_NONE: - copy_mask |= WRITEMASK_X << j; - } - } - - if (sphere_mask) { - build_sphere_texgen(p, out_texgen, sphere_mask); - } - - if (reflect_mask) { - build_reflect_texgen(p, out_texgen, reflect_mask); - } - - if (normal_mask) { - struct ureg normal = get_transformed_normal(p); - emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal ); - } - - if (copy_mask) { - struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i); - emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in ); - } - } - - if (texmat_enabled) { - struct ureg texmat[4]; - struct ureg in = (!is_undef(out_texgen) ? - out_texgen : - register_input(p, VERT_ATTRIB_TEX0+i)); - if (p->mvp_with_dp4) { - register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, - 0, texmat ); - emit_matrix_transform_vec4( p, out, texmat, in ); - } - else { - register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, - STATE_MATRIX_TRANSPOSE, texmat ); - emit_transpose_matrix_transform_vec4( p, out, texmat, in ); - } - } - - release_temps(p); - } - else { - emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i); - } - } -} - - -/** - * Point size attenuation computation. - */ -static void build_atten_pointsize( struct tnl_program *p ) -{ - struct ureg eye = get_eye_position_z(p); - struct ureg state_size = register_param2(p, STATE_INTERNAL, STATE_POINT_SIZE_CLAMPED); - struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION); - struct ureg out = register_output(p, VERT_RESULT_PSIZ); - struct ureg ut = get_temp(p); - - /* dist = |eyez| */ - emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z)); - /* p1 + dist * (p2 + dist * p3); */ - emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), - swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y)); - emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), - ut, swizzle1(state_attenuation, X)); - - /* 1 / sqrt(factor) */ - emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut ); - -#if 0 - /* out = pointSize / sqrt(factor) */ - emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size); -#else - /* this is a good place to clamp the point size since there's likely - * no hardware registers to clamp point size at rasterization time. - */ - emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size); - emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y)); - emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z)); -#endif - - release_temp(p, ut); -} - - -/** - * Pass-though per-vertex point size, from user's point size array. - */ -static void build_array_pointsize( struct tnl_program *p ) -{ - struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE); - struct ureg out = register_output(p, VERT_RESULT_PSIZ); - emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in); -} - - -static void build_tnl_program( struct tnl_program *p ) -{ - /* Emit the program, starting with modelviewproject: - */ - build_hpos(p); - - /* Lighting calculations: - */ - if (p->state->fragprog_inputs_read & (FRAG_BIT_COL0|FRAG_BIT_COL1)) { - if (p->state->light_global_enabled) - build_lighting(p); - else { - if (p->state->fragprog_inputs_read & FRAG_BIT_COL0) - emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0); - - if (p->state->fragprog_inputs_read & FRAG_BIT_COL1) - emit_passthrough(p, VERT_ATTRIB_COLOR1, VERT_RESULT_COL1); - } - } - - if (p->state->fragprog_inputs_read & FRAG_BIT_FOGC) - build_fog(p); - - if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY) - build_texture_transform(p); - - if (p->state->point_attenuated) - build_atten_pointsize(p); - else if (p->state->point_array) - build_array_pointsize(p); - - /* Finish up: - */ - emit_op1(p, OPCODE_END, undef, 0, undef); - - /* Disassemble: - */ - if (DISASSEM) { - printf ("\n"); - } -} - - -static void -create_new_program( const struct state_key *key, - struct gl_vertex_program *program, - GLboolean mvp_with_dp4, - GLuint max_temps) -{ - struct tnl_program p; - - memset(&p, 0, sizeof(p)); - p.state = key; - p.program = program; - p.eye_position = undef; - p.eye_position_z = undef; - p.eye_position_normalized = undef; - p.transformed_normal = undef; - p.identity = undef; - p.temp_in_use = 0; - p.mvp_with_dp4 = mvp_with_dp4; - - if (max_temps >= sizeof(int) * 8) - p.temp_reserved = 0; - else - p.temp_reserved = ~((1<Base.Instructions = _mesa_alloc_instructions(p.max_inst); - p.program->Base.String = NULL; - p.program->Base.NumInstructions = - p.program->Base.NumTemporaries = - p.program->Base.NumParameters = - p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; - p.program->Base.Parameters = _mesa_new_parameter_list(); - p.program->Base.InputsRead = 0; - p.program->Base.OutputsWritten = 0; - - build_tnl_program( &p ); -} - - -/** - * Return a vertex program which implements the current fixed-function - * transform/lighting/texgen operations. - * XXX move this into core mesa (main/) - */ -struct gl_vertex_program * -_mesa_get_fixed_func_vertex_program(struct gl_context *ctx) -{ - struct gl_vertex_program *prog; - struct state_key key; - - /* Grab all the relevent state and put it in a single structure: - */ - make_state_key(ctx, &key); - - /* Look for an already-prepared program for this state: - */ - prog = (struct gl_vertex_program *) - _mesa_search_program_cache(ctx->VertexProgram.Cache, &key, sizeof(key)); - - if (!prog) { - /* OK, we'll have to build a new one */ - if (0) - printf("Build new TNL program\n"); - - prog = (struct gl_vertex_program *) - ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); - if (!prog) - return NULL; - - create_new_program( &key, prog, - ctx->mvp_with_dp4, - ctx->Const.VertexProgram.MaxTemps ); - -#if 0 - if (ctx->Driver.ProgramStringNotify) - ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB, - &prog->Base ); -#endif - _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, - &key, sizeof(key), &prog->Base); - } - - return prog; -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file ffvertex_prog.c + * + * Create a vertex program to execute the current fixed function T&L pipeline. + * \author Keith Whitwell + */ + + +#include "main/glheader.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "main/enums.h" +#include "main/ffvertex_prog.h" +#include "program/program.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" + + +/** Max of number of lights and texture coord units */ +#define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS) + +struct state_key { + unsigned light_color_material_mask:12; + unsigned light_global_enabled:1; + unsigned light_local_viewer:1; + unsigned light_twoside:1; + unsigned material_shininess_is_zero:1; + unsigned need_eye_coords:1; + unsigned normalize:1; + unsigned rescale_normals:1; + + unsigned fog_source_is_depth:1; + unsigned separate_specular:1; + unsigned point_attenuated:1; + unsigned point_array:1; + unsigned texture_enabled_global:1; + unsigned fragprog_inputs_read:12; + + unsigned varying_vp_inputs; + + struct { + unsigned light_enabled:1; + unsigned light_eyepos3_is_zero:1; + unsigned light_spotcutoff_is_180:1; + unsigned light_attenuated:1; + unsigned texunit_really_enabled:1; + unsigned texmat_enabled:1; + unsigned coord_replace:1; + unsigned texgen_enabled:4; + unsigned texgen_mode0:4; + unsigned texgen_mode1:4; + unsigned texgen_mode2:4; + unsigned texgen_mode3:4; + } unit[NUM_UNITS]; +}; + + +#define TXG_NONE 0 +#define TXG_OBJ_LINEAR 1 +#define TXG_EYE_LINEAR 2 +#define TXG_SPHERE_MAP 3 +#define TXG_REFLECTION_MAP 4 +#define TXG_NORMAL_MAP 5 + +static GLuint translate_texgen( GLboolean enabled, GLenum mode ) +{ + if (!enabled) + return TXG_NONE; + + switch (mode) { + case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR; + case GL_EYE_LINEAR: return TXG_EYE_LINEAR; + case GL_SPHERE_MAP: return TXG_SPHERE_MAP; + case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP; + case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP; + default: return TXG_NONE; + } +} + + + +static GLboolean check_active_shininess( struct gl_context *ctx, + const struct state_key *key, + GLuint side ) +{ + GLuint bit = 1 << (MAT_ATTRIB_FRONT_SHININESS + side); + + if ((key->varying_vp_inputs & VERT_BIT_COLOR0) && + (key->light_color_material_mask & bit)) + return GL_TRUE; + + if (key->varying_vp_inputs & (bit << 16)) + return GL_TRUE; + + if (ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS + side][0] != 0.0F) + return GL_TRUE; + + return GL_FALSE; +} + + +static void make_state_key( struct gl_context *ctx, struct state_key *key ) +{ + const struct gl_fragment_program *fp; + GLuint i; + + memset(key, 0, sizeof(struct state_key)); + fp = ctx->FragmentProgram._Current; + + /* This now relies on texenvprogram.c being active: + */ + assert(fp); + + key->need_eye_coords = ctx->_NeedEyeCoords; + + key->fragprog_inputs_read = fp->Base.InputsRead; + key->varying_vp_inputs = ctx->varying_vp_inputs; + + if (ctx->RenderMode == GL_FEEDBACK) { + /* make sure the vertprog emits color and tex0 */ + key->fragprog_inputs_read |= (FRAG_BIT_COL0 | FRAG_BIT_TEX0); + } + + key->separate_specular = (ctx->Light.Model.ColorControl == + GL_SEPARATE_SPECULAR_COLOR); + + if (ctx->Light.Enabled) { + key->light_global_enabled = 1; + + if (ctx->Light.Model.LocalViewer) + key->light_local_viewer = 1; + + if (ctx->Light.Model.TwoSide) + key->light_twoside = 1; + + if (ctx->Light.ColorMaterialEnabled) { + key->light_color_material_mask = ctx->Light.ColorMaterialBitmask; + } + + for (i = 0; i < MAX_LIGHTS; i++) { + struct gl_light *light = &ctx->Light.Light[i]; + + if (light->Enabled) { + key->unit[i].light_enabled = 1; + + if (light->EyePosition[3] == 0.0) + key->unit[i].light_eyepos3_is_zero = 1; + + if (light->SpotCutoff == 180.0) + key->unit[i].light_spotcutoff_is_180 = 1; + + if (light->ConstantAttenuation != 1.0 || + light->LinearAttenuation != 0.0 || + light->QuadraticAttenuation != 0.0) + key->unit[i].light_attenuated = 1; + } + } + + if (check_active_shininess(ctx, key, 0)) { + key->material_shininess_is_zero = 0; + } + else if (key->light_twoside && + check_active_shininess(ctx, key, 1)) { + key->material_shininess_is_zero = 0; + } + else { + key->material_shininess_is_zero = 1; + } + } + + if (ctx->Transform.Normalize) + key->normalize = 1; + + if (ctx->Transform.RescaleNormals) + key->rescale_normals = 1; + + if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) + key->fog_source_is_depth = 1; + + if (ctx->Point._Attenuated) + key->point_attenuated = 1; + +#if FEATURE_point_size_array + if (ctx->Array.ArrayObj->PointSize.Enabled) + key->point_array = 1; +#endif + + if (ctx->Texture._TexGenEnabled || + ctx->Texture._TexMatEnabled || + ctx->Texture._EnabledUnits) + key->texture_enabled_global = 1; + + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; + + if (texUnit->_ReallyEnabled) + key->unit[i].texunit_really_enabled = 1; + + if (ctx->Point.PointSprite) + if (ctx->Point.CoordReplace[i]) + key->unit[i].coord_replace = 1; + + if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) + key->unit[i].texmat_enabled = 1; + + if (texUnit->TexGenEnabled) { + key->unit[i].texgen_enabled = 1; + + key->unit[i].texgen_mode0 = + translate_texgen( texUnit->TexGenEnabled & (1<<0), + texUnit->GenS.Mode ); + key->unit[i].texgen_mode1 = + translate_texgen( texUnit->TexGenEnabled & (1<<1), + texUnit->GenT.Mode ); + key->unit[i].texgen_mode2 = + translate_texgen( texUnit->TexGenEnabled & (1<<2), + texUnit->GenR.Mode ); + key->unit[i].texgen_mode3 = + translate_texgen( texUnit->TexGenEnabled & (1<<3), + texUnit->GenQ.Mode ); + } + } +} + + + +/* Very useful debugging tool - produces annotated listing of + * generated program with line/function references for each + * instruction back into this file: + */ +#define DISASSEM 0 + + +/* Use uregs to represent registers internally, translate to Mesa's + * expected formats on emit. + * + * NOTE: These are passed by value extensively in this file rather + * than as usual by pointer reference. If this disturbs you, try + * remembering they are just 32bits in size. + * + * GCC is smart enough to deal with these dword-sized structures in + * much the same way as if I had defined them as dwords and was using + * macros to access and set the fields. This is much nicer and easier + * to evolve. + */ +struct ureg { + GLuint file:4; + GLint idx:9; /* relative addressing may be negative */ + /* sizeof(idx) should == sizeof(prog_src_reg::Index) */ + GLuint negate:1; + GLuint swz:12; + GLuint pad:6; +}; + + +struct tnl_program { + const struct state_key *state; + struct gl_vertex_program *program; + GLint max_inst; /** number of instructions allocated for program */ + GLboolean mvp_with_dp4; + + GLuint temp_in_use; + GLuint temp_reserved; + + struct ureg eye_position; + struct ureg eye_position_z; + struct ureg eye_position_normalized; + struct ureg transformed_normal; + struct ureg identity; + + GLuint materials; + GLuint color_materials; +}; + + +static const struct ureg undef = { + PROGRAM_UNDEFINED, + 0, + 0, + 0, + 0 +}; + +/* Local shorthand: + */ +#define X SWIZZLE_X +#define Y SWIZZLE_Y +#define Z SWIZZLE_Z +#define W SWIZZLE_W + + +/* Construct a ureg: + */ +static struct ureg make_ureg(GLuint file, GLint idx) +{ + struct ureg reg; + reg.file = file; + reg.idx = idx; + reg.negate = 0; + reg.swz = SWIZZLE_NOOP; + reg.pad = 0; + return reg; +} + + + +static struct ureg negate( struct ureg reg ) +{ + reg.negate ^= 1; + return reg; +} + + +static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) +{ + reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), + GET_SWZ(reg.swz, y), + GET_SWZ(reg.swz, z), + GET_SWZ(reg.swz, w)); + return reg; +} + + +static struct ureg swizzle1( struct ureg reg, int x ) +{ + return swizzle(reg, x, x, x, x); +} + + +static struct ureg get_temp( struct tnl_program *p ) +{ + int bit = _mesa_ffs( ~p->temp_in_use ); + if (!bit) { + _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); + exit(1); + } + + if ((GLuint) bit > p->program->Base.NumTemporaries) + p->program->Base.NumTemporaries = bit; + + p->temp_in_use |= 1<<(bit-1); + return make_ureg(PROGRAM_TEMPORARY, bit-1); +} + + +static struct ureg reserve_temp( struct tnl_program *p ) +{ + struct ureg temp = get_temp( p ); + p->temp_reserved |= 1<temp_in_use &= ~(1<temp_in_use |= p->temp_reserved; /* can't release reserved temps */ + } +} + +static void release_temps( struct tnl_program *p ) +{ + p->temp_in_use = p->temp_reserved; +} + + +static struct ureg register_param5(struct tnl_program *p, + GLint s0, + GLint s1, + GLint s2, + GLint s3, + GLint s4) +{ + gl_state_index tokens[STATE_LENGTH]; + GLint idx; + tokens[0] = s0; + tokens[1] = s1; + tokens[2] = s2; + tokens[3] = s3; + tokens[4] = s4; + idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); + return make_ureg(PROGRAM_STATE_VAR, idx); +} + + +#define register_param1(p,s0) register_param5(p,s0,0,0,0,0) +#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) +#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) +#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) + + + +/** + * \param input one of VERT_ATTRIB_x tokens. + */ +static struct ureg register_input( struct tnl_program *p, GLuint input ) +{ + assert(input < 32); + + if (p->state->varying_vp_inputs & (1<program->Base.InputsRead |= (1<program->Base.OutputsWritten |= BITFIELD64_BIT(output); + return make_ureg(PROGRAM_OUTPUT, output); +} + + +static struct ureg register_const4f( struct tnl_program *p, + GLfloat s0, + GLfloat s1, + GLfloat s2, + GLfloat s3) +{ + gl_constant_value values[4]; + GLint idx; + GLuint swizzle; + values[0].f = s0; + values[1].f = s1; + values[2].f = s2; + values[3].f = s3; + idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, + &swizzle ); + ASSERT(swizzle == SWIZZLE_NOOP); + return make_ureg(PROGRAM_CONSTANT, idx); +} + +#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) +#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) +#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) +#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) + +static GLboolean is_undef( struct ureg reg ) +{ + return reg.file == PROGRAM_UNDEFINED; +} + + +static struct ureg get_identity_param( struct tnl_program *p ) +{ + if (is_undef(p->identity)) + p->identity = register_const4f(p, 0,0,0,1); + + return p->identity; +} + +static void register_matrix_param5( struct tnl_program *p, + GLint s0, /* modelview, projection, etc */ + GLint s1, /* texture matrix number */ + GLint s2, /* first row */ + GLint s3, /* last row */ + GLint s4, /* inverse, transpose, etc */ + struct ureg *matrix ) +{ + GLint i; + + /* This is a bit sad as the support is there to pull the whole + * matrix out in one go: + */ + for (i = 0; i <= s3 - s2; i++) + matrix[i] = register_param5( p, s0, s1, i, i, s4 ); +} + + +static void emit_arg( struct prog_src_register *src, + struct ureg reg ) +{ + src->File = reg.file; + src->Index = reg.idx; + src->Swizzle = reg.swz; + src->Negate = reg.negate ? NEGATE_XYZW : NEGATE_NONE; + src->Abs = 0; + src->RelAddr = 0; + /* Check that bitfield sizes aren't exceeded */ + ASSERT(src->Index == reg.idx); +} + + +static void emit_dst( struct prog_dst_register *dst, + struct ureg reg, GLuint mask ) +{ + dst->File = reg.file; + dst->Index = reg.idx; + /* allow zero as a shorthand for xyzw */ + dst->WriteMask = mask ? mask : WRITEMASK_XYZW; + dst->CondMask = COND_TR; /* always pass cond test */ + dst->CondSwizzle = SWIZZLE_NOOP; + dst->CondSrc = 0; + /* Check that bitfield sizes aren't exceeded */ + ASSERT(dst->Index == reg.idx); +} + + +static void debug_insn( struct prog_instruction *inst, const char *fn, + GLuint line ) +{ + if (DISASSEM) { + static const char *last_fn; + + if (fn != last_fn) { + last_fn = fn; + printf("%s:\n", fn); + } + + printf("%d:\t", line); + _mesa_print_instruction(inst); + } +} + + +static void emit_op3fn(struct tnl_program *p, + enum prog_opcode op, + struct ureg dest, + GLuint mask, + struct ureg src0, + struct ureg src1, + struct ureg src2, + const char *fn, + GLuint line) +{ + GLuint nr; + struct prog_instruction *inst; + + assert((GLint) p->program->Base.NumInstructions <= p->max_inst); + + if (p->program->Base.NumInstructions == p->max_inst) { + /* need to extend the program's instruction array */ + struct prog_instruction *newInst; + + /* double the size */ + p->max_inst *= 2; + + newInst = _mesa_alloc_instructions(p->max_inst); + if (!newInst) { + _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build"); + return; + } + + _mesa_copy_instructions(newInst, + p->program->Base.Instructions, + p->program->Base.NumInstructions); + + _mesa_free_instructions(p->program->Base.Instructions, + p->program->Base.NumInstructions); + + p->program->Base.Instructions = newInst; + } + + nr = p->program->Base.NumInstructions++; + + inst = &p->program->Base.Instructions[nr]; + inst->Opcode = (enum prog_opcode) op; + inst->Data = 0; + + emit_arg( &inst->SrcReg[0], src0 ); + emit_arg( &inst->SrcReg[1], src1 ); + emit_arg( &inst->SrcReg[2], src2 ); + + emit_dst( &inst->DstReg, dest, mask ); + + debug_insn(inst, fn, line); +} + + +#define emit_op3(p, op, dst, mask, src0, src1, src2) \ + emit_op3fn(p, op, dst, mask, src0, src1, src2, __FUNCTION__, __LINE__) + +#define emit_op2(p, op, dst, mask, src0, src1) \ + emit_op3fn(p, op, dst, mask, src0, src1, undef, __FUNCTION__, __LINE__) + +#define emit_op1(p, op, dst, mask, src0) \ + emit_op3fn(p, op, dst, mask, src0, undef, undef, __FUNCTION__, __LINE__) + + +static struct ureg make_temp( struct tnl_program *p, struct ureg reg ) +{ + if (reg.file == PROGRAM_TEMPORARY && + !(p->temp_reserved & (1<eye_position)) { + struct ureg pos = register_input( p, VERT_ATTRIB_POS ); + struct ureg modelview[4]; + + p->eye_position = reserve_temp(p); + + if (p->mvp_with_dp4) { + register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, + 0, modelview ); + + emit_matrix_transform_vec4(p, p->eye_position, modelview, pos); + } + else { + register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, + STATE_MATRIX_TRANSPOSE, modelview ); + + emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos); + } + } + + return p->eye_position; +} + + +static struct ureg get_eye_position_z( struct tnl_program *p ) +{ + if (!is_undef(p->eye_position)) + return swizzle1(p->eye_position, Z); + + if (is_undef(p->eye_position_z)) { + struct ureg pos = register_input( p, VERT_ATTRIB_POS ); + struct ureg modelview[4]; + + p->eye_position_z = reserve_temp(p); + + register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, + 0, modelview ); + + emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]); + } + + return p->eye_position_z; +} + + +static struct ureg get_eye_position_normalized( struct tnl_program *p ) +{ + if (is_undef(p->eye_position_normalized)) { + struct ureg eye = get_eye_position(p); + p->eye_position_normalized = reserve_temp(p); + emit_normalize_vec3(p, p->eye_position_normalized, eye); + } + + return p->eye_position_normalized; +} + + +static struct ureg get_transformed_normal( struct tnl_program *p ) +{ + if (is_undef(p->transformed_normal) && + !p->state->need_eye_coords && + !p->state->normalize && + !(p->state->need_eye_coords == p->state->rescale_normals)) + { + p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL ); + } + else if (is_undef(p->transformed_normal)) + { + struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL ); + struct ureg mvinv[3]; + struct ureg transformed_normal = reserve_temp(p); + + if (p->state->need_eye_coords) { + register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2, + STATE_MATRIX_INVTRANS, mvinv ); + + /* Transform to eye space: + */ + emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal ); + normal = transformed_normal; + } + + /* Normalize/Rescale: + */ + if (p->state->normalize) { + emit_normalize_vec3( p, transformed_normal, normal ); + normal = transformed_normal; + } + else if (p->state->need_eye_coords == p->state->rescale_normals) { + /* This is already adjusted for eye/non-eye rendering: + */ + struct ureg rescale = register_param2(p, STATE_INTERNAL, + STATE_NORMAL_SCALE); + + emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale ); + normal = transformed_normal; + } + + assert(normal.file == PROGRAM_TEMPORARY); + p->transformed_normal = normal; + } + + return p->transformed_normal; +} + + +static void build_hpos( struct tnl_program *p ) +{ + struct ureg pos = register_input( p, VERT_ATTRIB_POS ); + struct ureg hpos = register_output( p, VERT_RESULT_HPOS ); + struct ureg mvp[4]; + + if (p->mvp_with_dp4) { + register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, + 0, mvp ); + emit_matrix_transform_vec4( p, hpos, mvp, pos ); + } + else { + register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, + STATE_MATRIX_TRANSPOSE, mvp ); + emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos ); + } +} + + +static GLuint material_attrib( GLuint side, GLuint property ) +{ + return (property - STATE_AMBIENT) * 2 + side; +} + + +/** + * Get a bitmask of which material values vary on a per-vertex basis. + */ +static void set_material_flags( struct tnl_program *p ) +{ + p->color_materials = 0; + p->materials = 0; + + if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) { + p->materials = + p->color_materials = p->state->light_color_material_mask; + } + + p->materials |= (p->state->varying_vp_inputs >> 16); +} + + +static struct ureg get_material( struct tnl_program *p, GLuint side, + GLuint property ) +{ + GLuint attrib = material_attrib(side, property); + + if (p->color_materials & (1<materials & (1<materials & SCENE_COLOR_BITS(side)) { + struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT); + struct ureg material_emission = get_material(p, side, STATE_EMISSION); + struct ureg material_ambient = get_material(p, side, STATE_AMBIENT); + struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE); + struct ureg tmp = make_temp(p, material_diffuse); + emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient, + material_ambient, material_emission); + return tmp; + } + else + return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side ); +} + + +static struct ureg get_lightprod( struct tnl_program *p, GLuint light, + GLuint side, GLuint property ) +{ + GLuint attrib = material_attrib(side, property); + if (p->materials & (1<state->unit[i].light_spotcutoff_is_180) { + struct ureg spot_dir_norm = register_param3(p, STATE_INTERNAL, + STATE_LIGHT_SPOT_DIR_NORMALIZED, i); + struct ureg spot = get_temp(p); + struct ureg slt = get_temp(p); + + emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm); + emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot); + emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W)); + emit_op2(p, OPCODE_MUL, att, 0, slt, spot); + + release_temp(p, spot); + release_temp(p, slt); + } + + /* Calculate distance attenuation: + */ + if (p->state->unit[i].light_attenuated) { + /* 1/d,d,d,1/d */ + emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist); + /* 1,d,d*d,1/d */ + emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y)); + /* 1/dist-atten */ + emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist); + + if (!p->state->unit[i].light_spotcutoff_is_180) { + /* dist-atten */ + emit_op1(p, OPCODE_RCP, dist, 0, dist); + /* spot-atten * dist-atten */ + emit_op2(p, OPCODE_MUL, att, 0, dist, att); + } + else { + /* dist-atten */ + emit_op1(p, OPCODE_RCP, att, 0, dist); + } + } + + return att; +} + + +/** + * Compute: + * lit.y = MAX(0, dots.x) + * lit.z = SLT(0, dots.x) + */ +static void emit_degenerate_lit( struct tnl_program *p, + struct ureg lit, + struct ureg dots ) +{ + struct ureg id = get_identity_param(p); /* id = {0,0,0,1} */ + + /* Note that lit.x & lit.w will not be examined. Note also that + * dots.xyzw == dots.xxxx. + */ + + /* MAX lit, id, dots; + */ + emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots); + + /* result[2] = (in > 0 ? 1 : 0) + * SLT lit.z, id.z, dots; # lit.z = (0 < dots.z) ? 1 : 0 + */ + emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots); +} + + +/* Need to add some addtional parameters to allow lighting in object + * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye + * space lighting. + */ +static void build_lighting( struct tnl_program *p ) +{ + const GLboolean twoside = p->state->light_twoside; + const GLboolean separate = p->state->separate_specular; + GLuint nr_lights = 0, count = 0; + struct ureg normal = get_transformed_normal(p); + struct ureg lit = get_temp(p); + struct ureg dots = get_temp(p); + struct ureg _col0 = undef, _col1 = undef; + struct ureg _bfc0 = undef, _bfc1 = undef; + GLuint i; + + /* + * NOTE: + * dots.x = dot(normal, VPpli) + * dots.y = dot(normal, halfAngle) + * dots.z = back.shininess + * dots.w = front.shininess + */ + + for (i = 0; i < MAX_LIGHTS; i++) + if (p->state->unit[i].light_enabled) + nr_lights++; + + set_material_flags(p); + + { + if (!p->state->material_shininess_is_zero) { + struct ureg shininess = get_material(p, 0, STATE_SHININESS); + emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X)); + release_temp(p, shininess); + } + + _col0 = make_temp(p, get_scenecolor(p, 0)); + if (separate) + _col1 = make_temp(p, get_identity_param(p)); + else + _col1 = _col0; + } + + if (twoside) { + if (!p->state->material_shininess_is_zero) { + /* Note that we negate the back-face specular exponent here. + * The negation will be un-done later in the back-face code below. + */ + struct ureg shininess = get_material(p, 1, STATE_SHININESS); + emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z, + negate(swizzle1(shininess,X))); + release_temp(p, shininess); + } + + _bfc0 = make_temp(p, get_scenecolor(p, 1)); + if (separate) + _bfc1 = make_temp(p, get_identity_param(p)); + else + _bfc1 = _bfc0; + } + + /* If no lights, still need to emit the scenecolor. + */ + { + struct ureg res0 = register_output( p, VERT_RESULT_COL0 ); + emit_op1(p, OPCODE_MOV, res0, 0, _col0); + } + + if (separate) { + struct ureg res1 = register_output( p, VERT_RESULT_COL1 ); + emit_op1(p, OPCODE_MOV, res1, 0, _col1); + } + + if (twoside) { + struct ureg res0 = register_output( p, VERT_RESULT_BFC0 ); + emit_op1(p, OPCODE_MOV, res0, 0, _bfc0); + } + + if (twoside && separate) { + struct ureg res1 = register_output( p, VERT_RESULT_BFC1 ); + emit_op1(p, OPCODE_MOV, res1, 0, _bfc1); + } + + if (nr_lights == 0) { + release_temps(p); + return; + } + + for (i = 0; i < MAX_LIGHTS; i++) { + if (p->state->unit[i].light_enabled) { + struct ureg half = undef; + struct ureg att = undef, VPpli = undef; + + count++; + + if (p->state->unit[i].light_eyepos3_is_zero) { + /* Can used precomputed constants in this case. + * Attenuation never applies to infinite lights. + */ + VPpli = register_param3(p, STATE_INTERNAL, + STATE_LIGHT_POSITION_NORMALIZED, i); + + if (!p->state->material_shininess_is_zero) { + if (p->state->light_local_viewer) { + struct ureg eye_hat = get_eye_position_normalized(p); + half = get_temp(p); + emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); + emit_normalize_vec3(p, half, half); + } + else { + half = register_param3(p, STATE_INTERNAL, + STATE_LIGHT_HALF_VECTOR, i); + } + } + } + else { + struct ureg Ppli = register_param3(p, STATE_INTERNAL, + STATE_LIGHT_POSITION, i); + struct ureg V = get_eye_position(p); + struct ureg dist = get_temp(p); + + VPpli = get_temp(p); + + /* Calculate VPpli vector + */ + emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V); + + /* Normalize VPpli. The dist value also used in + * attenuation below. + */ + emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli); + emit_op1(p, OPCODE_RSQ, dist, 0, dist); + emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist); + + /* Calculate attenuation: + */ + if (!p->state->unit[i].light_spotcutoff_is_180 || + p->state->unit[i].light_attenuated) { + att = calculate_light_attenuation(p, i, VPpli, dist); + } + + /* Calculate viewer direction, or use infinite viewer: + */ + if (!p->state->material_shininess_is_zero) { + half = get_temp(p); + + if (p->state->light_local_viewer) { + struct ureg eye_hat = get_eye_position_normalized(p); + emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); + } + else { + struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z); + emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir); + } + + emit_normalize_vec3(p, half, half); + } + + release_temp(p, dist); + } + + /* Calculate dot products: + */ + if (p->state->material_shininess_is_zero) { + emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli); + } + else { + emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli); + emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half); + } + + /* Front face lighting: + */ + { + struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT); + struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE); + struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR); + struct ureg res0, res1; + GLuint mask0, mask1; + + if (count == nr_lights) { + if (separate) { + mask0 = WRITEMASK_XYZ; + mask1 = WRITEMASK_XYZ; + res0 = register_output( p, VERT_RESULT_COL0 ); + res1 = register_output( p, VERT_RESULT_COL1 ); + } + else { + mask0 = 0; + mask1 = WRITEMASK_XYZ; + res0 = _col0; + res1 = register_output( p, VERT_RESULT_COL0 ); + } + } + else { + mask0 = 0; + mask1 = 0; + res0 = _col0; + res1 = _col1; + } + + if (!is_undef(att)) { + /* light is attenuated by distance */ + emit_op1(p, OPCODE_LIT, lit, 0, dots); + emit_op2(p, OPCODE_MUL, lit, 0, lit, att); + emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0); + } + else if (!p->state->material_shininess_is_zero) { + /* there's a non-zero specular term */ + emit_op1(p, OPCODE_LIT, lit, 0, dots); + emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); + } + else { + /* no attenutation, no specular */ + emit_degenerate_lit(p, lit, dots); + emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); + } + + emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0); + emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1); + + release_temp(p, ambient); + release_temp(p, diffuse); + release_temp(p, specular); + } + + /* Back face lighting: + */ + if (twoside) { + struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT); + struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE); + struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR); + struct ureg res0, res1; + GLuint mask0, mask1; + + if (count == nr_lights) { + if (separate) { + mask0 = WRITEMASK_XYZ; + mask1 = WRITEMASK_XYZ; + res0 = register_output( p, VERT_RESULT_BFC0 ); + res1 = register_output( p, VERT_RESULT_BFC1 ); + } + else { + mask0 = 0; + mask1 = WRITEMASK_XYZ; + res0 = _bfc0; + res1 = register_output( p, VERT_RESULT_BFC0 ); + } + } + else { + res0 = _bfc0; + res1 = _bfc1; + mask0 = 0; + mask1 = 0; + } + + /* For the back face we need to negate the X and Y component + * dot products. dots.Z has the negated back-face specular + * exponent. We swizzle that into the W position. This + * negation makes the back-face specular term positive again. + */ + dots = negate(swizzle(dots,X,Y,W,Z)); + + if (!is_undef(att)) { + emit_op1(p, OPCODE_LIT, lit, 0, dots); + emit_op2(p, OPCODE_MUL, lit, 0, lit, att); + emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0); + } + else if (!p->state->material_shininess_is_zero) { + emit_op1(p, OPCODE_LIT, lit, 0, dots); + emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); /**/ + } + else { + emit_degenerate_lit(p, lit, dots); + emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); + } + + emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0); + emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1); + /* restore dots to its original state for subsequent lights + * by negating and swizzling again. + */ + dots = negate(swizzle(dots,X,Y,W,Z)); + + release_temp(p, ambient); + release_temp(p, diffuse); + release_temp(p, specular); + } + + release_temp(p, half); + release_temp(p, VPpli); + release_temp(p, att); + } + } + + release_temps( p ); +} + + +static void build_fog( struct tnl_program *p ) +{ + struct ureg fog = register_output(p, VERT_RESULT_FOGC); + struct ureg input; + + if (p->state->fog_source_is_depth) { + input = get_eye_position_z(p); + } + else { + input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X); + } + + /* result.fog = {abs(f),0,0,1}; */ + emit_op1(p, OPCODE_ABS, fog, WRITEMASK_X, input); + emit_op1(p, OPCODE_MOV, fog, WRITEMASK_YZW, get_identity_param(p)); +} + + +static void build_reflect_texgen( struct tnl_program *p, + struct ureg dest, + GLuint writemask ) +{ + struct ureg normal = get_transformed_normal(p); + struct ureg eye_hat = get_eye_position_normalized(p); + struct ureg tmp = get_temp(p); + + /* n.u */ + emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); + /* 2n.u */ + emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); + /* (-2n.u)n + u */ + emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat); + + release_temp(p, tmp); +} + + +static void build_sphere_texgen( struct tnl_program *p, + struct ureg dest, + GLuint writemask ) +{ + struct ureg normal = get_transformed_normal(p); + struct ureg eye_hat = get_eye_position_normalized(p); + struct ureg tmp = get_temp(p); + struct ureg half = register_scalar_const(p, .5); + struct ureg r = get_temp(p); + struct ureg inv_m = get_temp(p); + struct ureg id = get_identity_param(p); + + /* Could share the above calculations, but it would be + * a fairly odd state for someone to set (both sphere and + * reflection active for different texture coordinate + * components. Of course - if two texture units enable + * reflect and/or sphere, things start to tilt in favour + * of seperating this out: + */ + + /* n.u */ + emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); + /* 2n.u */ + emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); + /* (-2n.u)n + u */ + emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); + /* r + 0,0,1 */ + emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); + /* rx^2 + ry^2 + (rz+1)^2 */ + emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp); + /* 2/m */ + emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); + /* 1/m */ + emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half); + /* r/m + 1/2 */ + emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half); + + release_temp(p, tmp); + release_temp(p, r); + release_temp(p, inv_m); +} + + +static void build_texture_transform( struct tnl_program *p ) +{ + GLuint i, j; + + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { + + if (!(p->state->fragprog_inputs_read & FRAG_BIT_TEX(i))) + continue; + + if (p->state->unit[i].coord_replace) + continue; + + if (p->state->unit[i].texgen_enabled || + p->state->unit[i].texmat_enabled) { + + GLuint texmat_enabled = p->state->unit[i].texmat_enabled; + struct ureg out = register_output(p, VERT_RESULT_TEX0 + i); + struct ureg out_texgen = undef; + + if (p->state->unit[i].texgen_enabled) { + GLuint copy_mask = 0; + GLuint sphere_mask = 0; + GLuint reflect_mask = 0; + GLuint normal_mask = 0; + GLuint modes[4]; + + if (texmat_enabled) + out_texgen = get_temp(p); + else + out_texgen = out; + + modes[0] = p->state->unit[i].texgen_mode0; + modes[1] = p->state->unit[i].texgen_mode1; + modes[2] = p->state->unit[i].texgen_mode2; + modes[3] = p->state->unit[i].texgen_mode3; + + for (j = 0; j < 4; j++) { + switch (modes[j]) { + case TXG_OBJ_LINEAR: { + struct ureg obj = register_input(p, VERT_ATTRIB_POS); + struct ureg plane = + register_param3(p, STATE_TEXGEN, i, + STATE_TEXGEN_OBJECT_S + j); + + emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, + obj, plane ); + break; + } + case TXG_EYE_LINEAR: { + struct ureg eye = get_eye_position(p); + struct ureg plane = + register_param3(p, STATE_TEXGEN, i, + STATE_TEXGEN_EYE_S + j); + + emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, + eye, plane ); + break; + } + case TXG_SPHERE_MAP: + sphere_mask |= WRITEMASK_X << j; + break; + case TXG_REFLECTION_MAP: + reflect_mask |= WRITEMASK_X << j; + break; + case TXG_NORMAL_MAP: + normal_mask |= WRITEMASK_X << j; + break; + case TXG_NONE: + copy_mask |= WRITEMASK_X << j; + } + } + + if (sphere_mask) { + build_sphere_texgen(p, out_texgen, sphere_mask); + } + + if (reflect_mask) { + build_reflect_texgen(p, out_texgen, reflect_mask); + } + + if (normal_mask) { + struct ureg normal = get_transformed_normal(p); + emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal ); + } + + if (copy_mask) { + struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i); + emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in ); + } + } + + if (texmat_enabled) { + struct ureg texmat[4]; + struct ureg in = (!is_undef(out_texgen) ? + out_texgen : + register_input(p, VERT_ATTRIB_TEX0+i)); + if (p->mvp_with_dp4) { + register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, + 0, texmat ); + emit_matrix_transform_vec4( p, out, texmat, in ); + } + else { + register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, + STATE_MATRIX_TRANSPOSE, texmat ); + emit_transpose_matrix_transform_vec4( p, out, texmat, in ); + } + } + + release_temps(p); + } + else { + emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i); + } + } +} + + +/** + * Point size attenuation computation. + */ +static void build_atten_pointsize( struct tnl_program *p ) +{ + struct ureg eye = get_eye_position_z(p); + struct ureg state_size = register_param2(p, STATE_INTERNAL, STATE_POINT_SIZE_CLAMPED); + struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION); + struct ureg out = register_output(p, VERT_RESULT_PSIZ); + struct ureg ut = get_temp(p); + + /* dist = |eyez| */ + emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z)); + /* p1 + dist * (p2 + dist * p3); */ + emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), + swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y)); + emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), + ut, swizzle1(state_attenuation, X)); + + /* 1 / sqrt(factor) */ + emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut ); + +#if 0 + /* out = pointSize / sqrt(factor) */ + emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size); +#else + /* this is a good place to clamp the point size since there's likely + * no hardware registers to clamp point size at rasterization time. + */ + emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size); + emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y)); + emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z)); +#endif + + release_temp(p, ut); +} + + +/** + * Pass-though per-vertex point size, from user's point size array. + */ +static void build_array_pointsize( struct tnl_program *p ) +{ + struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE); + struct ureg out = register_output(p, VERT_RESULT_PSIZ); + emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in); +} + + +static void build_tnl_program( struct tnl_program *p ) +{ + /* Emit the program, starting with modelviewproject: + */ + build_hpos(p); + + /* Lighting calculations: + */ + if (p->state->fragprog_inputs_read & (FRAG_BIT_COL0|FRAG_BIT_COL1)) { + if (p->state->light_global_enabled) + build_lighting(p); + else { + if (p->state->fragprog_inputs_read & FRAG_BIT_COL0) + emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0); + + if (p->state->fragprog_inputs_read & FRAG_BIT_COL1) + emit_passthrough(p, VERT_ATTRIB_COLOR1, VERT_RESULT_COL1); + } + } + + if (p->state->fragprog_inputs_read & FRAG_BIT_FOGC) + build_fog(p); + + if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY) + build_texture_transform(p); + + if (p->state->point_attenuated) + build_atten_pointsize(p); + else if (p->state->point_array) + build_array_pointsize(p); + + /* Finish up: + */ + emit_op1(p, OPCODE_END, undef, 0, undef); + + /* Disassemble: + */ + if (DISASSEM) { + printf ("\n"); + } +} + + +static void +create_new_program( const struct state_key *key, + struct gl_vertex_program *program, + GLboolean mvp_with_dp4, + GLuint max_temps) +{ + struct tnl_program p; + + memset(&p, 0, sizeof(p)); + p.state = key; + p.program = program; + p.eye_position = undef; + p.eye_position_z = undef; + p.eye_position_normalized = undef; + p.transformed_normal = undef; + p.identity = undef; + p.temp_in_use = 0; + p.mvp_with_dp4 = mvp_with_dp4; + + if (max_temps >= sizeof(int) * 8) + p.temp_reserved = 0; + else + p.temp_reserved = ~((1<Base.Instructions = _mesa_alloc_instructions(p.max_inst); + p.program->Base.String = NULL; + p.program->Base.NumInstructions = + p.program->Base.NumTemporaries = + p.program->Base.NumParameters = + p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; + p.program->Base.Parameters = _mesa_new_parameter_list(); + p.program->Base.InputsRead = 0; + p.program->Base.OutputsWritten = 0; + + build_tnl_program( &p ); +} + + +/** + * Return a vertex program which implements the current fixed-function + * transform/lighting/texgen operations. + * XXX move this into core mesa (main/) + */ +struct gl_vertex_program * +_mesa_get_fixed_func_vertex_program(struct gl_context *ctx) +{ + struct gl_vertex_program *prog; + struct state_key key; + + /* Grab all the relevent state and put it in a single structure: + */ + make_state_key(ctx, &key); + + /* Look for an already-prepared program for this state: + */ + prog = (struct gl_vertex_program *) + _mesa_search_program_cache(ctx->VertexProgram.Cache, &key, sizeof(key)); + + if (!prog) { + /* OK, we'll have to build a new one */ + if (0) + printf("Build new TNL program\n"); + + prog = (struct gl_vertex_program *) + ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); + if (!prog) + return NULL; + + create_new_program( &key, prog, + ctx->mvp_with_dp4, + ctx->Const.VertexProgram.MaxTemps ); + +#if 0 + if (ctx->Driver.ProgramStringNotify) + ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB, + &prog->Base ); +#endif + _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, + &key, sizeof(key), &prog->Base); + } + + return prog; +} diff --git a/mesalib/src/mesa/main/nvprogram.c b/mesalib/src/mesa/main/nvprogram.c index 6b20fdae6..7ff7645b7 100644 --- a/mesalib/src/mesa/main/nvprogram.c +++ b/mesalib/src/mesa/main/nvprogram.c @@ -1,920 +1,920 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file nvprogram.c - * NVIDIA vertex/fragment program state management functions. - * \author Brian Paul - */ - -/* - * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc: - * - * Portions of this software may use or implement intellectual - * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims - * any and all warranties with respect to such intellectual property, - * including any use thereof or modifications thereto. - */ - -#include "main/glheader.h" -#include "main/context.h" -#include "main/hash.h" -#include "main/imports.h" -#include "main/macros.h" -#include "main/mtypes.h" -#include "main/nvprogram.h" -#include "program/arbprogparse.h" -#include "program/nvfragparse.h" -#include "program/nvvertparse.h" -#include "program/program.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" - - - -/** - * Execute a vertex state program. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) -{ - struct gl_vertex_program *vprog; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_VERTEX_STATE_PROGRAM_NV) { - _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - - vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id); - - if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); - return; - } - - _mesa_problem(ctx, "glExecuteProgramNV() not supported"); -} - - -/** - * Determine if a set of programs is resident in hardware. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -GLboolean GLAPIENTRY -_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, - GLboolean *residences) -{ - GLint i, j; - GLboolean allResident = GL_TRUE; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); - return GL_FALSE; - } - - for (i = 0; i < n; i++) { - const struct gl_program *prog; - if (ids[i] == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); - return GL_FALSE; - } - prog = _mesa_lookup_program(ctx, ids[i]); - if (!prog) { - _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); - return GL_FALSE; - } - if (prog->Resident) { - if (!allResident) - residences[i] = GL_TRUE; - } - else { - if (allResident) { - allResident = GL_FALSE; - for (j = 0; j < i; j++) - residences[j] = GL_TRUE; - } - residences[i] = GL_FALSE; - } - } - - return allResident; -} - - -/** - * Request that a set of programs be resident in hardware. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)"); - return; - } - - /* just error checking for now */ - for (i = 0; i < n; i++) { - struct gl_program *prog; - - if (ids[i] == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); - return; - } - - prog = _mesa_lookup_program(ctx, ids[i]); - if (!prog) { - _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); - return; - } - - /* XXX this is really a hardware thing we should hook out */ - prog->Resident = GL_TRUE; - } -} - - -/** - * Get a program parameter register. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, - GLenum pname, GLfloat *params) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target == GL_VERTEX_PROGRAM_NV) { - if (pname == GL_PROGRAM_PARAMETER_NV) { - if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { - COPY_4V(params, ctx->VertexProgram.Parameters[index]); - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramParameterfvNV(index)"); - return; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)"); - return; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)"); - return; - } -} - - -/** - * Get a program parameter register. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, - GLenum pname, GLdouble *params) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target == GL_VERTEX_PROGRAM_NV) { - if (pname == GL_PROGRAM_PARAMETER_NV) { - if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { - COPY_4V(params, ctx->VertexProgram.Parameters[index]); - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramParameterdvNV(index)"); - return; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)"); - return; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)"); - return; - } -} - - -/** - * Get a program attribute. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params) -{ - struct gl_program *prog; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - prog = _mesa_lookup_program(ctx, id); - if (!prog) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV"); - return; - } - - switch (pname) { - case GL_PROGRAM_TARGET_NV: - *params = prog->Target; - return; - case GL_PROGRAM_LENGTH_NV: - *params = prog->String ?(GLint) strlen((char *) prog->String) : 0; - return; - case GL_PROGRAM_RESIDENT_NV: - *params = prog->Resident; - return; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)"); - return; - } -} - - -/** - * Get the program source code. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program) -{ - struct gl_program *prog; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (pname != GL_PROGRAM_STRING_NV) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)"); - return; - } - - prog = _mesa_lookup_program(ctx, id); - if (!prog) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV"); - return; - } - - if (prog->String) { - memcpy(program, prog->String, strlen((char *) prog->String)); - } - else { - program[0] = 0; - } -} - - -/** - * Get matrix tracking information. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, - GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target == GL_VERTEX_PROGRAM_NV - && ctx->Extensions.NV_vertex_program) { - GLuint i; - - if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)"); - return; - } - - i = address / 4; - - switch (pname) { - case GL_TRACK_MATRIX_NV: - params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i]; - return; - case GL_TRACK_MATRIX_TRANSFORM_NV: - params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i]; - return; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); - return; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); - return; - } -} - - -/** - * Get a vertex (or vertex array) attribute. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params) -{ - const struct gl_client_array *array; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); - return; - } - - array = &ctx->Array.ArrayObj->VertexAttrib[index]; - - switch (pname) { - case GL_ATTRIB_ARRAY_SIZE_NV: - params[0] = array->Size; - break; - case GL_ATTRIB_ARRAY_STRIDE_NV: - params[0] = array->Stride; - break; - case GL_ATTRIB_ARRAY_TYPE_NV: - params[0] = array->Type; - break; - case GL_CURRENT_ATTRIB_NV: - if (index == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetVertexAttribdvNV(index == 0)"); - return; - } - FLUSH_CURRENT(ctx, 0); - COPY_4V(params, ctx->Current.Attrib[index]); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); - return; - } -} - -/** - * Get a vertex (or vertex array) attribute. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params) -{ - const struct gl_client_array *array; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); - return; - } - - array = &ctx->Array.ArrayObj->VertexAttrib[index]; - - switch (pname) { - case GL_ATTRIB_ARRAY_SIZE_NV: - params[0] = (GLfloat) array->Size; - break; - case GL_ATTRIB_ARRAY_STRIDE_NV: - params[0] = (GLfloat) array->Stride; - break; - case GL_ATTRIB_ARRAY_TYPE_NV: - params[0] = (GLfloat) array->Type; - break; - case GL_CURRENT_ATTRIB_NV: - if (index == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetVertexAttribfvNV(index == 0)"); - return; - } - FLUSH_CURRENT(ctx, 0); - COPY_4V(params, ctx->Current.Attrib[index]); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); - return; - } -} - -/** - * Get a vertex (or vertex array) attribute. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params) -{ - const struct gl_client_array *array; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); - return; - } - - array = &ctx->Array.ArrayObj->VertexAttrib[index]; - - switch (pname) { - case GL_ATTRIB_ARRAY_SIZE_NV: - params[0] = array->Size; - break; - case GL_ATTRIB_ARRAY_STRIDE_NV: - params[0] = array->Stride; - break; - case GL_ATTRIB_ARRAY_TYPE_NV: - params[0] = array->Type; - break; - case GL_CURRENT_ATTRIB_NV: - if (index == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetVertexAttribivNV(index == 0)"); - return; - } - FLUSH_CURRENT(ctx, 0); - params[0] = (GLint) ctx->Current.Attrib[index][0]; - params[1] = (GLint) ctx->Current.Attrib[index][1]; - params[2] = (GLint) ctx->Current.Attrib[index][2]; - params[3] = (GLint) ctx->Current.Attrib[index][3]; - break; - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: - params[0] = array->BufferObj->Name; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); - return; - } -} - - -/** - * Get a vertex array attribute pointer. - * \note Not compiled into display lists. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)"); - return; - } - - if (pname != GL_ATTRIB_ARRAY_POINTER_NV) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)"); - return; - } - - *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr; -} - -void -_mesa_emit_nv_temp_initialization(struct gl_context *ctx, - struct gl_program *program) -{ - struct prog_instruction *inst; - GLuint i; - struct gl_shader_compiler_options* options = - &ctx->ShaderCompilerOptions[_mesa_program_target_to_index(program->Target)]; - - if (!options->EmitNVTempInitialization) - return; - - /* We'll swizzle up a zero temporary so we can use it for the - * ARL. - */ - if (program->NumTemporaries == 0) - program->NumTemporaries = 1; - - _mesa_insert_instructions(program, 0, program->NumTemporaries + 1); - - for (i = 0; i < program->NumTemporaries; i++) { - struct prog_instruction *inst = &program->Instructions[i]; - - inst->Opcode = OPCODE_SWZ; - inst->DstReg.File = PROGRAM_TEMPORARY; - inst->DstReg.Index = i; - inst->DstReg.WriteMask = WRITEMASK_XYZW; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = 0; - inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO, - SWIZZLE_ZERO, - SWIZZLE_ZERO, - SWIZZLE_ZERO); - } - - inst = &program->Instructions[i]; - inst->Opcode = OPCODE_ARL; - inst->DstReg.File = PROGRAM_ADDRESS; - inst->DstReg.Index = 0; - inst->DstReg.WriteMask = WRITEMASK_XYZW; - inst->SrcReg[0].File = PROGRAM_TEMPORARY; - inst->SrcReg[0].Index = 0; - inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; - - if (program->NumAddressRegs == 0) - program->NumAddressRegs = 1; -} - -void -_mesa_setup_nv_temporary_count(struct gl_context *ctx, struct gl_program *program) -{ - GLuint i; - - program->NumTemporaries = 0; - for (i = 0; i < program->NumInstructions; i++) { - struct prog_instruction *inst = &program->Instructions[i]; - - if (inst->DstReg.File == PROGRAM_TEMPORARY) { - program->NumTemporaries = MAX2(program->NumTemporaries, - inst->DstReg.Index + 1); - } - if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) { - program->NumTemporaries = MAX2((GLint)program->NumTemporaries, - inst->SrcReg[0].Index + 1); - } - if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) { - program->NumTemporaries = MAX2((GLint)program->NumTemporaries, - inst->SrcReg[1].Index + 1); - } - if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) { - program->NumTemporaries = MAX2((GLint)program->NumTemporaries, - inst->SrcReg[2].Index + 1); - } - } -} - -/** - * Load/parse/compile a program. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, - const GLubyte *program) -{ - struct gl_program *prog; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.NV_vertex_program - && !ctx->Extensions.NV_fragment_program) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()"); - return; - } - - if (id == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); - return; - } - - if (len < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - - prog = _mesa_lookup_program(ctx, id); - - if (prog && prog->Target != 0 && prog->Target != target) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); - return; - } - - if ((target == GL_VERTEX_PROGRAM_NV || - target == GL_VERTEX_STATE_PROGRAM_NV) - && ctx->Extensions.NV_vertex_program) { - struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; - if (!vprog || prog == &_mesa_DummyProgram) { - vprog = (struct gl_vertex_program *) - ctx->Driver.NewProgram(ctx, target, id); - if (!vprog) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; - } - _mesa_HashInsert(ctx->Shared->Programs, id, vprog); - } - - if (ctx->Extensions.ARB_vertex_program - && (strncmp((char *) program, "!!ARB", 5) == 0)) { - _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog); - } else { - _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); - } - } - else if (target == GL_FRAGMENT_PROGRAM_NV - && ctx->Extensions.NV_fragment_program) { - struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; - if (!fprog || prog == &_mesa_DummyProgram) { - fprog = (struct gl_fragment_program *) - ctx->Driver.NewProgram(ctx, target, id); - if (!fprog) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; - } - _mesa_HashInsert(ctx->Shared->Programs, id, fprog); - } - _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); - } - else if (target == GL_FRAGMENT_PROGRAM_ARB - && ctx->Extensions.ARB_fragment_program) { - struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; - if (!fprog || prog == &_mesa_DummyProgram) { - fprog = (struct gl_fragment_program *) - ctx->Driver.NewProgram(ctx, target, id); - if (!fprog) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); - return; - } - _mesa_HashInsert(ctx->Shared->Programs, id, fprog); - } - _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog); - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); - } -} - - - -/** - * Set a sequence of program parameter registers. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, - GLsizei num, const GLdouble *params) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { - GLint i; - if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV"); - return; - } - for (i = 0; i < num; i++) { - ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0]; - ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1]; - ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2]; - ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3]; - params += 4; - }; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV"); - return; - } -} - - -/** - * Set a sequence of program parameter registers. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, - GLsizei num, const GLfloat *params) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { - GLint i; - if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { - _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV"); - return; - } - for (i = 0; i < num; i++) { - COPY_4V(ctx->VertexProgram.Parameters[index + i], params); - params += 4; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV"); - return; - } -} - - - -/** - * Setup tracking of matrices into program parameter registers. - * \note Called from the GL API dispatcher. - */ -void GLAPIENTRY -_mesa_TrackMatrixNV(GLenum target, GLuint address, - GLenum matrix, GLenum transform) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - - if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { - if (address & 0x3) { - /* addr must be multiple of four */ - _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)"); - return; - } - - switch (matrix) { - case GL_NONE: - case GL_MODELVIEW: - case GL_PROJECTION: - case GL_TEXTURE: - case GL_COLOR: - case GL_MODELVIEW_PROJECTION_NV: - case GL_MATRIX0_NV: - case GL_MATRIX1_NV: - case GL_MATRIX2_NV: - case GL_MATRIX3_NV: - case GL_MATRIX4_NV: - case GL_MATRIX5_NV: - case GL_MATRIX6_NV: - case GL_MATRIX7_NV: - /* OK, fallthrough */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)"); - return; - } - - switch (transform) { - case GL_IDENTITY_NV: - case GL_INVERSE_NV: - case GL_TRANSPOSE_NV: - case GL_INVERSE_TRANSPOSE_NV: - /* OK, fallthrough */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)"); - return; - } - - ctx->VertexProgram.TrackMatrix[address / 4] = matrix; - ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)"); - return; - } -} - - -void GLAPIENTRY -_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, - GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - struct gl_program *prog; - struct gl_fragment_program *fragProg; - GLfloat *v; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); - - prog = _mesa_lookup_program(ctx, id); - if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); - return; - } - - if (len <= 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); - return; - } - - fragProg = (struct gl_fragment_program *) prog; - v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, - (char *) name); - if (v) { - v[0] = x; - v[1] = y; - v[2] = z; - v[3] = w; - return; - } - - _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); -} - - -void GLAPIENTRY -_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, - const float v[]) -{ - _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]); -} - - -void GLAPIENTRY -_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, - GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y, - (GLfloat)z, (GLfloat)w); -} - - -void GLAPIENTRY -_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, - const double v[]) -{ - _mesa_ProgramNamedParameter4fNV(id, len, name, - (GLfloat)v[0], (GLfloat)v[1], - (GLfloat)v[2], (GLfloat)v[3]); -} - - -void GLAPIENTRY -_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, - GLfloat *params) -{ - struct gl_program *prog; - struct gl_fragment_program *fragProg; - const GLfloat *v; - - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - prog = _mesa_lookup_program(ctx, id); - if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); - return; - } - - if (len <= 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); - return; - } - - fragProg = (struct gl_fragment_program *) prog; - v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, - len, (char *) name); - if (v) { - params[0] = v[0]; - params[1] = v[1]; - params[2] = v[2]; - params[3] = v[3]; - return; - } - - _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); -} - - -void GLAPIENTRY -_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, - GLdouble *params) -{ - GLfloat floatParams[4]; - _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams); - COPY_4V(params, floatParams); -} +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvprogram.c + * NVIDIA vertex/fragment program state management functions. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "main/nvprogram.h" +#include "program/arbprogparse.h" +#include "program/nvfragparse.h" +#include "program/nvvertparse.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" + + + +/** + * Execute a vertex state program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) +{ + struct gl_vertex_program *vprog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id); + + if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); + return; + } + + _mesa_problem(ctx, "glExecuteProgramNV() not supported"); +} + + +/** + * Determine if a set of programs is resident in hardware. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +GLboolean GLAPIENTRY +_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, + GLboolean *residences) +{ + GLint i, j; + GLboolean allResident = GL_TRUE; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); + return GL_FALSE; + } + + for (i = 0; i < n; i++) { + const struct gl_program *prog; + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + if (prog->Resident) { + if (!allResident) + residences[i] = GL_TRUE; + } + else { + if (allResident) { + allResident = GL_FALSE; + for (j = 0; j < i; j++) + residences[j] = GL_TRUE; + } + residences[i] = GL_FALSE; + } + } + + return allResident; +} + + +/** + * Request that a set of programs be resident in hardware. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)"); + return; + } + + /* just error checking for now */ + for (i = 0; i < n; i++) { + struct gl_program *prog; + + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + /* XXX this is really a hardware thing we should hook out */ + prog->Resident = GL_TRUE; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, + GLenum pname, GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterfvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)"); + return; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, + GLenum pname, GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterdvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)"); + return; + } +} + + +/** + * Get a program attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV"); + return; + } + + switch (pname) { + case GL_PROGRAM_TARGET_NV: + *params = prog->Target; + return; + case GL_PROGRAM_LENGTH_NV: + *params = prog->String ?(GLint) strlen((char *) prog->String) : 0; + return; + case GL_PROGRAM_RESIDENT_NV: + *params = prog->Resident; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)"); + return; + } +} + + +/** + * Get the program source code. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (pname != GL_PROGRAM_STRING_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)"); + return; + } + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV"); + return; + } + + if (prog->String) { + memcpy(program, prog->String, strlen((char *) prog->String)); + } + else { + program[0] = 0; + } +} + + +/** + * Get matrix tracking information. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV + && ctx->Extensions.NV_vertex_program) { + GLuint i; + + if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)"); + return; + } + + i = address / 4; + + switch (pname) { + case GL_TRACK_MATRIX_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i]; + return; + case GL_TRACK_MATRIX_TRANSFORM_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i]; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } +} + + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribdvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = (GLfloat) array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = (GLfloat) array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = (GLfloat) array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribfvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribivNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + params[0] = (GLint) ctx->Current.Attrib[index][0]; + params[1] = (GLint) ctx->Current.Attrib[index][1]; + params[2] = (GLint) ctx->Current.Attrib[index][2]; + params[3] = (GLint) ctx->Current.Attrib[index][3]; + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: + params[0] = array->BufferObj->Name; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + + +/** + * Get a vertex array attribute pointer. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)"); + return; + } + + if (pname != GL_ATTRIB_ARRAY_POINTER_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)"); + return; + } + + *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr; +} + +void +_mesa_emit_nv_temp_initialization(struct gl_context *ctx, + struct gl_program *program) +{ + struct prog_instruction *inst; + GLuint i; + struct gl_shader_compiler_options* options = + &ctx->ShaderCompilerOptions[_mesa_program_target_to_index(program->Target)]; + + if (!options->EmitNVTempInitialization) + return; + + /* We'll swizzle up a zero temporary so we can use it for the + * ARL. + */ + if (program->NumTemporaries == 0) + program->NumTemporaries = 1; + + _mesa_insert_instructions(program, 0, program->NumTemporaries + 1); + + for (i = 0; i < program->NumTemporaries; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + inst->Opcode = OPCODE_SWZ; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = i; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO); + } + + inst = &program->Instructions[i]; + inst->Opcode = OPCODE_ARL; + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + + if (program->NumAddressRegs == 0) + program->NumAddressRegs = 1; +} + +void +_mesa_setup_nv_temporary_count(struct gl_context *ctx, struct gl_program *program) +{ + GLuint i; + + program->NumTemporaries = 0; + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->DstReg.Index + 1); + } + if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[0].Index + 1); + } + if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[1].Index + 1); + } + if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[2].Index + 1); + } + } +} + +/** + * Load/parse/compile a program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, + const GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.NV_vertex_program + && !ctx->Extensions.NV_fragment_program) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()"); + return; + } + + if (id == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); + return; + } + + if (len < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + prog = _mesa_lookup_program(ctx, id); + + if (prog && prog->Target != 0 && prog->Target != target) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); + return; + } + + if ((target == GL_VERTEX_PROGRAM_NV || + target == GL_VERTEX_STATE_PROGRAM_NV) + && ctx->Extensions.NV_vertex_program) { + struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; + if (!vprog || prog == &_mesa_DummyProgram) { + vprog = (struct gl_vertex_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!vprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, vprog); + } + + if (ctx->Extensions.ARB_vertex_program + && (strncmp((char *) program, "!!ARB", 5) == 0)) { + _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog); + } else { + _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); + } + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; + if (!fprog || prog == &_mesa_DummyProgram) { + fprog = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!fprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, fprog); + } + _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; + if (!fprog || prog == &_mesa_DummyProgram) { + fprog = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!fprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, fprog); + } + _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); + } +} + + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, + GLsizei num, const GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV"); + return; + } + for (i = 0; i < num; i++) { + ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0]; + ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1]; + ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2]; + ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3]; + params += 4; + }; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV"); + return; + } +} + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, + GLsizei num, const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV"); + return; + } + for (i = 0; i < num; i++) { + COPY_4V(ctx->VertexProgram.Parameters[index + i], params); + params += 4; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV"); + return; + } +} + + + +/** + * Setup tracking of matrices into program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_TrackMatrixNV(GLenum target, GLuint address, + GLenum matrix, GLenum transform) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + if (address & 0x3) { + /* addr must be multiple of four */ + _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)"); + return; + } + + switch (matrix) { + case GL_NONE: + case GL_MODELVIEW: + case GL_PROJECTION: + case GL_TEXTURE: + case GL_COLOR: + case GL_MODELVIEW_PROJECTION_NV: + case GL_MATRIX0_NV: + case GL_MATRIX1_NV: + case GL_MATRIX2_NV: + case GL_MATRIX3_NV: + case GL_MATRIX4_NV: + case GL_MATRIX5_NV: + case GL_MATRIX6_NV: + case GL_MATRIX7_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)"); + return; + } + + switch (transform) { + case GL_IDENTITY_NV: + case GL_INVERSE_NV: + case GL_TRANSPOSE_NV: + case GL_INVERSE_TRANSPOSE_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)"); + return; + } + + ctx->VertexProgram.TrackMatrix[address / 4] = matrix; + ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)"); + return; + } +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + gl_constant_value *v; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, + (char *) name); + if (v) { + v[0].f = x; + v[1].f = y; + v[2].f = z; + v[3].f = w; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, + const float v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y, + (GLfloat)z, (GLfloat)w); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, + const double v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, + (GLfloat)v[0], (GLfloat)v[1], + (GLfloat)v[2], (GLfloat)v[3]); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat *params) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + const gl_constant_value *v; + + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, + len, (char *) name); + if (v) { + params[0] = v[0].f; + params[1] = v[1].f; + params[2] = v[2].f; + params[3] = v[3].f; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble *params) +{ + GLfloat floatParams[4]; + _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams); + COPY_4V(params, floatParams); +} diff --git a/mesalib/src/mesa/main/texcompress_rgtc_tmp.h b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h index c8bf082a1..48bbd374e 100644 --- a/mesalib/src/mesa/main/texcompress_rgtc_tmp.h +++ b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h @@ -181,7 +181,7 @@ static void TAG(encode_rgtc_chan)(TYPE *blkaddr, TYPE srccolors[4][4], fprintf(stderr, "%d ", alphaenc1[i]); } fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { + for (i = 0; i < 7; i++) { fprintf(stderr, "%d ", acutValues[i]); } fprintf(stderr, "srcVals "); diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c index 3021716a0..078a43ab1 100644 --- a/mesalib/src/mesa/main/texobj.c +++ b/mesalib/src/mesa/main/texobj.c @@ -842,7 +842,7 @@ _mesa_GenTextures( GLsizei n, GLuint *textures ) struct gl_texture_object *texObj; GLuint name = first + i; GLenum target = 0; - texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); + texObj = ctx->Driver.NewTextureObject(ctx, name, target); if (!texObj) { _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); @@ -1066,7 +1066,7 @@ _mesa_BindTexture( GLenum target, GLuint texName ) } else { /* if this is a new texture id, allocate a texture object now */ - newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); + newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); if (!newTexObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); return; @@ -1108,7 +1108,7 @@ _mesa_BindTexture( GLenum target, GLuint texName ) /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) - (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); + ctx->Driver.BindTexture(ctx, target, newTexObj); } diff --git a/mesalib/src/mesa/main/texparam.c b/mesalib/src/mesa/main/texparam.c index 134f15346..bbbb306b2 100644 --- a/mesalib/src/mesa/main/texparam.c +++ b/mesalib/src/mesa/main/texparam.c @@ -994,28 +994,21 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, *params = 0; break; case GL_TEXTURE_DEPTH_SIZE_ARB: - if (ctx->Extensions.ARB_depth_texture) - *params = _mesa_get_format_bits(texFormat, pname); - else + if (!ctx->Extensions.ARB_depth_texture) goto invalid_pname; + *params = _mesa_get_format_bits(texFormat, pname); break; case GL_TEXTURE_STENCIL_SIZE_EXT: - if (ctx->Extensions.EXT_packed_depth_stencil || - ctx->Extensions.ARB_framebuffer_object) { - *params = _mesa_get_format_bits(texFormat, pname); - } - else { + if (!ctx->Extensions.EXT_packed_depth_stencil && + !ctx->Extensions.ARB_framebuffer_object) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, pname); break; case GL_TEXTURE_SHARED_SIZE: - if (ctx->VersionMajor >= 3 || - ctx->Extensions.EXT_texture_shared_exponent) { - *params = texFormat == MESA_FORMAT_RGB9_E5_FLOAT ? 5 : 0; - } - else { + if (ctx->VersionMajor < 3 && + !ctx->Extensions.EXT_texture_shared_exponent) goto invalid_pname; - } + *params = texFormat == MESA_FORMAT_RGB9_E5_FLOAT ? 5 : 0; break; /* GL_ARB_texture_compression */ @@ -1036,67 +1029,46 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, /* GL_ARB_texture_float */ case GL_TEXTURE_RED_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_GREEN_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_BLUE_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_ALPHA_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_LUMINANCE_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_LUMINANCE_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_LUMINANCE_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_INTENSITY_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_INTENSITY_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_INTENSITY_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; case GL_TEXTURE_DEPTH_TYPE_ARB: - if (ctx->Extensions.ARB_texture_float) { - *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE) ? - _mesa_get_format_datatype(texFormat) : GL_NONE; - } - else { + if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; - } + *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE) ? + _mesa_get_format_datatype(texFormat) : GL_NONE; break; default: @@ -1118,7 +1090,6 @@ void GLAPIENTRY _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) { struct gl_texture_object *obj; - GLboolean error = GL_FALSE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1144,17 +1115,15 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) *params = ENUM_TO_FLOAT(obj->Sampler.WrapR); break; case GL_TEXTURE_BORDER_COLOR: - if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP)) + if (ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP)) _mesa_update_state_locked(ctx); - if(ctx->Color._ClampFragmentColor) - { + if (ctx->Color._ClampFragmentColor) { params[0] = CLAMP(obj->Sampler.BorderColor.f[0], 0.0F, 1.0F); params[1] = CLAMP(obj->Sampler.BorderColor.f[1], 0.0F, 1.0F); params[2] = CLAMP(obj->Sampler.BorderColor.f[2], 0.0F, 1.0F); params[3] = CLAMP(obj->Sampler.BorderColor.f[3], 0.0F, 1.0F); } - else - { + else { params[0] = obj->Sampler.BorderColor.f[0]; params[1] = obj->Sampler.BorderColor.f[1]; params[2] = obj->Sampler.BorderColor.f[2]; @@ -1162,14 +1131,8 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) } break; case GL_TEXTURE_RESIDENT: - { - GLboolean resident; - if (ctx->Driver.IsTextureResident) - resident = ctx->Driver.IsTextureResident(ctx, obj); - else - resident = GL_TRUE; - *params = ENUM_TO_FLOAT(resident); - } + *params = ctx->Driver.IsTextureResident ? + ctx->Driver.IsTextureResident(ctx, obj) : 1.0F; break; case GL_TEXTURE_PRIORITY: *params = obj->Priority; @@ -1187,49 +1150,37 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) *params = (GLfloat) obj->MaxLevel; break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (ctx->Extensions.EXT_texture_filter_anisotropic) { - *params = obj->Sampler.MaxAnisotropy; - } - else - error = GL_TRUE; + if (!ctx->Extensions.EXT_texture_filter_anisotropic) + goto invalid_pname; + *params = obj->Sampler.MaxAnisotropy; break; case GL_TEXTURE_COMPARE_FAIL_VALUE_ARB: - if (ctx->Extensions.ARB_shadow_ambient) { - *params = obj->Sampler.CompareFailValue; - } - else - error = GL_TRUE; + if (!ctx->Extensions.ARB_shadow_ambient) + goto invalid_pname; + *params = obj->Sampler.CompareFailValue; break; case GL_GENERATE_MIPMAP_SGIS: *params = (GLfloat) obj->GenerateMipmap; break; case GL_TEXTURE_COMPARE_MODE_ARB: - if (ctx->Extensions.ARB_shadow) { - *params = (GLfloat) obj->Sampler.CompareMode; - } - else - error = GL_TRUE; + if (!ctx->Extensions.ARB_shadow) + goto invalid_pname; + *params = (GLfloat) obj->Sampler.CompareMode; break; case GL_TEXTURE_COMPARE_FUNC_ARB: - if (ctx->Extensions.ARB_shadow) { - *params = (GLfloat) obj->Sampler.CompareFunc; - } - else - error = GL_TRUE; + if (!ctx->Extensions.ARB_shadow) + goto invalid_pname; + *params = (GLfloat) obj->Sampler.CompareFunc; break; case GL_DEPTH_TEXTURE_MODE_ARB: - if (ctx->Extensions.ARB_depth_texture) { - *params = (GLfloat) obj->Sampler.DepthMode; - } - else - error = GL_TRUE; + if (!ctx->Extensions.ARB_depth_texture) + goto invalid_pname; + *params = (GLfloat) obj->Sampler.DepthMode; break; case GL_TEXTURE_LOD_BIAS: - if (ctx->Extensions.EXT_texture_lod_bias) { - *params = obj->Sampler.LodBias; - } - else - error = GL_TRUE; + if (!ctx->Extensions.EXT_texture_lod_bias) + goto invalid_pname; + *params = obj->Sampler.LodBias; break; #if FEATURE_OES_draw_texture case GL_TEXTURE_CROP_RECT_OES: @@ -1244,46 +1195,40 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) case GL_TEXTURE_SWIZZLE_G_EXT: case GL_TEXTURE_SWIZZLE_B_EXT: case GL_TEXTURE_SWIZZLE_A_EXT: - if (ctx->Extensions.EXT_texture_swizzle) { - GLuint comp = pname - GL_TEXTURE_SWIZZLE_R_EXT; - *params = (GLfloat) obj->Swizzle[comp]; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.EXT_texture_swizzle) + goto invalid_pname; + *params = (GLfloat) obj->Swizzle[pname - GL_TEXTURE_SWIZZLE_R_EXT]; break; case GL_TEXTURE_SWIZZLE_RGBA_EXT: - if (ctx->Extensions.EXT_texture_swizzle) { + if (!ctx->Extensions.EXT_texture_swizzle) { + goto invalid_pname; + } + else { GLuint comp; for (comp = 0; comp < 4; comp++) { params[comp] = (GLfloat) obj->Swizzle[comp]; } } - else { - error = GL_TRUE; - } break; case GL_TEXTURE_CUBE_MAP_SEAMLESS: - if (ctx->Extensions.AMD_seamless_cubemap_per_texture) { - *params = (GLfloat) obj->Sampler.CubeMapSeamless; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.AMD_seamless_cubemap_per_texture) + goto invalid_pname; + *params = (GLfloat) obj->Sampler.CubeMapSeamless; break; default: - error = GL_TRUE; - break; + goto invalid_pname; } - if (error) - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)", - pname); + /* no error if we get here */ + _mesa_unlock_texture(ctx, obj); + return; +invalid_pname: _mesa_unlock_texture(ctx, obj); + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)", pname); } @@ -1291,13 +1236,12 @@ void GLAPIENTRY _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params ) { struct gl_texture_object *obj; - GLboolean error = GL_FALSE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - obj = get_texobj(ctx, target, GL_TRUE); - if (!obj) - return; + obj = get_texobj(ctx, target, GL_TRUE); + if (!obj) + return; _mesa_lock_texture(ctx, obj); switch (pname) { @@ -1330,14 +1274,8 @@ _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params ) } break;; case GL_TEXTURE_RESIDENT: - { - GLboolean resident; - if (ctx->Driver.IsTextureResident) - resident = ctx->Driver.IsTextureResident(ctx, obj); - else - resident = GL_TRUE; - *params = (GLint) resident; - } + *params = ctx->Driver.IsTextureResident ? + ctx->Driver.IsTextureResident(ctx, obj) : 1; break;; case GL_TEXTURE_PRIORITY: *params = FLOAT_TO_INT(obj->Priority); @@ -1355,55 +1293,37 @@ _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params ) *params = obj->MaxLevel; break;; case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (ctx->Extensions.EXT_texture_filter_anisotropic) { - *params = (GLint) obj->Sampler.MaxAnisotropy; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.EXT_texture_filter_anisotropic) + goto invalid_pname; + *params = (GLint) obj->Sampler.MaxAnisotropy; break; case GL_TEXTURE_COMPARE_FAIL_VALUE_ARB: - if (ctx->Extensions.ARB_shadow_ambient) { - *params = (GLint) FLOAT_TO_INT(obj->Sampler.CompareFailValue); - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.ARB_shadow_ambient) + goto invalid_pname; + *params = (GLint) FLOAT_TO_INT(obj->Sampler.CompareFailValue); break; case GL_GENERATE_MIPMAP_SGIS: *params = (GLint) obj->GenerateMipmap; break; case GL_TEXTURE_COMPARE_MODE_ARB: - if (ctx->Extensions.ARB_shadow) { - *params = (GLint) obj->Sampler.CompareMode; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.ARB_shadow) + goto invalid_pname; + *params = (GLint) obj->Sampler.CompareMode; break; case GL_TEXTURE_COMPARE_FUNC_ARB: - if (ctx->Extensions.ARB_shadow) { - *params = (GLint) obj->Sampler.CompareFunc; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.ARB_shadow) + goto invalid_pname; + *params = (GLint) obj->Sampler.CompareFunc; break; case GL_DEPTH_TEXTURE_MODE_ARB: - if (ctx->Extensions.ARB_depth_texture) { - *params = (GLint) obj->Sampler.DepthMode; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.ARB_depth_texture) + goto invalid_pname; + *params = (GLint) obj->Sampler.DepthMode; break; case GL_TEXTURE_LOD_BIAS: - if (ctx->Extensions.EXT_texture_lod_bias) { - *params = (GLint) obj->Sampler.LodBias; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.EXT_texture_lod_bias) + goto invalid_pname; + *params = (GLint) obj->Sampler.LodBias; break; #if FEATURE_OES_draw_texture case GL_TEXTURE_CROP_RECT_OES: @@ -1417,42 +1337,34 @@ _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params ) case GL_TEXTURE_SWIZZLE_G_EXT: case GL_TEXTURE_SWIZZLE_B_EXT: case GL_TEXTURE_SWIZZLE_A_EXT: - if (ctx->Extensions.EXT_texture_swizzle) { - GLuint comp = pname - GL_TEXTURE_SWIZZLE_R_EXT; - *params = obj->Swizzle[comp]; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.EXT_texture_swizzle) + goto invalid_pname; + *params = obj->Swizzle[pname - GL_TEXTURE_SWIZZLE_R_EXT]; break; case GL_TEXTURE_SWIZZLE_RGBA_EXT: - if (ctx->Extensions.EXT_texture_swizzle) { - COPY_4V(params, obj->Swizzle); - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.EXT_texture_swizzle) + goto invalid_pname; + COPY_4V(params, obj->Swizzle); break; case GL_TEXTURE_CUBE_MAP_SEAMLESS: - if (ctx->Extensions.AMD_seamless_cubemap_per_texture) { - *params = (GLint) obj->Sampler.CubeMapSeamless; - } - else { - error = GL_TRUE; - } + if (!ctx->Extensions.AMD_seamless_cubemap_per_texture) + goto invalid_pname; + *params = (GLint) obj->Sampler.CubeMapSeamless; break; default: - ; /* silence warnings */ + goto invalid_pname; } - if (error) - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameteriv(pname=0x%x)", - pname); + /* no error if we get here */ + _mesa_unlock_texture(ctx, obj); + return; +invalid_pname: _mesa_unlock_texture(ctx, obj); + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameteriv(pname=0x%x)", pname); } @@ -1465,6 +1377,8 @@ _mesa_GetTexParameterIiv(GLenum target, GLenum pname, GLint *params) ASSERT_OUTSIDE_BEGIN_END(ctx); texObj = get_texobj(ctx, target, GL_TRUE); + if (!texObj) + return; switch (pname) { case GL_TEXTURE_BORDER_COLOR: @@ -1485,6 +1399,8 @@ _mesa_GetTexParameterIuiv(GLenum target, GLenum pname, GLuint *params) ASSERT_OUTSIDE_BEGIN_END(ctx); texObj = get_texobj(ctx, target, GL_TRUE); + if (!texObj) + return; switch (pname) { case GL_TEXTURE_BORDER_COLOR: diff --git a/mesalib/src/mesa/main/uniforms.c b/mesalib/src/mesa/main/uniforms.c index dd069a3a4..1329af4cd 100644 --- a/mesalib/src/mesa/main/uniforms.c +++ b/mesalib/src/mesa/main/uniforms.c @@ -429,7 +429,7 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location, for (i = 0; i < rows; i++) { const int base = paramPos + offset + i; for (j = 0; j < cols; j++ ) { - params[k++] = prog->Parameters->ParameterValues[base][j]; + params[k++] = prog->Parameters->ParameterValues[base][j].f; } } } @@ -442,7 +442,7 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location, const int base = paramPos + offset + i; for (j = 0; j < cols; j++ ) { params[k++] = (GLdouble) - prog->Parameters->ParameterValues[base][j]; + prog->Parameters->ParameterValues[base][j].f; } } } @@ -454,8 +454,9 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location, for (i = 0; i < rows; i++) { const int base = paramPos + offset + i; for (j = 0; j < cols; j++ ) { - params[k++] = (GLint) - prog->Parameters->ParameterValues[base][j]; + params[k++] = ctx->Const.GLSLVersion <= 120 ? + (GLint) prog->Parameters->ParameterValues[base][j].f : + prog->Parameters->ParameterValues[base][j].i; } } } @@ -467,8 +468,9 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location, for (i = 0; i < rows; i++) { const int base = paramPos + offset + i; for (j = 0; j < cols; j++ ) { - params[k++] = (GLuint) - prog->Parameters->ParameterValues[base][j]; + params[k++] = ctx->Const.GLSLVersion <= 120 ? + (GLuint) prog->Parameters->ParameterValues[base][j].f : + prog->Parameters->ParameterValues[base][j].u; } } } @@ -670,7 +672,7 @@ set_program_uniform(struct gl_context *ctx, struct gl_program *program, /* loop over number of samplers to change */ for (i = 0; i < count; i++) { GLuint sampler = (GLuint) - program->Parameters->ParameterValues[index + offset + i][0]; + program->Parameters->ParameterValues[index+offset + i][0].f; GLuint texUnit = ((GLuint *) values)[i]; /* check that the sampler (tex unit index) is legal */ @@ -735,42 +737,52 @@ set_program_uniform(struct gl_context *ctx, struct gl_program *program, /* loop over number of array elements */ for (k = 0; k < count; k++) { - GLfloat *uniformVal; + gl_constant_value *uniformVal; if (offset + k >= slots) { /* Extra array data is ignored */ break; } - /* uniformVal (the destination) is always float[4] */ + /* uniformVal (the destination) is always gl_constant_value[4] */ uniformVal = program->Parameters->ParameterValues[index + offset + k]; if (basicType == GL_INT) { - /* convert user's ints to floats */ const GLint *iValues = ((const GLint *) values) + k * elems; for (i = 0; i < elems; i++) { - uniformVal[i] = (GLfloat) iValues[i]; + if (ctx->Const.GLSLVersion <= 120) + uniformVal[i].f = (GLfloat) iValues[i]; + else + uniformVal[i].i = iValues[i]; } } else if (basicType == GL_UNSIGNED_INT) { - /* convert user's uints to floats */ const GLuint *iValues = ((const GLuint *) values) + k * elems; for (i = 0; i < elems; i++) { - uniformVal[i] = (GLfloat) iValues[i]; + if (ctx->Const.GLSLVersion <= 120) + uniformVal[i].f = (GLfloat)(GLuint) iValues[i]; + else + uniformVal[i].u = iValues[i]; } } else { const GLfloat *fValues = ((const GLfloat *) values) + k * elems; assert(basicType == GL_FLOAT); for (i = 0; i < elems; i++) { - uniformVal[i] = fValues[i]; + uniformVal[i].f = fValues[i]; } } - /* if the uniform is bool-valued, convert to 1.0 or 0.0 */ + /* if the uniform is bool-valued, convert to 1 or 0 */ if (isUniformBool) { for (i = 0; i < elems; i++) { - uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f; + if (basicType == GL_FLOAT) + uniformVal[i].b = uniformVal[i].f != 0.0f ? 1 : 0; + else + uniformVal[i].b = uniformVal[i].u ? 1 : 0; + + if (ctx->Const.GLSLVersion <= 120) + uniformVal[i].f = uniformVal[i].b ? 1.0f : 0.0f; } } } @@ -936,7 +948,7 @@ set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program, /* Ignore writes beyond the end of (the used part of) an array */ return; } - v = program->Parameters->ParameterValues[index + offset]; + v = (GLfloat *) program->Parameters->ParameterValues[index + offset]; for (row = 0; row < rows; row++) { if (transpose) { v[row] = values[src + row * cols + col]; -- cgit v1.2.3