X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fprogram%2Fir_to_mesa.cpp;h=c833a12f2aab1608d8b1c7c02d5a9882973231a7;hb=135b7e72601ab0c3923cafedcd30bb505e54f624;hp=5e565e4ed0859635bcabe930641af6f40d98738c;hpb=30be2cc6c7c3378ee17885b5bf41d7ae53bf6fe0;p=mesa.git diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 5e565e4ed08..c833a12f2aa 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -33,34 +33,37 @@ #include "main/compiler.h" #include "ir.h" #include "ir_visitor.h" -#include "ir_print_visitor.h" #include "ir_expression_flattening.h" +#include "ir_uniform.h" #include "glsl_types.h" #include "glsl_parser_extras.h" #include "../glsl/program.h" #include "ir_optimization.h" #include "ast.h" +#include "linker.h" -extern "C" { #include "main/mtypes.h" -#include "main/shaderapi.h" #include "main/shaderobj.h" #include "main/uniforms.h" #include "program/hash_table.h" + +extern "C" { +#include "main/shaderapi.h" #include "program/prog_instruction.h" #include "program/prog_optimize.h" #include "program/prog_print.h" #include "program/program.h" -#include "program/prog_uniform.h" #include "program/prog_parameter.h" #include "program/sampler.h" } +static int swizzle_for_size(int size); + +namespace { + class src_reg; class dst_reg; -static int swizzle_for_size(int size); - /** * This struct is a corresponding struct to Mesa prog_src_register, with * wider fields. @@ -91,7 +94,7 @@ public: explicit src_reg(dst_reg reg); gl_register_file file; /**< PROGRAM_* from Mesa */ - int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */ GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ int negate; /**< NEGATE_XYZW mask from mesa */ /** Register index should be offset by the integer in this reg. */ @@ -121,13 +124,15 @@ public: explicit dst_reg(src_reg reg); gl_register_file file; /**< PROGRAM_* from Mesa */ - int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */ int writemask; /**< Bitfield of WRITEMASK_[XYZW] */ GLuint cond_mask:4; /** Register index should be offset by the integer in this reg. */ src_reg *reladdr; }; +} /* anonymous namespace */ + src_reg::src_reg(dst_reg reg) { this->file = reg.file; @@ -146,19 +151,11 @@ dst_reg::dst_reg(src_reg reg) this->reladdr = reg.reladdr; } +namespace { + class ir_to_mesa_instruction : public exec_node { public: - /* Callers of this ralloc-based new need not call delete. It's - * easier to just ralloc_free 'ctx' (or any of its ancestors). */ - static void* operator new(size_t size, void *ctx) - { - void *node; - - node = rzalloc_size(ctx, size); - assert(node != NULL); - - return node; - } + DECLARE_RALLOC_CXX_OPERATORS(ir_to_mesa_instruction) enum prog_opcode op; dst_reg dst; @@ -170,8 +167,6 @@ public: int sampler; /**< sampler index */ int tex_target; /**< One of TEXTURE_*_INDEX */ GLboolean tex_shadow; - - class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */ }; class variable_storage : public exec_node { @@ -236,8 +231,6 @@ public: variable_storage *find_variable_storage(ir_variable *var); - function_entry *get_function_signature(ir_function_signature *sig); - src_reg get_temp(const glsl_type *type); void reladdr_to_temp(ir_instruction *ir, src_reg *reg, int *num_reladdr); @@ -268,6 +261,8 @@ public: virtual void visit(ir_discard *); virtual void visit(ir_texture *); virtual void visit(ir_if *); + virtual void visit(ir_emit_vertex *); + virtual void visit(ir_end_primitive *); /*@}*/ src_reg result; @@ -327,16 +322,18 @@ public: void *mem_ctx; }; -src_reg undef_src = src_reg(PROGRAM_UNDEFINED, 0, NULL); +} /* anonymous namespace */ -dst_reg undef_dst = dst_reg(PROGRAM_UNDEFINED, SWIZZLE_NOOP); +static src_reg undef_src = src_reg(PROGRAM_UNDEFINED, 0, NULL); -dst_reg address_reg = dst_reg(PROGRAM_ADDRESS, WRITEMASK_X); +static dst_reg undef_dst = dst_reg(PROGRAM_UNDEFINED, SWIZZLE_NOOP); + +static dst_reg address_reg = dst_reg(PROGRAM_ADDRESS, WRITEMASK_X); static int swizzle_for_size(int size) { - int size_swizzles[4] = { + static const int size_swizzles[4] = { MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), @@ -381,8 +378,6 @@ ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op, inst->src[2] = src2; inst->ir = ir; - inst->function = NULL; - this->instructions.push_tail(inst); return inst; @@ -627,10 +622,15 @@ type_size(const struct glsl_type *type) * at link time. */ return 1; - default: - assert(0); - return 0; + case GLSL_TYPE_ATOMIC_UINT: + case GLSL_TYPE_VOID: + case GLSL_TYPE_ERROR: + case GLSL_TYPE_INTERFACE: + assert(!"Invalid type in type_size"); + break; } + + return 0; } /** @@ -683,29 +683,6 @@ ir_to_mesa_visitor::visit(ir_variable *ir) fp->OriginUpperLeft = ir->origin_upper_left; fp->PixelCenterInteger = ir->pixel_center_integer; - - } else if (strcmp(ir->name, "gl_FragDepth") == 0) { - struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog; - switch (ir->depth_layout) { - case ir_depth_layout_none: - fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_NONE; - break; - case ir_depth_layout_any: - fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_ANY; - break; - case ir_depth_layout_greater: - fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_GREATER; - break; - case ir_depth_layout_less: - fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_LESS; - break; - case ir_depth_layout_unchanged: - fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_UNCHANGED; - break; - default: - assert(0); - break; - } } if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) { @@ -859,7 +836,7 @@ ir_to_mesa_visitor::visit(ir_function *ir) const ir_function_signature *sig; exec_list empty; - sig = ir->matching_signature(&empty); + sig = ir->matching_signature(NULL, &empty); assert(sig); @@ -1080,9 +1057,9 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir) this->result.file = PROGRAM_UNDEFINED; deref->accept(this); if (this->result.file == PROGRAM_UNDEFINED) { - ir_print_visitor v; printf("Failed to get tree for expression operand:\n"); - deref->accept(&v); + deref->print(); + printf("\n"); exit(1); } @@ -1152,9 +1129,9 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result.file = PROGRAM_UNDEFINED; ir->operands[operand]->accept(this); if (this->result.file == PROGRAM_UNDEFINED) { - ir_print_visitor v; printf("Failed to get tree for expression operand:\n"); - ir->operands[operand]->accept(&v); + ir->operands[operand]->print(); + printf("\n"); exit(1); } op[operand] = this->result; @@ -1261,8 +1238,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir) break; case ir_binop_div: assert(!"not reached: should be handled by ir_div_to_mul_rcp"); + break; case ir_binop_mod: - assert(!"ir_binop_mod should have been converted to b * fract(a/b)"); + /* Floating point should be lowered by MOD_TO_FRACT in the compiler. */ + assert(ir->type->is_integer()); + emit(ir, OPCODE_MUL, result_dst, op[0], op[1]); break; case ir_binop_less: @@ -1424,6 +1404,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) result_src = op[0]; break; case ir_unop_f2i: + case ir_unop_f2u: emit(ir, OPCODE_TRUNC, result_dst, op[0]); break; case ir_unop_f2b: @@ -1431,6 +1412,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir) emit(ir, OPCODE_SNE, result_dst, op[0], src_reg_for_float(0.0)); break; + case ir_unop_bitcast_f2i: // Ignore these 4, they can't happen here anyway + case ir_unop_bitcast_f2u: + case ir_unop_bitcast_i2f: + case ir_unop_bitcast_u2f: + break; case ir_unop_trunc: emit(ir, OPCODE_TRUNC, result_dst, op[0]); break; @@ -1445,7 +1431,25 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_fract: emit(ir, OPCODE_FRC, result_dst, op[0]); break; - + case ir_unop_pack_snorm_2x16: + case ir_unop_pack_snorm_4x8: + case ir_unop_pack_unorm_2x16: + case ir_unop_pack_unorm_4x8: + case ir_unop_pack_half_2x16: + case ir_unop_unpack_snorm_2x16: + case ir_unop_unpack_snorm_4x8: + case ir_unop_unpack_unorm_2x16: + case ir_unop_unpack_unorm_4x8: + case ir_unop_unpack_half_2x16: + case ir_unop_unpack_half_2x16_split_x: + case ir_unop_unpack_half_2x16_split_y: + case ir_binop_pack_half_2x16_split: + case ir_unop_bitfield_reverse: + case ir_unop_bit_count: + case ir_unop_find_msb: + case ir_unop_find_lsb: + assert(!"not supported"); + break; case ir_binop_min: emit(ir, OPCODE_MIN, result_dst, op[0], op[1]); break; @@ -1456,14 +1460,48 @@ ir_to_mesa_visitor::visit(ir_expression *ir) emit_scalar(ir, OPCODE_POW, result_dst, op[0], op[1]); break; - case ir_unop_bit_not: + /* GLSL 1.30 integer ops are unsupported in Mesa IR, but since + * hardware backends have no way to avoid Mesa IR generation + * even if they don't use it, we need to emit "something" and + * continue. + */ case ir_binop_lshift: case ir_binop_rshift: case ir_binop_bit_and: case ir_binop_bit_xor: case ir_binop_bit_or: + emit(ir, OPCODE_ADD, result_dst, op[0], op[1]); + break; + + case ir_unop_bit_not: case ir_unop_round_even: - assert(!"GLSL 1.30 features unsupported"); + emit(ir, OPCODE_MOV, result_dst, op[0]); + break; + + case ir_binop_ubo_load: + assert(!"not supported"); + break; + + case ir_triop_lrp: + /* ir_triop_lrp operands are (x, y, a) while + * OPCODE_LRP operands are (a, y, x) to match ARB_fragment_program. + */ + emit(ir, OPCODE_LRP, result_dst, op[2], op[1], op[0]); + break; + + case ir_binop_vector_extract: + case ir_binop_bfm: + case ir_triop_fma: + case ir_triop_bfi: + case ir_triop_bitfield_extract: + case ir_triop_vector_insert: + case ir_quadop_bitfield_insert: + case ir_binop_ldexp: + case ir_triop_csel: + case ir_binop_carry: + case ir_binop_borrow: + case ir_binop_imul_high: + assert(!"not supported"); break; case ir_quadop_vector: @@ -1535,29 +1573,18 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) var->location); this->variables.push_tail(entry); break; - case ir_var_in: - case ir_var_inout: + case ir_var_shader_in: /* The linker assigns locations for varyings and attributes, * including deprecated builtins (like gl_Color), * user-assigned generic attributes (glBindVertexLocation), * and user-defined varyings. - * - * FINISHME: We would hit this path for function arguments. Fix! */ assert(var->location != -1); entry = new(mem_ctx) variable_storage(var, PROGRAM_INPUT, var->location); - if (this->prog->Target == GL_VERTEX_PROGRAM_ARB && - var->location >= VERT_ATTRIB_GENERIC0) { - _mesa_add_attribute(this->prog->Attributes, - var->name, - _mesa_sizeof_glsl_type(var->type->gl_type), - var->type->gl_type, - var->location - VERT_ATTRIB_GENERIC0); - } break; - case ir_var_out: + case ir_var_shader_out: assert(var->location != -1); entry = new(mem_ctx) variable_storage(var, PROGRAM_OUTPUT, @@ -1974,126 +2001,10 @@ ir_to_mesa_visitor::visit(ir_constant *ir) &this->result.swizzle); } -function_entry * -ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig) -{ - function_entry *entry; - - foreach_iter(exec_list_iterator, iter, this->function_signatures) { - entry = (function_entry *)iter.get(); - - if (entry->sig == sig) - return entry; - } - - entry = ralloc(mem_ctx, function_entry); - entry->sig = sig; - entry->sig_id = this->next_signature_id++; - entry->bgn_inst = NULL; - - /* Allocate storage for all the parameters. */ - foreach_iter(exec_list_iterator, iter, sig->parameters) { - ir_variable *param = (ir_variable *)iter.get(); - variable_storage *storage; - - storage = find_variable_storage(param); - assert(!storage); - - storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY, - this->next_temp); - this->variables.push_tail(storage); - - this->next_temp += type_size(param->type); - } - - if (!sig->return_type->is_void()) { - entry->return_reg = get_temp(sig->return_type); - } else { - entry->return_reg = undef_src; - } - - this->function_signatures.push_tail(entry); - return entry; -} - void ir_to_mesa_visitor::visit(ir_call *ir) { - ir_to_mesa_instruction *call_inst; - ir_function_signature *sig = ir->get_callee(); - function_entry *entry = get_function_signature(sig); - int i; - - /* Process in parameters. */ - exec_list_iterator sig_iter = sig->parameters.iterator(); - foreach_iter(exec_list_iterator, iter, *ir) { - ir_rvalue *param_rval = (ir_rvalue *)iter.get(); - ir_variable *param = (ir_variable *)sig_iter.get(); - - if (param->mode == ir_var_in || - param->mode == ir_var_inout) { - variable_storage *storage = find_variable_storage(param); - assert(storage); - - param_rval->accept(this); - src_reg r = this->result; - - dst_reg l; - l.file = storage->file; - l.index = storage->index; - l.reladdr = NULL; - l.writemask = WRITEMASK_XYZW; - l.cond_mask = COND_TR; - - for (i = 0; i < type_size(param->type); i++) { - emit(ir, OPCODE_MOV, l, r); - l.index++; - r.index++; - } - } - - sig_iter.next(); - } - assert(!sig_iter.has_next()); - - /* Emit call instruction */ - call_inst = emit(ir, OPCODE_CAL); - call_inst->function = entry; - - /* Process out parameters. */ - sig_iter = sig->parameters.iterator(); - foreach_iter(exec_list_iterator, iter, *ir) { - ir_rvalue *param_rval = (ir_rvalue *)iter.get(); - ir_variable *param = (ir_variable *)sig_iter.get(); - - if (param->mode == ir_var_out || - param->mode == ir_var_inout) { - variable_storage *storage = find_variable_storage(param); - assert(storage); - - src_reg r; - r.file = storage->file; - r.index = storage->index; - r.reladdr = NULL; - r.swizzle = SWIZZLE_NOOP; - r.negate = 0; - - param_rval->accept(this); - dst_reg l = dst_reg(this->result); - - for (i = 0; i < type_size(param->type); i++) { - emit(ir, OPCODE_MOV, l, r); - l.index++; - r.index++; - } - } - - sig_iter.next(); - } - assert(!sig_iter.has_next()); - - /* Process return value. */ - this->result = entry->return_reg; + assert(!"ir_to_mesa: All function calls should have been inlined by now."); } void @@ -2153,6 +2064,18 @@ ir_to_mesa_visitor::visit(ir_texture *ir) ir->lod_info.grad.dPdy->accept(this); dy = this->result; break; + case ir_txf_ms: + assert(!"Unexpected ir_txf_ms opcode"); + break; + case ir_lod: + assert(!"Unexpected ir_lod opcode"); + break; + case ir_tg4: + assert(!"Unexpected ir_tg4 opcode"); + break; + case ir_query_levels: + assert(!"Unexpected ir_query_levels opcode"); + break; } const glsl_type *sampler_type = ir->sampler->type; @@ -2268,6 +2191,9 @@ ir_to_mesa_visitor::visit(ir_texture *ir) case GLSL_SAMPLER_DIM_BUF: assert(!"FINISHME: Implement ARB_texture_buffer_object"); break; + case GLSL_SAMPLER_DIM_EXTERNAL: + inst->tex_target = TEXTURE_EXTERNAL_INDEX; + break; default: assert(!"Should not get here."); } @@ -2278,32 +2204,16 @@ ir_to_mesa_visitor::visit(ir_texture *ir) void ir_to_mesa_visitor::visit(ir_return *ir) { - if (ir->get_value()) { - dst_reg l; - int i; - - assert(current_function); - - ir->get_value()->accept(this); - src_reg r = this->result; - - l = dst_reg(current_function->return_reg); - - for (i = 0; i < type_size(current_function->sig->return_type); i++) { - emit(ir, OPCODE_MOV, l, r); - l.index++; - r.index++; - } - } - + /* Non-void functions should have been inlined. We may still emit RETs + * from main() unless the EmitNoMainReturn option is set. + */ + assert(!ir->get_value()); emit(ir, OPCODE_RET); } void ir_to_mesa_visitor::visit(ir_discard *ir) { - struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog; - if (ir->condition) { ir->condition->accept(this); this->result.negate = ~this->result.negate; @@ -2311,8 +2221,6 @@ ir_to_mesa_visitor::visit(ir_discard *ir) } else { emit(ir, OPCODE_KIL_NV); } - - fp->UsesKill = GL_TRUE; } void @@ -2354,7 +2262,19 @@ ir_to_mesa_visitor::visit(ir_if *ir) visit_exec_list(&ir->else_instructions, this); } - if_inst = emit(ir->condition, OPCODE_ENDIF); + emit(ir->condition, OPCODE_ENDIF); +} + +void +ir_to_mesa_visitor::visit(ir_emit_vertex *ir) +{ + assert(!"Geometry shaders not supported."); +} + +void +ir_to_mesa_visitor::visit(ir_end_primitive *ir) +{ + assert(!"Geometry shaders not supported."); } ir_to_mesa_visitor::ir_to_mesa_visitor() @@ -2505,300 +2425,210 @@ print_program(struct prog_instruction *mesa_instructions, } } +namespace { -/** - * Count resources used by the given gpu program (number of texture - * samplers, etc). - */ -static void -count_resources(struct gl_program *prog) -{ - unsigned int i; - - prog->SamplersUsed = 0; - - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = &prog->Instructions[i]; - - if (_mesa_is_tex_instruction(inst->Opcode)) { - prog->SamplerTargets[inst->TexSrcUnit] = - (gl_texture_index)inst->TexSrcTarget; - prog->SamplersUsed |= 1 << inst->TexSrcUnit; - if (inst->TexShadow) { - prog->ShadowSamplers |= 1 << inst->TexSrcUnit; - } - } +class add_uniform_to_shader : public program_resource_visitor { +public: + add_uniform_to_shader(struct gl_shader_program *shader_program, + struct gl_program_parameter_list *params, + gl_shader_type shader_type) + : shader_program(shader_program), params(params), idx(-1), + shader_type(shader_type) + { + /* empty */ } - _mesa_update_shader_textures_used(prog); -} - + void process(ir_variable *var) + { + this->idx = -1; + this->program_resource_visitor::process(var); -/** - * Check if the given vertex/fragment/shader program is within the - * resource limits of the context (number of texture units, etc). - * If any of those checks fail, record a linker error. - * - * XXX more checks are needed... - */ -static void -check_resources(const struct gl_context *ctx, - struct gl_shader_program *shader_program, - struct gl_program *prog) -{ - switch (prog->Target) { - case GL_VERTEX_PROGRAM_ARB: - if (_mesa_bitcount(prog->SamplersUsed) > - ctx->Const.MaxVertexTextureImageUnits) { - linker_error(shader_program, - "Too many vertex shader texture samplers"); - } - if (prog->Parameters->NumParameters > MAX_UNIFORMS) { - linker_error(shader_program, "Too many vertex shader constants"); - } - break; - case MESA_GEOMETRY_PROGRAM: - if (_mesa_bitcount(prog->SamplersUsed) > - ctx->Const.MaxGeometryTextureImageUnits) { - linker_error(shader_program, - "Too many geometry shader texture samplers"); - } - if (prog->Parameters->NumParameters > - MAX_GEOMETRY_UNIFORM_COMPONENTS / 4) { - linker_error(shader_program, "Too many geometry shader constants"); - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - if (_mesa_bitcount(prog->SamplersUsed) > - ctx->Const.MaxTextureImageUnits) { - linker_error(shader_program, - "Too many fragment shader texture samplers"); - } - if (prog->Parameters->NumParameters > MAX_UNIFORMS) { - linker_error(shader_program, "Too many fragment shader constants"); - } - break; - default: - _mesa_problem(ctx, "unexpected program type in check_resources()"); + var->location = this->idx; } -} - +private: + virtual void visit_field(const glsl_type *type, const char *name, + bool row_major); -struct uniform_sort { - struct gl_uniform *u; - int pos; + struct gl_shader_program *shader_program; + struct gl_program_parameter_list *params; + int idx; + gl_shader_type shader_type; }; -/* The shader_program->Uniforms list is almost sorted in increasing - * uniform->{Frag,Vert}Pos locations, but not quite when there are - * uniforms shared between targets. We need to add parameters in - * increasing order for the targets. - */ -static int -sort_uniforms(const void *a, const void *b) -{ - struct uniform_sort *u1 = (struct uniform_sort *)a; - struct uniform_sort *u2 = (struct uniform_sort *)b; - - return u1->pos - u2->pos; -} +} /* anonymous namespace */ -/* Add the uniforms to the parameters. The linker chose locations - * in our parameters lists (which weren't created yet), which the - * uniforms code will use to poke values into our parameters list - * when uniforms are updated. - */ -static void -add_uniforms_to_parameters_list(struct gl_shader_program *shader_program, - struct gl_shader *shader, - struct gl_program *prog) +void +add_uniform_to_shader::visit_field(const glsl_type *type, const char *name, + bool row_major) { - unsigned int i; - unsigned int next_sampler = 0, num_uniforms = 0; - struct uniform_sort *sorted_uniforms; - - sorted_uniforms = ralloc_array(NULL, struct uniform_sort, - shader_program->Uniforms->NumUniforms); + unsigned int size; - for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) { - struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i; - int parameter_index = -1; - - switch (shader->Type) { - case GL_VERTEX_SHADER: - parameter_index = uniform->VertPos; - break; - case GL_FRAGMENT_SHADER: - parameter_index = uniform->FragPos; - break; - case GL_GEOMETRY_SHADER: - parameter_index = uniform->GeomPos; - break; - } + (void) row_major; - /* Only add uniforms used in our target. */ - if (parameter_index != -1) { - sorted_uniforms[num_uniforms].pos = parameter_index; - sorted_uniforms[num_uniforms].u = uniform; - num_uniforms++; - } + if (type->is_vector() || type->is_scalar()) { + size = type->vector_elements; + } else { + size = type_size(type) * 4; } - qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort), - sort_uniforms); - - for (i = 0; i < num_uniforms; i++) { - struct gl_uniform *uniform = sorted_uniforms[i].u; - int parameter_index = sorted_uniforms[i].pos; - const glsl_type *type = uniform->Type; - unsigned int size; - - if (type->is_vector() || - type->is_scalar()) { - size = type->vector_elements; - } else { - size = type_size(type) * 4; - } + gl_register_file file; + if (type->is_sampler() || + (type->is_array() && type->fields.array->is_sampler())) { + file = PROGRAM_SAMPLER; + } else { + file = PROGRAM_UNIFORM; + } - gl_register_file file; - if (type->is_sampler() || - (type->is_array() && type->fields.array->is_sampler())) { - file = PROGRAM_SAMPLER; - } else { - file = PROGRAM_UNIFORM; - } + int index = _mesa_lookup_parameter_index(params, -1, name); + if (index < 0) { + index = _mesa_add_parameter(params, file, name, size, type->gl_type, + NULL, NULL); - GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, - uniform->Name); + /* Sampler uniform values are stored in prog->SamplerUnits, + * and the entry in that array is selected by this index we + * store in ParameterValues[]. + */ + if (file == PROGRAM_SAMPLER) { + unsigned location; + const bool found = + this->shader_program->UniformHash->get(location, + params->Parameters[index].Name); + assert(found); + + if (!found) + return; - if (index < 0) { - index = _mesa_add_parameter(prog->Parameters, file, - uniform->Name, size, type->gl_type, - NULL, NULL, 0x0); + struct gl_uniform_storage *storage = + &this->shader_program->UniformStorage[location]; - /* Sampler uniform values are stored in prog->SamplerUnits, - * and the entry in that array is selected by this index we - * store in ParameterValues[]. - */ - if (file == PROGRAM_SAMPLER) { - for (unsigned int j = 0; j < size / 4; j++) - prog->Parameters->ParameterValues[index + j][0].f = next_sampler++; - } + assert(storage->sampler[shader_type].active); - /* The location chosen in the Parameters list here (returned - * from _mesa_add_uniform) has to match what the linker chose. - */ - if (index != parameter_index) { - linker_error(shader_program, - "Allocation of uniform `%s' to target failed " - "(%d vs %d)\n", - uniform->Name, index, parameter_index); - } + for (unsigned int j = 0; j < size / 4; j++) + params->ParameterValues[index + j][0].f = + storage->sampler[shader_type].index + j; } } - ralloc_free(sorted_uniforms); + /* The first part of the uniform that's processed determines the base + * location of the whole uniform (for structures). + */ + if (this->idx < 0) + this->idx = index; } -static void -set_uniform_initializer(struct gl_context *ctx, void *mem_ctx, - struct gl_shader_program *shader_program, - const char *name, const glsl_type *type, - ir_constant *val) +/** + * Generate the program parameters list for the user uniforms in a shader + * + * \param shader_program Linked shader program. This is only used to + * emit possible link errors to the info log. + * \param sh Shader whose uniforms are to be processed. + * \param params Parameter list to be filled in. + */ +void +_mesa_generate_parameters_list_for_uniforms(struct gl_shader_program + *shader_program, + struct gl_shader *sh, + struct gl_program_parameter_list + *params) { - if (type->is_record()) { - ir_constant *field_constant; - - field_constant = (ir_constant *)val->components.get_head(); - - for (unsigned int i = 0; i < type->length; i++) { - const glsl_type *field_type = type->fields.structure[i].type; - const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name, - type->fields.structure[i].name); - set_uniform_initializer(ctx, mem_ctx, shader_program, field_name, - field_type, field_constant); - field_constant = (ir_constant *)field_constant->next; - } - return; - } + add_uniform_to_shader add(shader_program, params, + _mesa_shader_type_to_index(sh->Type)); - int loc = _mesa_get_uniform_location(ctx, shader_program, name); + foreach_list(node, sh->ir) { + ir_variable *var = ((ir_instruction *) node)->as_variable(); - if (loc == -1) { - linker_error(shader_program, - "Couldn't find uniform for initializer %s\n", name); - return; - } - - for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) { - ir_constant *element; - const glsl_type *element_type; - if (type->is_array()) { - element = val->array_elements[i]; - element_type = type->fields.array; - } else { - element = val; - element_type = type; - } - - void *values; - - if (element_type->base_type == GLSL_TYPE_BOOL) { - int *conv = ralloc_array(mem_ctx, int, element_type->components()); - for (unsigned int j = 0; j < element_type->components(); j++) { - conv[j] = element->value.b[j]; - } - values = (void *)conv; - element_type = glsl_type::get_instance(GLSL_TYPE_INT, - element_type->vector_elements, - 1); - } else { - values = &element->value; - } + if ((var == NULL) || (var->mode != ir_var_uniform) + || var->is_in_uniform_block() || (strncmp(var->name, "gl_", 3) == 0)) + continue; - if (element_type->is_matrix()) { - _mesa_uniform_matrix(ctx, shader_program, - element_type->matrix_columns, - element_type->vector_elements, - loc, 1, GL_FALSE, (GLfloat *)values); - loc += element_type->matrix_columns; - } else { - _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns, - values, element_type->gl_type); - loc += type_size(element_type); - } + add.process(var); } } -static void -set_uniform_initializers(struct gl_context *ctx, - struct gl_shader_program *shader_program) +void +_mesa_associate_uniform_storage(struct gl_context *ctx, + struct gl_shader_program *shader_program, + struct gl_program_parameter_list *params) { - void *mem_ctx = NULL; + /* After adding each uniform to the parameter list, connect the storage for + * the parameter with the tracking structure used by the API for the + * uniform. + */ + unsigned last_location = unsigned(~0); + for (unsigned i = 0; i < params->NumParameters; i++) { + if (params->Parameters[i].Type != PROGRAM_UNIFORM) + continue; - for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) { - struct gl_shader *shader = shader_program->_LinkedShaders[i]; + unsigned location; + const bool found = + shader_program->UniformHash->get(location, params->Parameters[i].Name); + assert(found); - if (shader == NULL) + if (!found) continue; - foreach_iter(exec_list_iterator, iter, *shader->ir) { - ir_instruction *ir = (ir_instruction *)iter.get(); - ir_variable *var = ir->as_variable(); + if (location != last_location) { + struct gl_uniform_storage *storage = + &shader_program->UniformStorage[location]; + enum gl_uniform_driver_format format = uniform_native; + + unsigned columns = 0; + switch (storage->type->base_type) { + case GLSL_TYPE_UINT: + assert(ctx->Const.NativeIntegers); + format = uniform_native; + columns = 1; + break; + case GLSL_TYPE_INT: + format = + (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float; + columns = 1; + break; + case GLSL_TYPE_FLOAT: + format = uniform_native; + columns = storage->type->matrix_columns; + break; + case GLSL_TYPE_BOOL: + if (ctx->Const.NativeIntegers) { + format = (ctx->Const.UniformBooleanTrue == 1) + ? uniform_bool_int_0_1 : uniform_bool_int_0_not0; + } else { + format = uniform_bool_float; + } + columns = 1; + break; + case GLSL_TYPE_SAMPLER: + format = uniform_native; + columns = 1; + break; + case GLSL_TYPE_ATOMIC_UINT: + case GLSL_TYPE_ARRAY: + case GLSL_TYPE_VOID: + case GLSL_TYPE_STRUCT: + case GLSL_TYPE_ERROR: + case GLSL_TYPE_INTERFACE: + assert(!"Should not get here."); + break; + } - if (!var || var->mode != ir_var_uniform || !var->constant_value) - continue; + _mesa_uniform_attach_driver_storage(storage, + 4 * sizeof(float) * columns, + 4 * sizeof(float), + format, + ¶ms->ParameterValues[i]); - if (!mem_ctx) - mem_ctx = ralloc_context(NULL); + /* After attaching the driver's storage to the uniform, propagate any + * data from the linker's backing store. This will cause values from + * initializers in the source code to be copied over. + */ + _mesa_propagate_uniforms_to_driver_storage(storage, + 0, + MAX2(1, storage->array_elements)); - set_uniform_initializer(ctx, mem_ctx, shader_program, var->name, - var->type, var->constant_value); + last_location = location; } } - - ralloc_free(mem_ctx); } /* @@ -2976,6 +2806,8 @@ ir_to_mesa_visitor::copy_propagate(void) /* If this is a copy, add it to the ACP. */ if (inst->op == OPCODE_MOV && inst->dst.file == PROGRAM_TEMPORARY && + !(inst->dst.file == inst->src[0].file && + inst->dst.index == inst->src[0].index) && !inst->dst.reladdr && !inst->saturate && !inst->src[0].reladdr && @@ -3008,23 +2840,19 @@ get_mesa_program(struct gl_context *ctx, int i; struct gl_program *prog; GLenum target; - const char *target_string; - GLboolean progress; + const char *target_string = _mesa_glsl_shader_target_name(shader->Type); struct gl_shader_compiler_options *options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)]; switch (shader->Type) { case GL_VERTEX_SHADER: target = GL_VERTEX_PROGRAM_ARB; - target_string = "vertex"; break; case GL_FRAGMENT_SHADER: target = GL_FRAGMENT_PROGRAM_ARB; - target_string = "fragment"; break; case GL_GEOMETRY_SHADER: target = GL_GEOMETRY_PROGRAM_NV; - target_string = "geometry"; break; default: assert(!"should not be reached"); @@ -3037,48 +2865,18 @@ get_mesa_program(struct gl_context *ctx, if (!prog) return NULL; prog->Parameters = _mesa_new_parameter_list(); - prog->Varying = _mesa_new_parameter_list(); - prog->Attributes = _mesa_new_parameter_list(); v.ctx = ctx; v.prog = prog; v.shader_program = shader_program; v.options = options; - add_uniforms_to_parameters_list(shader_program, shader, prog); + _mesa_generate_parameters_list_for_uniforms(shader_program, shader, + prog->Parameters); /* Emit Mesa IR for main(). */ visit_exec_list(shader->ir, &v); v.emit(NULL, OPCODE_END); - /* Now emit bodies for any functions that were used. */ - do { - progress = GL_FALSE; - - foreach_iter(exec_list_iterator, iter, v.function_signatures) { - function_entry *entry = (function_entry *)iter.get(); - - if (!entry->bgn_inst) { - v.current_function = entry; - - entry->bgn_inst = v.emit(NULL, OPCODE_BGNSUB); - entry->bgn_inst->function = entry; - - visit_exec_list(&entry->sig->body, &v); - - ir_to_mesa_instruction *last; - last = (ir_to_mesa_instruction *)v.instructions.get_tail(); - if (last->op != OPCODE_RET) - v.emit(NULL, OPCODE_RET); - - ir_to_mesa_instruction *end; - end = v.emit(NULL, OPCODE_ENDSUB); - end->function = entry; - - progress = GL_TRUE; - } - } - } while (progress); - prog->NumTemporaries = v.next_temp; int num_instructions = 0; @@ -3152,16 +2950,6 @@ get_mesa_program(struct gl_context *ctx, "rasterization.\n"); } break; - case OPCODE_BGNSUB: - inst->function->inst = i; - mesa_inst->Comment = strdup(inst->function->sig->function_name()); - break; - case OPCODE_ENDSUB: - mesa_inst->Comment = strdup(inst->function->sig->function_name()); - break; - case OPCODE_CAL: - mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */ - break; case OPCODE_ARL: prog->NumAddressRegs = 1; break; @@ -3177,9 +2965,7 @@ get_mesa_program(struct gl_context *ctx, } if (!shader_program->LinkStatus) { - free(mesa_instructions); - _mesa_reference_program(ctx, &shader->Program, NULL); - return NULL; + goto fail_exit; } set_branchtargets(&v, mesa_instructions, num_instructions); @@ -3200,10 +2986,22 @@ get_mesa_program(struct gl_context *ctx, prog->Instructions = mesa_instructions; prog->NumInstructions = num_instructions; - do_set_program_inouts(shader->ir, prog); - count_resources(prog); + /* Setting this to NULL prevents a possible double free in the fail_exit + * path (far below). + */ + mesa_instructions = NULL; - check_resources(ctx, shader_program, prog); + do_set_program_inouts(shader->ir, prog, shader->Type); + + prog->SamplersUsed = shader->active_samplers; + prog->ShadowSamplers = shader->shadow_samplers; + _mesa_update_shader_textures_used(shader_program, prog); + + /* Set the gl_FragDepth layout. */ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + struct gl_fragment_program *fp = (struct gl_fragment_program *)prog; + fp->FragDepthLayout = shader_program->FragDepthLayout; + } _mesa_reference_program(ctx, &shader->Program, prog); @@ -3211,7 +3009,21 @@ get_mesa_program(struct gl_context *ctx, _mesa_optimize_program(ctx, prog); } + /* This has to be done last. Any operation that can cause + * prog->ParameterValues to get reallocated (e.g., anything that adds a + * program constant) has to happen before creating this linkage. + */ + _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters); + if (!shader_program->LinkStatus) { + goto fail_exit; + } + return prog; + +fail_exit: + free(mesa_instructions); + _mesa_reference_program(ctx, &shader->Program, NULL); + return NULL; } extern "C" { @@ -3247,7 +3059,10 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress; - progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress; + progress = do_common_optimization(ir, true, true, + options->MaxUnrollIterations, + options) + || progress; progress = lower_quadop_vector(ir, true) || progress; @@ -3273,6 +3088,7 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) || progress; progress = do_vec_index_to_cond_assign(ir) || progress; + progress = lower_vector_insert(ir, true) || progress; } while (progress); validate_ir_tree(ir); @@ -3287,29 +3103,13 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]); if (linked_prog) { - bool ok = true; - - switch (prog->_LinkedShaders[i]->Type) { - case GL_VERTEX_SHADER: - _mesa_reference_vertprog(ctx, &prog->VertexProgram, - (struct gl_vertex_program *)linked_prog); - ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, - linked_prog); - break; - case GL_FRAGMENT_SHADER: - _mesa_reference_fragprog(ctx, &prog->FragmentProgram, - (struct gl_fragment_program *)linked_prog); - ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, - linked_prog); - break; - case GL_GEOMETRY_SHADER: - _mesa_reference_geomprog(ctx, &prog->GeometryProgram, - (struct gl_geometry_program *)linked_prog); - ok = ctx->Driver.ProgramStringNotify(ctx, GL_GEOMETRY_PROGRAM_NV, - linked_prog); - break; - } - if (!ok) { + _mesa_copy_linked_program_data((gl_shader_type) i, prog, linked_prog); + + _mesa_reference_program(ctx, &prog->_LinkedShaders[i]->Program, + linked_prog); + if (!ctx->Driver.ProgramStringNotify(ctx, + _mesa_program_index_to_target(i), + linked_prog)) { return GL_FALSE; } } @@ -3317,94 +3117,9 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) _mesa_reference_program(ctx, &linked_prog, NULL); } - return GL_TRUE; + return prog->LinkStatus; } - -/** - * Compile a GLSL shader. Called via glCompileShader(). - */ -void -_mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader) -{ - struct _mesa_glsl_parse_state *state = - new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader); - - const char *source = shader->Source; - /* Check if the user called glCompileShader without first calling - * glShaderSource. This should fail to compile, but not raise a GL_ERROR. - */ - if (source == NULL) { - shader->CompileStatus = GL_FALSE; - return; - } - - state->error = preprocess(state, &source, &state->info_log, - &ctx->Extensions, ctx->API); - - if (ctx->Shader.Flags & GLSL_DUMP) { - printf("GLSL source for %s shader %d:\n", - _mesa_glsl_shader_target_name(state->target), shader->Name); - printf("%s\n", shader->Source); - } - - if (!state->error) { - _mesa_glsl_lexer_ctor(state, source); - _mesa_glsl_parse(state); - _mesa_glsl_lexer_dtor(state); - } - - ralloc_free(shader->ir); - shader->ir = new(shader) exec_list; - if (!state->error && !state->translation_unit.is_empty()) - _mesa_ast_to_hir(shader->ir, state); - - if (!state->error && !shader->ir->is_empty()) { - validate_ir_tree(shader->ir); - - /* Do some optimization at compile time to reduce shader IR size - * and reduce later work if the same shader is linked multiple times - */ - while (do_common_optimization(shader->ir, false, 32)) - ; - - validate_ir_tree(shader->ir); - } - - shader->symbols = state->symbols; - - shader->CompileStatus = !state->error; - shader->InfoLog = state->info_log; - shader->Version = state->language_version; - memcpy(shader->builtins_to_link, state->builtins_to_link, - sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link); - shader->num_builtins_to_link = state->num_builtins_to_link; - - if (ctx->Shader.Flags & GLSL_LOG) { - _mesa_write_shader_to_file(shader); - } - - if (ctx->Shader.Flags & GLSL_DUMP) { - if (shader->CompileStatus) { - printf("GLSL IR for shader %d:\n", shader->Name); - _mesa_print_ir(shader->ir, NULL); - printf("\n\n"); - } else { - printf("GLSL shader %d failed to compile.\n", shader->Name); - } - if (shader->InfoLog && shader->InfoLog[0] != 0) { - printf("GLSL shader %d info log:\n", shader->Name); - printf("%s\n", shader->InfoLog); - } - } - - /* Retain any live IR, but trash the rest. */ - reparent_ir(shader->ir, shader->ir); - - ralloc_free(state); -} - - /** * Link a GLSL shader program. Called via glLinkProgram(). */ @@ -3420,15 +3135,9 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) for (i = 0; i < prog->NumShaders; i++) { if (!prog->Shaders[i]->CompileStatus) { linker_error(prog, "linking with uncompiled shader"); - prog->LinkStatus = GL_FALSE; } } - prog->Varying = _mesa_new_parameter_list(); - _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL); - _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL); - _mesa_reference_geomprog(ctx, &prog->GeometryProgram, NULL); - if (prog->LinkStatus) { link_shaders(ctx, prog); } @@ -3439,8 +3148,6 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) } } - set_uniform_initializers(ctx, prog); - if (ctx->Shader.Flags & GLSL_DUMP) { if (!prog->LinkStatus) { printf("GLSL shader program %d failed to link\n", prog->Name);