X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fff_fragment_shader.cpp;h=3a80ab7f3b737d5b663634fc8197ad2ed263b565;hb=4fce0230fc3528be32562410bcddfc887c4d25a0;hp=50d6be70d403472831924ea4ef683757146796f6;hpb=7cb87dffce2c7a37f960f3a865cf92fd193dd8c5;p=mesa.git diff --git a/src/mesa/main/ff_fragment_shader.cpp b/src/mesa/main/ff_fragment_shader.cpp index 50d6be70d40..3a80ab7f3b7 100644 --- a/src/mesa/main/ff_fragment_shader.cpp +++ b/src/mesa/main/ff_fragment_shader.cpp @@ -3,7 +3,7 @@ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * Copyright 2009 VMware, Inc. All Rights Reserved. - * Copyright © 2010 Intel Corporation + * Copyright © 2010-2011 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -33,6 +33,7 @@ extern "C" { #include "mtypes.h" #include "main/uniforms.h" #include "main/macros.h" +#include "main/samplerobj.h" #include "program/program.h" #include "program/prog_parameter.h" #include "program/prog_cache.h" @@ -42,14 +43,18 @@ extern "C" { #include "program/programopt.h" #include "texenvprogram.h" } +#include "main/uniforms.h" #include "../glsl/glsl_types.h" #include "../glsl/ir.h" +#include "../glsl/ir_builder.h" #include "../glsl/glsl_symbol_table.h" #include "../glsl/glsl_parser_extras.h" #include "../glsl/ir_optimization.h" #include "../glsl/ir_print_visitor.h" #include "../program/ir_to_mesa.h" +using namespace ir_builder; + /* * Note on texture units: * @@ -108,7 +113,7 @@ struct state_key { /* NOTE: This array of structs must be last! (see "keySize" below) */ struct { GLuint enabled:1; - GLuint source_index:3; /**< TEXTURE_x_INDEX */ + GLuint source_index:4; /**< TEXTURE_x_INDEX */ GLuint shadow:1; GLuint ScaleShiftRGB:2; GLuint ScaleShiftA:2; @@ -294,7 +299,7 @@ need_saturate( GLuint mode ) static GLuint translate_tex_src_bit( GLbitfield bit ) { ASSERT(bit); - return _mesa_ffs(bit) - 1; + return ffs(bit) - 1; } @@ -316,7 +321,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx ) const GLboolean vertexShader = (ctx->Shader.CurrentVertexProgram && ctx->Shader.CurrentVertexProgram->LinkStatus && - ctx->Shader.CurrentVertexProgram->VertexProgram); + ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]); const GLboolean vertexProgram = ctx->VertexProgram._Enabled; GLbitfield fp_inputs = 0x0; @@ -331,11 +336,10 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx ) /* _NEW_RENDERMODE */ fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0); } - else if (!(vertexProgram || vertexShader) || - !ctx->VertexProgram._Current) { + else if (!(vertexProgram || vertexShader)) { /* Fixed function vertex logic */ - /* _NEW_ARRAY */ - GLbitfield varying_inputs = ctx->varying_vp_inputs; + /* _NEW_VARYING_VP_INPUTS */ + GLbitfield64 varying_inputs = ctx->varying_vp_inputs; /* These get generated in the setup routine regardless of the * vertex program: @@ -373,7 +377,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx ) } else { /* calculate from vp->outputs */ - struct gl_vertex_program *vprog; + struct gl_program *vprog; GLbitfield64 vp_outputs; /* Choose GLSL vertex shader over ARB vertex program. Need this @@ -381,11 +385,11 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx ) * validation (see additional comments in state.c). */ if (vertexShader) - vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; + vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program; else - vprog = ctx->VertexProgram.Current; + vprog = &ctx->VertexProgram.Current->Base; - vp_outputs = vprog->Base.OutputsWritten; + vp_outputs = vprog->OutputsWritten; /* These get generated in the setup routine regardless of the * vertex program: @@ -425,11 +429,13 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; const struct gl_texture_object *texObj = texUnit->_Current; const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine; + const struct gl_sampler_object *samp; GLenum format; if (!texUnit->_ReallyEnabled || !texUnit->Enabled) continue; + samp = _mesa_get_samplerobj(ctx, i); format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; key->unit[i].enabled = 1; @@ -440,9 +446,10 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) key->unit[i].source_index = translate_tex_src_bit(texUnit->_ReallyEnabled); - key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) && - ((format == GL_DEPTH_COMPONENT) || - (format == GL_DEPTH_STENCIL_EXT))); + key->unit[i].shadow = + ((samp->CompareMode == GL_COMPARE_R_TO_TEXTURE) && + ((format == GL_DEPTH_COMPONENT) || + (format == GL_DEPTH_STENCIL_EXT))); key->unit[i].NumArgsRGB = comb->_NumArgsRGB; key->unit[i].NumArgsA = comb->_NumArgsA; @@ -489,6 +496,12 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) /* _NEW_BUFFERS */ key->num_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers; + /* _NEW_COLOR */ + if (ctx->Color.AlphaEnabled && key->num_draw_buffers == 0) { + /* if alpha test is enabled we need to emit at least one color */ + key->num_draw_buffers = 1; + } + key->inputs_available = (inputs_available & inputs_referenced); /* compute size of state key, ignoring unused texture units */ @@ -501,27 +514,20 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) /** State used to build the fragment program: */ -struct texenv_fragment_program { +class texenv_fragment_program : public ir_factory { +public: struct gl_shader_program *shader_program; struct gl_shader *shader; - struct gl_fragment_program *program; - exec_list *instructions; exec_list *top_instructions; - void *mem_ctx; struct state_key *state; - GLbitfield alu_temps; /**< Track texture indirections, see spec. */ - GLbitfield temps_output; /**< Track texture indirections, see spec. */ - GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */ - GLboolean error; - ir_variable *src_texture[MAX_TEXTURE_COORD_UNITS]; /* Reg containing each texture unit's sampled texture color, * else undef. */ /* Texcoord override from bumpmapping. */ - struct ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS]; + ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS]; /* Reg containing texcoord for a texture unit, * needed for bump mapping, else undef. @@ -530,12 +536,35 @@ struct texenv_fragment_program { ir_rvalue *src_previous; /**< Reg containing color from previous * stage. May need to be decl'd. */ - - GLuint last_tex_stage; /**< Number of last enabled texture unit */ }; static ir_rvalue * -get_source(struct texenv_fragment_program *p, +get_current_attrib(texenv_fragment_program *p, GLuint attrib) +{ + ir_variable *current; + ir_rvalue *val; + + current = p->shader->symbols->get_variable("gl_CurrentAttribFragMESA"); + current->max_array_access = MAX2(current->max_array_access, attrib); + val = new(p->mem_ctx) ir_dereference_variable(current); + ir_rvalue *index = new(p->mem_ctx) ir_constant(attrib); + return new(p->mem_ctx) ir_dereference_array(val, index); +} + +static ir_rvalue * +get_gl_Color(texenv_fragment_program *p) +{ + if (p->state->inputs_available & FRAG_BIT_COL0) { + ir_variable *var = p->shader->symbols->get_variable("gl_Color"); + assert(var); + return new(p->mem_ctx) ir_dereference_variable(var); + } else { + return get_current_attrib(p, VERT_ATTRIB_COLOR0); + } +} + +static ir_rvalue * +get_source(texenv_fragment_program *p, GLuint src, GLuint unit) { ir_variable *var; @@ -574,9 +603,7 @@ get_source(struct texenv_fragment_program *p, case SRC_PREVIOUS: if (!p->src_previous) { - var = p->shader->symbols->get_variable("gl_Color"); - assert(var); - return new(p->mem_ctx) ir_dereference_variable(var); + return get_gl_Color(p); } else { return p->src_previous->clone(p->mem_ctx, NULL); } @@ -588,7 +615,7 @@ get_source(struct texenv_fragment_program *p, } static ir_rvalue * -emit_combine_source(struct texenv_fragment_program *p, +emit_combine_source(texenv_fragment_program *p, GLuint unit, GLuint source, GLuint operand) @@ -599,19 +626,17 @@ emit_combine_source(struct texenv_fragment_program *p, switch (operand) { case OPR_ONE_MINUS_SRC_COLOR: - return new(p->mem_ctx) ir_expression(ir_binop_sub, - new(p->mem_ctx) ir_constant(1.0f), - src); - - case OPR_SRC_ALPHA: - return new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1); - - case OPR_ONE_MINUS_SRC_ALPHA: - return new(p->mem_ctx) ir_expression(ir_binop_sub, - new(p->mem_ctx) ir_constant(1.0f), - new(p->mem_ctx) ir_swizzle(src, - 3, 3, - 3, 3, 1)); + return sub(new(p->mem_ctx) ir_constant(1.0f), src); + + case OPR_SRC_ALPHA: + return src->type->is_scalar() ? src : swizzle_w(src); + + case OPR_ONE_MINUS_SRC_ALPHA: { + ir_rvalue *const scalar = src->type->is_scalar() ? src : swizzle_w(src); + + return sub(new(p->mem_ctx) ir_constant(1.0f), scalar); + } + case OPR_ZERO: return new(p->mem_ctx) ir_constant(0.0f); case OPR_ONE: @@ -665,16 +690,16 @@ static GLboolean args_match( const struct state_key *key, GLuint unit ) } static ir_rvalue * -smear(struct texenv_fragment_program *p, ir_rvalue *val) +smear(texenv_fragment_program *p, ir_rvalue *val) { if (!val->type->is_scalar()) return val; - return new(p->mem_ctx) ir_swizzle(val, 0, 0, 0, 0, 4); + return swizzle_xxxx(val); } static ir_rvalue * -emit_combine(struct texenv_fragment_program *p, +emit_combine(texenv_fragment_program *p, GLuint unit, GLuint nr, GLuint mode, @@ -694,73 +719,52 @@ emit_combine(struct texenv_fragment_program *p, return src[0]; case MODE_MODULATE: - return new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]); + return mul(src[0], src[1]); case MODE_ADD: - return new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]); + return add(src[0], src[1]); case MODE_ADD_SIGNED: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]); - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, - new(p->mem_ctx) ir_constant(-0.5f)); + return add(add(src[0], src[1]), new(p->mem_ctx) ir_constant(-0.5f)); case MODE_INTERPOLATE: /* Arg0 * (Arg2) + Arg1 * (1-Arg2) */ - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]); - - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_sub, - new(p->mem_ctx) ir_constant(1.0f), - src[2]->clone(p->mem_ctx, NULL)); - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1], tmp1); - - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1); + tmp0 = mul(src[0], src[2]); + tmp1 = mul(src[1], sub(new(p->mem_ctx) ir_constant(1.0f), + src[2]->clone(p->mem_ctx, NULL))); + return add(tmp0, tmp1); case MODE_SUBTRACT: - return new(p->mem_ctx) ir_expression(ir_binop_sub, src[0], src[1]); + return sub(src[0], src[1]); case MODE_DOT3_RGBA: case MODE_DOT3_RGBA_EXT: case MODE_DOT3_RGB_EXT: case MODE_DOT3_RGB: { - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], - new(p->mem_ctx) ir_constant(2.0f)); - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, - new(p->mem_ctx) ir_constant(-1.0f)); - tmp0 = new(p->mem_ctx) ir_swizzle(smear(p, tmp0), 0, 1, 2, 3, 3); - - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1], - new(p->mem_ctx) ir_constant(2.0f)); - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp1, - new(p->mem_ctx) ir_constant(-1.0f)); - tmp1 = new(p->mem_ctx) ir_swizzle(smear(p, tmp1), 0, 1, 2, 3, 3); - - return new(p->mem_ctx) ir_expression(ir_binop_dot, tmp0, tmp1); + tmp0 = mul(src[0], new(p->mem_ctx) ir_constant(2.0f)); + tmp0 = add(tmp0, new(p->mem_ctx) ir_constant(-1.0f)); + + tmp1 = mul(src[1], new(p->mem_ctx) ir_constant(2.0f)); + tmp1 = add(tmp1, new(p->mem_ctx) ir_constant(-1.0f)); + + return dot(swizzle_xyz(smear(p, tmp0)), swizzle_xyz(smear(p, tmp1))); } case MODE_MODULATE_ADD_ATI: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]); - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]); + return add(mul(src[0], src[2]), src[1]); case MODE_MODULATE_SIGNED_ADD_ATI: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]); - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]); - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, - new(p->mem_ctx) ir_constant(-0.5f)); + return add(add(mul(src[0], src[2]), src[1]), + new(p->mem_ctx) ir_constant(-0.5f)); case MODE_MODULATE_SUBTRACT_ATI: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]); - return new(p->mem_ctx) ir_expression(ir_binop_sub, tmp0, src[1]); + return sub(mul(src[0], src[2]), src[1]); case MODE_ADD_PRODUCTS: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]); - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]); - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1); + return add(mul(src[0], src[1]), mul(src[2], src[3])); case MODE_ADD_PRODUCTS_SIGNED: - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]); - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]); - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1); - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, - new(p->mem_ctx) ir_constant(-0.5f)); + return add(add(mul(src[0], src[1]), mul(src[2], src[3])), + new(p->mem_ctx) ir_constant(-0.5f)); case MODE_BUMP_ENVMAP_ATI: /* special - not handled here */ @@ -772,20 +776,11 @@ emit_combine(struct texenv_fragment_program *p, } } -static ir_rvalue * -saturate(struct texenv_fragment_program *p, ir_rvalue *val) -{ - val = new(p->mem_ctx) ir_expression(ir_binop_min, val, - new(p->mem_ctx) ir_constant(1.0f)); - return new(p->mem_ctx) ir_expression(ir_binop_max, val, - new(p->mem_ctx) ir_constant(0.0f)); -} - /** * Generate instructions for one texture unit's env/combiner mode. */ static ir_rvalue * -emit_texenv(struct texenv_fragment_program *p, GLuint unit) +emit_texenv(texenv_fragment_program *p, GLuint unit) { const struct state_key *key = p->state; GLboolean rgb_saturate, alpha_saturate; @@ -831,13 +826,8 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) else alpha_saturate = GL_FALSE; - ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::vec4_type, - "texenv_combine", - ir_var_temporary); - p->instructions->push_tail(temp_var); - + ir_variable *temp_var = p->make_temp(glsl_type::vec4_type, "texenv_combine"); ir_dereference *deref; - ir_assignment *assign; ir_rvalue *val; /* Emit the RGB and A combine ops @@ -850,11 +840,9 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) key->unit[unit].OptRGB); val = smear(p, val); if (rgb_saturate) - val = saturate(p, val); + val = saturate(val); - deref = new(p->mem_ctx) ir_dereference_variable(temp_var); - assign = new(p->mem_ctx) ir_assignment(deref, val, NULL); - p->instructions->push_tail(assign); + p->emit(assign(temp_var, val)); } else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || key->unit[unit].ModeRGB == MODE_DOT3_RGBA) { @@ -864,10 +852,8 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) key->unit[unit].OptRGB); val = smear(p, val); if (rgb_saturate) - val = saturate(p, val); - deref = new(p->mem_ctx) ir_dereference_variable(temp_var); - assign = new(p->mem_ctx) ir_assignment(deref, val, NULL); - p->instructions->push_tail(assign); + val = saturate(val); + p->emit(assign(temp_var, val)); } else { /* Need to do something to stop from re-emitting identical @@ -877,25 +863,19 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, key->unit[unit].OptRGB); - val = smear(p, val); - val = new(p->mem_ctx) ir_swizzle(val, 0, 1, 2, 3, 3); + val = swizzle_xyz(smear(p, val)); if (rgb_saturate) - val = saturate(p, val); - deref = new(p->mem_ctx) ir_dereference_variable(temp_var); - assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_XYZ); - p->instructions->push_tail(assign); + val = saturate(val); + p->emit(assign(temp_var, val, WRITEMASK_XYZ)); val = emit_combine(p, unit, key->unit[unit].NumArgsA, key->unit[unit].ModeA, key->unit[unit].OptA); - val = smear(p, val); - val = new(p->mem_ctx) ir_swizzle(val, 3, 3, 3, 3, 1); + val = swizzle_w(smear(p, val)); if (alpha_saturate) - val = saturate(p, val); - deref = new(p->mem_ctx) ir_dereference_variable(temp_var); - assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_W); - p->instructions->push_tail(assign); + val = saturate(val); + p->emit(assign(temp_var, val, WRITEMASK_W)); } deref = new(p->mem_ctx) ir_dereference_variable(temp_var); @@ -910,17 +890,16 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) } else { float const_data[4] = { - 1 << rgb_shift, - 1 << rgb_shift, - 1 << rgb_shift, - 1 << alpha_shift + float(1 << rgb_shift), + float(1 << rgb_shift), + float(1 << rgb_shift), + float(1 << alpha_shift) }; shift = new(p->mem_ctx) ir_constant(glsl_type::vec4_type, (ir_constant_data *)const_data); } - return saturate(p, new(p->mem_ctx) ir_expression(ir_binop_mul, - deref, shift)); + return saturate(mul(deref, shift)); } else return deref; @@ -930,132 +909,137 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) /** * Generate instruction for getting a texture source term. */ - static void load_texture( struct texenv_fragment_program *p, GLuint unit ) - { - ir_dereference *deref; - ir_assignment *assign; - - if (p->src_texture[unit]) - return; - - const GLuint texTarget = p->state->unit[unit].source_index; - ir_rvalue *texcoord; - - if (p->texcoord_tex[unit]) { - texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]); - } - else { - ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord"); - assert(tc_array); - texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array); - ir_rvalue *index = new(p->mem_ctx) ir_constant(unit); - texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index); - tc_array->max_array_access = MAX2(tc_array->max_array_access, unit); - } - - if (!p->state->unit[unit].enabled) { - p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type, - "dummy_tex", - ir_var_temporary); - p->instructions->push_tail(p->src_texture[unit]); - - deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]); - assign = new(p->mem_ctx) ir_assignment(deref, - new(p->mem_ctx) ir_constant(0.0f), - NULL); - p->instructions->push_tail(assign); - return ; - } - - const glsl_type *sampler_type = NULL; - int coords = 0; - - switch (texTarget) { - case TEXTURE_1D_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("sampler1DShadow"); - else - sampler_type = p->shader->symbols->get_type("sampler1D"); - coords = 1; - break; - case TEXTURE_1D_ARRAY_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow"); - else - sampler_type = p->shader->symbols->get_type("sampler1DArray"); - coords = 2; - break; - case TEXTURE_2D_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("sampler2DShadow"); - else - sampler_type = p->shader->symbols->get_type("sampler2D"); - coords = 2; - break; - case TEXTURE_2D_ARRAY_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow"); - else - sampler_type = p->shader->symbols->get_type("sampler2DArray"); - coords = 3; - break; - case TEXTURE_RECT_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("sampler2DRectShadow"); - else - sampler_type = p->shader->symbols->get_type("sampler2DRect"); - coords = 2; - break; - case TEXTURE_3D_INDEX: - assert(!p->state->unit[unit].shadow); - sampler_type = p->shader->symbols->get_type("sampler3D"); - coords = 3; - break; - case TEXTURE_CUBE_INDEX: - if (p->state->unit[unit].shadow) - sampler_type = p->shader->symbols->get_type("samplerCubeShadow"); - else - sampler_type = p->shader->symbols->get_type("samplerCube"); - coords = 3; - break; - } - - p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type, - "tex", - ir_var_temporary); - p->instructions->push_tail(p->src_texture[unit]); - - ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex); - - - char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit); - ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type, - sampler_name, - ir_var_uniform); - p->top_instructions->push_head(sampler); - deref = new(p->mem_ctx) ir_dereference_variable(sampler); - tex->set_sampler(deref); - - tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords); - - if (p->state->unit[unit].shadow) { - texcoord = texcoord->clone(p->mem_ctx, NULL); - tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord, - coords, 0, 0, 0, - 1); - coords++; - } - - texcoord = texcoord->clone(p->mem_ctx, NULL); - tex->projector = new(p->mem_ctx) ir_swizzle(texcoord, 3, 0, 0, 0, 1); - - deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]); - assign = new(p->mem_ctx) ir_assignment(deref, tex, NULL); - p->instructions->push_tail(assign); - } +static void load_texture( texenv_fragment_program *p, GLuint unit ) +{ + ir_dereference *deref; + + if (p->src_texture[unit]) + return; + + const GLuint texTarget = p->state->unit[unit].source_index; + ir_rvalue *texcoord; + + if (!(p->state->inputs_available & (FRAG_BIT_TEX0 << unit))) { + texcoord = get_current_attrib(p, VERT_ATTRIB_TEX0 + unit); + } else if (p->texcoord_tex[unit]) { + texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]); + } else { + ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord"); + assert(tc_array); + texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array); + ir_rvalue *index = new(p->mem_ctx) ir_constant(unit); + texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index); + tc_array->max_array_access = MAX2(tc_array->max_array_access, unit); + } + + if (!p->state->unit[unit].enabled) { + p->src_texture[unit] = p->make_temp(glsl_type::vec4_type, + "dummy_tex"); + p->emit(p->src_texture[unit]); + + p->emit(assign(p->src_texture[unit], new(p->mem_ctx) ir_constant(0.0f))); + return ; + } + + const glsl_type *sampler_type = NULL; + int coords = 0; + + switch (texTarget) { + case TEXTURE_1D_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("sampler1DShadow"); + else + sampler_type = p->shader->symbols->get_type("sampler1D"); + coords = 1; + break; + case TEXTURE_1D_ARRAY_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow"); + else + sampler_type = p->shader->symbols->get_type("sampler1DArray"); + coords = 2; + break; + case TEXTURE_2D_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("sampler2DShadow"); + else + sampler_type = p->shader->symbols->get_type("sampler2D"); + coords = 2; + break; + case TEXTURE_2D_ARRAY_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow"); + else + sampler_type = p->shader->symbols->get_type("sampler2DArray"); + coords = 3; + break; + case TEXTURE_RECT_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("sampler2DRectShadow"); + else + sampler_type = p->shader->symbols->get_type("sampler2DRect"); + coords = 2; + break; + case TEXTURE_3D_INDEX: + assert(!p->state->unit[unit].shadow); + sampler_type = p->shader->symbols->get_type("sampler3D"); + coords = 3; + break; + case TEXTURE_CUBE_INDEX: + if (p->state->unit[unit].shadow) + sampler_type = p->shader->symbols->get_type("samplerCubeShadow"); + else + sampler_type = p->shader->symbols->get_type("samplerCube"); + coords = 3; + break; + case TEXTURE_EXTERNAL_INDEX: + assert(!p->state->unit[unit].shadow); + sampler_type = p->shader->symbols->get_type("samplerExternalOES"); + coords = 2; + break; + } + + p->src_texture[unit] = p->make_temp(glsl_type::vec4_type, + "tex"); + + ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex); + + + char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit); + ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type, + sampler_name, + ir_var_uniform); + p->top_instructions->push_head(sampler); + + /* Set the texture unit for this sampler. The linker will pick this value + * up and do-the-right-thing. + * + * NOTE: The cast to int is important. Without it, the constant will have + * type uint, and things later on may get confused. + */ + sampler->constant_value = new(p->mem_ctx) ir_constant(int(unit)); + + deref = new(p->mem_ctx) ir_dereference_variable(sampler); + tex->set_sampler(deref, glsl_type::vec4_type); + + tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords); + + if (p->state->unit[unit].shadow) { + texcoord = texcoord->clone(p->mem_ctx, NULL); + tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord, + coords, 0, 0, 0, + 1); + coords++; + } + + texcoord = texcoord->clone(p->mem_ctx, NULL); + tex->projector = swizzle_w(texcoord); + + p->emit(assign(p->src_texture[unit], tex)); +} static void -load_texenv_source(struct texenv_fragment_program *p, +load_texenv_source(texenv_fragment_program *p, GLuint src, GLuint unit) { switch (src) { @@ -1085,7 +1069,7 @@ load_texenv_source(struct texenv_fragment_program *p, * Generate instructions for loading all texture source terms. */ static GLboolean -load_texunit_sources( struct texenv_fragment_program *p, GLuint unit ) +load_texunit_sources( texenv_fragment_program *p, GLuint unit ) { const struct state_key *key = p->state; GLuint i; @@ -1105,19 +1089,16 @@ load_texunit_sources( struct texenv_fragment_program *p, GLuint unit ) * Generate instructions for loading bump map textures. */ static void -load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit ) +load_texunit_bumpmap( texenv_fragment_program *p, GLuint unit ) { const struct state_key *key = p->state; GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0; ir_rvalue *bump; ir_rvalue *texcoord; - ir_variable *rot_mat_0_var, *rot_mat_1_var; - ir_dereference_variable *rot_mat_0, *rot_mat_1; + ir_variable *rot_mat_0, *rot_mat_1; - rot_mat_0_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix0"); - rot_mat_1_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix1"); - rot_mat_0 = new(p->mem_ctx) ir_dereference_variable(rot_mat_0_var); - rot_mat_1 = new(p->mem_ctx) ir_dereference_variable(rot_mat_1_var); + rot_mat_0 = p->shader->symbols->get_variable("gl_BumpRotMatrix0MESA"); + rot_mat_1 = p->shader->symbols->get_variable("gl_BumpRotMatrix1MESA"); ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord"); assert(tc_array); @@ -1132,44 +1113,22 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit ) * dest = Arg1 + (Arg0.xx * rotMat0) + (Arg0.yy * rotMat1) * note only 2 coords are affected the rest are left unchanged (mul by 0) */ - ir_dereference *deref; - ir_assignment *assign; ir_rvalue *bump_x, *bump_y; texcoord = smear(p, texcoord); /* bump_texcoord = texcoord */ - ir_variable *bumped = new(p->mem_ctx) ir_variable(texcoord->type, - "bump_texcoord", - ir_var_temporary); - p->instructions->push_tail(bumped); - - deref = new(p->mem_ctx) ir_dereference_variable(bumped); - assign = new(p->mem_ctx) ir_assignment(deref, texcoord, NULL); - p->instructions->push_tail(assign); + ir_variable *bumped = p->make_temp(texcoord->type, "bump_texcoord"); + p->emit(bumped); + p->emit(assign(bumped, texcoord)); /* bump_texcoord.xy += arg0.x * rotmat0 + arg0.y * rotmat1 */ bump = get_source(p, key->unit[unit].OptRGB[0].Source, unit); - bump_x = new(p->mem_ctx) ir_swizzle(bump, 0, 0, 0, 0, 1); - bump = bump->clone(p->mem_ctx, NULL); - bump_y = new(p->mem_ctx) ir_swizzle(bump, 1, 0, 0, 0, 1); + bump_x = mul(swizzle_x(bump), rot_mat_0); + bump_y = mul(swizzle_y(bump->clone(p->mem_ctx, NULL)), rot_mat_1); - bump_x = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_x, rot_mat_0); - bump_y = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_y, rot_mat_1); - - ir_expression *expr; - expr = new(p->mem_ctx) ir_expression(ir_binop_add, bump_x, bump_y); - - deref = new(p->mem_ctx) ir_dereference_variable(bumped); - expr = new(p->mem_ctx) ir_expression(ir_binop_add, - new(p->mem_ctx) ir_swizzle(deref, - 0, 1, 1, 1, - 2), - expr); - - deref = new(p->mem_ctx) ir_dereference_variable(bumped); - assign = new(p->mem_ctx) ir_assignment(deref, expr, NULL, WRITEMASK_XY); - p->instructions->push_tail(assign); + p->emit(assign(bumped, add(swizzle_xy(bumped), add(bump_x, bump_y)), + WRITEMASK_XY)); p->texcoord_tex[bumpedUnitNr] = bumped; } @@ -1182,38 +1141,29 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit ) * GL_FOG_COORDINATE_EXT is set to GL_FRAGMENT_DEPTH_EXT. */ static ir_rvalue * -emit_fog_instructions(struct texenv_fragment_program *p, +emit_fog_instructions(texenv_fragment_program *p, ir_rvalue *fragcolor) { struct state_key *key = p->state; ir_rvalue *f, *temp; ir_variable *params, *oparams; ir_variable *fogcoord; - ir_assignment *assign; /* Temporary storage for the whole fog result. Fog calculations * only affect rgb so we're hanging on to the .a value of fragcolor * this way. */ - ir_variable *fog_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type, - "fog_result", - ir_var_auto); - p->instructions->push_tail(fog_result); - temp = new(p->mem_ctx) ir_dereference_variable(fog_result); - assign = new(p->mem_ctx) ir_assignment(temp, fragcolor, NULL); - p->instructions->push_tail(assign); - - temp = new(p->mem_ctx) ir_dereference_variable(fog_result); - fragcolor = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3); - - oparams = p->shader->symbols->get_variable("gl_MESAFogParamsOptimized"); + ir_variable *fog_result = p->make_temp(glsl_type::vec4_type, "fog_result"); + p->emit(assign(fog_result, fragcolor)); + + fragcolor = swizzle_xyz(fog_result); + + oparams = p->shader->symbols->get_variable("gl_FogParamsOptimizedMESA"); fogcoord = p->shader->symbols->get_variable("gl_FogFragCoord"); params = p->shader->symbols->get_variable("gl_Fog"); f = new(p->mem_ctx) ir_dereference_variable(fogcoord); - ir_variable *f_var = new(p->mem_ctx) ir_variable(glsl_type::float_type, - "fog_factor", ir_var_auto); - p->instructions->push_tail(f_var); + ir_variable *f_var = p->make_temp(glsl_type::float_type, "fog_factor"); switch (key->fog_mode) { case FOG_LINEAR: @@ -1222,13 +1172,7 @@ emit_fog_instructions(struct texenv_fragment_program *p, * gl_MesaFogParamsOptimized gives us (-1 / (end - start)) and * (end / (end - start)) so we can generate a single MAD. */ - temp = new(p->mem_ctx) ir_dereference_variable(oparams); - temp = new(p->mem_ctx) ir_swizzle(temp, 0, 0, 0, 0, 1); - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp); - - temp = new(p->mem_ctx) ir_dereference_variable(oparams); - temp = new(p->mem_ctx) ir_swizzle(temp, 1, 0, 0, 0, 1); - f = new(p->mem_ctx) ir_expression(ir_binop_add, f, temp); + f = add(mul(f, swizzle_x(oparams)), swizzle_y(oparams)); break; case FOG_EXP: /* f = e^(-(density * fogcoord)) @@ -1237,9 +1181,7 @@ emit_fog_instructions(struct texenv_fragment_program *p, * use EXP2 which is generally the native instruction without * having to do any further math on the fog density uniform. */ - temp = new(p->mem_ctx) ir_dereference_variable(oparams); - temp = new(p->mem_ctx) ir_swizzle(temp, 2, 0, 0, 0, 1); - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp); + f = mul(f, swizzle_z(oparams)); f = new(p->mem_ctx) ir_expression(ir_unop_neg, f); f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f); break; @@ -1250,56 +1192,29 @@ emit_fog_instructions(struct texenv_fragment_program *p, * can do this like FOG_EXP but with a squaring after the * multiply by density. */ - ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::float_type, - "fog_temp", - ir_var_auto); - p->instructions->push_tail(temp_var); - - temp = new(p->mem_ctx) ir_dereference_variable(oparams); - temp = new(p->mem_ctx) ir_swizzle(temp, 3, 0, 0, 0, 1); - f = new(p->mem_ctx) ir_expression(ir_binop_mul, - f, temp); - - temp = new(p->mem_ctx) ir_dereference_variable(temp_var); - ir_assignment *assign = new(p->mem_ctx) ir_assignment(temp, f, NULL); - p->instructions->push_tail(assign); - - f = new(p->mem_ctx) ir_dereference_variable(temp_var); - temp = new(p->mem_ctx) ir_dereference_variable(temp_var); - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp); + ir_variable *temp_var = p->make_temp(glsl_type::float_type, "fog_temp"); + p->emit(assign(temp_var, mul(f, swizzle_w(oparams)))); + + f = mul(temp_var, temp_var); f = new(p->mem_ctx) ir_expression(ir_unop_neg, f); f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f); break; } - f = saturate(p, f); + p->emit(assign(f_var, saturate(f))); - temp = new(p->mem_ctx) ir_dereference_variable(f_var); - assign = new(p->mem_ctx) ir_assignment(temp, f, NULL); - p->instructions->push_tail(assign); - - f = new(p->mem_ctx) ir_dereference_variable(f_var); - f = new(p->mem_ctx) ir_expression(ir_binop_sub, - new(p->mem_ctx) ir_constant(1.0f), - f); + f = sub(new(p->mem_ctx) ir_constant(1.0f), f_var); temp = new(p->mem_ctx) ir_dereference_variable(params); temp = new(p->mem_ctx) ir_dereference_record(temp, "color"); - temp = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3); - temp = new(p->mem_ctx) ir_expression(ir_binop_mul, temp, f); - - f = new(p->mem_ctx) ir_dereference_variable(f_var); - f = new(p->mem_ctx) ir_expression(ir_binop_mul, fragcolor, f); - f = new(p->mem_ctx) ir_expression(ir_binop_add, temp, f); + temp = mul(swizzle_xyz(temp), f); - ir_dereference *deref = new(p->mem_ctx) ir_dereference_variable(fog_result); - assign = new(p->mem_ctx) ir_assignment(deref, f, NULL, WRITEMASK_XYZ); - p->instructions->push_tail(assign); + p->emit(assign(fog_result, add(temp, mul(fragcolor, f_var)), WRITEMASK_XYZ)); return new(p->mem_ctx) ir_dereference_variable(fog_result); } static void -emit_instructions(struct texenv_fragment_program *p) +emit_instructions(texenv_fragment_program *p) { struct state_key *key = p->state; GLuint unit; @@ -1320,7 +1235,6 @@ emit_instructions(struct texenv_fragment_program *p) for (unit = 0; unit < key->nr_enabled_units; unit++) if (key->unit[unit].enabled) { load_texunit_sources(p, unit); - p->last_tex_stage = unit; } /* Second pass - emit combine instructions to build final color: @@ -1333,36 +1247,24 @@ emit_instructions(struct texenv_fragment_program *p) } ir_rvalue *cf = get_source(p, SRC_PREVIOUS, 0); - ir_dereference_variable *deref; - ir_assignment *assign; if (key->separate_specular) { - ir_rvalue *tmp0, *tmp1; - ir_variable *spec_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type, - "specular_add", - ir_var_temporary); - - p->instructions->push_tail(spec_result); - - deref = new(p->mem_ctx) ir_dereference_variable(spec_result); - assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL); - p->instructions->push_tail(assign); - - deref = new(p->mem_ctx) ir_dereference_variable(spec_result); - tmp0 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3); - - ir_variable *secondary = - p->shader->symbols->get_variable("gl_SecondaryColor"); - assert(secondary); - deref = new(p->mem_ctx) ir_dereference_variable(secondary); - tmp1 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3); - - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, - tmp0, tmp1); + ir_variable *spec_result = p->make_temp(glsl_type::vec4_type, + "specular_add"); + p->emit(assign(spec_result, cf)); + + ir_rvalue *secondary; + if (p->state->inputs_available & FRAG_BIT_COL1) { + ir_variable *var = + p->shader->symbols->get_variable("gl_SecondaryColor"); + assert(var); + secondary = swizzle_xyz(var); + } else { + secondary = swizzle_xyz(get_current_attrib(p, VERT_ATTRIB_COLOR1)); + } - deref = new(p->mem_ctx) ir_dereference_variable(spec_result); - assign = new(p->mem_ctx) ir_assignment(deref, tmp0, NULL, WRITEMASK_XYZ); - p->instructions->push_tail(assign); + p->emit(assign(spec_result, add(swizzle_xyz(spec_result), secondary), + WRITEMASK_XYZ)); cf = new(p->mem_ctx) ir_dereference_variable(spec_result); } @@ -1373,9 +1275,7 @@ emit_instructions(struct texenv_fragment_program *p) ir_variable *frag_color = p->shader->symbols->get_variable("gl_FragColor"); assert(frag_color); - deref = new(p->mem_ctx) ir_dereference_variable(frag_color); - assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL); - p->instructions->push_tail(assign); + p->emit(assign(frag_color, cf)); } /** @@ -1385,11 +1285,10 @@ emit_instructions(struct texenv_fragment_program *p) static struct gl_shader_program * create_new_program(struct gl_context *ctx, struct state_key *key) { - struct texenv_fragment_program p; + texenv_fragment_program p; unsigned int unit; _mesa_glsl_parse_state *state; - memset(&p, 0, sizeof(p)); p.mem_ctx = ralloc_context(NULL); p.shader = ctx->Driver.NewShader(ctx, 0, GL_FRAGMENT_SHADER); p.shader->ir = new(p.shader) exec_list; @@ -1401,7 +1300,17 @@ create_new_program(struct gl_context *ctx, struct state_key *key) p.state = key; p.shader_program = ctx->Driver.NewShaderProgram(ctx, 0); - state->language_version = 120; + /* Tell the linker to ignore the fact that we're building a + * separate shader, in case we're in a GLES2 context that would + * normally reject that. The real problem is that we're building a + * fixed function program in a GLES2 context at all, but that's a + * big mess to clean up. + */ + p.shader_program->InternalSeparateShader = GL_TRUE; + + state->language_version = 130; + if (ctx->Extensions.OES_EGL_image_external) + state->OES_EGL_image_external_enable = true; _mesa_glsl_initialize_types(state); _mesa_glsl_initialize_variables(p.instructions, state); @@ -1412,10 +1321,8 @@ create_new_program(struct gl_context *ctx, struct state_key *key) p.src_previous = NULL; - p.last_tex_stage = 0; - ir_function *main_f = new(p.mem_ctx) ir_function("main"); - p.instructions->push_tail(main_f); + p.emit(main_f); state->symbols->add_function(main_f); ir_function_signature *main_sig = @@ -1429,7 +1336,7 @@ create_new_program(struct gl_context *ctx, struct state_key *key) validate_ir_tree(p.shader->ir); - while (do_common_optimization(p.shader->ir, false, 32)) + while (do_common_optimization(p.shader->ir, false, false, 32)) ; reparent_ir(p.shader->ir, p.shader->ir); @@ -1446,23 +1353,18 @@ create_new_program(struct gl_context *ctx, struct state_key *key) /* Set the sampler uniforms, and relink to get them into the linked * program. */ - struct gl_fragment_program *fp = p.shader_program->FragmentProgram; - for (unsigned int i = 0; i < MAX_TEXTURE_UNITS; i++) { - char *name = ralloc_asprintf(p.mem_ctx, "sampler_%d", i); - int loc = _mesa_get_uniform_location(ctx, p.shader_program, name); - if (loc != -1) { - /* Avoid using _mesa_uniform() because it flags state - * updates, so if we're generating this shader_program in a - * state update, we end up recursing. Instead, just set the - * value, which is picked up at re-link. - */ - loc = (loc & 0xffff) + (loc >> 16); - int sampler = fp->Base.Parameters->ParameterValues[loc][0]; - fp->Base.SamplerUnits[sampler] = i; - } - } - _mesa_update_shader_textures_used(&fp->Base); - (void) ctx->Driver.ProgramStringNotify(ctx, fp->Base.Target, &fp->Base); + struct gl_shader *const fs = + p.shader_program->_LinkedShaders[MESA_SHADER_FRAGMENT]; + struct gl_program *const fp = fs->Program; + + _mesa_generate_parameters_list_for_uniforms(p.shader_program, fs, + fp->Parameters); + + _mesa_associate_uniform_storage(ctx, p.shader_program, fp->Parameters); + + _mesa_update_shader_textures_used(p.shader_program, fp); + if (ctx->Driver.SamplerUniformChange) + ctx->Driver.SamplerUniformChange(ctx, fp->Target, fp); if (!p.shader_program->LinkStatus) _mesa_problem(ctx, "Failed to link fixed function fragment shader: %s\n",