From 84771df82ed2ed8718013795089edd38cf5bd84d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 29 Apr 2010 09:02:09 -0700 Subject: ir_to_mesa: Start building GLSL IR to Mesa IR conversion. There are major missing pieces here. Most operations aren't supported. Matrices need to be broken down to vector ops before we get here. Scalar operations (RSQ, RCP) are handled incorrectly. Arrays and structures are not even considered. --- Makefile.am | 15 +- ir_to_mesa.cpp | 548 +++++++++++++++++++++++++++++++++++++++++ ir_to_mesa.h | 170 +++++++++++++ main/mtypes.h | 32 +++ mesa/shader/prog_instruction.h | 437 ++++++++++++++++++++++++++++++++ mesa_codegen.brg | 173 +++++++++++++ program.h | 2 +- 7 files changed, 1375 insertions(+), 2 deletions(-) create mode 100644 ir_to_mesa.cpp create mode 100644 ir_to_mesa.h create mode 100644 mesa/shader/prog_instruction.h create mode 100644 mesa_codegen.brg diff --git a/Makefile.am b/Makefile.am index a88bf0022ad..88d8f0587c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,7 @@ # USE OR OTHER DEALINGS IN THE SOFTWARE. AUTOMAKE_OPTIONS = foreign +AM_CPPFLAGS = -I mesa SUBDIRS = glcpp @@ -57,9 +58,16 @@ glsl_SOURCES = \ ir_hierarchical_visitor.h \ ir_hierarchical_visitor.cpp \ ir_swizzle_swizzle.cpp \ + ir_to_mesa.cpp \ + ir_to_mesa.h \ ir_validate.cpp \ ir_vec_index_to_swizzle.cpp \ - linker.cpp + linker.cpp \ + mesa_codegen.cpp \ + msea_codegen.h + +DISTFILES = \ + mesa_codegen.brg BUILT_SOURCES = glsl_parser.h glsl_parser.cpp glsl_lexer.cpp CLEANFILES = $(BUILT_SOURCES) @@ -70,3 +78,8 @@ glsl_parser.h: glsl_parser.cpp .lpp.cpp: $(LEXCOMPILE) --outfile="$@" $< + +mesa_codegen.h: mesa_codegen.cpp + +mesa_codegen.cpp: mesa_codegen.brg + monoburg --no-glib -s $@ -d mesa_codegen.h $< diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp new file mode 100644 index 00000000000..5cbd451b214 --- /dev/null +++ b/ir_to_mesa.cpp @@ -0,0 +1,548 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_to_mesa.cpp + * + * Translates the IR to ARB_fragment_program text if possible, + * printing the result + * + * The code generation is performed using monoburg. Because monoburg + * produces a single C file with the definitions of the node types in + * it, this file is included from the monoburg output. + */ + +/* Quiet compiler warnings due to monoburg not marking functions defined + * in the header as inline. + */ +#define g_new +#define g_error +#include "mesa_codegen.h" + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_print_visitor.h" +#include "ir_expression_flattening.h" +#include "glsl_types.h" + +#include "shader/prog_instruction.h" + +ir_to_mesa_src_reg ir_to_mesa_undef = { + PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP +}; + +ir_to_mesa_instruction * +ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2) +{ + ir_to_mesa_instruction *inst = new ir_to_mesa_instruction(); + + inst->op = op; + inst->dst_reg = dst; + inst->src_reg[0] = src0; + inst->src_reg[1] = src1; + inst->src_reg[2] = src2; + + tree->v->instructions.push_tail(inst); + + return inst; +} + + +ir_to_mesa_instruction * +ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1) +{ + return ir_to_mesa_emit_op3(tree, op, dst, src0, src1, ir_to_mesa_undef); +} + +ir_to_mesa_instruction * +ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) +{ + return ir_to_mesa_emit_op3(tree, op, + dst, src0, ir_to_mesa_undef, ir_to_mesa_undef); +} + +struct mbtree * +ir_to_mesa_visitor::create_tree(int op, struct mbtree *left, struct mbtree *right) +{ + struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1); + + tree->op = op; + tree->left = left; + tree->right = right; + tree->v = this; + tree->src_reg.swizzle = SWIZZLE_XYZW; + + return tree; +} + +const char * +produce_swizzle(int8_t *swizzle, const char *reg_name, + const char **swizzle_reg_name) +{ + if (swizzle[0] == 0 && + swizzle[1] == 1 && + swizzle[2] == 2 && + swizzle[3] == 3) + { + *swizzle_reg_name = reg_name; + } else { + char swizzle_letters[4] = { 'x', 'y', 'z', 'w' }; + char *temp; + asprintf(&temp, "%s.%c%c%c%c", + reg_name, + swizzle_letters[swizzle[0]], + swizzle_letters[swizzle[1]], + swizzle_letters[swizzle[2]], + swizzle_letters[swizzle[3]]); + *swizzle_reg_name = temp; + } + return *swizzle_reg_name; +} + +/** + * In the initial pass of codegen, we assign temporary numbers to + * intermediate results. (not SSA -- variable assignments will reuse + * storage). Actual register allocation for the Mesa VM occurs in a + * pass over the Mesa IR later. + */ +void +ir_to_mesa_visitor::get_temp(struct mbtree *tree) +{ + tree->src_reg.file = PROGRAM_TEMPORARY; + tree->src_reg.index = this->next_temp++; +} + +void +ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) +{ + temp_entry *entry; + + foreach_iter(exec_list_iterator, iter, this->variable_storage) { + entry = (temp_entry *)iter.get(); + + if (entry->var == var) { + tree->src_reg.file = entry->file; + tree->src_reg.index = entry->index; + return; + } + } + + entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp++); + this->variable_storage.push_tail(entry); + + tree->src_reg.file = entry->file; + tree->src_reg.index = entry->index; +} + +static void +reduce(struct mbtree *t, int goal) +{ + struct mbtree *kids[10]; + int rule = mono_burg_rule((MBState *)t->state, goal); + const uint16_t *nts = mono_burg_nts[rule]; + int i; + + mono_burg_kids (t, rule, kids); + + for (i = 0; nts[i]; i++) { + reduce(kids[i], nts[i]); + } + + if (t->left) { + if (mono_burg_func[rule]) { + mono_burg_func[rule](t, NULL); + } else { + printf("no code for rules %s\n", mono_burg_rule_string[rule]); + exit(1); + } + } else { + if (mono_burg_func[rule]) { + printf("unused code for rule %s\n", mono_burg_rule_string[rule]); + exit(1); + } + } +} + +void +ir_to_mesa_visitor::visit(ir_variable *ir) +{ + (void)ir; +} + +void +ir_to_mesa_visitor::visit(ir_loop *ir) +{ + (void)ir; + + printf("Can't support loops, should be flattened before here\n"); + exit(1); +} + +void +ir_to_mesa_visitor::visit(ir_loop_jump *ir) +{ + (void) ir; + printf("Can't support loops, should be flattened before here\n"); + exit(1); +} + + +void +ir_to_mesa_visitor::visit(ir_function_signature *ir) +{ + assert(0); + (void)ir; +} + +void +ir_to_mesa_visitor::visit(ir_function *ir) +{ + /* Ignore function bodies other than main() -- we shouldn't see calls to + * them since they should all be inlined before we get to ir_to_mesa. + */ + if (strcmp(ir->name, "main") == 0) { + const ir_function_signature *sig; + exec_list empty; + + sig = ir->matching_signature(&empty); + + assert(sig); + + foreach_iter(exec_list_iterator, iter, sig->body) { + ir_instruction *ir = (ir_instruction *)iter.get(); + + ir->accept(this); + } + } +} + +void +ir_to_mesa_visitor::visit(ir_expression *ir) +{ + unsigned int operand; + struct mbtree *op[2]; + const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1); + const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1); + const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1); + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + this->result = NULL; + ir->operands[operand]->accept(this); + if (!this->result) { + ir_print_visitor v; + printf("Failed to get tree for expression operand:\n"); + ir->operands[operand]->accept(&v); + exit(1); + } + op[operand] = this->result; + } + + this->result = NULL; + + switch (ir->operation) { + case ir_binop_add: + this->result = this->create_tree(MB_TERM_add_vec4_vec4, op[0], op[1]); + break; + case ir_binop_sub: + this->result = this->create_tree(MB_TERM_sub_vec4_vec4, op[0], op[1]); + break; + case ir_binop_mul: + this->result = this->create_tree(MB_TERM_mul_vec4_vec4, op[0], op[1]); + break; + case ir_binop_div: + this->result = this->create_tree(MB_TERM_div_vec4_vec4, op[0], op[1]); + break; + case ir_binop_dot: + if (ir->operands[0]->type == vec4_type) { + assert(ir->operands[1]->type == vec4_type); + this->result = this->create_tree(MB_TERM_dp4_vec4_vec4, op[0], op[1]); + } else if (ir->operands[0]->type == vec3_type) { + assert(ir->operands[1]->type == vec3_type); + this->result = this->create_tree(MB_TERM_dp3_vec4_vec4, op[0], op[1]); + } else if (ir->operands[0]->type == vec2_type) { + assert(ir->operands[1]->type == vec2_type); + this->result = this->create_tree(MB_TERM_dp2_vec4_vec4, op[0], op[1]); + } + break; + case ir_unop_sqrt: + this->result = this->create_tree(MB_TERM_sqrt_vec4, op[0], op[1]); + break; + default: + break; + } + if (!this->result) { + ir_print_visitor v; + printf("Failed to get tree for expression:\n"); + ir->accept(&v); + exit(1); + } +} + + +void +ir_to_mesa_visitor::visit(ir_swizzle *ir) +{ + struct mbtree *tree; + int i; + int swizzle[4]; + + /* FINISHME: Handle swizzles on the left side of an assignment. */ + + ir->val->accept(this); + assert(this->result); + + tree = this->create_tree(MB_TERM_swizzle_vec4, this->result, NULL); + + for (i = 0; i < 4; i++) { + if (i < ir->type->vector_elements) { + switch (i) { + case 0: + swizzle[i] = ir->mask.x; + break; + case 1: + swizzle[i] = ir->mask.y; + break; + case 2: + swizzle[i] = ir->mask.z; + break; + case 3: + swizzle[i] = ir->mask.w; + break; + } + } else { + /* If the type is smaller than a vec4, replicate the last + * channel out. + */ + swizzle[i] = ir->type->vector_elements - 1; + } + } + + tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], + swizzle[1], + swizzle[2], + swizzle[3]); + + this->result = tree; +} + + +void +ir_to_mesa_visitor::visit(ir_dereference_variable *ir) +{ + struct mbtree *tree; + int size_swizzles[4] = { + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), + }; + + ir_variable *var = ir->var->as_variable(); + + /* By the time we make it to this stage, matric`es should be broken down + * to vectors. + */ + assert(!var->type->is_matrix()); + + tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + + if (strncmp(var->name, "gl_", 3) == 0) { + if (strcmp(var->name, "gl_FragColor") == 0) { + tree->src_reg.file = PROGRAM_INPUT; + tree->src_reg.index = FRAG_ATTRIB_COL0; + } else { + assert(0); + } + } else { + this->get_temp_for_var(var, tree); + } + + /* If the type is smaller than a vec4, replicate the last channel out. */ + tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; + + this->result = tree; +} + +void +ir_to_mesa_visitor::visit(ir_dereference_array *ir) +{ + struct mbtree *tree; + int size_swizzles[4] = { + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), + }; + + ir_variable *var = ir->array->as_variable(); + ir_constant *index = ir->array_index->constant_expression_value(); + char *name; + + assert(var); + assert(index); + assert(strcmp(var->name, "gl_TexCoord") == 0); + + asprintf(&name, "fragment.texcoord[%d]", index->value.i[0]); + tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + tree->reg_name = name; + + /* If the type is smaller than a vec4, replicate the last channel out. */ + tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; + + this->result = tree; +} + +void +ir_to_mesa_visitor::visit(ir_dereference_record *ir) +{ + (void)ir; + assert(0); +} + +void +ir_to_mesa_visitor::visit(ir_assignment *ir) +{ + struct mbtree *l, *r, *t; + + ir->lhs->accept(this); + l = this->result; + ir->rhs->accept(this); + r = this->result; + assert(l); + assert(r); + + assert(!ir->condition); + + t = this->create_tree(MB_TERM_assign, l, r); + mono_burg_label(t, NULL); + reduce(t, MB_NTERM_stmt); +} + + +void +ir_to_mesa_visitor::visit(ir_constant *ir) +{ + struct mbtree *tree; + + assert(!ir->type->is_matrix()); + + tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + + assert(ir->type->base_type == GLSL_TYPE_FLOAT); + + /* FINISHME: This will end up being _mesa_add_unnamed_constant, + * which handles sharing values and sharing channels of vec4 + * constants for small values. + */ + /* FINISHME: Do something with the constant values for now. + */ + tree->src_reg.file = PROGRAM_CONSTANT; + tree->src_reg.index = this->next_constant++; + tree->src_reg.swizzle = SWIZZLE_NOOP; + + this->result = tree; +} + + +void +ir_to_mesa_visitor::visit(ir_call *ir) +{ + printf("Can't support call to %s\n", ir->callee_name()); + exit(1); +} + + +void +ir_to_mesa_visitor::visit(ir_texture *ir) +{ + assert(0); + + ir->coordinate->accept(this); +} + +void +ir_to_mesa_visitor::visit(ir_return *ir) +{ + assert(0); + + ir->get_value()->accept(this); +} + + +void +ir_to_mesa_visitor::visit(ir_if *ir) +{ + (void)ir; + printf("Can't support conditionals, should be flattened before here.\n"); + exit(1); +} + +static struct prog_src_register +mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) +{ + struct prog_src_register mesa_reg; + + mesa_reg.File = reg.file; + mesa_reg.Index = reg.index; + + return mesa_reg; +} + +void +do_ir_to_mesa(exec_list *instructions) +{ + ir_to_mesa_visitor v; + struct prog_instruction *mesa_instructions, *mesa_inst; + + visit_exec_list(instructions, &v); + + int num_instructions = 0; + foreach_iter(exec_list_iterator, iter, v.instructions) { + num_instructions++; + } + + mesa_instructions = + (struct prog_instruction *)calloc(num_instructions, + sizeof(*mesa_instructions)); + + mesa_inst = mesa_instructions; + foreach_iter(exec_list_iterator, iter, v.instructions) { + ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); + mesa_inst->Opcode = inst->op; + mesa_inst->DstReg.File = inst->dst_reg.file; + mesa_inst->DstReg.Index = inst->dst_reg.index; + mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); + mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); + mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); + mesa_inst++; + } +} diff --git a/ir_to_mesa.h b/ir_to_mesa.h new file mode 100644 index 00000000000..6154c1ca583 --- /dev/null +++ b/ir_to_mesa.h @@ -0,0 +1,170 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +#include "ir.h" +#include "shader/prog_instruction.h" + +/** + * \file ir_to_mesa.h + * + * Translates the IR to Mesa IR if possible. + */ + +/** + * This struct is a corresponding struct to Mesa prog_src_register, with + * wider fields. + */ +typedef struct ir_to_mesa_src_reg { + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ +} ir_to_mesa_src_reg; + +typedef struct ir_to_mesa_dst_reg { + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ +} ir_to_mesa_dst_reg; + +extern ir_to_mesa_src_reg ir_to_mesa_undef; + +class ir_to_mesa_instruction : public exec_node { +public: + enum prog_opcode op; + ir_to_mesa_dst_reg dst_reg; + ir_to_mesa_src_reg src_reg[3]; +}; + +struct mbtree { + struct mbtree *left; + struct mbtree *right; + void *state; + uint16_t op; + const char *reg_name; + const char *swizzle_reg_name; + class ir_to_mesa_visitor *v; + + /** + * This is the representation of this tree node's results as a + * source register for its consumer. + */ + ir_to_mesa_src_reg src_reg; +}; + +void do_ir_to_mesa(exec_list *instructions); + +class temp_entry : public exec_node { +public: + temp_entry(ir_variable *var, int file, int index) + : file(file), index(index), var(var) + { + /* empty */ + } + + int file; + int index; + ir_variable *var; /* variable that maps to this, if any */ +}; + +class ir_to_mesa_visitor : public ir_visitor { +public: + ir_to_mesa_visitor() + { + result = NULL; + next_temp = 0; + next_constant = 0; + } + + int next_temp; + int next_constant; + + void get_temp(struct mbtree *tree); + + void get_temp_for_var(ir_variable *var, struct mbtree *tree); + + struct mbtree *create_tree(int op, + struct mbtree *left, + struct mbtree *right); + + /** + * \name Visit methods + * + * As typical for the visitor pattern, there must be one \c visit method for + * each concrete subclass of \c ir_instruction. Virtual base classes within + * the hierarchy should not have \c visit methods. + */ + /*@{*/ + virtual void visit(ir_variable *); + virtual void visit(ir_loop *); + virtual void visit(ir_loop_jump *); + virtual void visit(ir_function_signature *); + virtual void visit(ir_function *); + virtual void visit(ir_expression *); + virtual void visit(ir_swizzle *); + virtual void visit(ir_dereference_variable *); + virtual void visit(ir_dereference_array *); + virtual void visit(ir_dereference_record *); + virtual void visit(ir_assignment *); + virtual void visit(ir_constant *); + virtual void visit(ir_call *); + virtual void visit(ir_return *); + virtual void visit(ir_texture *); + virtual void visit(ir_if *); + /*@}*/ + + struct mbtree *result; + + /** List of temp_entry */ + exec_list variable_storage; + + /** List of ir_to_mesa_instruction */ + exec_list instructions; +}; + +ir_to_mesa_instruction * +ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + +ir_to_mesa_instruction * +ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); + +ir_to_mesa_instruction * +ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2); + +inline ir_to_mesa_dst_reg +ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) +{ + ir_to_mesa_dst_reg dst_reg; + + dst_reg.file = reg.file; + dst_reg.index = reg.index; + + return dst_reg; +} diff --git a/main/mtypes.h b/main/mtypes.h index f168b6605b3..cab5ffde6cc 100644 --- a/main/mtypes.h +++ b/main/mtypes.h @@ -36,6 +36,8 @@ #define MAX_DRAW_BUFFERS 8 #define MAX_VARYING 16 +#include + /** * Indexes for vertex program attributes. * GL_NV_vertex_program aliases generic attributes over the conventional @@ -218,4 +220,34 @@ typedef enum FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) } gl_frag_result; +/** + * Names of the various vertex/fragment program register files, etc. + * + * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c) + * All values should fit in a 4-bit field. + * + * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM, + * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to + * be "uniform" variables since they can only be set outside glBegin/End. + * They're also all stored in the same Parameters array. + */ +typedef enum +{ + PROGRAM_TEMPORARY, /**< machine->Temporary[] */ + PROGRAM_INPUT, /**< machine->Inputs[] */ + PROGRAM_OUTPUT, /**< machine->Outputs[] */ + PROGRAM_VARYING, /**< machine->Inputs[]/Outputs[] */ + PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */ + PROGRAM_ENV_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_STATE_VAR, /**< gl_program->Parameters[] */ + PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_CONSTANT, /**< gl_program->Parameters[] */ + PROGRAM_UNIFORM, /**< gl_program->Parameters[] */ + PROGRAM_WRITE_ONLY, /**< A dummy, write-only register */ + PROGRAM_ADDRESS, /**< machine->AddressReg */ + PROGRAM_SAMPLER, /**< for shader samplers, compile-time only */ + PROGRAM_UNDEFINED, /**< Invalid/TBD value */ + PROGRAM_FILE_MAX +} gl_register_file; + #endif diff --git a/mesa/shader/prog_instruction.h b/mesa/shader/prog_instruction.h new file mode 100644 index 00000000000..2c95d274cab --- /dev/null +++ b/mesa/shader/prog_instruction.h @@ -0,0 +1,437 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 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 prog_instruction.h + * + * Vertex/fragment program instruction datatypes and constants. + * + * \author Brian Paul + * \author Keith Whitwell + * \author Ian Romanick + */ + + +#ifndef PROG_INSTRUCTION_H +#define PROG_INSTRUCTION_H + + +#include "main/mtypes.h" + + +/** + * Swizzle indexes. + * Do not change! + */ +/*@{*/ +#define SWIZZLE_X 0 +#define SWIZZLE_Y 1 +#define SWIZZLE_Z 2 +#define SWIZZLE_W 3 +#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */ +#define SWIZZLE_ONE 5 /**< For SWZ instruction only */ +#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */ +/*@}*/ + +#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) +#define SWIZZLE_NOOP MAKE_SWIZZLE4(0,1,2,3) +#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) +#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) + +#define SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) +#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X) +#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y) +#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z) +#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) + + +/** + * Writemask values, 1 bit per component. + */ +/*@{*/ +#define WRITEMASK_X 0x1 +#define WRITEMASK_Y 0x2 +#define WRITEMASK_XY 0x3 +#define WRITEMASK_Z 0x4 +#define WRITEMASK_XZ 0x5 +#define WRITEMASK_YZ 0x6 +#define WRITEMASK_XYZ 0x7 +#define WRITEMASK_W 0x8 +#define WRITEMASK_XW 0x9 +#define WRITEMASK_YW 0xa +#define WRITEMASK_XYW 0xb +#define WRITEMASK_ZW 0xc +#define WRITEMASK_XZW 0xd +#define WRITEMASK_YZW 0xe +#define WRITEMASK_XYZW 0xf +/*@}*/ + + +/** + * Condition codes + */ +/*@{*/ +#define COND_GT 1 /**< greater than zero */ +#define COND_EQ 2 /**< equal to zero */ +#define COND_LT 3 /**< less than zero */ +#define COND_UN 4 /**< unordered (NaN) */ +#define COND_GE 5 /**< greater than or equal to zero */ +#define COND_LE 6 /**< less than or equal to zero */ +#define COND_NE 7 /**< not equal to zero */ +#define COND_TR 8 /**< always true */ +#define COND_FL 9 /**< always false */ +/*@}*/ + + +/** + * Instruction precision for GL_NV_fragment_program + */ +/*@{*/ +#define FLOAT32 0x1 +#define FLOAT16 0x2 +#define FIXED12 0x4 +/*@}*/ + + +/** + * Saturation modes when storing values. + */ +/*@{*/ +#define SATURATE_OFF 0 +#define SATURATE_ZERO_ONE 1 +/*@}*/ + + +/** + * Per-component negation masks + */ +/*@{*/ +#define NEGATE_X 0x1 +#define NEGATE_Y 0x2 +#define NEGATE_Z 0x4 +#define NEGATE_W 0x8 +#define NEGATE_XYZ 0x7 +#define NEGATE_XYZW 0xf +#define NEGATE_NONE 0x0 +/*@}*/ + + +/** + * Program instruction opcodes, for both vertex and fragment programs. + * \note changes to this opcode list must be reflected in t_vb_arbprogram.c + */ +typedef enum prog_opcode { + /* ARB_vp ARB_fp NV_vp NV_fp GLSL */ + /*------------------------------------------*/ + OPCODE_NOP = 0, /* X */ + OPCODE_ABS, /* X X 1.1 X */ + OPCODE_ADD, /* X X X X X */ + OPCODE_AND, /* */ + OPCODE_ARA, /* 2 */ + OPCODE_ARL, /* X X */ + OPCODE_ARL_NV, /* 2 */ + OPCODE_ARR, /* 2 */ + OPCODE_BGNLOOP, /* opt */ + OPCODE_BGNSUB, /* opt */ + OPCODE_BRA, /* 2 X */ + OPCODE_BRK, /* 2 opt */ + OPCODE_CAL, /* 2 2 */ + OPCODE_CMP, /* X */ + OPCODE_CONT, /* opt */ + OPCODE_COS, /* X 2 X X */ + OPCODE_DDX, /* X X */ + OPCODE_DDY, /* X X */ + OPCODE_DP2, /* 2 */ + OPCODE_DP2A, /* 2 */ + OPCODE_DP3, /* X X X X X */ + OPCODE_DP4, /* X X X X X */ + OPCODE_DPH, /* X X 1.1 */ + OPCODE_DST, /* X X X X */ + OPCODE_ELSE, /* X */ + OPCODE_END, /* X X X X opt */ + OPCODE_ENDIF, /* opt */ + OPCODE_ENDLOOP, /* opt */ + OPCODE_ENDSUB, /* opt */ + OPCODE_EX2, /* X X 2 X X */ + OPCODE_EXP, /* X X X */ + OPCODE_FLR, /* X X 2 X X */ + OPCODE_FRC, /* X X 2 X X */ + OPCODE_IF, /* opt */ + OPCODE_KIL, /* X */ + OPCODE_KIL_NV, /* X X */ + OPCODE_LG2, /* X X 2 X X */ + OPCODE_LIT, /* X X X X */ + OPCODE_LOG, /* X X X */ + OPCODE_LRP, /* X X */ + OPCODE_MAD, /* X X X X X */ + OPCODE_MAX, /* X X X X X */ + OPCODE_MIN, /* X X X X X */ + OPCODE_MOV, /* X X X X X */ + OPCODE_MUL, /* X X X X X */ + OPCODE_NOISE1, /* X */ + OPCODE_NOISE2, /* X */ + OPCODE_NOISE3, /* X */ + OPCODE_NOISE4, /* X */ + OPCODE_NOT, /* */ + OPCODE_NRM3, /* */ + OPCODE_NRM4, /* */ + OPCODE_OR, /* */ + OPCODE_PK2H, /* X */ + OPCODE_PK2US, /* X */ + OPCODE_PK4B, /* X */ + OPCODE_PK4UB, /* X */ + OPCODE_POW, /* X X X X */ + OPCODE_POPA, /* 3 */ + OPCODE_PRINT, /* X X */ + OPCODE_PUSHA, /* 3 */ + OPCODE_RCC, /* 1.1 */ + OPCODE_RCP, /* X X X X X */ + OPCODE_RET, /* 2 2 */ + OPCODE_RFL, /* X X */ + OPCODE_RSQ, /* X X X X X */ + OPCODE_SCS, /* X */ + OPCODE_SEQ, /* 2 X X */ + OPCODE_SFL, /* 2 X */ + OPCODE_SGE, /* X X X X X */ + OPCODE_SGT, /* 2 X X */ + OPCODE_SIN, /* X 2 X X */ + OPCODE_SLE, /* 2 X X */ + OPCODE_SLT, /* X X X X X */ + OPCODE_SNE, /* 2 X X */ + OPCODE_SSG, /* 2 */ + OPCODE_STR, /* 2 X */ + OPCODE_SUB, /* X X 1.1 X X */ + OPCODE_SWZ, /* X X */ + OPCODE_TEX, /* X 3 X X */ + OPCODE_TXB, /* X 3 X */ + OPCODE_TXD, /* X X */ + OPCODE_TXL, /* 3 2 X */ + OPCODE_TXP, /* X X */ + OPCODE_TXP_NV, /* 3 X */ + OPCODE_TRUNC, /* X */ + OPCODE_UP2H, /* X */ + OPCODE_UP2US, /* X */ + OPCODE_UP4B, /* X */ + OPCODE_UP4UB, /* X */ + OPCODE_X2D, /* X */ + OPCODE_XOR, /* */ + OPCODE_XPD, /* X X X */ + MAX_OPCODE +} gl_inst_opcode; + + +/** + * Number of bits for the src/dst register Index field. + * This limits the size of temp/uniform register files. + */ +#define INST_INDEX_BITS 10 + + +/** + * Instruction source register. + */ +struct prog_src_register +{ + GLuint File:4; /**< One of the PROGRAM_* register file values. */ + GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit. + * May be negative for relative addressing. + */ + GLuint Swizzle:12; + GLuint RelAddr:1; + + /** Take the component-wise absolute value */ + GLuint Abs:1; + + /** + * Post-Abs negation. + * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ + * instruction which allows per-component negation. + */ + GLuint Negate:4; +}; + + +/** + * Instruction destination register. + */ +struct prog_dst_register +{ + GLuint File:4; /**< One of the PROGRAM_* register file values */ + GLuint Index:INST_INDEX_BITS; /**< Unsigned, never negative */ + GLuint WriteMask:4; + GLuint RelAddr:1; + + /** + * \name Conditional destination update control. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + /*@{*/ + /** + * Takes one of the 9 possible condition values (EQ, FL, GT, GE, LE, LT, + * NE, TR, or UN). Dest reg is only written to if the matching + * (swizzled) condition code value passes. When a conditional update mask + * is not specified, this will be \c COND_TR. + */ + GLuint CondMask:4; + + /** + * Condition code swizzle value. + */ + GLuint CondSwizzle:12; + + /** + * Selects the condition code register to use for conditional destination + * update masking. In NV_fragmnet_program or NV_vertex_program2 mode, only + * condition code register 0 is available. In NV_vertex_program3 mode, + * condition code registers 0 and 1 are available. + */ + GLuint CondSrc:1; + /*@}*/ +}; + + +/** + * Vertex/fragment program instruction. + */ +struct prog_instruction +{ + gl_inst_opcode Opcode; + struct prog_src_register SrcReg[3]; + struct prog_dst_register DstReg; + + /** + * Indicates that the instruction should update the condition code + * register. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + GLuint CondUpdate:1; + + /** + * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the + * condition code register that is to be updated. + * + * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition + * code register 0 is available. In GL_NV_vertex_program3 mode, condition + * code registers 0 and 1 are available. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2, + * NV_vertex_program2_option. + */ + GLuint CondDst:1; + + /** + * Saturate each value of the vectored result to the range [0,1] or the + * range [-1,1]. \c SSAT mode (i.e., saturation to the range [-1,1]) is + * only available in NV_fragment_program2 mode. + * Value is one of the SATURATE_* tokens. + * + * \since + * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3. + */ + GLuint SaturateMode:2; + + /** + * Per-instruction selectable precision: FLOAT32, FLOAT16, FIXED12. + * + * \since + * NV_fragment_program, NV_fragment_program_option. + */ + GLuint Precision:3; + + /** + * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions. + */ + /*@{*/ + /** Source texture unit. */ + GLuint TexSrcUnit:5; + + /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */ + GLuint TexSrcTarget:3; + + /** True if tex instruction should do shadow comparison */ + GLuint TexShadow:1; + /*@}*/ + + /** + * For BRA and CAL instructions, the location to jump to. + * For BGNLOOP, points to ENDLOOP (and vice-versa). + * For BRK, points to BGNLOOP (which points to ENDLOOP). + * For IF, points to ELSE or ENDIF. + * For ELSE, points to ENDIF. + */ + GLint BranchTarget; + + /** for debugging purposes */ + const char *Comment; + + /** Arbitrary data. Used for OPCODE_PRINT and some drivers */ + void *Data; + + /** for driver use (try to remove someday) */ + GLint Aux; +}; + + +extern void +_mesa_init_instructions(struct prog_instruction *inst, GLuint count); + +extern struct prog_instruction * +_mesa_alloc_instructions(GLuint numInst); + +extern struct prog_instruction * +_mesa_realloc_instructions(struct prog_instruction *oldInst, + GLuint numOldInst, GLuint numNewInst); + +extern struct prog_instruction * +_mesa_copy_instructions(struct prog_instruction *dest, + const struct prog_instruction *src, GLuint n); + +extern void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count); + +extern GLuint +_mesa_num_inst_src_regs(gl_inst_opcode opcode); + +extern GLuint +_mesa_num_inst_dst_regs(gl_inst_opcode opcode); + +extern GLboolean +_mesa_is_tex_instruction(gl_inst_opcode opcode); + +extern GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst); + +extern const char * +_mesa_opcode_string(gl_inst_opcode opcode); + + +#endif /* PROG_INSTRUCTION_H */ diff --git a/mesa_codegen.brg b/mesa_codegen.brg new file mode 100644 index 00000000000..1f6ccfaf0c2 --- /dev/null +++ b/mesa_codegen.brg @@ -0,0 +1,173 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt + * + */ + +/* DO NOT EDIT mesa_codegen.h. It is a generated file produced + * from mesa_codegen.brg and will be overwritten. + */ + +#include +#include +#include +#include +#include + +/* Everything before the first %% is pasted at the start of the + * mesa_codegen.h header file. + */ + +#include "ir_to_mesa.h" + +#define MBTREE_TYPE struct mbtree + +%% +%term assign +%term reference_vec4 +%term add_vec4_vec4 +%term sub_vec4_vec4 +%term mul_vec4_vec4 +%term div_vec4_vec4 +%term dp4_vec4_vec4 +%term dp3_vec4_vec4 +%term dp2_vec4_vec4 +%term sqrt_vec4 +%term swizzle_vec4 + +%start stmt + +alloced_vec4: reference_vec4 0 + +vec4: alloced_vec4 0 +alloced_vec4: vec4 1 +{ + /* FINISHME */ + tree->v->get_temp(tree); +} + +stmt: assign(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op1(tree, OPCODE_MOV, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg); +} + +vec4: swizzle_vec4(alloced_vec4) 1 +{ + ir_to_mesa_src_reg reg = tree->left->src_reg; + int swiz[4]; + int i; + + for (i = 0; i < 4; i++) { + swiz[i] = GET_SWZ(tree->src_reg.swizzle, i); + if (swiz[i] >= SWIZZLE_X && swiz[i] <= SWIZZLE_Y) { + swiz[i] = GET_SWZ(tree->left->src_reg.swizzle, swiz[i]); + } + } + reg.swizzle = MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); + + ir_to_mesa_emit_op1(tree, OPCODE_MOV, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + reg); +} + +vec4: add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_ADD, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); +} + +vec4: sub_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_SUB, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); +} + +vec4: mul_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_MUL, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); +} + +vec4: dp4_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_DP4, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); + tree->src_reg.swizzle = SWIZZLE_XXXX; +} + +vec4: dp3_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_DP3, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); + tree->src_reg.swizzle = SWIZZLE_XXXX; +} + + +vec4: dp2_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + ir_to_mesa_emit_op2(tree, OPCODE_DP2, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg, + tree->right->src_reg); + tree->src_reg.swizzle = SWIZZLE_XXXX; +} + +vec4: div_vec4_vec4(alloced_vec4, alloced_vec4) 1 +{ + /* FINISHME: Mesa RCP only uses the X channel, this node is for vec4. */ + ir_to_mesa_emit_op1(tree, OPCODE_RCP, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->right->src_reg); + + ir_to_mesa_emit_op2(tree, OPCODE_MUL, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->src_reg, + tree->left->src_reg); +} + +vec4: sqrt_vec4(alloced_vec4) 1 +{ + /* FINISHME: Mesa RSQ only uses the X channel, this node is for vec4. */ + ir_to_mesa_emit_op1(tree, OPCODE_RSQ, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg); + + ir_to_mesa_emit_op1(tree, OPCODE_RCP, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->src_reg); +} + +%% diff --git a/program.h b/program.h index 5c900b53cc0..d21b04344cd 100644 --- a/program.h +++ b/program.h @@ -22,6 +22,7 @@ */ #include +#include "main/mtypes.h" /** * Based on gl_shader in Mesa's mtypes.h. @@ -41,7 +42,6 @@ struct glsl_shader { }; -typedef int gl_register_file; typedef int gl_state_index; #define STATE_LENGTH 5 -- cgit v1.2.3 From 182b623de3beafaf586644014e108339a644b2db Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 10:16:57 -0700 Subject: Ignore the generated codegen files for now. Later we'll throw them in revision control. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b3ce5e7086e..376aaeda13a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ glsl_parser.output glsl_parser.cpp glsl_parser.h glsl +mesa_codegen.cpp +mesa_codegen.h -- cgit v1.2.3 From b5039eff3f361f281e0da65fb413180357e2a762 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 10:19:33 -0700 Subject: Add missing dist file. --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 88d8f0587c1..bb2cc34ccc3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,7 +64,8 @@ glsl_SOURCES = \ ir_vec_index_to_swizzle.cpp \ linker.cpp \ mesa_codegen.cpp \ - msea_codegen.h + mesa_codegen.h \ + mesa/shader/prog_instruction.h DISTFILES = \ mesa_codegen.brg -- cgit v1.2.3 From aaee40e107cf07a12c8e373d8bb910254f4ba30b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 10:16:20 -0700 Subject: ir_to_mesa: Print out the resulting program. --- Makefile.am | 7 +- ir_to_mesa.cpp | 7 + ir_to_mesa.h | 2 + main/mtypes.h | 19 +- mesa/shader/prog_instruction.c | 363 ++++++++++++++ mesa/shader/prog_print.c | 1089 ++++++++++++++++++++++++++++++++++++++++ mesa/shader/prog_print.h | 98 ++++ 7 files changed, 1582 insertions(+), 3 deletions(-) create mode 100644 mesa/shader/prog_instruction.c create mode 100644 mesa/shader/prog_print.c create mode 100644 mesa/shader/prog_print.h diff --git a/Makefile.am b/Makefile.am index bb2cc34ccc3..bf062595a9d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,8 +64,11 @@ glsl_SOURCES = \ ir_vec_index_to_swizzle.cpp \ linker.cpp \ mesa_codegen.cpp \ - mesa_codegen.h \ - mesa/shader/prog_instruction.h + msea_codegen.h \ + mesa/shader/prog_instruction.c \ + mesa/shader/prog_instruction.h \ + mesa/shader/prog_print.c \ + mesa/shader/prog_print.h DISTFILES = \ mesa_codegen.brg diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 5cbd451b214..a0d3ae9c8d4 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -45,7 +45,10 @@ #include "ir_expression_flattening.h" #include "glsl_types.h" +extern "C" { #include "shader/prog_instruction.h" +#include "shader/prog_print.h" +} ir_to_mesa_src_reg ir_to_mesa_undef = { PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP @@ -512,6 +515,7 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) struct prog_src_register mesa_reg; mesa_reg.File = reg.file; + assert(reg.index < (1 << INST_INDEX_BITS) - 1); mesa_reg.Index = reg.index; return mesa_reg; @@ -543,6 +547,9 @@ do_ir_to_mesa(exec_list *instructions) mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); + + _mesa_print_instruction(mesa_inst); + mesa_inst++; } } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 6154c1ca583..cdf4f2c621a 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -22,7 +22,9 @@ */ #include "ir.h" +extern "C" { #include "shader/prog_instruction.h" +}; /** * \file ir_to_mesa.h diff --git a/main/mtypes.h b/main/mtypes.h index cab5ffde6cc..06e2dd4b540 100644 --- a/main/mtypes.h +++ b/main/mtypes.h @@ -250,4 +250,21 @@ typedef enum PROGRAM_FILE_MAX } gl_register_file; -#endif +/** + * An index for each type of texture object. These correspond to the GL + * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. + * Note: the order is from highest priority to lowest priority. + */ +typedef enum +{ + TEXTURE_2D_ARRAY_INDEX, + TEXTURE_1D_ARRAY_INDEX, + TEXTURE_CUBE_INDEX, + TEXTURE_3D_INDEX, + TEXTURE_RECT_INDEX, + TEXTURE_2D_INDEX, + TEXTURE_1D_INDEX, + NUM_TEXTURE_TARGETS +} gl_texture_index; + +#endif /* MTYPES_H */ diff --git a/mesa/shader/prog_instruction.c b/mesa/shader/prog_instruction.c new file mode 100644 index 00000000000..fbcf868f509 --- /dev/null +++ b/mesa/shader/prog_instruction.c @@ -0,0 +1,363 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2009 VMware, Inc. 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. + */ + + +#define _GNU_SOURCE +#include +#include +#include + +#if 0 +#include "main/glheader.h" +#else +#define _mesa_strdup strdup +#define _mesa_snprintf snprintf +#define ASSERT assert +#endif +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_instruction.h" + + +/** + * Initialize program instruction fields to defaults. + * \param inst first instruction to initialize + * \param count number of instructions to initialize + */ +void +_mesa_init_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + + memset(inst, 0, count * sizeof(struct prog_instruction)); + + for (i = 0; i < count; i++) { + inst[i].SrcReg[0].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[1].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[2].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP; + + inst[i].DstReg.File = PROGRAM_UNDEFINED; + inst[i].DstReg.WriteMask = WRITEMASK_XYZW; + inst[i].DstReg.CondMask = COND_TR; + inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP; + + inst[i].SaturateMode = SATURATE_OFF; + inst[i].Precision = FLOAT32; + } +} + + +/** + * Allocate an array of program instructions. + * \param numInst number of instructions + * \return pointer to instruction memory + */ +struct prog_instruction * +_mesa_alloc_instructions(GLuint numInst) +{ + return (struct prog_instruction *) + calloc(1, numInst * sizeof(struct prog_instruction)); +} + + +/** + * Reallocate memory storing an array of program instructions. + * This is used when we need to append additional instructions onto an + * program. + * \param oldInst pointer to first of old/src instructions + * \param numOldInst number of instructions at + * \param numNewInst desired size of new instruction array. + * \return pointer to start of new instruction array. + */ +struct prog_instruction * +_mesa_realloc_instructions(struct prog_instruction *oldInst, + GLuint numOldInst, GLuint numNewInst) +{ + struct prog_instruction *newInst; + + (void)numOldInst; + newInst = (struct prog_instruction *) + realloc(oldInst, + numNewInst * sizeof(struct prog_instruction)); + + return newInst; +} + + +/** + * Copy an array of program instructions. + * \param dest pointer to destination. + * \param src pointer to source. + * \param n number of instructions to copy. + * \return pointer to destination. + */ +struct prog_instruction * +_mesa_copy_instructions(struct prog_instruction *dest, + const struct prog_instruction *src, GLuint n) +{ + GLuint i; + memcpy(dest, src, n * sizeof(struct prog_instruction)); + for (i = 0; i < n; i++) { + if (src[i].Comment) + dest[i].Comment = _mesa_strdup(src[i].Comment); + } + return dest; +} + + +/** + * Free an array of instructions + */ +void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + for (i = 0; i < count; i++) { + if (inst[i].Data) + free(inst[i].Data); + if (inst[i].Comment) + free((char *) inst[i].Comment); + } + free(inst); +} + + +/** + * Basic info about each instruction + */ +struct instruction_info +{ + gl_inst_opcode Opcode; + const char *Name; + GLuint NumSrcRegs; + GLuint NumDstRegs; +}; + +/** + * Instruction info + * \note Opcode should equal array index! + */ +static const struct instruction_info InstInfo[MAX_OPCODE] = { + { OPCODE_NOP, "NOP", 0, 0 }, + { OPCODE_ABS, "ABS", 1, 1 }, + { OPCODE_ADD, "ADD", 2, 1 }, + { OPCODE_AND, "AND", 2, 1 }, + { OPCODE_ARA, "ARA", 1, 1 }, + { OPCODE_ARL, "ARL", 1, 1 }, + { OPCODE_ARL_NV, "ARL_NV", 1, 1 }, + { OPCODE_ARR, "ARL", 1, 1 }, + { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 }, + { OPCODE_BGNSUB, "BGNSUB", 0, 0 }, + { OPCODE_BRA, "BRA", 0, 0 }, + { OPCODE_BRK, "BRK", 0, 0 }, + { OPCODE_CAL, "CAL", 0, 0 }, + { OPCODE_CMP, "CMP", 3, 1 }, + { OPCODE_CONT, "CONT", 0, 0 }, + { OPCODE_COS, "COS", 1, 1 }, + { OPCODE_DDX, "DDX", 1, 1 }, + { OPCODE_DDY, "DDY", 1, 1 }, + { OPCODE_DP2, "DP2", 2, 1 }, + { OPCODE_DP2A, "DP2A", 3, 1 }, + { OPCODE_DP3, "DP3", 2, 1 }, + { OPCODE_DP4, "DP4", 2, 1 }, + { OPCODE_DPH, "DPH", 2, 1 }, + { OPCODE_DST, "DST", 2, 1 }, + { OPCODE_ELSE, "ELSE", 0, 0 }, + { OPCODE_END, "END", 0, 0 }, + { OPCODE_ENDIF, "ENDIF", 0, 0 }, + { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 }, + { OPCODE_ENDSUB, "ENDSUB", 0, 0 }, + { OPCODE_EX2, "EX2", 1, 1 }, + { OPCODE_EXP, "EXP", 1, 1 }, + { OPCODE_FLR, "FLR", 1, 1 }, + { OPCODE_FRC, "FRC", 1, 1 }, + { OPCODE_IF, "IF", 1, 0 }, + { OPCODE_KIL, "KIL", 1, 0 }, + { OPCODE_KIL_NV, "KIL_NV", 0, 0 }, + { OPCODE_LG2, "LG2", 1, 1 }, + { OPCODE_LIT, "LIT", 1, 1 }, + { OPCODE_LOG, "LOG", 1, 1 }, + { OPCODE_LRP, "LRP", 3, 1 }, + { OPCODE_MAD, "MAD", 3, 1 }, + { OPCODE_MAX, "MAX", 2, 1 }, + { OPCODE_MIN, "MIN", 2, 1 }, + { OPCODE_MOV, "MOV", 1, 1 }, + { OPCODE_MUL, "MUL", 2, 1 }, + { OPCODE_NOISE1, "NOISE1", 1, 1 }, + { OPCODE_NOISE2, "NOISE2", 1, 1 }, + { OPCODE_NOISE3, "NOISE3", 1, 1 }, + { OPCODE_NOISE4, "NOISE4", 1, 1 }, + { OPCODE_NOT, "NOT", 1, 1 }, + { OPCODE_NRM3, "NRM3", 1, 1 }, + { OPCODE_NRM4, "NRM4", 1, 1 }, + { OPCODE_OR, "OR", 2, 1 }, + { OPCODE_PK2H, "PK2H", 1, 1 }, + { OPCODE_PK2US, "PK2US", 1, 1 }, + { OPCODE_PK4B, "PK4B", 1, 1 }, + { OPCODE_PK4UB, "PK4UB", 1, 1 }, + { OPCODE_POW, "POW", 2, 1 }, + { OPCODE_POPA, "POPA", 0, 0 }, + { OPCODE_PRINT, "PRINT", 1, 0 }, + { OPCODE_PUSHA, "PUSHA", 0, 0 }, + { OPCODE_RCC, "RCC", 1, 1 }, + { OPCODE_RCP, "RCP", 1, 1 }, + { OPCODE_RET, "RET", 0, 0 }, + { OPCODE_RFL, "RFL", 1, 1 }, + { OPCODE_RSQ, "RSQ", 1, 1 }, + { OPCODE_SCS, "SCS", 1, 1 }, + { OPCODE_SEQ, "SEQ", 2, 1 }, + { OPCODE_SFL, "SFL", 0, 1 }, + { OPCODE_SGE, "SGE", 2, 1 }, + { OPCODE_SGT, "SGT", 2, 1 }, + { OPCODE_SIN, "SIN", 1, 1 }, + { OPCODE_SLE, "SLE", 2, 1 }, + { OPCODE_SLT, "SLT", 2, 1 }, + { OPCODE_SNE, "SNE", 2, 1 }, + { OPCODE_SSG, "SSG", 1, 1 }, + { OPCODE_STR, "STR", 0, 1 }, + { OPCODE_SUB, "SUB", 2, 1 }, + { OPCODE_SWZ, "SWZ", 1, 1 }, + { OPCODE_TEX, "TEX", 1, 1 }, + { OPCODE_TXB, "TXB", 1, 1 }, + { OPCODE_TXD, "TXD", 3, 1 }, + { OPCODE_TXL, "TXL", 1, 1 }, + { OPCODE_TXP, "TXP", 1, 1 }, + { OPCODE_TXP_NV, "TXP_NV", 1, 1 }, + { OPCODE_TRUNC, "TRUNC", 1, 1 }, + { OPCODE_UP2H, "UP2H", 1, 1 }, + { OPCODE_UP2US, "UP2US", 1, 1 }, + { OPCODE_UP4B, "UP4B", 1, 1 }, + { OPCODE_UP4UB, "UP4UB", 1, 1 }, + { OPCODE_X2D, "X2D", 3, 1 }, + { OPCODE_XOR, "XOR", 2, 1 }, + { OPCODE_XPD, "XPD", 2, 1 } +}; + + +/** + * Return the number of src registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_src_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumSrcRegs; +} + + +/** + * Return the number of dst registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_dst_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumDstRegs; +} + + +GLboolean +_mesa_is_tex_instruction(gl_inst_opcode opcode) +{ + return (opcode == OPCODE_TEX || + opcode == OPCODE_TXB || + opcode == OPCODE_TXD || + opcode == OPCODE_TXL || + opcode == OPCODE_TXP); +} + + +/** + * Check if there's a potential src/dst register data dependency when + * using SOA execution. + * Example: + * MOV T, T.yxwz; + * This would expand into: + * MOV t0, t1; + * MOV t1, t0; + * MOV t2, t3; + * MOV t3, t2; + * The second instruction will have the wrong value for t0 if executed as-is. + */ +GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst) +{ + GLuint i, chan; + + if (inst->DstReg.WriteMask == WRITEMASK_X || + inst->DstReg.WriteMask == WRITEMASK_Y || + inst->DstReg.WriteMask == WRITEMASK_Z || + inst->DstReg.WriteMask == WRITEMASK_W || + inst->DstReg.WriteMask == 0x0) { + /* no chance of data dependency */ + return GL_FALSE; + } + + /* loop over src regs */ + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].File == inst->DstReg.File && + inst->SrcReg[i].Index == inst->DstReg.Index) { + /* loop over dest channels */ + GLuint channelsWritten = 0x0; + for (chan = 0; chan < 4; chan++) { + if (inst->DstReg.WriteMask & (1 << chan)) { + /* check if we're reading a channel that's been written */ + GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan); + if (swizzle <= SWIZZLE_W && + (channelsWritten & (1 << swizzle))) { + return GL_TRUE; + } + + channelsWritten |= (1 << chan); + } + } + } + } + return GL_FALSE; +} + + +/** + * Return string name for given program opcode. + */ +const char * +_mesa_opcode_string(gl_inst_opcode opcode) +{ + if (opcode < MAX_OPCODE) + return InstInfo[opcode].Name; + else { + static char s[20]; + _mesa_snprintf(s, sizeof(s), "OP%u", opcode); + return s; + } +} + diff --git a/mesa/shader/prog_print.c b/mesa/shader/prog_print.c new file mode 100644 index 00000000000..9ac090b2617 --- /dev/null +++ b/mesa/shader/prog_print.c @@ -0,0 +1,1089 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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 prog_print.c + * Print vertex/fragment programs - for debugging. + * \author Brian Paul + */ + +#if 0 +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#else + +#define _GNU_SOURCE + +#include +#include +#include +#include +struct gl_program { + int Target; +}; + +void _mesa_problem(void *ctx, char *msg) +{ + (void)ctx; + fprintf(stderr, "%s", msg); + exit(1); +} + +#endif + +#include "prog_instruction.h" +#include "prog_print.h" + + + +/** + * Return string name for given program/register file. + */ +static const char * +file_string(gl_register_file f, gl_prog_print_mode mode) +{ + (void)mode; + switch (f) { + case PROGRAM_TEMPORARY: + return "TEMP"; + case PROGRAM_LOCAL_PARAM: + return "LOCAL"; + case PROGRAM_ENV_PARAM: + return "ENV"; + case PROGRAM_STATE_VAR: + return "STATE"; + case PROGRAM_INPUT: + return "INPUT"; + case PROGRAM_OUTPUT: + return "OUTPUT"; + case PROGRAM_NAMED_PARAM: + return "NAMED"; + case PROGRAM_CONSTANT: + return "CONST"; + case PROGRAM_UNIFORM: + return "UNIFORM"; + case PROGRAM_VARYING: + return "VARYING"; + case PROGRAM_WRITE_ONLY: + return "WRITE_ONLY"; + case PROGRAM_ADDRESS: + return "ADDR"; + case PROGRAM_SAMPLER: + return "SAMPLER"; + case PROGRAM_UNDEFINED: + return "UNDEFINED"; + default: + { + static char s[20]; + snprintf(s, sizeof(s), "FILE%u", f); + return s; + } + } +} + + +/** + * Return ARB_v/f_prog-style input attrib string. + */ +static const char * +arb_input_attrib_string(GLint index, GLenum progType) +{ + /* + * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens. + */ + const char *vertAttribs[] = { + "vertex.position", + "vertex.weight", + "vertex.normal", + "vertex.color.primary", + "vertex.color.secondary", + "vertex.fogcoord", + "vertex.(six)", + "vertex.(seven)", + "vertex.texcoord[0]", + "vertex.texcoord[1]", + "vertex.texcoord[2]", + "vertex.texcoord[3]", + "vertex.texcoord[4]", + "vertex.texcoord[5]", + "vertex.texcoord[6]", + "vertex.texcoord[7]", + "vertex.attrib[0]", + "vertex.attrib[1]", + "vertex.attrib[2]", + "vertex.attrib[3]", + "vertex.attrib[4]", + "vertex.attrib[5]", + "vertex.attrib[6]", + "vertex.attrib[7]", + "vertex.attrib[8]", + "vertex.attrib[9]", + "vertex.attrib[10]", + "vertex.attrib[11]", + "vertex.attrib[12]", + "vertex.attrib[13]", + "vertex.attrib[14]", + "vertex.attrib[15]" + }; + const char *fragAttribs[] = { + "fragment.position", + "fragment.color.primary", + "fragment.color.secondary", + "fragment.fogcoord", + "fragment.texcoord[0]", + "fragment.texcoord[1]", + "fragment.texcoord[2]", + "fragment.texcoord[3]", + "fragment.texcoord[4]", + "fragment.texcoord[5]", + "fragment.texcoord[6]", + "fragment.texcoord[7]", + "fragment.varying[0]", + "fragment.varying[1]", + "fragment.varying[2]", + "fragment.varying[3]", + "fragment.varying[4]", + "fragment.varying[5]", + "fragment.varying[6]", + "fragment.varying[7]" + }; + + /* sanity checks */ + assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0); + assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0); + + if (progType == GL_VERTEX_PROGRAM_ARB) { + assert((unsigned int)index < sizeof(vertAttribs) / sizeof(vertAttribs[0])); + return vertAttribs[index]; + } + else { + assert((unsigned int)index < sizeof(fragAttribs) / sizeof(fragAttribs[0])); + return fragAttribs[index]; + } +} + + +/** + * Print a vertex program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_vp_inputs(GLbitfield inputs) +{ + printf("VP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_VERTEX_PROGRAM_ARB); + printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + +/** + * Print a fragment program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_fp_inputs(GLbitfield inputs) +{ + printf("FP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_FRAGMENT_PROGRAM_ARB); + printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + +#if 0 +/** + * Return ARB_v/f_prog-style output attrib string. + */ +static const char * +arb_output_attrib_string(GLint index, GLenum progType) +{ + /* + * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens. + */ + const char *vertResults[] = { + "result.position", + "result.color.primary", + "result.color.secondary", + "result.fogcoord", + "result.texcoord[0]", + "result.texcoord[1]", + "result.texcoord[2]", + "result.texcoord[3]", + "result.texcoord[4]", + "result.texcoord[5]", + "result.texcoord[6]", + "result.texcoord[7]", + "result.varying[0]", + "result.varying[1]", + "result.varying[2]", + "result.varying[3]", + "result.varying[4]", + "result.varying[5]", + "result.varying[6]", + "result.varying[7]" + }; + const char *fragResults[] = { + "result.color", + "result.color(half)", + "result.depth", + "result.color[0]", + "result.color[1]", + "result.color[2]", + "result.color[3]" + }; + + if (progType == GL_VERTEX_PROGRAM_ARB) { + assert(index < sizeof(vertResults) / sizeof(vertResults[0])); + return vertResults[index]; + } + else { + assert(index < sizeof(fragResults) / sizeof(fragResults[0])); + return fragResults[index]; + } +} +#endif + +/** + * Return string representation of the given register. + * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined + * by the ARB/NV program languages so we've taken some liberties here. + * \param f the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc) + * \param index number of the register in the register file + * \param mode the output format/mode/style + * \param prog pointer to containing program + */ +static const char * +reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode, + GLboolean relAddr, const struct gl_program *prog) +{ + static char str[100]; + const char *addr = relAddr ? "ADDR+" : ""; + + str[0] = 0; + + switch (mode) { + case PROG_PRINT_DEBUG: + sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index); + break; + case PROG_PRINT_ARB: +#if 0 + switch (f) { + case PROGRAM_INPUT: + sprintf(str, "%s", arb_input_attrib_string(index, prog->Target)); + break; + case PROGRAM_OUTPUT: + sprintf(str, "%s", arb_output_attrib_string(index, prog->Target)); + break; + case PROGRAM_TEMPORARY: + sprintf(str, "temp%d", index); + break; + case PROGRAM_ENV_PARAM: + sprintf(str, "program.env[%s%d]", addr, index); + break; + case PROGRAM_LOCAL_PARAM: + sprintf(str, "program.local[%s%d]", addr, index); + break; + case PROGRAM_VARYING: /* extension */ + sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + sprintf(str, "uniform[%s%d]", addr, index); + break; + case PROGRAM_STATE_VAR: + { + struct gl_program_parameter *param + = prog->Parameters->Parameters + index; + char *state = _mesa_program_state_string(param->StateIndexes); + sprintf(str, "%s", state); + free(state); + } + break; + case PROGRAM_ADDRESS: + sprintf(str, "A%d", index); + break; + default: + _mesa_problem(NULL, "bad file in reg_string()"); + } + break; +#else + assert(0); + break; +#endif + + case PROG_PRINT_NV: + switch (f) { + case PROGRAM_INPUT: + if (prog->Target == GL_VERTEX_PROGRAM_ARB) + sprintf(str, "v[%d]", index); + else + sprintf(str, "f[%d]", index); + break; + case PROGRAM_OUTPUT: + sprintf(str, "o[%d]", index); + break; + case PROGRAM_TEMPORARY: + sprintf(str, "R%d", index); + break; + case PROGRAM_ENV_PARAM: + sprintf(str, "c[%d]", index); + break; + case PROGRAM_VARYING: /* extension */ + sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + sprintf(str, "uniform[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_STATE_VAR: /* extension */ + sprintf(str, "state[%s%d]", addr, index); + break; + default: + _mesa_problem(NULL, "bad file in reg_string()"); + } + break; + + default: + _mesa_problem(NULL, "bad mode in reg_string()"); + } + + return str; +} + + +/** + * Return a string representation of the given swizzle word. + * If extended is true, use extended (comma-separated) format. + * \param swizzle the swizzle field + * \param negateBase 4-bit negation vector + * \param extended if true, also allow 0, 1 values + */ +const char * +_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended) +{ + static const char swz[] = "xyzw01!?"; /* See SWIZZLE_x definitions */ + static char s[20]; + GLuint i = 0; + + if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0) + return ""; /* no swizzle/negation */ + + if (!extended) + s[i++] = '.'; + + if (negateMask & NEGATE_X) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 0)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_Y) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 1)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_Z) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 2)]; + + if (extended) { + s[i++] = ','; + } + + if (negateMask & NEGATE_W) + s[i++] = '-'; + s[i++] = swz[GET_SWZ(swizzle, 3)]; + + s[i] = 0; + return s; +} + + +void +_mesa_print_swizzle(GLuint swizzle) +{ + if (swizzle == SWIZZLE_XYZW) { + printf(".xyzw\n"); + } + else { + const char *s = _mesa_swizzle_string(swizzle, 0, 0); + printf("%s\n", s); + } +} + + +const char * +_mesa_writemask_string(GLuint writeMask) +{ + static char s[10]; + GLuint i = 0; + + if (writeMask == WRITEMASK_XYZW) + return ""; + + s[i++] = '.'; + if (writeMask & WRITEMASK_X) + s[i++] = 'x'; + if (writeMask & WRITEMASK_Y) + s[i++] = 'y'; + if (writeMask & WRITEMASK_Z) + s[i++] = 'z'; + if (writeMask & WRITEMASK_W) + s[i++] = 'w'; + + s[i] = 0; + return s; +} + + +const char * +_mesa_condcode_string(GLuint condcode) +{ + switch (condcode) { + case COND_GT: return "GT"; + case COND_EQ: return "EQ"; + case COND_LT: return "LT"; + case COND_UN: return "UN"; + case COND_GE: return "GE"; + case COND_LE: return "LE"; + case COND_NE: return "NE"; + case COND_TR: return "TR"; + case COND_FL: return "FL"; + default: return "cond???"; + } +} + + +static void +fprint_dst_reg(FILE * f, + const struct prog_dst_register *dstReg, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + fprintf(f, "%s%s", + reg_string((gl_register_file) dstReg->File, + dstReg->Index, mode, dstReg->RelAddr, prog), + _mesa_writemask_string(dstReg->WriteMask)); + + if (dstReg->CondMask != COND_TR) { + fprintf(f, " (%s.%s)", + _mesa_condcode_string(dstReg->CondMask), + _mesa_swizzle_string(dstReg->CondSwizzle, + GL_FALSE, GL_FALSE)); + } + +#if 0 + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) dstReg->File, mode), + dstReg->Index, + _mesa_writemask_string(dstReg->WriteMask)); +#endif +} + + +static void +fprint_src_reg(FILE *f, + const struct prog_src_register *srcReg, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + const char *abs = srcReg->Abs ? "|" : ""; + + fprintf(f, "%s%s%s%s", + abs, + reg_string((gl_register_file) srcReg->File, + srcReg->Index, mode, srcReg->RelAddr, prog), + _mesa_swizzle_string(srcReg->Swizzle, + srcReg->Negate, GL_FALSE), + abs); +#if 0 + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) srcReg->File, mode), + srcReg->Index, + _mesa_swizzle_string(srcReg->Swizzle, + srcReg->Negate, GL_FALSE)); +#endif +} + + +static void +fprint_comment(FILE *f, const struct prog_instruction *inst) +{ + if (inst->Comment) + fprintf(f, "; # %s\n", inst->Comment); + else + fprintf(f, ";\n"); +} + + +static void +fprint_alu_instruction(FILE *f, + const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + GLuint j; + + fprintf(f, "%s", opcode_string); + if (inst->CondUpdate) + fprintf(f, ".C"); + + /* frag prog only */ + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + + fprintf(f, " "); + if (inst->DstReg.File != PROGRAM_UNDEFINED) { + fprint_dst_reg(f, &inst->DstReg, mode, prog); + } + else { + fprintf(f, " ???"); + } + + if (numRegs > 0) + fprintf(f, ", "); + + for (j = 0; j < numRegs; j++) { + fprint_src_reg(f, inst->SrcReg + j, mode, prog); + if (j + 1 < numRegs) + fprintf(f, ", "); + } + + fprint_comment(f, inst); +} + + +void +_mesa_print_alu_instruction(const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs) +{ + fprint_alu_instruction(stderr, inst, opcode_string, + numRegs, PROG_PRINT_DEBUG, NULL); +} + + +/** + * Print a single vertex/fragment program instruction. + */ +GLint +_mesa_fprint_instruction_opt(FILE *f, + const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + GLint i; + + if (inst->Opcode == OPCODE_ELSE || + inst->Opcode == OPCODE_ENDIF || + inst->Opcode == OPCODE_ENDLOOP || + inst->Opcode == OPCODE_ENDSUB) { + indent -= 3; + } + for (i = 0; i < indent; i++) { + fprintf(f, " "); + } + + switch (inst->Opcode) { + case OPCODE_PRINT: + fprintf(f, "PRINT '%s'", (char *) inst->Data); + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + fprintf(f, ", "); + fprintf(f, "%s[%d]%s", + file_string((gl_register_file) inst->SrcReg[0].File, + mode), + inst->SrcReg[0].Index, + _mesa_swizzle_string(inst->SrcReg[0].Swizzle, + inst->SrcReg[0].Negate, GL_FALSE)); + } + if (inst->Comment) + fprintf(f, " # %s", inst->Comment); + fprint_comment(f, inst); + break; + case OPCODE_SWZ: + fprintf(f, "SWZ"); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", %s[%d], %s", + file_string((gl_register_file) inst->SrcReg[0].File, + mode), + inst->SrcReg[0].Index, + _mesa_swizzle_string(inst->SrcReg[0].Swizzle, + inst->SrcReg[0].Negate, GL_TRUE)); + fprint_comment(f, inst); + break; + case OPCODE_TEX: + case OPCODE_TXP: + case OPCODE_TXL: + case OPCODE_TXB: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + fprintf(f, "_SAT"); + fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprintf(f, ", texture[%d], ", inst->TexSrcUnit); + switch (inst->TexSrcTarget) { + case TEXTURE_1D_INDEX: fprintf(f, "1D"); break; + case TEXTURE_2D_INDEX: fprintf(f, "2D"); break; + case TEXTURE_3D_INDEX: fprintf(f, "3D"); break; + case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE"); break; + case TEXTURE_RECT_INDEX: fprintf(f, "RECT"); break; + case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break; + case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break; + default: + ; + } + if (inst->TexShadow) + fprintf(f, " SHADOW"); + fprint_comment(f, inst); + break; + + case OPCODE_KIL: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + fprintf(f, " "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_KIL_NV: + fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + fprintf(f, " "); + fprintf(f, "%s.%s", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + GL_FALSE, GL_FALSE)); + fprint_comment(f, inst); + break; + + case OPCODE_ARL: + fprintf(f, "ARL "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_BRA: + fprintf(f, "BRA %d (%s%s)", + inst->BranchTarget, + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + fprint_comment(f, inst); + break; + case OPCODE_IF: + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + /* Use ordinary register */ + fprintf(f, "IF "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprintf(f, "; "); + } + else { + /* Use cond codes */ + fprintf(f, "IF (%s%s);", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + 0, GL_FALSE)); + } + fprintf(f, " # (if false, goto %d)", inst->BranchTarget); + fprint_comment(f, inst); + return indent + 3; + case OPCODE_ELSE: + fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDIF: + fprintf(f, "ENDIF;\n"); + break; + case OPCODE_BGNLOOP: + fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDLOOP: + fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget); + break; + case OPCODE_BRK: + case OPCODE_CONT: + fprintf(f, "%s (%s%s); # (goto %d)", + _mesa_opcode_string(inst->Opcode), + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), + inst->BranchTarget); + fprint_comment(f, inst); + break; + + case OPCODE_BGNSUB: + if (mode == PROG_PRINT_NV) { + fprintf(f, "%s:\n", inst->Comment); /* comment is label */ + return indent; + } + else { + fprintf(f, "BGNSUB"); + fprint_comment(f, inst); + return indent + 3; + } + case OPCODE_ENDSUB: + if (mode == PROG_PRINT_DEBUG) { + fprintf(f, "ENDSUB"); + fprint_comment(f, inst); + } + break; + case OPCODE_CAL: + if (mode == PROG_PRINT_NV) { + fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget); + } + else { + fprintf(f, "CAL %u", inst->BranchTarget); + fprint_comment(f, inst); + } + break; + case OPCODE_RET: + fprintf(f, "RET (%s%s)", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + fprint_comment(f, inst); + break; + + case OPCODE_END: + fprintf(f, "END\n"); + break; + case OPCODE_NOP: + if (mode == PROG_PRINT_DEBUG) { + fprintf(f, "NOP"); + fprint_comment(f, inst); + } + else if (inst->Comment) { + /* ARB/NV extensions don't have NOP instruction */ + fprintf(f, "# %s\n", inst->Comment); + } + break; + /* XXX may need other special-case instructions */ + default: + if (inst->Opcode < MAX_OPCODE) { + /* typical alu instruction */ + fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + _mesa_num_inst_src_regs(inst->Opcode), + mode, prog); + } + else { + fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + 3/*_mesa_num_inst_src_regs(inst->Opcode)*/, + mode, prog); + } + break; + } + return indent; +} + + +GLint +_mesa_print_instruction_opt(const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog) +{ + return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog); +} + + +void +_mesa_print_instruction(const struct prog_instruction *inst) +{ + /* note: 4th param should be ignored for PROG_PRINT_DEBUG */ + _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL); +} + +#if 0 +/** + * Print program, with options. + */ +void +_mesa_fprint_program_opt(FILE *f, + const struct gl_program *prog, + gl_prog_print_mode mode, + GLboolean lineNumbers) +{ + GLuint i, indent = 0; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: + if (mode == PROG_PRINT_ARB) + fprintf(f, "!!ARBvp1.0\n"); + else if (mode == PROG_PRINT_NV) + fprintf(f, "!!VP1.0\n"); + else + fprintf(f, "# Vertex Program/Shader %u\n", prog->Id); + break; + case GL_FRAGMENT_PROGRAM_ARB: + case GL_FRAGMENT_PROGRAM_NV: + if (mode == PROG_PRINT_ARB) + fprintf(f, "!!ARBfp1.0\n"); + else if (mode == PROG_PRINT_NV) + fprintf(f, "!!FP1.0\n"); + else + fprintf(f, "# Fragment Program/Shader %u\n", prog->Id); + break; + } + + for (i = 0; i < prog->NumInstructions; i++) { + if (lineNumbers) + fprintf(f, "%3d: ", i); + indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i, + indent, mode, prog); + } +} + + +/** + * Print program to stderr, default options. + */ +void +_mesa_print_program(const struct gl_program *prog) +{ + _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE); +} + +/** + * Return binary representation of 64-bit value (as a string). + * Insert a comma to separate each group of 8 bits. + * Note we return a pointer to local static storage so this is not + * re-entrant, etc. + * XXX move to imports.[ch] if useful elsewhere. + */ +static const char * +binary(GLbitfield64 val) +{ + static char buf[80]; + GLint i, len = 0; + for (i = 63; i >= 0; --i) { + if (val & (1ULL << i)) + buf[len++] = '1'; + else if (len > 0 || i == 0) + buf[len++] = '0'; + if (len > 0 && ((i-1) % 8) == 7) + buf[len++] = ','; + } + buf[len] = '\0'; + return buf; +} + + +/** + * Print all of a program's parameters/fields to given file. + */ +static void +_mesa_fprint_program_parameters(FILE *f, + GLcontext *ctx, + const struct gl_program *prog) +{ + GLuint i; + + fprintf(f, "InputsRead: 0x%x (0b%s)\n", + prog->InputsRead, binary(prog->InputsRead)); + fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n", + prog->OutputsWritten, binary(prog->OutputsWritten)); + fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); + fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); + fprintf(f, "NumParameters=%d\n", prog->NumParameters); + fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); + fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); + fprintf(f, "SamplersUsed: 0x%x (0b%s)\n", + prog->SamplersUsed, binary(prog->SamplersUsed)); + fprintf(f, "Samplers=[ "); + for (i = 0; i < MAX_SAMPLERS; i++) { + fprintf(f, "%d ", prog->SamplerUnits[i]); + } + fprintf(f, "]\n"); + + _mesa_load_state_parameters(ctx, prog->Parameters); + +#if 0 + fprintf(f, "Local Params:\n"); + for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ + const GLfloat *p = prog->LocalParams[i]; + fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); + } +#endif + _mesa_print_parameter_list(prog->Parameters); +} + + +/** + * Print all of a program's parameters/fields to stderr. + */ +void +_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog) +{ + _mesa_fprint_program_parameters(stderr, ctx, prog); +} + + +/** + * Print a program parameter list to given file. + */ +static void +_mesa_fprint_parameter_list(FILE *f, + const struct gl_program_parameter_list *list) +{ + const gl_prog_print_mode mode = PROG_PRINT_DEBUG; + GLuint i; + + if (!list) + return; + + if (0) + fprintf(f, "param list %p\n", (void *) list); + fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags); + for (i = 0; i < list->NumParameters; i++){ + struct gl_program_parameter *param = list->Parameters + i; + const GLfloat *v = list->ParameterValues[i]; + fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}", + i, param->Size, + file_string(list->Parameters[i].Type, mode), + param->Name, v[0], v[1], v[2], v[3]); + if (param->Flags & PROG_PARAM_BIT_CENTROID) + fprintf(f, " Centroid"); + if (param->Flags & PROG_PARAM_BIT_INVARIANT) + fprintf(f, " Invariant"); + if (param->Flags & PROG_PARAM_BIT_FLAT) + fprintf(f, " Flat"); + if (param->Flags & PROG_PARAM_BIT_LINEAR) + fprintf(f, " Linear"); + fprintf(f, "\n"); + } +} + + +/** + * Print a program parameter list to stderr. + */ +void +_mesa_print_parameter_list(const struct gl_program_parameter_list *list) +{ + _mesa_fprint_parameter_list(stderr, list); +} + + +/** + * Write shader and associated info to a file. + */ +void +_mesa_write_shader_to_file(const struct gl_shader *shader) +{ + const char *type; + char filename[100]; + FILE *f; + + if (shader->Type == GL_FRAGMENT_SHADER) + type = "frag"; + else + type = "vert"; + + snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); + f = fopen(filename, "w"); + if (!f) { + fprintf(stderr, "Unable to open %s for writing\n", filename); + return; + } + + fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum); + fputs(shader->Source, f); + fprintf(f, "\n"); + + fprintf(f, "/* Compile status: %s */\n", + shader->CompileStatus ? "ok" : "fail"); + if (!shader->CompileStatus) { + fprintf(f, "/* Log Info: */\n"); + fputs(shader->InfoLog, f); + } + else { + fprintf(f, "/* GPU code */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); + fprintf(f, "*/\n"); + fprintf(f, "/* Parameters / constants */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_parameter_list(f, shader->Program->Parameters); + fprintf(f, "*/\n"); + } + + fclose(f); +} + + +/** + * Append the shader's uniform info/values to the shader log file. + * The log file will typically have been created by the + * _mesa_write_shader_to_file function. + */ +void +_mesa_append_uniforms_to_file(const struct gl_shader *shader, + const struct gl_program *prog) +{ + const char *type; + char filename[100]; + FILE *f; + + if (shader->Type == GL_FRAGMENT_SHADER) + type = "frag"; + else + type = "vert"; + + snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); + f = fopen(filename, "a"); /* append */ + if (!f) { + fprintf(stderr, "Unable to open %s for appending\n", filename); + return; + } + + fprintf(f, "/* First-draw parameters / constants */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_parameter_list(f, prog->Parameters); + fprintf(f, "*/\n"); + + fclose(f); +} +#endif diff --git a/mesa/shader/prog_print.h b/mesa/shader/prog_print.h new file mode 100644 index 00000000000..f0df77b5129 --- /dev/null +++ b/mesa/shader/prog_print.h @@ -0,0 +1,98 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 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. + */ + + +#ifndef PROG_PRINT_H +#define PROG_PRINT_H + + +/** + * The output style to use when printing programs. + */ +typedef enum { + PROG_PRINT_ARB, + PROG_PRINT_NV, + PROG_PRINT_DEBUG +} gl_prog_print_mode; + + +extern void +_mesa_print_vp_inputs(GLbitfield inputs); + +extern void +_mesa_print_fp_inputs(GLbitfield inputs); + +extern const char * +_mesa_condcode_string(GLuint condcode); + +extern const char * +_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended); + +const char * +_mesa_writemask_string(GLuint writeMask); + +extern void +_mesa_print_swizzle(GLuint swizzle); + +extern void +_mesa_print_alu_instruction(const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs); + +extern void +_mesa_print_instruction(const struct prog_instruction *inst); + +extern GLint +_mesa_fprint_instruction_opt(FILE *f, + const struct prog_instruction *inst, + GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog); + +extern GLint +_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent, + gl_prog_print_mode mode, + const struct gl_program *prog); + +extern void +_mesa_print_program(const struct gl_program *prog); + +extern void +_mesa_fprint_program_opt(FILE *f, + const struct gl_program *prog, gl_prog_print_mode mode, + GLboolean lineNumbers); + +#if 0 +extern void +_mesa_print_parameter_list(const struct gl_program_parameter_list *list); + +extern void +_mesa_write_shader_to_file(const struct gl_shader *shader); + +extern void +_mesa_append_uniforms_to_file(const struct gl_shader *shader, + const struct gl_program *prog); +#endif + + +#endif /* PROG_PRINT_H */ -- cgit v1.2.3 From 8197eeee3bbca4ab2deacfbf675285560f49e13c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 16:17:57 -0700 Subject: ir_to_mesa: Fill in more bits of dest resg. --- ir_to_mesa.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index a0d3ae9c8d4..b55e5df9f66 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -544,6 +544,8 @@ do_ir_to_mesa(exec_list *instructions) mesa_inst->Opcode = inst->op; mesa_inst->DstReg.File = inst->dst_reg.file; mesa_inst->DstReg.Index = inst->dst_reg.index; + mesa_inst->DstReg.CondMask = COND_TR; + mesa_inst->DstReg.WriteMask = WRITEMASK_XYZW; mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); -- cgit v1.2.3 From c554d7cedee51bc170916c554c5f3dda51b3ab1e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 16:20:04 -0700 Subject: ir_to_mesa: Remove dead code from when this was an ARB_fp printer. --- ir_to_mesa.cpp | 24 ------------------------ ir_to_mesa.h | 2 -- 2 files changed, 26 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index b55e5df9f66..feb7f454679 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -107,30 +107,6 @@ ir_to_mesa_visitor::create_tree(int op, struct mbtree *left, struct mbtree *righ return tree; } -const char * -produce_swizzle(int8_t *swizzle, const char *reg_name, - const char **swizzle_reg_name) -{ - if (swizzle[0] == 0 && - swizzle[1] == 1 && - swizzle[2] == 2 && - swizzle[3] == 3) - { - *swizzle_reg_name = reg_name; - } else { - char swizzle_letters[4] = { 'x', 'y', 'z', 'w' }; - char *temp; - asprintf(&temp, "%s.%c%c%c%c", - reg_name, - swizzle_letters[swizzle[0]], - swizzle_letters[swizzle[1]], - swizzle_letters[swizzle[2]], - swizzle_letters[swizzle[3]]); - *swizzle_reg_name = temp; - } - return *swizzle_reg_name; -} - /** * In the initial pass of codegen, we assign temporary numbers to * intermediate results. (not SSA -- variable assignments will reuse diff --git a/ir_to_mesa.h b/ir_to_mesa.h index cdf4f2c621a..e4c6940a338 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -61,8 +61,6 @@ struct mbtree { struct mbtree *right; void *state; uint16_t op; - const char *reg_name; - const char *swizzle_reg_name; class ir_to_mesa_visitor *v; /** -- cgit v1.2.3 From 34195832669f0eb7c4a80997cc524f8d10319307 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 16:22:59 -0700 Subject: ir_to_mesa: Fix up src reg swizzling. --- ir_to_mesa.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index feb7f454679..11665a93e78 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -339,10 +339,10 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) { struct mbtree *tree; int size_swizzles[4] = { - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), 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), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), }; ir_variable *var = ir->var->as_variable(); @@ -493,6 +493,7 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) mesa_reg.File = reg.file; assert(reg.index < (1 << INST_INDEX_BITS) - 1); mesa_reg.Index = reg.index; + mesa_reg.Swizzle = reg.swizzle; return mesa_reg; } -- cgit v1.2.3 From b7abce770fe9bb09a6f435d35c1a4afd134fa855 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 May 2010 17:26:14 -0700 Subject: ir_to_mesa: Print out the ir along with the Mesa IR. Ideally this would be hooked up by ir_print_visitor dumping into a string that we could include as prog_instruction->Comment when in debug mode, and not try keeping ir_instruction trees around after conversion to Mesa. The ir_print_visitor isn't set up to do that for us today. --- ir_to_mesa.cpp | 46 +++++++++++++++++++++++++++++++++------------- ir_to_mesa.h | 6 ++++++ mesa/shader/prog_print.c | 2 +- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 11665a93e78..fc0649c60ee 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -68,6 +68,7 @@ ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, inst->src_reg[0] = src0; inst->src_reg[1] = src1; inst->src_reg[2] = src2; + inst->ir = tree->ir; tree->v->instructions.push_tail(inst); @@ -94,15 +95,20 @@ ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, } struct mbtree * -ir_to_mesa_visitor::create_tree(int op, struct mbtree *left, struct mbtree *right) +ir_to_mesa_visitor::create_tree(int op, + ir_instruction *ir, + struct mbtree *left, struct mbtree *right) { struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1); + assert(ir); + tree->op = op; tree->left = left; tree->right = right; tree->v = this; tree->src_reg.swizzle = SWIZZLE_XYZW; + tree->ir = ir; return tree; } @@ -249,31 +255,34 @@ ir_to_mesa_visitor::visit(ir_expression *ir) switch (ir->operation) { case ir_binop_add: - this->result = this->create_tree(MB_TERM_add_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); break; case ir_binop_sub: - this->result = this->create_tree(MB_TERM_sub_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_sub_vec4_vec4, ir, op[0], op[1]); break; case ir_binop_mul: - this->result = this->create_tree(MB_TERM_mul_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]); break; case ir_binop_div: - this->result = this->create_tree(MB_TERM_div_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_div_vec4_vec4, ir, op[0], op[1]); break; case ir_binop_dot: if (ir->operands[0]->type == vec4_type) { assert(ir->operands[1]->type == vec4_type); - this->result = this->create_tree(MB_TERM_dp4_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_dp4_vec4_vec4, + ir, op[0], op[1]); } else if (ir->operands[0]->type == vec3_type) { assert(ir->operands[1]->type == vec3_type); - this->result = this->create_tree(MB_TERM_dp3_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_dp3_vec4_vec4, + ir, op[0], op[1]); } else if (ir->operands[0]->type == vec2_type) { assert(ir->operands[1]->type == vec2_type); - this->result = this->create_tree(MB_TERM_dp2_vec4_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_dp2_vec4_vec4, + ir, op[0], op[1]); } break; case ir_unop_sqrt: - this->result = this->create_tree(MB_TERM_sqrt_vec4, op[0], op[1]); + this->result = this->create_tree(MB_TERM_sqrt_vec4, ir, op[0], op[1]); break; default: break; @@ -299,7 +308,7 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) ir->val->accept(this); assert(this->result); - tree = this->create_tree(MB_TERM_swizzle_vec4, this->result, NULL); + tree = this->create_tree(MB_TERM_swizzle_vec4, ir, this->result, NULL); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { @@ -391,7 +400,9 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) assert(strcmp(var->name, "gl_TexCoord") == 0); asprintf(&name, "fragment.texcoord[%d]", index->value.i[0]); - tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); + tree->src_reg.file = PROGRAM_INPUT; + tree->src_reg.index = FRAG_ATTRIB_TEX0 + index->value.i[0]; tree->reg_name = name; /* If the type is smaller than a vec4, replicate the last channel out. */ @@ -421,7 +432,7 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) assert(!ir->condition); - t = this->create_tree(MB_TERM_assign, l, r); + t = this->create_tree(MB_TERM_assign, ir, l, r); mono_burg_label(t, NULL); reduce(t, MB_NTERM_stmt); } @@ -434,7 +445,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) assert(!ir->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); assert(ir->type->base_type == GLSL_TYPE_FLOAT); @@ -503,6 +514,7 @@ do_ir_to_mesa(exec_list *instructions) { ir_to_mesa_visitor v; struct prog_instruction *mesa_instructions, *mesa_inst; + ir_instruction *last_ir = NULL; visit_exec_list(instructions, &v); @@ -518,6 +530,14 @@ do_ir_to_mesa(exec_list *instructions) mesa_inst = mesa_instructions; foreach_iter(exec_list_iterator, iter, v.instructions) { ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); + + if (last_ir != inst->ir) { + ir_print_visitor print; + inst->ir->accept(&print); + printf("\n"); + last_ir = inst->ir; + } + mesa_inst->Opcode = inst->op; mesa_inst->DstReg.File = inst->dst_reg.file; mesa_inst->DstReg.Index = inst->dst_reg.index; diff --git a/ir_to_mesa.h b/ir_to_mesa.h index e4c6940a338..d9482264d46 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -54,6 +54,8 @@ public: enum prog_opcode op; ir_to_mesa_dst_reg dst_reg; ir_to_mesa_src_reg src_reg[3]; + /** Pointer to the ir source this tree came from for debugging */ + ir_instruction *ir; }; struct mbtree { @@ -63,6 +65,9 @@ struct mbtree { uint16_t op; class ir_to_mesa_visitor *v; + /** Pointer to the ir source this tree came from for debugging */ + ir_instruction *ir; + /** * This is the representation of this tree node's results as a * source register for its consumer. @@ -102,6 +107,7 @@ public: void get_temp_for_var(ir_variable *var, struct mbtree *tree); struct mbtree *create_tree(int op, + ir_instruction *ir, struct mbtree *left, struct mbtree *right); diff --git a/mesa/shader/prog_print.c b/mesa/shader/prog_print.c index 9ac090b2617..3f1cb48e4bf 100644 --- a/mesa/shader/prog_print.c +++ b/mesa/shader/prog_print.c @@ -833,7 +833,7 @@ void _mesa_print_instruction(const struct prog_instruction *inst) { /* note: 4th param should be ignored for PROG_PRINT_DEBUG */ - _mesa_fprint_instruction_opt(stderr, inst, 0, PROG_PRINT_DEBUG, NULL); + _mesa_fprint_instruction_opt(stdout, inst, 0, PROG_PRINT_DEBUG, NULL); } #if 0 -- cgit v1.2.3 From f14913d4b7ede498803615296651cab4bbd341d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 May 2010 11:42:20 -0700 Subject: ir_to_mesa: Do my best to explain how the codegen rules work. --- mesa_codegen.brg | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 1f6ccfaf0c2..6a34b68068e 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -44,6 +44,8 @@ #define MBTREE_TYPE struct mbtree %% +# The list of terminals is the set of things that ir_to_mesa.cpp will +# generate in its trees. %term assign %term reference_vec4 %term add_vec4_vec4 @@ -56,17 +58,65 @@ %term sqrt_vec4 %term swizzle_vec4 +# Each tree will produce stmt. Currently, the only production for +# stmt is from an assign rule -- every statement tree from +# ir_to_mesa.cpp assigns a result to a register. + %start stmt +# Now comes all the rules for code generation. Each rule is of the +# general form +# +# produced: term(term, term) cost +# { +# code_run_when_we_choose_this_rule(); +# } +# +# where choosing this rule means we turn term(term, term) into +# produced at the cost of "cost". We measure "cost" in approximate +# instruction count. The BURG should then more or less minimize the +# number of instructions. +# +# A reference of a variable has an allocated register already, so it +# can be used as an argument for pretty much anything. alloced_vec4: reference_vec4 0 +# If something produces a vec4 with a location already, then we don't need +# to allocate a temp reg for it. vec4: alloced_vec4 0 + +# If something produces a vec4 result that needs a place to live, +# then there's a cost with allocating a temporary for it. We +# approximate that as one instruction's cost, even though sometimes +# that temp might not be a newly-allocated temp due to later +# live-dead analysis. alloced_vec4: vec4 1 { /* FINISHME */ tree->v->get_temp(tree); } +# Here's the rule everyone will hit: Moving the result of an +# expression into a variable-dereference register location. +# +# Note that this is likely a gratuitous move. We could make variants +# of each of the following rules, e.g: +# +# vec4: add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +# { +# emit(ADD, tree, tree->left, tree->right); +# } +# +# becoming +# +# vec4: assign(alloced_vec4_vec4, add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +# { +# emit(ADD, tree->left, tree->right->left, tree->right->right); +# } +# +# But it seems like a lot of extra typing and duped code, when we +# probably want copy propagation and dead code after codegen anyway, +# which would clean these up. stmt: assign(alloced_vec4, alloced_vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_MOV, @@ -74,6 +124,8 @@ stmt: assign(alloced_vec4, alloced_vec4) 1 tree->left->src_reg); } +# Perform a swizzle by composing our swizzle with the swizzle +# required to get at the src reg. vec4: swizzle_vec4(alloced_vec4) 1 { ir_to_mesa_src_reg reg = tree->left->src_reg; -- cgit v1.2.3 From 7aa0b034f70e3140aece94091b2ab200427077e9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 May 2010 11:47:57 -0700 Subject: ir_to_mesa: Fix up the assign rule to use left and right correctly. The destination of assign is in left, not in the node itself. --- mesa_codegen.brg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 6a34b68068e..9f2761b08e2 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -120,8 +120,8 @@ alloced_vec4: vec4 1 stmt: assign(alloced_vec4, alloced_vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_MOV, - ir_to_mesa_dst_reg_from_src(tree->src_reg), - tree->left->src_reg); + ir_to_mesa_dst_reg_from_src(tree->left->src_reg), + tree->right->src_reg); } # Perform a swizzle by composing our swizzle with the swizzle -- cgit v1.2.3 From ae252d3613d10a051657c4ca6db27409f7cf40ae Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 May 2010 11:51:41 -0700 Subject: ir_to_mesa: Make the first temp index we use 1 to show off bugs. Regs aren't allocated at the right times yet, so we see TEMP[0] a lot. --- ir_to_mesa.cpp | 7 +++++++ ir_to_mesa.h | 7 +------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index fc0649c60ee..f36dea5f314 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -496,6 +496,13 @@ ir_to_mesa_visitor::visit(ir_if *ir) exit(1); } +ir_to_mesa_visitor::ir_to_mesa_visitor() +{ + result = NULL; + next_temp = 1; + next_constant = 0; +} + static struct prog_src_register mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) { diff --git a/ir_to_mesa.h b/ir_to_mesa.h index d9482264d46..cef27f8b79c 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -92,12 +92,7 @@ public: class ir_to_mesa_visitor : public ir_visitor { public: - ir_to_mesa_visitor() - { - result = NULL; - next_temp = 0; - next_constant = 0; - } + ir_to_mesa_visitor(); int next_temp; int next_constant; -- cgit v1.2.3 From b2ed4dd7b0270e469302965269007292117d02e2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 May 2010 11:58:03 -0700 Subject: ir_to_mesa: Get temps allocated at the right times. The alloced_vec4/vec4 distinction was an experiment to expose the cost of temps to the codegen. But the problem is that the temporary production rule gets called after the emit rule that was using the temp. We could have the args to emit_op be pointers to where the temp would get allocated later, but that seems overly hard while just trying to bring this thing up. Besides, the temps used in expressions bear only the vaguest relation to how many temps will be used after register allocation. --- ir_to_mesa.cpp | 4 ++++ mesa_codegen.brg | 47 ++++++++++++++++------------------------------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index f36dea5f314..eb55f82e27f 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -293,6 +293,9 @@ ir_to_mesa_visitor::visit(ir_expression *ir) ir->accept(&v); exit(1); } + + /* Allocate a temporary for the result. */ + this->get_temp(this->result); } @@ -309,6 +312,7 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) assert(this->result); tree = this->create_tree(MB_TERM_swizzle_vec4, ir, this->result, NULL); + this->get_temp(tree); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 9f2761b08e2..f1f24dab84f 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -76,25 +76,10 @@ # produced at the cost of "cost". We measure "cost" in approximate # instruction count. The BURG should then more or less minimize the # number of instructions. -# -# A reference of a variable has an allocated register already, so it -# can be used as an argument for pretty much anything. -alloced_vec4: reference_vec4 0 - -# If something produces a vec4 with a location already, then we don't need -# to allocate a temp reg for it. -vec4: alloced_vec4 0 - -# If something produces a vec4 result that needs a place to live, -# then there's a cost with allocating a temporary for it. We -# approximate that as one instruction's cost, even though sometimes -# that temp might not be a newly-allocated temp due to later -# live-dead analysis. -alloced_vec4: vec4 1 -{ - /* FINISHME */ - tree->v->get_temp(tree); -} + +# A reference of a variable is just a vec4 register location, +# so it can be used as an argument for pretty much anything. +vec4: reference_vec4 0 # Here's the rule everyone will hit: Moving the result of an # expression into a variable-dereference register location. @@ -102,14 +87,14 @@ alloced_vec4: vec4 1 # Note that this is likely a gratuitous move. We could make variants # of each of the following rules, e.g: # -# vec4: add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +# vec4: add_vec4_vec4(vec4, vec4) 1 # { # emit(ADD, tree, tree->left, tree->right); # } # # becoming # -# vec4: assign(alloced_vec4_vec4, add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +# vec4: assign(vec4_vec4, add_vec4_vec4(vec4, vec4) 1 # { # emit(ADD, tree->left, tree->right->left, tree->right->right); # } @@ -117,7 +102,7 @@ alloced_vec4: vec4 1 # But it seems like a lot of extra typing and duped code, when we # probably want copy propagation and dead code after codegen anyway, # which would clean these up. -stmt: assign(alloced_vec4, alloced_vec4) 1 +stmt: assign(vec4, vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_MOV, ir_to_mesa_dst_reg_from_src(tree->left->src_reg), @@ -126,7 +111,7 @@ stmt: assign(alloced_vec4, alloced_vec4) 1 # Perform a swizzle by composing our swizzle with the swizzle # required to get at the src reg. -vec4: swizzle_vec4(alloced_vec4) 1 +vec4: swizzle_vec4(vec4) 1 { ir_to_mesa_src_reg reg = tree->left->src_reg; int swiz[4]; @@ -145,7 +130,7 @@ vec4: swizzle_vec4(alloced_vec4) 1 reg); } -vec4: add_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: add_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_ADD, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -153,7 +138,7 @@ vec4: add_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->right->src_reg); } -vec4: sub_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: sub_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SUB, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -161,7 +146,7 @@ vec4: sub_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->right->src_reg); } -vec4: mul_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: mul_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MUL, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -169,7 +154,7 @@ vec4: mul_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->right->src_reg); } -vec4: dp4_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: dp4_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP4, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -178,7 +163,7 @@ vec4: dp4_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->src_reg.swizzle = SWIZZLE_XXXX; } -vec4: dp3_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: dp3_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP3, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -188,7 +173,7 @@ vec4: dp3_vec4_vec4(alloced_vec4, alloced_vec4) 1 } -vec4: dp2_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: dp2_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP2, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -197,7 +182,7 @@ vec4: dp2_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->src_reg.swizzle = SWIZZLE_XXXX; } -vec4: div_vec4_vec4(alloced_vec4, alloced_vec4) 1 +vec4: div_vec4_vec4(vec4, vec4) 1 { /* FINISHME: Mesa RCP only uses the X channel, this node is for vec4. */ ir_to_mesa_emit_op1(tree, OPCODE_RCP, @@ -210,7 +195,7 @@ vec4: div_vec4_vec4(alloced_vec4, alloced_vec4) 1 tree->left->src_reg); } -vec4: sqrt_vec4(alloced_vec4) 1 +vec4: sqrt_vec4(vec4) 1 { /* FINISHME: Mesa RSQ only uses the X channel, this node is for vec4. */ ir_to_mesa_emit_op1(tree, OPCODE_RSQ, -- cgit v1.2.3 From 12f654c63bc42d353e258cde989d9114cdde26c6 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 5 May 2010 17:21:18 -0700 Subject: ir_to_mesa: Produce multiple scalar ops when required to produce vec4s. Fixes the code emitted in a test shader for vec2 texcoord / vec2 tex_size. --- ir_to_mesa.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- ir_to_mesa.h | 7 +++++++ mesa_codegen.brg | 14 ++++++-------- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index eb55f82e27f..77ca6df73c7 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -94,6 +94,51 @@ ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, dst, src0, ir_to_mesa_undef, ir_to_mesa_undef); } +/** + * Emits Mesa scalar opcodes to produce unique answers across channels. + * + * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X + * channel determines the result across all channels. So to do a vec4 + * of this operation, we want to emit a scalar per source channel used + * to produce dest channels. + */ +void +ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) +{ + int i, j; + int done_mask = 0; + + /* Mesa RCP is a scalar operation splatting results to all channels, + * like ARB_fp/vp. So emit as many RCPs as necessary to cover our + * dst channels. + */ + for (i = 0; i < 4; i++) { + int this_mask = (1 << i); + ir_to_mesa_instruction *inst; + ir_to_mesa_src_reg src = src0; + + if (done_mask & this_mask) + continue; + + int src_swiz = GET_SWZ(src.swizzle, i); + for (j = i + 1; j < 4; j++) { + if (GET_SWZ(src.swizzle, j) == src_swiz) { + this_mask |= (1 << j); + } + } + src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz, + src_swiz, src_swiz); + + inst = ir_to_mesa_emit_op1(tree, op, + dst, + src); + inst->dst_reg.writemask = this_mask; + done_mask |= this_mask; + } +} + struct mbtree * ir_to_mesa_visitor::create_tree(int op, ir_instruction *ir, @@ -553,7 +598,7 @@ do_ir_to_mesa(exec_list *instructions) mesa_inst->DstReg.File = inst->dst_reg.file; mesa_inst->DstReg.Index = inst->dst_reg.index; mesa_inst->DstReg.CondMask = COND_TR; - mesa_inst->DstReg.WriteMask = WRITEMASK_XYZW; + mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask; mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); diff --git a/ir_to_mesa.h b/ir_to_mesa.h index cef27f8b79c..c8ceb4c1715 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -45,6 +45,7 @@ typedef struct ir_to_mesa_src_reg { typedef struct ir_to_mesa_dst_reg { int file; /**< PROGRAM_* from Mesa */ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int writemask; /**< Bitfield of WRITEMASK_[XYZW] */ } ir_to_mesa_dst_reg; extern ir_to_mesa_src_reg ir_to_mesa_undef; @@ -159,6 +160,11 @@ ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, ir_to_mesa_src_reg src1, ir_to_mesa_src_reg src2); +void +ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + inline ir_to_mesa_dst_reg ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) { @@ -166,6 +172,7 @@ ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) dst_reg.file = reg.file; dst_reg.index = reg.index; + dst_reg.writemask = WRITEMASK_XYZW; return dst_reg; } diff --git a/mesa_codegen.brg b/mesa_codegen.brg index f1f24dab84f..3191a44c210 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -184,10 +184,9 @@ vec4: dp2_vec4_vec4(vec4, vec4) 1 vec4: div_vec4_vec4(vec4, vec4) 1 { - /* FINISHME: Mesa RCP only uses the X channel, this node is for vec4. */ - ir_to_mesa_emit_op1(tree, OPCODE_RCP, - ir_to_mesa_dst_reg_from_src(tree->src_reg), - tree->right->src_reg); + ir_to_mesa_emit_scalar_op1(tree, OPCODE_RCP, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg); ir_to_mesa_emit_op2(tree, OPCODE_MUL, ir_to_mesa_dst_reg_from_src(tree->src_reg), @@ -197,10 +196,9 @@ vec4: div_vec4_vec4(vec4, vec4) 1 vec4: sqrt_vec4(vec4) 1 { - /* FINISHME: Mesa RSQ only uses the X channel, this node is for vec4. */ - ir_to_mesa_emit_op1(tree, OPCODE_RSQ, - ir_to_mesa_dst_reg_from_src(tree->src_reg), - tree->left->src_reg); + ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, + ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->left->src_reg); ir_to_mesa_emit_op1(tree, OPCODE_RCP, ir_to_mesa_dst_reg_from_src(tree->src_reg), -- cgit v1.2.3 From b07cc372c6360d0e59c84bb7586597f028c74b02 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 09:25:56 -0700 Subject: ir_to_mesa: Handle swizzles on LHS of assignment (writemasks). --- ir_to_mesa.cpp | 73 +++++++++++++++++++++++++++++++++++++++++--------------- ir_to_mesa.h | 2 ++ mesa_codegen.brg | 24 +++++++++---------- 3 files changed, 68 insertions(+), 31 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 77ca6df73c7..3976f437f93 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -139,6 +139,16 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, } } +static void +ir_to_mesa_set_tree_reg(struct mbtree *tree, int file, int index) +{ + tree->dst_reg.file = file; + tree->dst_reg.index = index; + + tree->src_reg.file = file; + tree->src_reg.index = index; +} + struct mbtree * ir_to_mesa_visitor::create_tree(int op, ir_instruction *ir, @@ -153,6 +163,8 @@ ir_to_mesa_visitor::create_tree(int op, tree->right = right; tree->v = this; tree->src_reg.swizzle = SWIZZLE_XYZW; + tree->dst_reg.writemask = WRITEMASK_XYZW; + ir_to_mesa_set_tree_reg(tree, PROGRAM_UNDEFINED, 0); tree->ir = ir; return tree; @@ -167,8 +179,7 @@ ir_to_mesa_visitor::create_tree(int op, void ir_to_mesa_visitor::get_temp(struct mbtree *tree) { - tree->src_reg.file = PROGRAM_TEMPORARY; - tree->src_reg.index = this->next_temp++; + ir_to_mesa_set_tree_reg(tree, PROGRAM_TEMPORARY, this->next_temp++); } void @@ -180,8 +191,7 @@ ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) entry = (temp_entry *)iter.get(); if (entry->var == var) { - tree->src_reg.file = entry->file; - tree->src_reg.index = entry->index; + ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); return; } } @@ -189,8 +199,7 @@ ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp++); this->variable_storage.push_tail(entry); - tree->src_reg.file = entry->file; - tree->src_reg.index = entry->index; + ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); } static void @@ -351,7 +360,10 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) int i; int swizzle[4]; - /* FINISHME: Handle swizzles on the left side of an assignment. */ + /* Note that this is only swizzles in expressions, not those on the left + * hand side of an assignment, which do write masking. See ir_assignment + * for that. + */ ir->val->accept(this); assert(this->result); @@ -410,12 +422,11 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) */ assert(!var->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL); + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); if (strncmp(var->name, "gl_", 3) == 0) { if (strcmp(var->name, "gl_FragColor") == 0) { - tree->src_reg.file = PROGRAM_INPUT; - tree->src_reg.index = FRAG_ATTRIB_COL0; + ir_to_mesa_set_tree_reg(tree, PROGRAM_INPUT, FRAG_ATTRIB_COL0); } else { assert(0); } @@ -442,17 +453,14 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) ir_variable *var = ir->array->as_variable(); ir_constant *index = ir->array_index->constant_expression_value(); - char *name; assert(var); assert(index); assert(strcmp(var->name, "gl_TexCoord") == 0); - asprintf(&name, "fragment.texcoord[%d]", index->value.i[0]); tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - tree->src_reg.file = PROGRAM_INPUT; - tree->src_reg.index = FRAG_ATTRIB_TEX0 + index->value.i[0]; - tree->reg_name = name; + ir_to_mesa_set_tree_reg(tree, PROGRAM_INPUT, + FRAG_ATTRIB_TEX0 + index->value.i[0]); /* If the type is smaller than a vec4, replicate the last channel out. */ tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; @@ -460,6 +468,34 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) this->result = tree; } +static struct mbtree * +get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v) +{ + struct mbtree *tree = NULL; + ir_dereference *deref; + ir_swizzle *swiz; + + if ((deref = ir->as_dereference())) { + ir->accept(v); + tree = v->result; + } else if ((swiz = ir->as_swizzle())) { + tree = get_assignment_lhs(swiz->val, v); + tree->dst_reg.writemask = 0; + if (swiz->mask.num_components >= 1) + tree->dst_reg.writemask |= (1 << swiz->mask.x); + if (swiz->mask.num_components >= 2) + tree->dst_reg.writemask |= (1 << swiz->mask.y); + if (swiz->mask.num_components >= 3) + tree->dst_reg.writemask |= (1 << swiz->mask.z); + if (swiz->mask.num_components >= 4) + tree->dst_reg.writemask |= (1 << swiz->mask.w); + } + + assert(tree); + + return tree; +} + void ir_to_mesa_visitor::visit(ir_dereference_record *ir) { @@ -472,8 +508,8 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) { struct mbtree *l, *r, *t; - ir->lhs->accept(this); - l = this->result; + l = get_assignment_lhs(ir->lhs, this); + ir->rhs->accept(this); r = this->result; assert(l); @@ -504,8 +540,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) */ /* FINISHME: Do something with the constant values for now. */ - tree->src_reg.file = PROGRAM_CONSTANT; - tree->src_reg.index = this->next_constant++; + ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++); tree->src_reg.swizzle = SWIZZLE_NOOP; this->result = tree; diff --git a/ir_to_mesa.h b/ir_to_mesa.h index c8ceb4c1715..00328e5fab2 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -69,6 +69,8 @@ struct mbtree { /** Pointer to the ir source this tree came from for debugging */ ir_instruction *ir; + ir_to_mesa_dst_reg dst_reg; + /** * This is the representation of this tree node's results as a * source register for its consumer. diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 3191a44c210..b117aff0f6b 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -105,7 +105,7 @@ vec4: reference_vec4 0 stmt: assign(vec4, vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_MOV, - ir_to_mesa_dst_reg_from_src(tree->left->src_reg), + tree->left->dst_reg, tree->right->src_reg); } @@ -126,14 +126,14 @@ vec4: swizzle_vec4(vec4) 1 reg.swizzle = MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); ir_to_mesa_emit_op1(tree, OPCODE_MOV, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, reg); } vec4: add_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_ADD, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); } @@ -141,7 +141,7 @@ vec4: add_vec4_vec4(vec4, vec4) 1 vec4: sub_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SUB, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); } @@ -149,7 +149,7 @@ vec4: sub_vec4_vec4(vec4, vec4) 1 vec4: mul_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MUL, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); } @@ -157,7 +157,7 @@ vec4: mul_vec4_vec4(vec4, vec4) 1 vec4: dp4_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP4, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); tree->src_reg.swizzle = SWIZZLE_XXXX; @@ -166,7 +166,7 @@ vec4: dp4_vec4_vec4(vec4, vec4) 1 vec4: dp3_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP3, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); tree->src_reg.swizzle = SWIZZLE_XXXX; @@ -176,7 +176,7 @@ vec4: dp3_vec4_vec4(vec4, vec4) 1 vec4: dp2_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_DP2, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg, tree->right->src_reg); tree->src_reg.swizzle = SWIZZLE_XXXX; @@ -185,11 +185,11 @@ vec4: dp2_vec4_vec4(vec4, vec4) 1 vec4: div_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_RCP, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg); ir_to_mesa_emit_op2(tree, OPCODE_MUL, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->src_reg, tree->left->src_reg); } @@ -197,11 +197,11 @@ vec4: div_vec4_vec4(vec4, vec4) 1 vec4: sqrt_vec4(vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->left->src_reg); ir_to_mesa_emit_op1(tree, OPCODE_RCP, - ir_to_mesa_dst_reg_from_src(tree->src_reg), + tree->dst_reg, tree->src_reg); } -- cgit v1.2.3 From 3d70d1f4d684a943b8b4a65319641415882b72cb Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 09:35:56 -0700 Subject: ir_to_mesa: Emit more reduced writemasks for ops on small types. This should help prevent Mesa from having to be smart to give channel-wise drivers better information. --- ir_to_mesa.cpp | 16 +++++++++++++--- ir_to_mesa.h | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 3976f437f93..a01c50cbc2f 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -177,9 +177,19 @@ ir_to_mesa_visitor::create_tree(int op, * pass over the Mesa IR later. */ void -ir_to_mesa_visitor::get_temp(struct mbtree *tree) +ir_to_mesa_visitor::get_temp(struct mbtree *tree, int size) { + int swizzle = 0; + int i; + ir_to_mesa_set_tree_reg(tree, PROGRAM_TEMPORARY, this->next_temp++); + + for (i = 0; i < size; i++) + swizzle |= 1 << i; + for (; i < 4; i++) + swizzle |= 1 << (size - 1); + tree->src_reg.swizzle = swizzle; + tree->dst_reg.writemask = (1 << size) - 1; } void @@ -349,7 +359,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) } /* Allocate a temporary for the result. */ - this->get_temp(this->result); + this->get_temp(this->result, ir->type->vector_elements); } @@ -369,7 +379,7 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) assert(this->result); tree = this->create_tree(MB_TERM_swizzle_vec4, ir, this->result, NULL); - this->get_temp(tree); + this->get_temp(tree, 4); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 00328e5fab2..fbf10d86bb6 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -100,7 +100,7 @@ public: int next_temp; int next_constant; - void get_temp(struct mbtree *tree); + void get_temp(struct mbtree *tree, int size); void get_temp_for_var(ir_variable *var, struct mbtree *tree); -- cgit v1.2.3 From f30100c19c5f4e95e18c03292947de2dbd9e28cf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 10:31:44 -0700 Subject: ir_to_mesa: Fix copy'n'paste bug where divide multiplied left by 1/left. Multiply left by 1/right, please. --- mesa_codegen.brg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesa_codegen.brg b/mesa_codegen.brg index b117aff0f6b..0bfd8dae903 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -186,7 +186,7 @@ vec4: div_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_RCP, tree->dst_reg, - tree->left->src_reg); + tree->right->src_reg); ir_to_mesa_emit_op2(tree, OPCODE_MUL, tree->dst_reg, -- cgit v1.2.3 From 315c638b8cf0a92f9f0a8ee496e77e90e4b66d09 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 10:38:40 -0700 Subject: ir_to_mesa: Fix bugs in swizzle handling for scalar operations. Looking at a vec2 / float codegen, the writemasks on the RCPs were wrong and the swizzle on the multiply by the RCP results was wrong. --- ir_to_mesa.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index a01c50cbc2f..35c24ca174d 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -108,7 +108,7 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, ir_to_mesa_src_reg src0) { int i, j; - int done_mask = 0; + int done_mask = ~dst.writemask; /* Mesa RCP is a scalar operation splatting results to all channels, * like ARB_fp/vp. So emit as many RCPs as necessary to cover our @@ -124,7 +124,7 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, int src_swiz = GET_SWZ(src.swizzle, i); for (j = i + 1; j < 4; j++) { - if (GET_SWZ(src.swizzle, j) == src_swiz) { + if (!(done_mask & (1 << j)) && GET_SWZ(src.swizzle, j) == src_swiz) { this_mask |= (1 << j); } } @@ -179,16 +179,17 @@ ir_to_mesa_visitor::create_tree(int op, void ir_to_mesa_visitor::get_temp(struct mbtree *tree, int size) { - int swizzle = 0; + int swizzle[4]; int i; ir_to_mesa_set_tree_reg(tree, PROGRAM_TEMPORARY, this->next_temp++); for (i = 0; i < size; i++) - swizzle |= 1 << i; + swizzle[i] = i; for (; i < 4; i++) - swizzle |= 1 << (size - 1); - tree->src_reg.swizzle = swizzle; + swizzle[i] = size - 1; + tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], + swizzle[2], swizzle[3]); tree->dst_reg.writemask = (1 << size) - 1; } -- cgit v1.2.3 From 50ad96ebce6ea19b414a02d2d45f0b0c73586abf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 10:53:51 -0700 Subject: ir_to_mesa: Start doing some int support. --- ir_to_mesa.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 35c24ca174d..e77a6e2ddd3 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -349,6 +349,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_sqrt: this->result = this->create_tree(MB_TERM_sqrt_vec4, ir, op[0], op[1]); break; + case ir_unop_i2f: + /* Mesa IR lacks types, ints are stored as floats. */ + this->result = op[0]; + break; default: break; } @@ -543,7 +547,10 @@ ir_to_mesa_visitor::visit(ir_constant *ir) tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - assert(ir->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->type->base_type == GLSL_TYPE_FLOAT || + ir->type->base_type == GLSL_TYPE_UINT || + ir->type->base_type == GLSL_TYPE_INT || + ir->type->base_type == GLSL_TYPE_BOOL); /* FINISHME: This will end up being _mesa_add_unnamed_constant, * which handles sharing values and sharing channels of vec4 -- cgit v1.2.3 From 48e282d8a2dc7b3ef9f37efdae4618b25ef28628 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 11:17:47 -0700 Subject: ir_to_mesa: Support gl_FragData[] output. --- ir_to_mesa.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index e77a6e2ddd3..40b7f65afbe 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -465,17 +465,23 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), }; - - ir_variable *var = ir->array->as_variable(); - ir_constant *index = ir->array_index->constant_expression_value(); + ir_variable *var = ir->var->as_variable(); + ir_constant *index = ir->selector.array_index->constant_expression_value(); + int file = PROGRAM_UNDEFINED; + int base_index = 0; assert(var); assert(index); - assert(strcmp(var->name, "gl_TexCoord") == 0); + if (strcmp(var->name, "gl_TexCoord") == 0) { + file = PROGRAM_INPUT; + base_index = FRAG_ATTRIB_TEX0; + } else if (strcmp(var->name, "gl_FragData") == 0) { + file = PROGRAM_OUTPUT; + base_index = FRAG_RESULT_DATA0; + } tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - ir_to_mesa_set_tree_reg(tree, PROGRAM_INPUT, - FRAG_ATTRIB_TEX0 + index->value.i[0]); + ir_to_mesa_set_tree_reg(tree, file, base_index + index->value.i[0]); /* If the type is smaller than a vec4, replicate the last channel out. */ tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; -- cgit v1.2.3 From 8041bce333a48033975eb83d47ecc6bd7a91cd1d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 11:17:47 -0700 Subject: ir_to_mesa: Support gl_FragData[] output. --- ir_to_mesa.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 40b7f65afbe..f8b37dd2028 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -465,8 +465,8 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), }; - ir_variable *var = ir->var->as_variable(); - ir_constant *index = ir->selector.array_index->constant_expression_value(); + ir_variable *var = ir->variable_referenced(); + ir_constant *index = ir->array_index->constant_expression_value(); int file = PROGRAM_UNDEFINED; int base_index = 0; -- cgit v1.2.3 From 110d5cc83c18999e578ef7485e3c976446176b81 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 11:24:50 -0700 Subject: ir_to_mesa: Support gl_Position output. --- ir_to_mesa.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index f8b37dd2028..9f9113d2c31 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -442,6 +442,9 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) if (strncmp(var->name, "gl_", 3) == 0) { if (strcmp(var->name, "gl_FragColor") == 0) { ir_to_mesa_set_tree_reg(tree, PROGRAM_INPUT, FRAG_ATTRIB_COL0); + } else if (strcmp(var->name, "gl_Position") == 0) { + ir_to_mesa_set_tree_reg(tree, PROGRAM_OUTPUT, + VERT_RESULT_HPOS); } else { assert(0); } -- cgit v1.2.3 From 829e0a8eff0e657c85fa7fc53a4b456375b434cc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 13:09:54 -0700 Subject: ir_to_mesa: Add (almost) the rest of the builtin varyings. --- ir.h | 4 ++++ ir_to_mesa.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/ir.h b/ir.h index 9277f762042..dbf5df893a9 100644 --- a/ir.h +++ b/ir.h @@ -33,6 +33,10 @@ #include "ir_visitor.h" #include "ir_hierarchical_visitor.h" +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + struct ir_program { void *bong_hits; }; diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 9f9113d2c31..bc9ad252d02 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -418,6 +418,51 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) this->result = tree; } +/* This list should match up with builtin_variables.h */ +static const struct { + const char *name; + int file; + int index; +} builtin_var_to_mesa_reg[] = { + /* core_vs */ + {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS}, + {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ}, + + /* core_fs */ + {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS}, + {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE}, + {"gl_FragColor", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, + {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */ + + /* 110_deprecated_fs */ + {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, + {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1}, + {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC}, + + /* 110_deprecated_vs */ + {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS}, + {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL}, + {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0}, + {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1}, + {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0}, + {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1}, + {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2}, + {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3}, + {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4}, + {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5}, + {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6}, + {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7}, + {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC}, + /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ + {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0}, + {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0}, + {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1}, + {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1}, + {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC}, + + /* 130_vs */ + /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ +}; void ir_to_mesa_visitor::visit(ir_dereference_variable *ir) @@ -432,7 +477,7 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) ir_variable *var = ir->var->as_variable(); - /* By the time we make it to this stage, matric`es should be broken down + /* By the time we make it to this stage, matrices should be broken down * to vectors. */ assert(!var->type->is_matrix()); @@ -440,14 +485,15 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); if (strncmp(var->name, "gl_", 3) == 0) { - if (strcmp(var->name, "gl_FragColor") == 0) { - ir_to_mesa_set_tree_reg(tree, PROGRAM_INPUT, FRAG_ATTRIB_COL0); - } else if (strcmp(var->name, "gl_Position") == 0) { - ir_to_mesa_set_tree_reg(tree, PROGRAM_OUTPUT, - VERT_RESULT_HPOS); - } else { - assert(0); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { + if (strcmp(var->name, builtin_var_to_mesa_reg[i].name) == 0) + break; } + assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg)); + ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, + builtin_var_to_mesa_reg[i].index); } else { this->get_temp_for_var(var, tree); } -- cgit v1.2.3 From 8c29a1d84d738cfddf16d5f013876ee2cca96a81 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 13:20:44 -0700 Subject: ir_to_mesa: Add exp/log expression operations. --- ir_to_mesa.cpp | 12 ++++++++++++ mesa_codegen.brg | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index bc9ad252d02..3fed1577796 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -319,6 +319,18 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = NULL; switch (ir->operation) { + case ir_unop_exp: + this->result = this->create_tree(MB_TERM_exp_vec4, ir, op[0], NULL); + break; + case ir_unop_exp2: + this->result = this->create_tree(MB_TERM_exp2_vec4, ir, op[0], NULL); + break; + case ir_unop_log: + this->result = this->create_tree(MB_TERM_log_vec4, ir, op[0], NULL); + break; + case ir_unop_log2: + this->result = this->create_tree(MB_TERM_log2_vec4, ir, op[0], NULL); + break; case ir_binop_add: this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); break; diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 0bfd8dae903..ed9afdc57cd 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -48,6 +48,10 @@ # generate in its trees. %term assign %term reference_vec4 +%term exp_vec4 +%term exp2_vec4 +%term log_vec4 +%term log2_vec4 %term add_vec4_vec4 %term sub_vec4_vec4 %term mul_vec4_vec4 @@ -205,4 +209,32 @@ vec4: sqrt_vec4(vec4) 1 tree->src_reg); } +vec4: exp_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_EXP, + tree->dst_reg, + tree->left->src_reg); +} + +vec4: exp2_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_EX2, + tree->dst_reg, + tree->left->src_reg); +} + +vec4: log_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_LOG, + tree->dst_reg, + tree->left->src_reg); +} + +vec4: log2_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_LG2, + tree->dst_reg, + tree->left->src_reg); +} + %% -- cgit v1.2.3 From 878740bedf418e5bf42ed6d350c938d29abaaf25 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 14:52:16 -0700 Subject: ir_to_mesa: Add codegen for rsq expression operation. --- ir_to_mesa.cpp | 3 +++ mesa_codegen.brg | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 3fed1577796..b28747e6a26 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -361,6 +361,9 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_sqrt: this->result = this->create_tree(MB_TERM_sqrt_vec4, ir, op[0], op[1]); break; + case ir_unop_rsq: + this->result = this->create_tree(MB_TERM_rsq_vec4, ir, op[0], op[1]); + break; case ir_unop_i2f: /* Mesa IR lacks types, ints are stored as floats. */ this->result = op[0]; diff --git a/mesa_codegen.brg b/mesa_codegen.brg index ed9afdc57cd..e8d499fd74e 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -60,6 +60,7 @@ %term dp3_vec4_vec4 %term dp2_vec4_vec4 %term sqrt_vec4 +%term rsq_vec4 %term swizzle_vec4 # Each tree will produce stmt. Currently, the only production for @@ -209,6 +210,13 @@ vec4: sqrt_vec4(vec4) 1 tree->src_reg); } +vec4: rsq_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, + tree->dst_reg, + tree->left->src_reg); +} + vec4: exp_vec4(vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_EXP, -- cgit v1.2.3 From 423a75c5d607a33cb5fe76a0a9c903cccc645fa7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 15:52:05 -0700 Subject: ir_to_mesa: Add ir_unop_f2i -> OPCODE_TRUNC. --- ir_to_mesa.cpp | 5 ++++- mesa_codegen.brg | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index b28747e6a26..77a8822934e 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -365,9 +365,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = this->create_tree(MB_TERM_rsq_vec4, ir, op[0], op[1]); break; case ir_unop_i2f: - /* Mesa IR lacks types, ints are stored as floats. */ + /* Mesa IR lacks types, ints are stored as truncated floats. */ this->result = op[0]; break; + case ir_unop_f2i: + this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL); + break; default: break; } diff --git a/mesa_codegen.brg b/mesa_codegen.brg index e8d499fd74e..5e7953b75c7 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -62,6 +62,7 @@ %term sqrt_vec4 %term rsq_vec4 %term swizzle_vec4 +%term trunc_vec4 # Each tree will produce stmt. Currently, the only production for # stmt is from an assign rule -- every statement tree from @@ -245,4 +246,11 @@ vec4: log2_vec4(vec4) 1 tree->left->src_reg); } +vec4: trunc_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_TRUNC, + tree->dst_reg, + tree->left->src_reg); +} + %% -- cgit v1.2.3 From bf9953335031b3de721245ec7a2986d0b4f70027 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 17:38:27 -0700 Subject: ir_to_mesa: Introduce shorthand for common Mesa IR emit patterns. --- ir_to_mesa.cpp | 37 ++++++++++++++++++++++--------- ir_to_mesa.h | 20 +++++++++++------ mesa_codegen.brg | 67 ++++++++++++++++---------------------------------------- 3 files changed, 59 insertions(+), 65 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 77a8822934e..1bdb61801c0 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -77,23 +77,40 @@ ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, ir_to_mesa_instruction * -ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1) +ir_to_mesa_emit_op2_full(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1) { return ir_to_mesa_emit_op3(tree, op, dst, src0, src1, ir_to_mesa_undef); } ir_to_mesa_instruction * -ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0) +ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op) +{ + return ir_to_mesa_emit_op2_full(tree, op, + tree->dst_reg, + tree->left->src_reg, + tree->right->src_reg); +} + +ir_to_mesa_instruction * +ir_to_mesa_emit_op1_full(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) { return ir_to_mesa_emit_op3(tree, op, dst, src0, ir_to_mesa_undef, ir_to_mesa_undef); } +ir_to_mesa_instruction * +ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op) +{ + return ir_to_mesa_emit_op1_full(tree, op, + tree->dst_reg, + tree->left->src_reg); +} + /** * Emits Mesa scalar opcodes to produce unique answers across channels. * @@ -131,9 +148,9 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz, src_swiz, src_swiz); - inst = ir_to_mesa_emit_op1(tree, op, - dst, - src); + inst = ir_to_mesa_emit_op1_full(tree, op, + dst, + src); inst->dst_reg.writemask = this_mask; done_mask |= this_mask; } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index fbf10d86bb6..ee776bd55fe 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -145,15 +145,21 @@ public: }; ir_to_mesa_instruction * -ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0); +ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op); ir_to_mesa_instruction * -ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1); +ir_to_mesa_emit_op1_full(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + +ir_to_mesa_instruction * +ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op); + +ir_to_mesa_instruction * +ir_to_mesa_emit_op2_full(struct mbtree *tree, enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); ir_to_mesa_instruction * ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 5e7953b75c7..e52798bcf51 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -110,9 +110,9 @@ vec4: reference_vec4 0 # which would clean these up. stmt: assign(vec4, vec4) 1 { - ir_to_mesa_emit_op1(tree, OPCODE_MOV, - tree->left->dst_reg, - tree->right->src_reg); + ir_to_mesa_emit_op1_full(tree, OPCODE_MOV, + tree->left->dst_reg, + tree->right->src_reg); } # Perform a swizzle by composing our swizzle with the swizzle @@ -131,60 +131,31 @@ vec4: swizzle_vec4(vec4) 1 } reg.swizzle = MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); - ir_to_mesa_emit_op1(tree, OPCODE_MOV, - tree->dst_reg, - reg); + ir_to_mesa_emit_op1_full(tree, OPCODE_MOV, + tree->dst_reg, + reg); } -vec4: add_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_ADD, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); -} - -vec4: sub_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_SUB, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); -} - -vec4: mul_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_MUL, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); -} +vec4: add_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_ADD); } +vec4: sub_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SUB); } +vec4: mul_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MUL); } vec4: dp4_vec4_vec4(vec4, vec4) 1 { - ir_to_mesa_emit_op2(tree, OPCODE_DP4, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); + ir_to_mesa_emit_op2(tree, OPCODE_DP4); tree->src_reg.swizzle = SWIZZLE_XXXX; } vec4: dp3_vec4_vec4(vec4, vec4) 1 { - ir_to_mesa_emit_op2(tree, OPCODE_DP3, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); + ir_to_mesa_emit_op2(tree, OPCODE_DP3); tree->src_reg.swizzle = SWIZZLE_XXXX; } vec4: dp2_vec4_vec4(vec4, vec4) 1 { - ir_to_mesa_emit_op2(tree, OPCODE_DP2, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); + ir_to_mesa_emit_op2(tree, OPCODE_DP2); tree->src_reg.swizzle = SWIZZLE_XXXX; } @@ -194,10 +165,10 @@ vec4: div_vec4_vec4(vec4, vec4) 1 tree->dst_reg, tree->right->src_reg); - ir_to_mesa_emit_op2(tree, OPCODE_MUL, - tree->dst_reg, - tree->src_reg, - tree->left->src_reg); + ir_to_mesa_emit_op2_full(tree, OPCODE_MUL, + tree->dst_reg, + tree->src_reg, + tree->left->src_reg); } vec4: sqrt_vec4(vec4) 1 @@ -206,9 +177,9 @@ vec4: sqrt_vec4(vec4) 1 tree->dst_reg, tree->left->src_reg); - ir_to_mesa_emit_op1(tree, OPCODE_RCP, - tree->dst_reg, - tree->src_reg); + ir_to_mesa_emit_op1_full(tree, OPCODE_RCP, + tree->dst_reg, + tree->src_reg); } vec4: rsq_vec4(vec4) 1 -- cgit v1.2.3 From 38315079571512dc5b502d9522d7a8c3eaf2cc8f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 May 2010 17:41:22 -0700 Subject: ir_to_mesa: Add support for comparison operations. --- ir_to_mesa.cpp | 20 ++++++++++++++++++++ ir_to_mesa.h | 3 +++ mesa_codegen.brg | 13 +++++++++++++ 3 files changed, 36 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 1bdb61801c0..465a8e19164 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -360,6 +360,26 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_binop_div: this->result = this->create_tree(MB_TERM_div_vec4_vec4, ir, op[0], op[1]); break; + + case ir_binop_less: + this->result = this->create_tree(MB_TERM_slt_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_greater: + this->result = this->create_tree(MB_TERM_sgt_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_lequal: + this->result = this->create_tree(MB_TERM_sle_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_gequal: + this->result = this->create_tree(MB_TERM_sge_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_equal: + this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_nequal: + this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_dot: if (ir->operands[0]->type == vec4_type) { assert(ir->operands[1]->type == vec4_type); diff --git a/ir_to_mesa.h b/ir_to_mesa.h index ee776bd55fe..ffa27dbd00f 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -161,6 +161,9 @@ ir_to_mesa_emit_op2_full(struct mbtree *tree, enum prog_opcode op, ir_to_mesa_src_reg src0, ir_to_mesa_src_reg src1); +ir_to_mesa_instruction * +ir_to_mesa_emit_simple_op2(struct mbtree *tree, enum prog_opcode op); + ir_to_mesa_instruction * ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, ir_to_mesa_dst_reg dst, diff --git a/mesa_codegen.brg b/mesa_codegen.brg index e52798bcf51..4e761343ae3 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -56,6 +56,12 @@ %term sub_vec4_vec4 %term mul_vec4_vec4 %term div_vec4_vec4 +%term slt_vec4_vec4 +%term sgt_vec4_vec4 +%term sle_vec4_vec4 +%term sge_vec4_vec4 +%term seq_vec4_vec4 +%term sne_vec4_vec4 %term dp4_vec4_vec4 %term dp3_vec4_vec4 %term dp2_vec4_vec4 @@ -171,6 +177,13 @@ vec4: div_vec4_vec4(vec4, vec4) 1 tree->left->src_reg); } +vec4: slt_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SLT); } +vec4: sgt_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SGT); } +vec4: sle_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SLE); } +vec4: sge_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SGE); } +vec4: sne_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SNE); } +vec4: seq_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SEQ); } + vec4: sqrt_vec4(vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, -- cgit v1.2.3 From c5ca73e72c27b2e5d7fcf4662b9921ddb3a9627b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 11:31:47 -0700 Subject: ir_to_mesa: Add support for ir_if. --- ir_to_mesa.cpp | 138 +++++++++++++++++++++++++++++++++++++++++++++---------- ir_to_mesa.h | 9 ++-- mesa_codegen.brg | 8 ++-- 3 files changed, 125 insertions(+), 30 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 465a8e19164..487e24986f9 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -54,8 +54,13 @@ ir_to_mesa_src_reg ir_to_mesa_undef = { PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP }; +ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { + PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP +}; + ir_to_mesa_instruction * -ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0, ir_to_mesa_src_reg src1, @@ -68,45 +73,48 @@ ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, inst->src_reg[0] = src0; inst->src_reg[1] = src1; inst->src_reg[2] = src2; - inst->ir = tree->ir; + inst->ir = ir; - tree->v->instructions.push_tail(inst); + v->instructions.push_tail(inst); return inst; } ir_to_mesa_instruction * -ir_to_mesa_emit_op2_full(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op2_full(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0, ir_to_mesa_src_reg src1) { - return ir_to_mesa_emit_op3(tree, op, dst, src0, src1, ir_to_mesa_undef); + return ir_to_mesa_emit_op3(v, ir, + op, dst, src0, src1, ir_to_mesa_undef); } ir_to_mesa_instruction * ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op) { - return ir_to_mesa_emit_op2_full(tree, op, + return ir_to_mesa_emit_op2_full(tree->v, tree->ir, op, tree->dst_reg, tree->left->src_reg, tree->right->src_reg); } ir_to_mesa_instruction * -ir_to_mesa_emit_op1_full(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op1_full(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0) { - return ir_to_mesa_emit_op3(tree, op, + return ir_to_mesa_emit_op3(v, ir, op, dst, src0, ir_to_mesa_undef, ir_to_mesa_undef); } ir_to_mesa_instruction * ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op) { - return ir_to_mesa_emit_op1_full(tree, op, + return ir_to_mesa_emit_op1_full(tree->v, tree->ir, op, tree->dst_reg, tree->left->src_reg); } @@ -148,7 +156,7 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz, src_swiz, src_swiz); - inst = ir_to_mesa_emit_op1_full(tree, op, + inst = ir_to_mesa_emit_op1_full(tree->v, tree->ir, op, dst, src); inst->dst_reg.writemask = this_mask; @@ -703,9 +711,29 @@ ir_to_mesa_visitor::visit(ir_return *ir) void ir_to_mesa_visitor::visit(ir_if *ir) { - (void)ir; - printf("Can't support conditionals, should be flattened before here.\n"); - exit(1); + ir_to_mesa_instruction *if_inst, *else_inst = NULL; + + ir->condition->accept(this); + assert(this->result); + + if_inst = ir_to_mesa_emit_op1_full(this, ir->condition, + OPCODE_IF, ir_to_mesa_undef_dst, + this->result->src_reg); + + this->instructions.push_tail(if_inst); + + visit_exec_list(&ir->then_instructions, this); + + if (!ir->else_instructions.is_empty()) { + else_inst = ir_to_mesa_emit_op1_full(this, ir->condition, + OPCODE_ELSE, ir_to_mesa_undef_dst, + ir_to_mesa_undef); + visit_exec_list(&ir->then_instructions, this); + } + + if_inst = ir_to_mesa_emit_op1_full(this, ir->condition, + OPCODE_ENDIF, ir_to_mesa_undef_dst, + ir_to_mesa_undef); } ir_to_mesa_visitor::ir_to_mesa_visitor() @@ -728,12 +756,74 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) return mesa_reg; } +static void +set_branchtargets(struct prog_instruction *mesa_instructions, + int num_instructions) +{ + int if_count = 0; + struct prog_instruction **if_stack; + int if_stack_pos = 0; + int i; + + for (i = 0; i < num_instructions; i++) { + if (mesa_instructions[i].Opcode == OPCODE_IF) + if_count++; + } + + if_stack = (struct prog_instruction **)calloc(if_count, sizeof(*if_stack)); + + for (i = 0; i < num_instructions; i++) { + switch (mesa_instructions[i].Opcode) { + case OPCODE_IF: + if_stack[if_stack_pos] = mesa_instructions + i; + if_stack_pos++; + break; + case OPCODE_ELSE: + if_stack[if_stack_pos - 1]->BranchTarget = i; + if_stack[if_stack_pos - 1] = mesa_instructions + i; + break; + case OPCODE_ENDIF: + if_stack[if_stack_pos - 1]->BranchTarget = i; + if_stack_pos--; + break; + default: + break; + } + } + + free(if_stack); +} + +static void +print_program(struct prog_instruction *mesa_instructions, + ir_instruction **mesa_instruction_annotation, + int num_instructions) +{ + ir_instruction *last_ir = NULL; + int i; + + for (i = 0; i < num_instructions; i++) { + struct prog_instruction *mesa_inst = mesa_instructions + i; + ir_instruction *ir = mesa_instruction_annotation[i]; + + if (last_ir != ir) { + ir_print_visitor print; + ir->accept(&print); + printf("\n"); + last_ir = ir; + } + + _mesa_print_instruction(mesa_inst); + } +} + void do_ir_to_mesa(exec_list *instructions) { ir_to_mesa_visitor v; struct prog_instruction *mesa_instructions, *mesa_inst; - ir_instruction *last_ir = NULL; + ir_instruction **mesa_instruction_annotation; + int i; visit_exec_list(instructions, &v); @@ -745,18 +835,15 @@ do_ir_to_mesa(exec_list *instructions) mesa_instructions = (struct prog_instruction *)calloc(num_instructions, sizeof(*mesa_instructions)); + mesa_instruction_annotation = + (ir_instruction **)calloc(num_instructions, + sizeof(*mesa_instruction_annotation)); mesa_inst = mesa_instructions; + i = 0; foreach_iter(exec_list_iterator, iter, v.instructions) { ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); - if (last_ir != inst->ir) { - ir_print_visitor print; - inst->ir->accept(&print); - printf("\n"); - last_ir = inst->ir; - } - mesa_inst->Opcode = inst->op; mesa_inst->DstReg.File = inst->dst_reg.file; mesa_inst->DstReg.Index = inst->dst_reg.index; @@ -765,9 +852,14 @@ do_ir_to_mesa(exec_list *instructions) mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); - - _mesa_print_instruction(mesa_inst); + mesa_instruction_annotation[i] = inst->ir; mesa_inst++; + i++; } + + set_branchtargets(mesa_instructions, num_instructions); + print_program(mesa_instructions, mesa_instruction_annotation, num_instructions); + + free(mesa_instruction_annotation); } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index ffa27dbd00f..3aa88bcdc40 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -148,7 +148,8 @@ ir_to_mesa_instruction * ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op); ir_to_mesa_instruction * -ir_to_mesa_emit_op1_full(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op1_full(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0); @@ -156,7 +157,8 @@ ir_to_mesa_instruction * ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op); ir_to_mesa_instruction * -ir_to_mesa_emit_op2_full(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op2_full(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0, ir_to_mesa_src_reg src1); @@ -165,7 +167,8 @@ ir_to_mesa_instruction * ir_to_mesa_emit_simple_op2(struct mbtree *tree, enum prog_opcode op); ir_to_mesa_instruction * -ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op, +ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir, + enum prog_opcode op, ir_to_mesa_dst_reg dst, ir_to_mesa_src_reg src0, ir_to_mesa_src_reg src1, diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 4e761343ae3..a906542dd53 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -116,7 +116,7 @@ vec4: reference_vec4 0 # which would clean these up. stmt: assign(vec4, vec4) 1 { - ir_to_mesa_emit_op1_full(tree, OPCODE_MOV, + ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, tree->left->dst_reg, tree->right->src_reg); } @@ -137,7 +137,7 @@ vec4: swizzle_vec4(vec4) 1 } reg.swizzle = MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); - ir_to_mesa_emit_op1_full(tree, OPCODE_MOV, + ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, tree->dst_reg, reg); } @@ -171,7 +171,7 @@ vec4: div_vec4_vec4(vec4, vec4) 1 tree->dst_reg, tree->right->src_reg); - ir_to_mesa_emit_op2_full(tree, OPCODE_MUL, + ir_to_mesa_emit_op2_full(tree->v, tree->ir, OPCODE_MUL, tree->dst_reg, tree->src_reg, tree->left->src_reg); @@ -190,7 +190,7 @@ vec4: sqrt_vec4(vec4) 1 tree->dst_reg, tree->left->src_reg); - ir_to_mesa_emit_op1_full(tree, OPCODE_RCP, + ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_RCP, tree->dst_reg, tree->src_reg); } -- cgit v1.2.3 From 1d20862c8a0e100e43458f01217c047c76da05f3 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 12:12:49 -0700 Subject: ir_to_mesa: add logic_not and f2b to get CorrectParse2.frag working. --- ir_to_mesa.cpp | 31 +++++++++++++++++++++++++++++++ ir_to_mesa.h | 1 + 2 files changed, 32 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 487e24986f9..8858d4be68e 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -195,6 +195,27 @@ ir_to_mesa_visitor::create_tree(int op, return tree; } +struct mbtree * +ir_to_mesa_visitor::create_tree_for_float(ir_instruction *ir, float val) +{ + struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1); + + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); + + /* FINISHME: This will end up being _mesa_add_unnamed_constant, + * which handles sharing values and sharing channels of vec4 + * constants for small values. + */ + /* FINISHME: Do something with the constant values for now. + */ + (void)val; + ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++); + tree->src_reg.swizzle = SWIZZLE_NOOP; + + this->result = tree; + return tree; +} + /** * In the initial pass of codegen, we assign temporary numbers to * intermediate results. (not SSA -- variable assignments will reuse @@ -344,6 +365,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = NULL; switch (ir->operation) { + case ir_unop_logic_not: + this->result = this->create_tree_for_float(ir, 0.0); + this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, + op[0], this->result); + break; case ir_unop_exp: this->result = this->create_tree(MB_TERM_exp_vec4, ir, op[0], NULL); break; @@ -416,6 +442,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_f2i: this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL); break; + case ir_unop_f2b: + this->result = this->create_tree_for_float(ir, 0.0); + this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, + op[0], this->result); + break; default: break; } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 3aa88bcdc40..43ddd5fe517 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -108,6 +108,7 @@ public: ir_instruction *ir, struct mbtree *left, struct mbtree *right); + struct mbtree *create_tree_for_float(ir_instruction *ir, float val); /** * \name Visit methods -- cgit v1.2.3 From 763cd75863ed9a16912e585887580c44d1e8109f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 12:14:41 -0700 Subject: ir_to_mesa: add logic_xor to get CorrectParse2.vert working. --- ir_to_mesa.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 8858d4be68e..3ae848a21bc 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -410,6 +410,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_binop_equal: this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, op[0], op[1]); break; + case ir_binop_logic_xor: case ir_binop_nequal: this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], op[1]); break; -- cgit v1.2.3 From 4380099c98119611ceee684669d00be26195c7d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 12:20:58 -0700 Subject: ir_to_mesa: Add logic_or and logic_and to get CorrectFunction1.vert working. --- ir_to_mesa.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 3ae848a21bc..f45421057b2 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -415,6 +415,19 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], op[1]); break; + case ir_binop_logic_or: + /* This could be a saturated add. */ + this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); + this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, + this->create_tree_for_float(ir, 0.0), + this->result); + break; + + case ir_binop_logic_and: + /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */ + this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_dot: if (ir->operands[0]->type == vec4_type) { assert(ir->operands[1]->type == vec4_type); -- cgit v1.2.3 From 0c005bd773784ee5feb2ee3d7d00c2c4335eafb4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 12:35:47 -0700 Subject: Make loop jump mode public so I can switch on it. --- ir.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ir.h b/ir.h index dbf5df893a9..ab041aa848a 100644 --- a/ir.h +++ b/ir.h @@ -756,9 +756,9 @@ public: }; ir_loop_jump(jump_mode mode) - : mode(mode) { - /* empty */ + this->mode = mode; + this->loop = loop; } virtual ir_instruction *clone(struct hash_table *) const; @@ -780,9 +780,11 @@ public: return mode == jump_continue; } -private: /** Mode selector for the jump instruction. */ enum jump_mode mode; +private: + /** Loop containing this break instruction. */ + ir_loop *loop; }; /*@}*/ -- cgit v1.2.3 From 64fcbbca9ca8191b5131304af2026d0ed914b765 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 7 May 2010 12:59:08 -0700 Subject: ir_to_mesa: Add support for loops. Fixes CorrectParse1 and the glsl2 loop tests that don't use arrays. --- ir_to_mesa.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index f45421057b2..2be5bf1ef05 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -297,18 +297,37 @@ ir_to_mesa_visitor::visit(ir_variable *ir) void ir_to_mesa_visitor::visit(ir_loop *ir) { - (void)ir; + assert(!ir->from); + assert(!ir->to); + assert(!ir->increment); + assert(!ir->counter); - printf("Can't support loops, should be flattened before here\n"); - exit(1); + ir_to_mesa_emit_op1_full(this, NULL, + OPCODE_BGNLOOP, ir_to_mesa_undef_dst, + ir_to_mesa_undef); + + visit_exec_list(&ir->body_instructions, this); + + ir_to_mesa_emit_op1_full(this, NULL, + OPCODE_ENDLOOP, ir_to_mesa_undef_dst, + ir_to_mesa_undef); } void ir_to_mesa_visitor::visit(ir_loop_jump *ir) { - (void) ir; - printf("Can't support loops, should be flattened before here\n"); - exit(1); + switch (ir->mode) { + case ir_loop_jump::jump_break: + ir_to_mesa_emit_op1_full(this, NULL, + OPCODE_BRK, ir_to_mesa_undef_dst, + ir_to_mesa_undef); + break; + case ir_loop_jump::jump_continue: + ir_to_mesa_emit_op1_full(this, NULL, + OPCODE_CONT, ir_to_mesa_undef_dst, + ir_to_mesa_undef); + break; + } } @@ -805,32 +824,66 @@ static void set_branchtargets(struct prog_instruction *mesa_instructions, int num_instructions) { - int if_count = 0; - struct prog_instruction **if_stack; - int if_stack_pos = 0; - int i; + int if_count = 0, loop_count; + int *if_stack, *loop_stack; + int if_stack_pos = 0, loop_stack_pos = 0; + int i, j; for (i = 0; i < num_instructions; i++) { - if (mesa_instructions[i].Opcode == OPCODE_IF) + switch (mesa_instructions[i].Opcode) { + case OPCODE_IF: if_count++; + break; + case OPCODE_BGNLOOP: + loop_count++; + break; + case OPCODE_BRK: + case OPCODE_CONT: + mesa_instructions[i].BranchTarget = -1; + break; + default: + break; + } } - if_stack = (struct prog_instruction **)calloc(if_count, sizeof(*if_stack)); + if_stack = (int *)calloc(if_count, sizeof(*if_stack)); + loop_stack = (int *)calloc(loop_count, sizeof(*loop_stack)); for (i = 0; i < num_instructions; i++) { switch (mesa_instructions[i].Opcode) { case OPCODE_IF: - if_stack[if_stack_pos] = mesa_instructions + i; + if_stack[if_stack_pos] = i; if_stack_pos++; break; case OPCODE_ELSE: - if_stack[if_stack_pos - 1]->BranchTarget = i; - if_stack[if_stack_pos - 1] = mesa_instructions + i; + mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i; + if_stack[if_stack_pos - 1] = i; break; case OPCODE_ENDIF: - if_stack[if_stack_pos - 1]->BranchTarget = i; + mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i; if_stack_pos--; break; + case OPCODE_BGNLOOP: + loop_stack[loop_stack_pos] = i; + loop_stack_pos++; + break; + case OPCODE_ENDLOOP: + loop_stack_pos--; + /* Rewrite any breaks/conts at this nesting level (haven't + * already had a BranchTarget assigned) to point to the end + * of the loop. + */ + for (j = loop_stack[loop_stack_pos]; j < i; j++) { + if (mesa_instructions[j].Opcode == OPCODE_BRK || + mesa_instructions[j].Opcode == OPCODE_CONT) { + if (mesa_instructions[j].BranchTarget == -1) { + mesa_instructions[j].BranchTarget = i; + } + } + } + /* The loop ends point at each other. */ + mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos]; + mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i; default: break; } @@ -851,7 +904,7 @@ print_program(struct prog_instruction *mesa_instructions, struct prog_instruction *mesa_inst = mesa_instructions + i; ir_instruction *ir = mesa_instruction_annotation[i]; - if (last_ir != ir) { + if (last_ir != ir && ir) { ir_print_visitor print; ir->accept(&print); printf("\n"); -- cgit v1.2.3 From 4e5e0f018baedb2d0aa0e1f43efe339da16a09c6 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 10 May 2010 18:15:33 -0700 Subject: ir_to_mesa: Clean up some handling of builtins and arrays. Constant-index dereferences of arrays should work now. One test is regressed, but it should have been failing before this commit, too. --- ir_to_mesa.cpp | 57 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 2be5bf1ef05..3451fc887db 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -253,9 +253,17 @@ ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) } } - entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp++); + entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); this->variable_storage.push_tail(entry); + /* Store each array element in a temp. This is poor packing for + * things like floats, but we can't do better in the Mesa IR. + */ + if (var->type->length > 1) + next_temp += var->type->length; + else + next_temp++; + ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); } @@ -579,6 +587,7 @@ static const struct { {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5}, {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6}, {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7}, + {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */ {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC}, /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0}, @@ -589,6 +598,8 @@ static const struct { /* 130_vs */ /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ + + {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */ }; void @@ -601,8 +612,7 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), }; - - ir_variable *var = ir->var->as_variable(); + ir_variable *var = ir->var; /* By the time we make it to this stage, matrices should be broken down * to vectors. @@ -643,21 +653,36 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) }; ir_variable *var = ir->variable_referenced(); ir_constant *index = ir->array_index->constant_expression_value(); - int file = PROGRAM_UNDEFINED; - int base_index = 0; - - assert(var); - assert(index); - if (strcmp(var->name, "gl_TexCoord") == 0) { - file = PROGRAM_INPUT; - base_index = FRAG_ATTRIB_TEX0; - } else if (strcmp(var->name, "gl_FragData") == 0) { - file = PROGRAM_OUTPUT; - base_index = FRAG_RESULT_DATA0; - } + + /* By the time we make it to this stage, matrices should be broken down + * to vectors. + */ + assert(!var->type->is_matrix()); tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - ir_to_mesa_set_tree_reg(tree, file, base_index + index->value.i[0]); + + if (strncmp(var->name, "gl_", 3) == 0) { + unsigned int i; + unsigned int offset = 0; + + assert(index); /* FINISHME: Handle variable indexing of builtins. */ + + offset = index->value.i[0]; + + for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { + if (strcmp(var->name, builtin_var_to_mesa_reg[i].name) == 0) + break; + } + assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg)); + ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, + builtin_var_to_mesa_reg[i].index + offset); + } else { + this->get_temp_for_var(var, tree); + assert(index); /* FINISHME: Handle variable indexing. */ + + tree->src_reg.index += index->value.i[0]; + tree->dst_reg.index += index->value.i[0]; + } /* If the type is smaller than a vec4, replicate the last channel out. */ tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; -- cgit v1.2.3 From bdbd9f112e2832eeddce8fc4f70f11005bbe4027 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 10 May 2010 10:06:36 -0700 Subject: ir_to_mesa: Add support for variable indexing of temporary arrays. Fixes loop-01.vert, loop-02.vert. --- ir_to_mesa.cpp | 26 +++++++++++++++++++------- ir_to_mesa.h | 4 ++++ mesa_codegen.brg | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 3451fc887db..44786258db1 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -51,7 +51,7 @@ extern "C" { } ir_to_mesa_src_reg ir_to_mesa_undef = { - PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP + PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, false, }; ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { @@ -659,13 +659,11 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) */ assert(!var->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - if (strncmp(var->name, "gl_", 3) == 0) { unsigned int i; unsigned int offset = 0; - assert(index); /* FINISHME: Handle variable indexing of builtins. */ + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); offset = index->value.i[0]; @@ -677,11 +675,24 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, builtin_var_to_mesa_reg[i].index + offset); } else { + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); this->get_temp_for_var(var, tree); - assert(index); /* FINISHME: Handle variable indexing. */ - tree->src_reg.index += index->value.i[0]; - tree->dst_reg.index += index->value.i[0]; + if (index) { + tree->src_reg.index += index->value.i[0]; + tree->dst_reg.index += index->value.i[0]; + } else { + /* Variable index array dereference. It eats the "vec4" of the + * base of the array and an index that offsets the Mesa register + * index. + */ + ir->array_index->accept(this); + + tree->src_reg.reladdr = true; + tree = this->create_tree(MB_TERM_array_reference_vec4_vec4, + ir, tree, this->result); + this->get_temp(tree, ir->type->vector_elements); + } } /* If the type is smaller than a vec4, replicate the last channel out. */ @@ -841,6 +852,7 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) assert(reg.index < (1 << INST_INDEX_BITS) - 1); mesa_reg.Index = reg.index; mesa_reg.Swizzle = reg.swizzle; + mesa_reg.RelAddr = reg.reladdr; return mesa_reg; } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 43ddd5fe517..515feb19a38 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -40,6 +40,7 @@ typedef struct ir_to_mesa_src_reg { int file; /**< PROGRAM_* from Mesa */ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ + bool reladdr; /**< Register index should be offset by address reg. */ } ir_to_mesa_src_reg; typedef struct ir_to_mesa_dst_reg { @@ -145,6 +146,9 @@ public: exec_list instructions; }; +extern ir_to_mesa_src_reg ir_to_mesa_undef; +extern ir_to_mesa_dst_reg ir_to_mesa_undef_dst; + ir_to_mesa_instruction * ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op); diff --git a/mesa_codegen.brg b/mesa_codegen.brg index a906542dd53..109e8b2d513 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -48,6 +48,7 @@ # generate in its trees. %term assign %term reference_vec4 +%term array_reference_vec4_vec4 %term exp_vec4 %term exp2_vec4 %term log_vec4 @@ -93,6 +94,20 @@ # so it can be used as an argument for pretty much anything. vec4: reference_vec4 0 +# A reference of a variable is just a vec4 register location, +# so it can be used as an argument for pretty much anything. +vec4: array_reference_vec4_vec4 1 +{ + ir_to_mesa_dst_reg address_reg = {PROGRAM_ADDRESS, 0, WRITEMASK_X}; + + ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_ARL, + address_reg, + tree->right->src_reg); + ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, + tree->dst_reg, + tree->left->src_reg); +} + # Here's the rule everyone will hit: Moving the result of an # expression into a variable-dereference register location. # -- cgit v1.2.3 From 2ee85e20c888d45d3a05ed020dbaf616337f8955 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 11 May 2010 00:00:35 -0700 Subject: ir_to_mesa: Remove stale comment about monoburg. --- ir_to_mesa.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 44786258db1..1485b6a2c0f 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -26,10 +26,6 @@ * * Translates the IR to ARB_fragment_program text if possible, * printing the result - * - * The code generation is performed using monoburg. Because monoburg - * produces a single C file with the definitions of the node types in - * it, this file is included from the monoburg output. */ /* Quiet compiler warnings due to monoburg not marking functions defined -- cgit v1.2.3 From 4a1bd916e79659abfa9dfdcf013eaff2daa66c29 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 11 May 2010 16:20:21 -0700 Subject: ir_to_mesa: Fix up array indexing. The grammar for array_reference_vec4_vec4 was set up wrong, so we weren't generating instructions if necessary for the array index. --- mesa_codegen.brg | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 109e8b2d513..a0ab7c86305 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -96,7 +96,7 @@ vec4: reference_vec4 0 # A reference of a variable is just a vec4 register location, # so it can be used as an argument for pretty much anything. -vec4: array_reference_vec4_vec4 1 +vec4: array_reference_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_dst_reg address_reg = {PROGRAM_ADDRESS, 0, WRITEMASK_X}; @@ -245,11 +245,6 @@ vec4: log2_vec4(vec4) 1 tree->left->src_reg); } -vec4: trunc_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_TRUNC, - tree->dst_reg, - tree->left->src_reg); -} +vec4: trunc_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_TRUNC); } %% -- cgit v1.2.3 From 2c432637d0960aa522ccd09416ba1d8a65c6988b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 May 2010 10:16:11 -0700 Subject: ir_to_mesa: Start trying to support struct storage. --- ir_to_mesa.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 1485b6a2c0f..67c79b66ee5 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -235,6 +235,37 @@ ir_to_mesa_visitor::get_temp(struct mbtree *tree, int size) tree->dst_reg.writemask = (1 << size) - 1; } +static int +type_size(const struct glsl_type *type) +{ + unsigned int i; + int size; + + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + assert(!type->is_matrix()); + /* Regardless of size of vector, it gets a vec4. This is bad + * packing for things like floats, but otherwise arrays become a + * mess. Hopefully a later pass over the code can pack scalars + * down if appropriate. + */ + return 1; + case GLSL_TYPE_ARRAY: + return type_size(type->fields.array) * type->length; + case GLSL_TYPE_STRUCT: + size = 0; + for (i = 0; i < type->length; i++) { + size += type_size(type->fields.structure[i].type); + } + return size; + default: + assert(0); + } +} + void ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) { @@ -252,13 +283,7 @@ ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); this->variable_storage.push_tail(entry); - /* Store each array element in a temp. This is poor packing for - * things like floats, but we can't do better in the Mesa IR. - */ - if (var->type->length > 1) - next_temp += var->type->length; - else - next_temp++; + next_temp += type_size(var->type); ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); } @@ -697,6 +722,39 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) this->result = tree; } +void +ir_to_mesa_visitor::visit(ir_dereference_record *ir) +{ + ir_variable *var = ir->variable_referenced(); + const char *field = ir->field; + struct mbtree *tree; + unsigned int i; + + const glsl_type *struct_type = var->type; + int offset = 0; + + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); + this->get_temp_for_var(var, tree); + + for (i = 0; i < struct_type->length; i++) { + if (strcmp(struct_type->fields.structure[i].name, field) == 0) + break; + offset += type_size(struct_type->fields.structure[i].type); + } + tree->src_reg.index += offset; + tree->dst_reg.index += offset; +} + +/** + * We want to be careful in assignment setup to hit the actual storage + * instead of potentially using a temporary like we might with the + * ir_dereference handler. + * + * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we + * should only see potentially one variable array index of a vector, + * and one swizzle, before getting to actual vec4 storage. So handle + * those, then go use ir_dereference to handle the rest. + */ static struct mbtree * get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v) { @@ -704,11 +762,16 @@ get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v) ir_dereference *deref; ir_swizzle *swiz; + ir->accept(v); + tree = v->result; + if ((deref = ir->as_dereference())) { + ir_dereference_array *deref_array = ir->as_dereference_array(); + assert(!deref_array || deref_array->array->type->is_array()); + ir->accept(v); tree = v->result; } else if ((swiz = ir->as_swizzle())) { - tree = get_assignment_lhs(swiz->val, v); tree->dst_reg.writemask = 0; if (swiz->mask.num_components >= 1) tree->dst_reg.writemask |= (1 << swiz->mask.x); @@ -725,18 +788,15 @@ get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v) return tree; } -void -ir_to_mesa_visitor::visit(ir_dereference_record *ir) -{ - (void)ir; - assert(0); -} - void ir_to_mesa_visitor::visit(ir_assignment *ir) { struct mbtree *l, *r, *t; + assert(!ir->lhs->type->is_matrix()); + assert(!ir->lhs->type->is_array()); + assert(ir->lhs->type->base_type != GLSL_TYPE_STRUCT); + l = get_assignment_lhs(ir->lhs, this); ir->rhs->accept(this); -- cgit v1.2.3 From 3c5979565facebc82000a611b991d2977b8e9bbf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 19 May 2010 15:50:02 -0700 Subject: ir_to_mesa: Add sin/cos. --- ir_to_mesa.cpp | 6 ++++++ mesa_codegen.brg | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 67c79b66ee5..205e2fc8c95 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -430,6 +430,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_log2: this->result = this->create_tree(MB_TERM_log2_vec4, ir, op[0], NULL); break; + case ir_unop_sin: + this->result = this->create_tree(MB_TERM_sin_vec4, ir, op[0], NULL); + break; + case ir_unop_cos: + this->result = this->create_tree(MB_TERM_cos_vec4, ir, op[0], NULL); + break; case ir_binop_add: this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); break; diff --git a/mesa_codegen.brg b/mesa_codegen.brg index a0ab7c86305..fc59a834f05 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -53,6 +53,8 @@ %term exp2_vec4 %term log_vec4 %term log2_vec4 +%term sin_vec4 +%term cos_vec4 %term add_vec4_vec4 %term sub_vec4_vec4 %term mul_vec4_vec4 @@ -157,6 +159,20 @@ vec4: swizzle_vec4(vec4) 1 reg); } +vec4: sin_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_SIN, + tree->dst_reg, + tree->left->src_reg); +} + +vec4: cos_vec4(vec4) 1 +{ + ir_to_mesa_emit_scalar_op1(tree, OPCODE_COS, + tree->dst_reg, + tree->left->src_reg); +} + vec4: add_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_ADD); } vec4: sub_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SUB); } vec4: mul_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MUL); } -- cgit v1.2.3 From c45b615a379e5b9cbcf951f9d738a1be77a5964b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 19 May 2010 15:54:28 -0700 Subject: ir_to_mesa: Implement neg expression. --- ir_to_mesa.cpp | 7 ++++++- ir_to_mesa.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 205e2fc8c95..722e93a7977 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -47,7 +47,7 @@ extern "C" { } ir_to_mesa_src_reg ir_to_mesa_undef = { - PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, false, + PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false, }; ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { @@ -184,6 +184,7 @@ ir_to_mesa_visitor::create_tree(int op, tree->right = right; tree->v = this; tree->src_reg.swizzle = SWIZZLE_XYZW; + tree->src_reg.negate = 0; tree->dst_reg.writemask = WRITEMASK_XYZW; ir_to_mesa_set_tree_reg(tree, PROGRAM_UNDEFINED, 0); tree->ir = ir; @@ -418,6 +419,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, op[0], this->result); break; + case ir_unop_neg: + op[0]->src_reg.negate = ~op[0]->src_reg.negate; + this->result = op[0]; + break; case ir_unop_exp: this->result = this->create_tree(MB_TERM_exp_vec4, ir, op[0], NULL); break; diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 515feb19a38..0535bc08a2a 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -40,6 +40,7 @@ typedef struct ir_to_mesa_src_reg { int file; /**< PROGRAM_* from Mesa */ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ + int negate; /**< NEGATE_XYZW mask from mesa */ bool reladdr; /**< Register index should be offset by address reg. */ } ir_to_mesa_src_reg; -- cgit v1.2.3 From c2014f03e8d6b7e21e2d0c31270ced04e1025653 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 19 May 2010 16:02:00 -0700 Subject: ir_to_mesa: Add support for trunc/ceil/floor. --- ir_to_mesa.cpp | 9 +++++++++ mesa_codegen.brg | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 722e93a7977..edc95eb5caa 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -520,6 +520,15 @@ ir_to_mesa_visitor::visit(ir_expression *ir) this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], this->result); break; + case ir_unop_trunc: + this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL); + break; + case ir_unop_ceil: + this->result = this->create_tree(MB_TERM_ceil_vec4, ir, op[0], NULL); + break; + case ir_unop_floor: + this->result = this->create_tree(MB_TERM_floor_vec4, ir, op[0], NULL); + break; default: break; } diff --git a/mesa_codegen.brg b/mesa_codegen.brg index fc59a834f05..25c0c47c02f 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -53,6 +53,9 @@ %term exp2_vec4 %term log_vec4 %term log2_vec4 +%term trunc_vec4 +%term ceil_vec4 +%term floor_vec4 %term sin_vec4 %term cos_vec4 %term add_vec4_vec4 @@ -71,7 +74,6 @@ %term sqrt_vec4 %term rsq_vec4 %term swizzle_vec4 -%term trunc_vec4 # Each tree will produce stmt. Currently, the only production for # stmt is from an assign rule -- every statement tree from @@ -159,6 +161,16 @@ vec4: swizzle_vec4(vec4) 1 reg); } +vec4: trunc_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_TRUNC); } + +vec4: ceil_vec4(vec4) 1 { + tree->left->src_reg.negate = ~tree->left->src_reg.negate; + ir_to_mesa_emit_op1(tree, OPCODE_FLR); + tree->src_reg.negate = ~tree->left->src_reg.negate; +} + +vec4: floor_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_FLR); } + vec4: sin_vec4(vec4) 1 { ir_to_mesa_emit_scalar_op1(tree, OPCODE_SIN, @@ -261,6 +273,4 @@ vec4: log2_vec4(vec4) 1 tree->left->src_reg); } -vec4: trunc_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_TRUNC); } - %% -- cgit v1.2.3 From 346daeca07d3c19c051799f96fa9f442262bd49f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 19 May 2010 16:06:37 -0700 Subject: ir_to_mesa: Don't assert over assignments with a constant-true condition. --- ir_to_mesa.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index edc95eb5caa..4238d9a8c81 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -824,7 +824,13 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) assert(l); assert(r); - assert(!ir->condition); + if (ir->condition) { + ir_constant *condition_constant; + + condition_constant = ir->condition->constant_expression_value(); + + assert(condition_constant && condition_constant->value.b[0]); + } t = this->create_tree(MB_TERM_assign, ir, l, r); mono_burg_label(t, NULL); -- cgit v1.2.3 From c23c6c773a5c79b458e52ff42bd9f431c87d4036 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 19 May 2010 16:10:37 -0700 Subject: ir_to_mesa: Implement min and max expressions. fixes glsl-orangebook-ch06-bump.frag. --- ir_to_mesa.cpp | 6 ++++++ mesa_codegen.brg | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 4238d9a8c81..59ee3b29f0a 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -529,6 +529,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_floor: this->result = this->create_tree(MB_TERM_floor_vec4, ir, op[0], NULL); break; + case ir_binop_min: + this->result = this->create_tree(MB_TERM_min_vec4_vec4, ir, op[0], op[1]); + break; + case ir_binop_max: + this->result = this->create_tree(MB_TERM_max_vec4_vec4, ir, op[0], op[1]); + break; default: break; } diff --git a/mesa_codegen.brg b/mesa_codegen.brg index 25c0c47c02f..d53ccf39070 100644 --- a/mesa_codegen.brg +++ b/mesa_codegen.brg @@ -74,6 +74,8 @@ %term sqrt_vec4 %term rsq_vec4 %term swizzle_vec4 +%term min_vec4_vec4 +%term max_vec4_vec4 # Each tree will produce stmt. Currently, the only production for # stmt is from an assign rule -- every statement tree from @@ -273,4 +275,7 @@ vec4: log2_vec4(vec4) 1 tree->left->src_reg); } +vec4: min_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MIN); } +vec4: max_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MAX); } + %% -- cgit v1.2.3 From ab386f18b045fe260112bd9a239cb503e737c1db Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 1 Jun 2010 16:23:57 -0700 Subject: ir_to_mesa: Try to fix up the dereference handling for the visitor rework. One of the gstreamer shaders I play with now compiles, but input mappings are wrong. --- ir_to_mesa.cpp | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 59ee3b29f0a..8d3f65ffb20 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -659,27 +659,26 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), }; - ir_variable *var = ir->var; /* By the time we make it to this stage, matrices should be broken down * to vectors. */ - assert(!var->type->is_matrix()); + assert(!ir->var->type->is_matrix()); tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - if (strncmp(var->name, "gl_", 3) == 0) { + if (strncmp(ir->var->name, "gl_", 3) == 0) { unsigned int i; for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { - if (strcmp(var->name, builtin_var_to_mesa_reg[i].name) == 0) + if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0) break; } assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg)); ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, builtin_var_to_mesa_reg[i].index); } else { - this->get_temp_for_var(var, tree); + this->get_temp_for_var(ir->var, tree); } /* If the type is smaller than a vec4, replicate the last channel out. */ @@ -698,33 +697,25 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), }; - ir_variable *var = ir->variable_referenced(); - ir_constant *index = ir->array_index->constant_expression_value(); + ir_constant *index; + + index = ir->array_index->constant_expression_value(); /* By the time we make it to this stage, matrices should be broken down * to vectors. */ - assert(!var->type->is_matrix()); - - if (strncmp(var->name, "gl_", 3) == 0) { - unsigned int i; - unsigned int offset = 0; + assert(!ir->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); + ir->array->accept(this); + tree = this->result; - offset = index->value.i[0]; + if (tree->src_reg.file == PROGRAM_INPUT || + tree->src_reg.file == PROGRAM_OUTPUT) { + assert(index); /* FINISHME: Handle variable indexing of builtins. */ - for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { - if (strcmp(var->name, builtin_var_to_mesa_reg[i].name) == 0) - break; - } - assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg)); - ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, - builtin_var_to_mesa_reg[i].index + offset); + tree->src_reg.index += index->value.i[0]; + tree->dst_reg.index += index->value.i[0]; } else { - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - this->get_temp_for_var(var, tree); - if (index) { tree->src_reg.index += index->value.i[0]; tree->dst_reg.index += index->value.i[0]; -- cgit v1.2.3 From 224f712950494730c76b48864f2ca19acde1c8cf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 1 Jun 2010 16:32:46 -0700 Subject: ir_to_mesa: Fix mapping of FS texcoord inputs and color output. --- ir_to_mesa.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 8d3f65ffb20..f121fc88b34 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -613,13 +613,14 @@ static const struct { /* core_fs */ {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS}, {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE}, - {"gl_FragColor", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, + {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0}, {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */ /* 110_deprecated_fs */ {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1}, {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC}, + {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */ /* 110_deprecated_vs */ {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS}, @@ -669,12 +670,24 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) if (strncmp(ir->var->name, "gl_", 3) == 0) { unsigned int i; + bool var_in = (ir->var->mode == ir_var_in || + ir->var->mode == ir_var_inout); + + tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { - if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0) + bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT; + + if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 && + !(var_in ^ in)) break; } - assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg)); + if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) { + printf("Failed to find builtin for %s variable %s\n", + var_in ? "in" : "out", + ir->var->name); + abort(); + } ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, builtin_var_to_mesa_reg[i].index); } else { -- cgit v1.2.3 From 0161515c395c44233529c8d51f823b60050bc7ba Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 2 Jun 2010 17:43:43 -0700 Subject: ir_to_mesa: Remove the BURG code. The promise of the BURG was to recognize multi-instruction sequences and emit reduced sequences for them. It would have worked well for recognizing MUL+ADD -> MAD and possibly even MIN(MAX(val, 0), 1) -> MOV_SAT with some grammar changes. However, that potential benefit in making those optimizations easy is outweighed by the fragility of monoburg, the amount of (incorrect, as I wrote it) code for using it, and the burden it was going to cause for handling operations on aggregate types. --- Makefile.am | 10 -- ir_to_mesa.cpp | 509 +++++++++++++++++++++++++------------------------------ ir_to_mesa.h | 81 +++------ mesa_codegen.brg | 281 ------------------------------ 4 files changed, 258 insertions(+), 623 deletions(-) delete mode 100644 mesa_codegen.brg diff --git a/Makefile.am b/Makefile.am index bf062595a9d..c34f7d8abfb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,16 +63,11 @@ glsl_SOURCES = \ ir_validate.cpp \ ir_vec_index_to_swizzle.cpp \ linker.cpp \ - mesa_codegen.cpp \ - msea_codegen.h \ mesa/shader/prog_instruction.c \ mesa/shader/prog_instruction.h \ mesa/shader/prog_print.c \ mesa/shader/prog_print.h -DISTFILES = \ - mesa_codegen.brg - BUILT_SOURCES = glsl_parser.h glsl_parser.cpp glsl_lexer.cpp CLEANFILES = $(BUILT_SOURCES) @@ -82,8 +77,3 @@ glsl_parser.h: glsl_parser.cpp .lpp.cpp: $(LEXCOMPILE) --outfile="$@" $< - -mesa_codegen.h: mesa_codegen.cpp - -mesa_codegen.cpp: mesa_codegen.brg - monoburg --no-glib -s $@ -d mesa_codegen.h $< diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index f121fc88b34..3376e897050 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -33,10 +33,11 @@ */ #define g_new #define g_error -#include "mesa_codegen.h" +#include #include "ir.h" #include "ir_visitor.h" +#include "ir_to_mesa.h" #include "ir_print_visitor.h" #include "ir_expression_flattening.h" #include "glsl_types.h" @@ -54,13 +55,29 @@ ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP }; +ir_to_mesa_dst_reg ir_to_mesa_address_reg = { + PROGRAM_ADDRESS, 0, WRITEMASK_X +}; + +static int swizzle_for_size(int size) +{ + 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), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + }; + + return size_swizzles[size - 1]; +} + ir_to_mesa_instruction * -ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1, - ir_to_mesa_src_reg src2) +ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2) { ir_to_mesa_instruction *inst = new ir_to_mesa_instruction(); @@ -71,48 +88,42 @@ ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir, inst->src_reg[2] = src2; inst->ir = ir; - v->instructions.push_tail(inst); + this->instructions.push_tail(inst); return inst; } ir_to_mesa_instruction * -ir_to_mesa_emit_op2_full(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1) +ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1) { - return ir_to_mesa_emit_op3(v, ir, - op, dst, src0, src1, ir_to_mesa_undef); + return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef); } ir_to_mesa_instruction * -ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op) +ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) { - return ir_to_mesa_emit_op2_full(tree->v, tree->ir, op, - tree->dst_reg, - tree->left->src_reg, - tree->right->src_reg); + return ir_to_mesa_emit_op3(ir, op, dst, + src0, ir_to_mesa_undef, ir_to_mesa_undef); } -ir_to_mesa_instruction * -ir_to_mesa_emit_op1_full(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0) +inline ir_to_mesa_dst_reg +ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) { - return ir_to_mesa_emit_op3(v, ir, op, - dst, src0, ir_to_mesa_undef, ir_to_mesa_undef); -} + ir_to_mesa_dst_reg dst_reg; -ir_to_mesa_instruction * -ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op) -{ - return ir_to_mesa_emit_op1_full(tree->v, tree->ir, op, - tree->dst_reg, - tree->left->src_reg); + dst_reg.file = reg.file; + dst_reg.index = reg.index; + dst_reg.writemask = WRITEMASK_XYZW; + + return dst_reg; } /** @@ -124,9 +135,10 @@ ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op) * to produce dest channels. */ void -ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0) +ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) { int i, j; int done_mask = ~dst.writemask; @@ -152,52 +164,18 @@ ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz, src_swiz, src_swiz); - inst = ir_to_mesa_emit_op1_full(tree->v, tree->ir, op, - dst, - src); + inst = ir_to_mesa_emit_op1(ir, op, + dst, + src); inst->dst_reg.writemask = this_mask; done_mask |= this_mask; } } -static void -ir_to_mesa_set_tree_reg(struct mbtree *tree, int file, int index) -{ - tree->dst_reg.file = file; - tree->dst_reg.index = index; - - tree->src_reg.file = file; - tree->src_reg.index = index; -} - -struct mbtree * -ir_to_mesa_visitor::create_tree(int op, - ir_instruction *ir, - struct mbtree *left, struct mbtree *right) -{ - struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1); - - assert(ir); - - tree->op = op; - tree->left = left; - tree->right = right; - tree->v = this; - tree->src_reg.swizzle = SWIZZLE_XYZW; - tree->src_reg.negate = 0; - tree->dst_reg.writemask = WRITEMASK_XYZW; - ir_to_mesa_set_tree_reg(tree, PROGRAM_UNDEFINED, 0); - tree->ir = ir; - - return tree; -} - -struct mbtree * -ir_to_mesa_visitor::create_tree_for_float(ir_instruction *ir, float val) +struct ir_to_mesa_src_reg +ir_to_mesa_visitor::src_reg_for_float(float val) { - struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1); - - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); + ir_to_mesa_src_reg src_reg; /* FINISHME: This will end up being _mesa_add_unnamed_constant, * which handles sharing values and sharing channels of vec4 @@ -206,11 +184,11 @@ ir_to_mesa_visitor::create_tree_for_float(ir_instruction *ir, float val) /* FINISHME: Do something with the constant values for now. */ (void)val; - ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++); - tree->src_reg.swizzle = SWIZZLE_NOOP; + src_reg.file = PROGRAM_CONSTANT; + src_reg.index = this->next_constant++; + src_reg.swizzle = SWIZZLE_NOOP; - this->result = tree; - return tree; + return src_reg; } /** @@ -219,21 +197,24 @@ ir_to_mesa_visitor::create_tree_for_float(ir_instruction *ir, float val) * storage). Actual register allocation for the Mesa VM occurs in a * pass over the Mesa IR later. */ -void -ir_to_mesa_visitor::get_temp(struct mbtree *tree, int size) +ir_to_mesa_src_reg +ir_to_mesa_visitor::get_temp(int size) { + ir_to_mesa_src_reg src_reg; int swizzle[4]; int i; - ir_to_mesa_set_tree_reg(tree, PROGRAM_TEMPORARY, this->next_temp++); + src_reg.file = PROGRAM_TEMPORARY; + src_reg.index = this->next_temp++; for (i = 0; i < size; i++) swizzle[i] = i; for (; i < 4; i++) swizzle[i] = size - 1; - tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], - swizzle[2], swizzle[3]); - tree->dst_reg.writemask = (1 << size) - 1; + src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], + swizzle[2], swizzle[3]); + + return src_reg; } static int @@ -267,18 +248,18 @@ type_size(const struct glsl_type *type) } } -void -ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) +ir_to_mesa_src_reg +ir_to_mesa_visitor::get_temp_for_var(ir_variable *var) { + ir_to_mesa_src_reg src_reg; + temp_entry *entry; foreach_iter(exec_list_iterator, iter, this->variable_storage) { entry = (temp_entry *)iter.get(); - if (entry->var == var) { - ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); - return; - } + if (entry->var == var) + goto done; } entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); @@ -286,36 +267,12 @@ ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree) next_temp += type_size(var->type); - ir_to_mesa_set_tree_reg(tree, entry->file, entry->index); -} +done: + src_reg.file = entry->file; + src_reg.index = entry->index; + src_reg.swizzle = swizzle_for_size(var->type->vector_elements); -static void -reduce(struct mbtree *t, int goal) -{ - struct mbtree *kids[10]; - int rule = mono_burg_rule((MBState *)t->state, goal); - const uint16_t *nts = mono_burg_nts[rule]; - int i; - - mono_burg_kids (t, rule, kids); - - for (i = 0; nts[i]; i++) { - reduce(kids[i], nts[i]); - } - - if (t->left) { - if (mono_burg_func[rule]) { - mono_burg_func[rule](t, NULL); - } else { - printf("no code for rules %s\n", mono_burg_rule_string[rule]); - exit(1); - } - } else { - if (mono_burg_func[rule]) { - printf("unused code for rule %s\n", mono_burg_rule_string[rule]); - exit(1); - } - } + return src_reg; } void @@ -332,15 +289,13 @@ ir_to_mesa_visitor::visit(ir_loop *ir) assert(!ir->increment); assert(!ir->counter); - ir_to_mesa_emit_op1_full(this, NULL, - OPCODE_BGNLOOP, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + ir_to_mesa_emit_op1(NULL, OPCODE_BGNLOOP, + ir_to_mesa_undef_dst, ir_to_mesa_undef); visit_exec_list(&ir->body_instructions, this); - ir_to_mesa_emit_op1_full(this, NULL, - OPCODE_ENDLOOP, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + ir_to_mesa_emit_op1(NULL, OPCODE_ENDLOOP, + ir_to_mesa_undef_dst, ir_to_mesa_undef); } void @@ -348,14 +303,12 @@ ir_to_mesa_visitor::visit(ir_loop_jump *ir) { switch (ir->mode) { case ir_loop_jump::jump_break: - ir_to_mesa_emit_op1_full(this, NULL, - OPCODE_BRK, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + ir_to_mesa_emit_op1(NULL, OPCODE_BRK, + ir_to_mesa_undef_dst, ir_to_mesa_undef); break; case ir_loop_jump::jump_continue: - ir_to_mesa_emit_op1_full(this, NULL, - OPCODE_CONT, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + ir_to_mesa_emit_op1(NULL, OPCODE_CONT, + ir_to_mesa_undef_dst, ir_to_mesa_undef); break; } } @@ -394,15 +347,17 @@ void ir_to_mesa_visitor::visit(ir_expression *ir) { unsigned int operand; - struct mbtree *op[2]; + struct ir_to_mesa_src_reg op[2], temp; + struct ir_to_mesa_src_reg result_src; + struct ir_to_mesa_dst_reg result_dst; const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1); const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1); const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1); for (operand = 0; operand < ir->get_num_operands(); operand++) { - this->result = NULL; + this->result.file = PROGRAM_UNDEFINED; ir->operands[operand]->accept(this); - if (!this->result) { + if (this->result.file == PROGRAM_UNDEFINED) { ir_print_visitor v; printf("Failed to get tree for expression operand:\n"); ir->operands[operand]->accept(&v); @@ -411,149 +366,163 @@ ir_to_mesa_visitor::visit(ir_expression *ir) op[operand] = this->result; } - this->result = NULL; + this->result.file = PROGRAM_UNDEFINED; + + /* Storage for our result. Ideally for an assignment we'd be using + * the actual storage for the result here, instead. + */ + result_src = get_temp(4); + /* convenience for the emit functions below. */ + result_dst = ir_to_mesa_dst_reg_from_src(result_src); switch (ir->operation) { case ir_unop_logic_not: - this->result = this->create_tree_for_float(ir, 0.0); - this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, - op[0], this->result); + temp = src_reg_for_float(0.0); + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], temp); break; case ir_unop_neg: - op[0]->src_reg.negate = ~op[0]->src_reg.negate; - this->result = op[0]; + op[0].negate = ~op[0].negate; + result_src = op[0]; break; case ir_unop_exp: - this->result = this->create_tree(MB_TERM_exp_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_EXP, result_dst, op[0]); break; case ir_unop_exp2: - this->result = this->create_tree(MB_TERM_exp2_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]); break; case ir_unop_log: - this->result = this->create_tree(MB_TERM_log_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_LOG, result_dst, op[0]); break; case ir_unop_log2: - this->result = this->create_tree(MB_TERM_log2_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]); break; case ir_unop_sin: - this->result = this->create_tree(MB_TERM_sin_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]); break; case ir_unop_cos: - this->result = this->create_tree(MB_TERM_cos_vec4, ir, op[0], NULL); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]); break; case ir_binop_add: - this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]); break; case ir_binop_sub: - this->result = this->create_tree(MB_TERM_sub_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]); break; case ir_binop_mul: - this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]); break; case ir_binop_div: - this->result = this->create_tree(MB_TERM_div_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_RCP, result_dst, op[0], result_src); break; case ir_binop_less: - this->result = this->create_tree(MB_TERM_slt_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], temp); break; case ir_binop_greater: - this->result = this->create_tree(MB_TERM_sgt_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], temp); break; case ir_binop_lequal: - this->result = this->create_tree(MB_TERM_sle_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], temp); break; case ir_binop_gequal: - this->result = this->create_tree(MB_TERM_sge_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], temp); break; case ir_binop_equal: - this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], temp); break; case ir_binop_logic_xor: case ir_binop_nequal: - this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], temp); break; case ir_binop_logic_or: - /* This could be a saturated add. */ - this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]); - this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, - this->create_tree_for_float(ir, 0.0), - this->result); + /* This could be a saturated add and skip the SNE. */ + ir_to_mesa_emit_op2(ir, OPCODE_ADD, + result_dst, + op[0], op[1]); + + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + result_dst, + result_src, src_reg_for_float(0.0)); break; case ir_binop_logic_and: /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */ - this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, + result_dst, + op[0], op[1]); break; case ir_binop_dot: if (ir->operands[0]->type == vec4_type) { assert(ir->operands[1]->type == vec4_type); - this->result = this->create_tree(MB_TERM_dp4_vec4_vec4, - ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_DP4, + result_dst, + op[0], op[1]); } else if (ir->operands[0]->type == vec3_type) { assert(ir->operands[1]->type == vec3_type); - this->result = this->create_tree(MB_TERM_dp3_vec4_vec4, - ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_DP3, + result_dst, + op[0], op[1]); } else if (ir->operands[0]->type == vec2_type) { assert(ir->operands[1]->type == vec2_type); - this->result = this->create_tree(MB_TERM_dp2_vec4_vec4, - ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_DP2, + result_dst, + op[0], op[1]); } break; case ir_unop_sqrt: - this->result = this->create_tree(MB_TERM_sqrt_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); + ir_to_mesa_emit_op1(ir, OPCODE_RCP, result_dst, result_src); break; case ir_unop_rsq: - this->result = this->create_tree(MB_TERM_rsq_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); break; case ir_unop_i2f: /* Mesa IR lacks types, ints are stored as truncated floats. */ - this->result = op[0]; + result_src = op[0]; break; case ir_unop_f2i: - this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL); + ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); break; case ir_unop_f2b: - this->result = this->create_tree_for_float(ir, 0.0); - this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, - op[0], this->result); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, + result_src, src_reg_for_float(0.0)); break; case ir_unop_trunc: - this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL); + ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); break; case ir_unop_ceil: - this->result = this->create_tree(MB_TERM_ceil_vec4, ir, op[0], NULL); + op[0].negate = ~op[0].negate; + ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); + result_src.negate = ~result_src.negate; break; case ir_unop_floor: - this->result = this->create_tree(MB_TERM_floor_vec4, ir, op[0], NULL); + ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); break; case ir_binop_min: - this->result = this->create_tree(MB_TERM_min_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]); break; case ir_binop_max: - this->result = this->create_tree(MB_TERM_max_vec4_vec4, ir, op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]); break; default: - break; - } - if (!this->result) { ir_print_visitor v; printf("Failed to get tree for expression:\n"); ir->accept(&v); exit(1); + break; } - /* Allocate a temporary for the result. */ - this->get_temp(this->result, ir->type->vector_elements); + this->result = result_src; } void ir_to_mesa_visitor::visit(ir_swizzle *ir) { - struct mbtree *tree; + ir_to_mesa_src_reg src_reg; int i; int swizzle[4]; @@ -563,10 +532,9 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) */ ir->val->accept(this); - assert(this->result); + assert(this->result.file != PROGRAM_UNDEFINED); - tree = this->create_tree(MB_TERM_swizzle_vec4, ir, this->result, NULL); - this->get_temp(tree, 4); + src_reg = this->get_temp(4); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { @@ -592,12 +560,12 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) } } - tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], - swizzle[1], - swizzle[2], - swizzle[3]); + src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], + swizzle[1], + swizzle[2], + swizzle[3]); - this->result = tree; + this->result = src_reg; } /* This list should match up with builtin_variables.h */ @@ -653,28 +621,18 @@ static const struct { void ir_to_mesa_visitor::visit(ir_dereference_variable *ir) { - struct mbtree *tree; - 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), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), - }; + ir_to_mesa_src_reg src_reg; /* By the time we make it to this stage, matrices should be broken down * to vectors. */ assert(!ir->var->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - if (strncmp(ir->var->name, "gl_", 3) == 0) { unsigned int i; bool var_in = (ir->var->mode == ir_var_in || ir->var->mode == ir_var_inout); - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT; @@ -688,29 +646,25 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) ir->var->name); abort(); } - ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file, - builtin_var_to_mesa_reg[i].index); + src_reg.file = builtin_var_to_mesa_reg[i].file; + src_reg.index = builtin_var_to_mesa_reg[i].index; } else { - this->get_temp_for_var(ir->var, tree); + src_reg = get_temp_for_var(ir->var); } /* If the type is smaller than a vec4, replicate the last channel out. */ - tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; + src_reg.swizzle = swizzle_for_size(ir->type->vector_elements); + src_reg.reladdr = false; + src_reg.negate = 0; - this->result = tree; + this->result = src_reg; } void ir_to_mesa_visitor::visit(ir_dereference_array *ir) { - struct mbtree *tree; - int size_swizzles[4] = { - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), - }; ir_constant *index; + ir_to_mesa_src_reg src_reg; index = ir->array_index->constant_expression_value(); @@ -720,59 +674,59 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) assert(!ir->type->is_matrix()); ir->array->accept(this); - tree = this->result; + src_reg = this->result; - if (tree->src_reg.file == PROGRAM_INPUT || - tree->src_reg.file == PROGRAM_OUTPUT) { + if (src_reg.file == PROGRAM_INPUT || + src_reg.file == PROGRAM_OUTPUT) { assert(index); /* FINISHME: Handle variable indexing of builtins. */ - tree->src_reg.index += index->value.i[0]; - tree->dst_reg.index += index->value.i[0]; + src_reg.index += index->value.i[0]; } else { if (index) { - tree->src_reg.index += index->value.i[0]; - tree->dst_reg.index += index->value.i[0]; + src_reg.index += index->value.i[0]; } else { + ir_to_mesa_src_reg array_base = this->result; /* Variable index array dereference. It eats the "vec4" of the * base of the array and an index that offsets the Mesa register * index. */ ir->array_index->accept(this); - tree->src_reg.reladdr = true; - tree = this->create_tree(MB_TERM_array_reference_vec4_vec4, - ir, tree, this->result); - this->get_temp(tree, ir->type->vector_elements); + /* FINISHME: This doesn't work when we're trying to do the LHS + * of an assignment. + */ + src_reg.reladdr = true; + ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, + this->result); + + this->result = get_temp(ir->type->vector_elements); + ir_to_mesa_emit_op1(ir, OPCODE_MOV, + ir_to_mesa_dst_reg_from_src(this->result), + src_reg); } } /* If the type is smaller than a vec4, replicate the last channel out. */ - tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1]; + src_reg.swizzle = swizzle_for_size(ir->type->vector_elements); - this->result = tree; + this->result = src_reg; } void ir_to_mesa_visitor::visit(ir_dereference_record *ir) { - ir_variable *var = ir->variable_referenced(); - const char *field = ir->field; - struct mbtree *tree; unsigned int i; - - const glsl_type *struct_type = var->type; + const glsl_type *struct_type = ir->record->type; int offset = 0; - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - this->get_temp_for_var(var, tree); + ir->record->accept(this); for (i = 0; i < struct_type->length; i++) { - if (strcmp(struct_type->fields.structure[i].name, field) == 0) + if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0) break; offset += type_size(struct_type->fields.structure[i].type); } - tree->src_reg.index += offset; - tree->dst_reg.index += offset; + this->result.index += offset; } /** @@ -785,43 +739,44 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir) * and one swizzle, before getting to actual vec4 storage. So handle * those, then go use ir_dereference to handle the rest. */ -static struct mbtree * +static struct ir_to_mesa_dst_reg get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v) { - struct mbtree *tree = NULL; + struct ir_to_mesa_dst_reg dst_reg; ir_dereference *deref; ir_swizzle *swiz; + /* Use the rvalue deref handler for the most part. We'll ignore + * swizzles in it and write swizzles using writemask, though. + */ ir->accept(v); - tree = v->result; + dst_reg = ir_to_mesa_dst_reg_from_src(v->result); if ((deref = ir->as_dereference())) { ir_dereference_array *deref_array = ir->as_dereference_array(); assert(!deref_array || deref_array->array->type->is_array()); ir->accept(v); - tree = v->result; } else if ((swiz = ir->as_swizzle())) { - tree->dst_reg.writemask = 0; + dst_reg.writemask = 0; if (swiz->mask.num_components >= 1) - tree->dst_reg.writemask |= (1 << swiz->mask.x); + dst_reg.writemask |= (1 << swiz->mask.x); if (swiz->mask.num_components >= 2) - tree->dst_reg.writemask |= (1 << swiz->mask.y); + dst_reg.writemask |= (1 << swiz->mask.y); if (swiz->mask.num_components >= 3) - tree->dst_reg.writemask |= (1 << swiz->mask.z); + dst_reg.writemask |= (1 << swiz->mask.z); if (swiz->mask.num_components >= 4) - tree->dst_reg.writemask |= (1 << swiz->mask.w); + dst_reg.writemask |= (1 << swiz->mask.w); } - assert(tree); - - return tree; + return dst_reg; } void ir_to_mesa_visitor::visit(ir_assignment *ir) { - struct mbtree *l, *r, *t; + struct ir_to_mesa_dst_reg l; + struct ir_to_mesa_src_reg r; assert(!ir->lhs->type->is_matrix()); assert(!ir->lhs->type->is_array()); @@ -831,8 +786,8 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) ir->rhs->accept(this); r = this->result; - assert(l); - assert(r); + assert(l.file != PROGRAM_UNDEFINED); + assert(r.file != PROGRAM_UNDEFINED); if (ir->condition) { ir_constant *condition_constant; @@ -842,21 +797,17 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) assert(condition_constant && condition_constant->value.b[0]); } - t = this->create_tree(MB_TERM_assign, ir, l, r); - mono_burg_label(t, NULL); - reduce(t, MB_NTERM_stmt); + ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); } void ir_to_mesa_visitor::visit(ir_constant *ir) { - struct mbtree *tree; + ir_to_mesa_src_reg src_reg; assert(!ir->type->is_matrix()); - tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL); - assert(ir->type->base_type == GLSL_TYPE_FLOAT || ir->type->base_type == GLSL_TYPE_UINT || ir->type->base_type == GLSL_TYPE_INT || @@ -868,10 +819,13 @@ ir_to_mesa_visitor::visit(ir_constant *ir) */ /* FINISHME: Do something with the constant values for now. */ - ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++); - tree->src_reg.swizzle = SWIZZLE_NOOP; + src_reg.file = PROGRAM_CONSTANT; + src_reg.index = this->next_constant++; + src_reg.swizzle = SWIZZLE_NOOP; + src_reg.reladdr = false; + src_reg.negate = 0; - this->result = tree; + this->result = src_reg; } @@ -906,31 +860,30 @@ ir_to_mesa_visitor::visit(ir_if *ir) ir_to_mesa_instruction *if_inst, *else_inst = NULL; ir->condition->accept(this); - assert(this->result); + assert(this->result.file != PROGRAM_UNDEFINED); - if_inst = ir_to_mesa_emit_op1_full(this, ir->condition, - OPCODE_IF, ir_to_mesa_undef_dst, - this->result->src_reg); + if_inst = ir_to_mesa_emit_op1(ir->condition, + OPCODE_IF, ir_to_mesa_undef_dst, + this->result); this->instructions.push_tail(if_inst); visit_exec_list(&ir->then_instructions, this); if (!ir->else_instructions.is_empty()) { - else_inst = ir_to_mesa_emit_op1_full(this, ir->condition, - OPCODE_ELSE, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + else_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ELSE, + ir_to_mesa_undef_dst, + ir_to_mesa_undef); visit_exec_list(&ir->then_instructions, this); } - if_inst = ir_to_mesa_emit_op1_full(this, ir->condition, - OPCODE_ENDIF, ir_to_mesa_undef_dst, - ir_to_mesa_undef); + if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF, + ir_to_mesa_undef_dst, ir_to_mesa_undef); } ir_to_mesa_visitor::ir_to_mesa_visitor() { - result = NULL; + result.file = PROGRAM_UNDEFINED; next_temp = 1; next_constant = 0; } diff --git a/ir_to_mesa.h b/ir_to_mesa.h index 0535bc08a2a..b05b9ebc7ae 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -102,15 +102,11 @@ public: int next_temp; int next_constant; - void get_temp(struct mbtree *tree, int size); + ir_to_mesa_src_reg get_temp(int size); - void get_temp_for_var(ir_variable *var, struct mbtree *tree); + ir_to_mesa_src_reg get_temp_for_var(ir_variable *var); - struct mbtree *create_tree(int op, - ir_instruction *ir, - struct mbtree *left, - struct mbtree *right); - struct mbtree *create_tree_for_float(ir_instruction *ir, float val); + struct ir_to_mesa_src_reg src_reg_for_float(float val); /** * \name Visit methods @@ -138,61 +134,38 @@ public: virtual void visit(ir_if *); /*@}*/ - struct mbtree *result; + struct ir_to_mesa_src_reg result; /** List of temp_entry */ exec_list variable_storage; /** List of ir_to_mesa_instruction */ exec_list instructions; + + ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + + ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); + + ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2); + + void ir_to_mesa_emit_scalar_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); }; extern ir_to_mesa_src_reg ir_to_mesa_undef; extern ir_to_mesa_dst_reg ir_to_mesa_undef_dst; -ir_to_mesa_instruction * -ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op); - -ir_to_mesa_instruction * -ir_to_mesa_emit_op1_full(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0); - -ir_to_mesa_instruction * -ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op); - -ir_to_mesa_instruction * -ir_to_mesa_emit_op2_full(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1); - -ir_to_mesa_instruction * -ir_to_mesa_emit_simple_op2(struct mbtree *tree, enum prog_opcode op); - -ir_to_mesa_instruction * -ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1, - ir_to_mesa_src_reg src2); - -void -ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0); - -inline ir_to_mesa_dst_reg -ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) -{ - ir_to_mesa_dst_reg dst_reg; - - dst_reg.file = reg.file; - dst_reg.index = reg.index; - dst_reg.writemask = WRITEMASK_XYZW; - - return dst_reg; -} diff --git a/mesa_codegen.brg b/mesa_codegen.brg deleted file mode 100644 index d53ccf39070..00000000000 --- a/mesa_codegen.brg +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS 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. - * - * Authors: - * Eric Anholt - * - */ - -/* DO NOT EDIT mesa_codegen.h. It is a generated file produced - * from mesa_codegen.brg and will be overwritten. - */ - -#include -#include -#include -#include -#include - -/* Everything before the first %% is pasted at the start of the - * mesa_codegen.h header file. - */ - -#include "ir_to_mesa.h" - -#define MBTREE_TYPE struct mbtree - -%% -# The list of terminals is the set of things that ir_to_mesa.cpp will -# generate in its trees. -%term assign -%term reference_vec4 -%term array_reference_vec4_vec4 -%term exp_vec4 -%term exp2_vec4 -%term log_vec4 -%term log2_vec4 -%term trunc_vec4 -%term ceil_vec4 -%term floor_vec4 -%term sin_vec4 -%term cos_vec4 -%term add_vec4_vec4 -%term sub_vec4_vec4 -%term mul_vec4_vec4 -%term div_vec4_vec4 -%term slt_vec4_vec4 -%term sgt_vec4_vec4 -%term sle_vec4_vec4 -%term sge_vec4_vec4 -%term seq_vec4_vec4 -%term sne_vec4_vec4 -%term dp4_vec4_vec4 -%term dp3_vec4_vec4 -%term dp2_vec4_vec4 -%term sqrt_vec4 -%term rsq_vec4 -%term swizzle_vec4 -%term min_vec4_vec4 -%term max_vec4_vec4 - -# Each tree will produce stmt. Currently, the only production for -# stmt is from an assign rule -- every statement tree from -# ir_to_mesa.cpp assigns a result to a register. - -%start stmt - -# Now comes all the rules for code generation. Each rule is of the -# general form -# -# produced: term(term, term) cost -# { -# code_run_when_we_choose_this_rule(); -# } -# -# where choosing this rule means we turn term(term, term) into -# produced at the cost of "cost". We measure "cost" in approximate -# instruction count. The BURG should then more or less minimize the -# number of instructions. - -# A reference of a variable is just a vec4 register location, -# so it can be used as an argument for pretty much anything. -vec4: reference_vec4 0 - -# A reference of a variable is just a vec4 register location, -# so it can be used as an argument for pretty much anything. -vec4: array_reference_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_dst_reg address_reg = {PROGRAM_ADDRESS, 0, WRITEMASK_X}; - - ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_ARL, - address_reg, - tree->right->src_reg); - ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, - tree->dst_reg, - tree->left->src_reg); -} - -# Here's the rule everyone will hit: Moving the result of an -# expression into a variable-dereference register location. -# -# Note that this is likely a gratuitous move. We could make variants -# of each of the following rules, e.g: -# -# vec4: add_vec4_vec4(vec4, vec4) 1 -# { -# emit(ADD, tree, tree->left, tree->right); -# } -# -# becoming -# -# vec4: assign(vec4_vec4, add_vec4_vec4(vec4, vec4) 1 -# { -# emit(ADD, tree->left, tree->right->left, tree->right->right); -# } -# -# But it seems like a lot of extra typing and duped code, when we -# probably want copy propagation and dead code after codegen anyway, -# which would clean these up. -stmt: assign(vec4, vec4) 1 -{ - ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, - tree->left->dst_reg, - tree->right->src_reg); -} - -# Perform a swizzle by composing our swizzle with the swizzle -# required to get at the src reg. -vec4: swizzle_vec4(vec4) 1 -{ - ir_to_mesa_src_reg reg = tree->left->src_reg; - int swiz[4]; - int i; - - for (i = 0; i < 4; i++) { - swiz[i] = GET_SWZ(tree->src_reg.swizzle, i); - if (swiz[i] >= SWIZZLE_X && swiz[i] <= SWIZZLE_Y) { - swiz[i] = GET_SWZ(tree->left->src_reg.swizzle, swiz[i]); - } - } - reg.swizzle = MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); - - ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_MOV, - tree->dst_reg, - reg); -} - -vec4: trunc_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_TRUNC); } - -vec4: ceil_vec4(vec4) 1 { - tree->left->src_reg.negate = ~tree->left->src_reg.negate; - ir_to_mesa_emit_op1(tree, OPCODE_FLR); - tree->src_reg.negate = ~tree->left->src_reg.negate; -} - -vec4: floor_vec4(vec4) 1 { ir_to_mesa_emit_op1(tree, OPCODE_FLR); } - -vec4: sin_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_SIN, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: cos_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_COS, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: add_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_ADD); } -vec4: sub_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SUB); } -vec4: mul_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MUL); } - -vec4: dp4_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_DP4); - tree->src_reg.swizzle = SWIZZLE_XXXX; -} - -vec4: dp3_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_DP3); - tree->src_reg.swizzle = SWIZZLE_XXXX; -} - - -vec4: dp2_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_op2(tree, OPCODE_DP2); - tree->src_reg.swizzle = SWIZZLE_XXXX; -} - -vec4: div_vec4_vec4(vec4, vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_RCP, - tree->dst_reg, - tree->right->src_reg); - - ir_to_mesa_emit_op2_full(tree->v, tree->ir, OPCODE_MUL, - tree->dst_reg, - tree->src_reg, - tree->left->src_reg); -} - -vec4: slt_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SLT); } -vec4: sgt_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SGT); } -vec4: sle_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SLE); } -vec4: sge_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SGE); } -vec4: sne_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SNE); } -vec4: seq_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_SEQ); } - -vec4: sqrt_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, - tree->dst_reg, - tree->left->src_reg); - - ir_to_mesa_emit_op1_full(tree->v, tree->ir, OPCODE_RCP, - tree->dst_reg, - tree->src_reg); -} - -vec4: rsq_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: exp_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_EXP, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: exp2_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_EX2, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: log_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_LOG, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: log2_vec4(vec4) 1 -{ - ir_to_mesa_emit_scalar_op1(tree, OPCODE_LG2, - tree->dst_reg, - tree->left->src_reg); -} - -vec4: min_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MIN); } -vec4: max_vec4_vec4(vec4, vec4) 1 { ir_to_mesa_emit_op2(tree, OPCODE_MAX); } - -%% -- cgit v1.2.3 From 9d2b8e0b70acce2678bea2cb6a990e0dee380b37 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 09:04:57 -0700 Subject: ir_to_mesa: Fix copy-and-wasted DIV instruction sequence. --- ir_to_mesa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 3376e897050..d9d7a91b296 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -413,7 +413,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) break; case ir_binop_div: ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]); - ir_to_mesa_emit_op2(ir, OPCODE_RCP, result_dst, op[0], result_src); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], result_src); break; case ir_binop_less: -- cgit v1.2.3 From 9cd8cad9f3dc4774366193acbfc5ab22198096e7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 09:17:54 -0700 Subject: ir_to_mesa: Restrict dst writemasks like we did in the monoburg setup. --- ir_to_mesa.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index d9d7a91b296..8a5b2a6dbbb 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -371,9 +371,14 @@ ir_to_mesa_visitor::visit(ir_expression *ir) /* Storage for our result. Ideally for an assignment we'd be using * the actual storage for the result here, instead. */ - result_src = get_temp(4); + result_src = get_temp(ir->type->vector_elements); /* convenience for the emit functions below. */ result_dst = ir_to_mesa_dst_reg_from_src(result_src); + /* Limit writes to the channels that will be used by result_src later. + * This does limit this temp's use as a temporary for multi-instruction + * sequences. + */ + result_dst.writemask = (1 << ir->type->vector_elements) - 1; switch (ir->operation) { case ir_unop_logic_not: -- cgit v1.2.3 From 2401338ef8ba73e8a0b85ea1129a8e6127842117 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 09:29:29 -0700 Subject: ir_to_mesa: Remove old monoburg structure. --- ir_to_mesa.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/ir_to_mesa.h b/ir_to_mesa.h index b05b9ebc7ae..839d36964f0 100644 --- a/ir_to_mesa.h +++ b/ir_to_mesa.h @@ -61,25 +61,6 @@ public: ir_instruction *ir; }; -struct mbtree { - struct mbtree *left; - struct mbtree *right; - void *state; - uint16_t op; - class ir_to_mesa_visitor *v; - - /** Pointer to the ir source this tree came from for debugging */ - ir_instruction *ir; - - ir_to_mesa_dst_reg dst_reg; - - /** - * This is the representation of this tree node's results as a - * source register for its consumer. - */ - ir_to_mesa_src_reg src_reg; -}; - void do_ir_to_mesa(exec_list *instructions); class temp_entry : public exec_node { -- cgit v1.2.3 From 554dbcce77cc7eb38b786c77eee87a5f391b090b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 09:31:46 -0700 Subject: ir_to_mesa: Move the classes into the file now that we don't have the burg. At 1kloc, it doesn't look like I'll want to split the ir_to_mesa file up even once it's feature-complete. Move definitions closer to usage, and prevent rebuilding the world when changing the definitions. --- glsl_parser_extras.h | 2 + ir_to_mesa.cpp | 120 +++++++++++++++++++++++++++++++++++++--- ir_to_mesa.h | 152 --------------------------------------------------- 3 files changed, 115 insertions(+), 159 deletions(-) delete mode 100644 ir_to_mesa.h diff --git a/glsl_parser_extras.h b/glsl_parser_extras.h index 87de9083c06..cfe02e3b0c1 100644 --- a/glsl_parser_extras.h +++ b/glsl_parser_extras.h @@ -134,4 +134,6 @@ extern bool _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, extern const char * _mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target); +void do_ir_to_mesa(exec_list *instructions); + #endif /* GLSL_PARSER_EXTRAS_H */ diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 8a5b2a6dbbb..7a1f206cd41 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -28,16 +28,9 @@ * printing the result */ -/* Quiet compiler warnings due to monoburg not marking functions defined - * in the header as inline. - */ -#define g_new -#define g_error - #include #include "ir.h" #include "ir_visitor.h" -#include "ir_to_mesa.h" #include "ir_print_visitor.h" #include "ir_expression_flattening.h" #include "glsl_types.h" @@ -47,6 +40,119 @@ extern "C" { #include "shader/prog_print.h" } +/** + * This struct is a corresponding struct to Mesa prog_src_register, with + * wider fields. + */ +typedef struct ir_to_mesa_src_reg { + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ + int negate; /**< NEGATE_XYZW mask from mesa */ + bool reladdr; /**< Register index should be offset by address reg. */ +} ir_to_mesa_src_reg; + +typedef struct ir_to_mesa_dst_reg { + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int writemask; /**< Bitfield of WRITEMASK_[XYZW] */ +} ir_to_mesa_dst_reg; + +extern ir_to_mesa_src_reg ir_to_mesa_undef; + +class ir_to_mesa_instruction : public exec_node { +public: + enum prog_opcode op; + ir_to_mesa_dst_reg dst_reg; + ir_to_mesa_src_reg src_reg[3]; + /** Pointer to the ir source this tree came from for debugging */ + ir_instruction *ir; +}; + +class temp_entry : public exec_node { +public: + temp_entry(ir_variable *var, int file, int index) + : file(file), index(index), var(var) + { + /* empty */ + } + + int file; + int index; + ir_variable *var; /* variable that maps to this, if any */ +}; + +class ir_to_mesa_visitor : public ir_visitor { +public: + ir_to_mesa_visitor(); + + int next_temp; + int next_constant; + + ir_to_mesa_src_reg get_temp(int size); + + ir_to_mesa_src_reg get_temp_for_var(ir_variable *var); + + struct ir_to_mesa_src_reg src_reg_for_float(float val); + + /** + * \name Visit methods + * + * As typical for the visitor pattern, there must be one \c visit method for + * each concrete subclass of \c ir_instruction. Virtual base classes within + * the hierarchy should not have \c visit methods. + */ + /*@{*/ + virtual void visit(ir_variable *); + virtual void visit(ir_loop *); + virtual void visit(ir_loop_jump *); + virtual void visit(ir_function_signature *); + virtual void visit(ir_function *); + virtual void visit(ir_expression *); + virtual void visit(ir_swizzle *); + virtual void visit(ir_dereference_variable *); + virtual void visit(ir_dereference_array *); + virtual void visit(ir_dereference_record *); + virtual void visit(ir_assignment *); + virtual void visit(ir_constant *); + virtual void visit(ir_call *); + virtual void visit(ir_return *); + virtual void visit(ir_texture *); + virtual void visit(ir_if *); + /*@}*/ + + struct ir_to_mesa_src_reg result; + + /** List of temp_entry */ + exec_list variable_storage; + + /** List of ir_to_mesa_instruction */ + exec_list instructions; + + ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + + ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); + + ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2); + + void ir_to_mesa_emit_scalar_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); +}; + ir_to_mesa_src_reg ir_to_mesa_undef = { PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false, }; diff --git a/ir_to_mesa.h b/ir_to_mesa.h deleted file mode 100644 index 839d36964f0..00000000000 --- a/ir_to_mesa.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -#include "ir.h" -extern "C" { -#include "shader/prog_instruction.h" -}; - -/** - * \file ir_to_mesa.h - * - * Translates the IR to Mesa IR if possible. - */ - -/** - * This struct is a corresponding struct to Mesa prog_src_register, with - * wider fields. - */ -typedef struct ir_to_mesa_src_reg { - int file; /**< PROGRAM_* from Mesa */ - int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ - int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ - int negate; /**< NEGATE_XYZW mask from mesa */ - bool reladdr; /**< Register index should be offset by address reg. */ -} ir_to_mesa_src_reg; - -typedef struct ir_to_mesa_dst_reg { - int file; /**< PROGRAM_* from Mesa */ - int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ - int writemask; /**< Bitfield of WRITEMASK_[XYZW] */ -} ir_to_mesa_dst_reg; - -extern ir_to_mesa_src_reg ir_to_mesa_undef; - -class ir_to_mesa_instruction : public exec_node { -public: - enum prog_opcode op; - ir_to_mesa_dst_reg dst_reg; - ir_to_mesa_src_reg src_reg[3]; - /** Pointer to the ir source this tree came from for debugging */ - ir_instruction *ir; -}; - -void do_ir_to_mesa(exec_list *instructions); - -class temp_entry : public exec_node { -public: - temp_entry(ir_variable *var, int file, int index) - : file(file), index(index), var(var) - { - /* empty */ - } - - int file; - int index; - ir_variable *var; /* variable that maps to this, if any */ -}; - -class ir_to_mesa_visitor : public ir_visitor { -public: - ir_to_mesa_visitor(); - - int next_temp; - int next_constant; - - ir_to_mesa_src_reg get_temp(int size); - - ir_to_mesa_src_reg get_temp_for_var(ir_variable *var); - - struct ir_to_mesa_src_reg src_reg_for_float(float val); - - /** - * \name Visit methods - * - * As typical for the visitor pattern, there must be one \c visit method for - * each concrete subclass of \c ir_instruction. Virtual base classes within - * the hierarchy should not have \c visit methods. - */ - /*@{*/ - virtual void visit(ir_variable *); - virtual void visit(ir_loop *); - virtual void visit(ir_loop_jump *); - virtual void visit(ir_function_signature *); - virtual void visit(ir_function *); - virtual void visit(ir_expression *); - virtual void visit(ir_swizzle *); - virtual void visit(ir_dereference_variable *); - virtual void visit(ir_dereference_array *); - virtual void visit(ir_dereference_record *); - virtual void visit(ir_assignment *); - virtual void visit(ir_constant *); - virtual void visit(ir_call *); - virtual void visit(ir_return *); - virtual void visit(ir_texture *); - virtual void visit(ir_if *); - /*@}*/ - - struct ir_to_mesa_src_reg result; - - /** List of temp_entry */ - exec_list variable_storage; - - /** List of ir_to_mesa_instruction */ - exec_list instructions; - - ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0); - - ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1); - - ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1, - ir_to_mesa_src_reg src2); - - void ir_to_mesa_emit_scalar_op1(ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0); -}; - -extern ir_to_mesa_src_reg ir_to_mesa_undef; -extern ir_to_mesa_dst_reg ir_to_mesa_undef_dst; - -- cgit v1.2.3 From a9b619bb3b96a90d14650771dedaf1db840d70a6 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 09:39:54 -0700 Subject: ir_to_mesa: Set up storage for uniform vars. --- ir_to_mesa.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 7a1f206cd41..56815ac8e1a 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -88,6 +88,9 @@ public: int next_temp; int next_constant; + int next_uniform; + + temp_entry *find_variable_storage(ir_variable *var); ir_to_mesa_src_reg get_temp(int size); @@ -334,13 +337,16 @@ type_size(const struct glsl_type *type) case GLSL_TYPE_INT: case GLSL_TYPE_FLOAT: case GLSL_TYPE_BOOL: - assert(!type->is_matrix()); - /* Regardless of size of vector, it gets a vec4. This is bad - * packing for things like floats, but otherwise arrays become a - * mess. Hopefully a later pass over the code can pack scalars - * down if appropriate. - */ - return 1; + if (type->is_matrix()) { + return 4; /* FINISHME: Not all matrices are 4x4. */ + } else { + /* Regardless of size of vector, it gets a vec4. This is bad + * packing for things like floats, but otherwise arrays become a + * mess. Hopefully a later pass over the code can pack scalars + * down if appropriate. + */ + return 1; + } case GLSL_TYPE_ARRAY: return type_size(type->fields.array) * type->length; case GLSL_TYPE_STRUCT: @@ -354,29 +360,40 @@ type_size(const struct glsl_type *type) } } -ir_to_mesa_src_reg -ir_to_mesa_visitor::get_temp_for_var(ir_variable *var) +temp_entry * +ir_to_mesa_visitor::find_variable_storage(ir_variable *var) { - ir_to_mesa_src_reg src_reg; - + temp_entry *entry; foreach_iter(exec_list_iterator, iter, this->variable_storage) { entry = (temp_entry *)iter.get(); if (entry->var == var) - goto done; + return entry; } - entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); - this->variable_storage.push_tail(entry); + return NULL; +} - next_temp += type_size(var->type); +ir_to_mesa_src_reg +ir_to_mesa_visitor::get_temp_for_var(ir_variable *var) +{ + temp_entry *entry; + ir_to_mesa_src_reg src_reg; + + entry = find_variable_storage(var); + if (!entry) { + entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); + this->variable_storage.push_tail(entry); + + next_temp += type_size(var->type); + } -done: src_reg.file = entry->file; src_reg.index = entry->index; src_reg.swizzle = swizzle_for_size(var->type->vector_elements); + src_reg.reladdr = false; return src_reg; } @@ -384,7 +401,16 @@ done: void ir_to_mesa_visitor::visit(ir_variable *ir) { - (void)ir; + if (ir->mode == ir_var_uniform) { + temp_entry *entry = find_variable_storage(ir); + + if (!entry) { + entry = new temp_entry(ir, PROGRAM_UNIFORM, this->next_uniform); + this->variable_storage.push_tail(entry); + + this->next_uniform += type_size(ir->type); + } + } } void @@ -997,6 +1023,7 @@ ir_to_mesa_visitor::ir_to_mesa_visitor() result.file = PROGRAM_UNDEFINED; next_temp = 1; next_constant = 0; + next_uniform = 0; } static struct prog_src_register -- cgit v1.2.3 From 4006424f5b5b3b189209faf03f2335f45c22b148 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 10:13:18 -0700 Subject: ir_to_mesa: Don't allocate temps for swizzles. We do them in place by actually, you know, swizzling. --- ir_to_mesa.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 56815ac8e1a..53b7337d64b 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -669,9 +669,8 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) */ ir->val->accept(this); - assert(this->result.file != PROGRAM_UNDEFINED); - - src_reg = this->get_temp(4); + src_reg = this->result; + assert(src_reg.file != PROGRAM_UNDEFINED); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { -- cgit v1.2.3 From f4bd7f262e43301158f059af90176a476ffdbf60 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 11:18:51 -0700 Subject: ir_to_mesa: Fix copy-and-wasted second argument to compare expresssion ops. Fixes CorrectParse2.vert assertion due to uninitialized values. --- ir_to_mesa.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 53b7337d64b..afb5ad0e468 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -315,6 +315,7 @@ ir_to_mesa_visitor::get_temp(int size) src_reg.file = PROGRAM_TEMPORARY; src_reg.index = this->next_temp++; + src_reg.reladdr = false; for (i = 0; i < size; i++) swizzle[i] = i; @@ -479,7 +480,7 @@ void ir_to_mesa_visitor::visit(ir_expression *ir) { unsigned int operand; - struct ir_to_mesa_src_reg op[2], temp; + struct ir_to_mesa_src_reg op[2]; struct ir_to_mesa_src_reg result_src; struct ir_to_mesa_dst_reg result_dst; const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1); @@ -514,8 +515,8 @@ ir_to_mesa_visitor::visit(ir_expression *ir) switch (ir->operation) { case ir_unop_logic_not: - temp = src_reg_for_float(0.0); - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, + op[0], src_reg_for_float(0.0)); break; case ir_unop_neg: op[0].negate = ~op[0].negate; @@ -554,23 +555,23 @@ ir_to_mesa_visitor::visit(ir_expression *ir) break; case ir_binop_less: - ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]); break; case ir_binop_greater: - ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]); break; case ir_binop_lequal: - ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]); break; case ir_binop_gequal: - ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]); break; case ir_binop_equal: - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]); break; case ir_binop_logic_xor: case ir_binop_nequal: - ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], temp); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); break; case ir_binop_logic_or: -- cgit v1.2.3 From 76720647566db8126b9f29a0e705ba03ebcdad27 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 16:31:14 -0700 Subject: ir_to_mesa: Handle constant matrices. There's not much to it since we're not actually storing constant data yet. --- ir_to_mesa.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index afb5ad0e468..2ec2b11f03e 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -943,8 +943,6 @@ ir_to_mesa_visitor::visit(ir_constant *ir) { ir_to_mesa_src_reg src_reg; - assert(!ir->type->is_matrix()); - assert(ir->type->base_type == GLSL_TYPE_FLOAT || ir->type->base_type == GLSL_TYPE_UINT || ir->type->base_type == GLSL_TYPE_INT || @@ -957,11 +955,13 @@ ir_to_mesa_visitor::visit(ir_constant *ir) /* FINISHME: Do something with the constant values for now. */ src_reg.file = PROGRAM_CONSTANT; - src_reg.index = this->next_constant++; + src_reg.index = this->next_constant; src_reg.swizzle = SWIZZLE_NOOP; src_reg.reladdr = false; src_reg.negate = 0; + this->next_constant += type_size(ir->type); + this->result = src_reg; } -- cgit v1.2.3 From 8364fc85b8273b4d0f2ecebe7e0085e250d29990 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Jun 2010 16:37:17 -0700 Subject: ir_to_mesa: Handle a limited subset of matrix multiplication. glsl-mvp.vert now generates believable code, and mesa mode fails only 5 tests that master doesn't. I must have left out some asserts... --- ir_to_mesa.cpp | 253 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 137 insertions(+), 116 deletions(-) diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp index 2ec2b11f03e..b496a87df56 100644 --- a/ir_to_mesa.cpp +++ b/ir_to_mesa.cpp @@ -92,9 +92,7 @@ public: temp_entry *find_variable_storage(ir_variable *var); - ir_to_mesa_src_reg get_temp(int size); - - ir_to_mesa_src_reg get_temp_for_var(ir_variable *var); + ir_to_mesa_src_reg get_temp(const glsl_type *type); struct ir_to_mesa_src_reg src_reg_for_float(float val); @@ -180,6 +178,56 @@ static int swizzle_for_size(int size) return size_swizzles[size - 1]; } +/* This list should match up with builtin_variables.h */ +static const struct { + const char *name; + int file; + int index; +} builtin_var_to_mesa_reg[] = { + /* core_vs */ + {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS}, + {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ}, + + /* core_fs */ + {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS}, + {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE}, + {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0}, + {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */ + + /* 110_deprecated_fs */ + {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, + {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1}, + {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC}, + {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */ + + /* 110_deprecated_vs */ + {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS}, + {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL}, + {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0}, + {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1}, + {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0}, + {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1}, + {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2}, + {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3}, + {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4}, + {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5}, + {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6}, + {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7}, + {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */ + {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC}, + /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ + {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0}, + {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0}, + {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1}, + {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1}, + {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC}, + + /* 130_vs */ + /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ + + {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */ +}; + ir_to_mesa_instruction * ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir, enum prog_opcode op, @@ -307,20 +355,22 @@ ir_to_mesa_visitor::src_reg_for_float(float val) * pass over the Mesa IR later. */ ir_to_mesa_src_reg -ir_to_mesa_visitor::get_temp(int size) +ir_to_mesa_visitor::get_temp(const glsl_type *type) { ir_to_mesa_src_reg src_reg; int swizzle[4]; int i; + assert(!type->is_array()); + src_reg.file = PROGRAM_TEMPORARY; - src_reg.index = this->next_temp++; + src_reg.index = type->matrix_columns; src_reg.reladdr = false; - for (i = 0; i < size; i++) + for (i = 0; i < type->vector_elements; i++) swizzle[i] = i; for (; i < 4; i++) - swizzle[i] = size - 1; + swizzle[i] = type->vector_elements - 1; src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]); @@ -377,41 +427,10 @@ ir_to_mesa_visitor::find_variable_storage(ir_variable *var) return NULL; } -ir_to_mesa_src_reg -ir_to_mesa_visitor::get_temp_for_var(ir_variable *var) -{ - temp_entry *entry; - ir_to_mesa_src_reg src_reg; - - entry = find_variable_storage(var); - if (!entry) { - entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp); - this->variable_storage.push_tail(entry); - - next_temp += type_size(var->type); - } - - src_reg.file = entry->file; - src_reg.index = entry->index; - src_reg.swizzle = swizzle_for_size(var->type->vector_elements); - src_reg.reladdr = false; - - return src_reg; -} - void ir_to_mesa_visitor::visit(ir_variable *ir) { - if (ir->mode == ir_var_uniform) { - temp_entry *entry = find_variable_storage(ir); - - if (!entry) { - entry = new temp_entry(ir, PROGRAM_UNIFORM, this->next_uniform); - this->variable_storage.push_tail(entry); - - this->next_uniform += type_size(ir->type); - } - } + (void)ir; } void @@ -497,6 +516,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir) exit(1); } op[operand] = this->result; + + /* Only expression implemented for matrices yet */ + assert(!ir->operands[operand]->type->is_matrix() || + ir->operation == ir_binop_mul); } this->result.file = PROGRAM_UNDEFINED; @@ -504,7 +527,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) /* Storage for our result. Ideally for an assignment we'd be using * the actual storage for the result here, instead. */ - result_src = get_temp(ir->type->vector_elements); + result_src = get_temp(ir->type); /* convenience for the emit functions below. */ result_dst = ir_to_mesa_dst_reg_from_src(result_src); /* Limit writes to the channels that will be used by result_src later. @@ -547,7 +570,34 @@ ir_to_mesa_visitor::visit(ir_expression *ir) ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]); break; case ir_binop_mul: - ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]); + if (ir->operands[0]->type->is_matrix() && + !ir->operands[1]->type->is_matrix()) { + if (ir->operands[0]->type->is_scalar()) { + ir_to_mesa_dst_reg dst_column = result_dst; + ir_to_mesa_src_reg src_column = op[0]; + for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) { + ir_to_mesa_emit_op2(ir, OPCODE_MUL, + dst_column, src_column, op[1]); + dst_column.index++; + src_column.index++; + } + } else { + ir_to_mesa_dst_reg dst_chan = result_dst; + ir_to_mesa_src_reg src_column = op[0]; + ir_to_mesa_src_reg src_chan = op[1]; + for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) { + dst_chan.writemask = (1 << i); + src_chan.swizzle = MAKE_SWIZZLE4(i, i, i, i); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, + dst_chan, src_column, src_chan); + src_column.index++; + } + } + } else { + assert(!ir->operands[0]->type->is_matrix()); + assert(!ir->operands[1]->type->is_matrix()); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]); + } break; case ir_binop_div: ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]); @@ -705,92 +755,63 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) this->result = src_reg; } -/* This list should match up with builtin_variables.h */ -static const struct { - const char *name; - int file; - int index; -} builtin_var_to_mesa_reg[] = { - /* core_vs */ - {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS}, - {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ}, - - /* core_fs */ - {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS}, - {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE}, - {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0}, - {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */ - - /* 110_deprecated_fs */ - {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0}, - {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1}, - {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC}, - {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */ - - /* 110_deprecated_vs */ - {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS}, - {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL}, - {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0}, - {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1}, - {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0}, - {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1}, - {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2}, - {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3}, - {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4}, - {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5}, - {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6}, - {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7}, - {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */ - {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC}, - /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ - {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0}, - {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0}, - {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1}, - {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1}, - {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC}, - - /* 130_vs */ - /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */ - - {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */ -}; - void ir_to_mesa_visitor::visit(ir_dereference_variable *ir) { ir_to_mesa_src_reg src_reg; + temp_entry *entry = find_variable_storage(ir->var); + unsigned int i; + bool var_in; - /* By the time we make it to this stage, matrices should be broken down - * to vectors. - */ - assert(!ir->var->type->is_matrix()); - - if (strncmp(ir->var->name, "gl_", 3) == 0) { - unsigned int i; - bool var_in = (ir->var->mode == ir_var_in || - ir->var->mode == ir_var_inout); + if (!entry) { + switch (ir->var->mode) { + case ir_var_uniform: + entry = new temp_entry(ir->var, PROGRAM_UNIFORM, this->next_uniform); + this->variable_storage.push_tail(entry); - for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { - bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT; + this->next_uniform += type_size(ir->var->type); + break; + case ir_var_in: + case ir_var_out: + case ir_var_inout: + var_in = (ir->var->mode == ir_var_in || + ir->var->mode == ir_var_inout); + + for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) { + bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT; + + if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 && + !(var_in ^ in)) + break; + } + if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) { + printf("Failed to find builtin for %s variable %s\n", + var_in ? "in" : "out", + ir->var->name); + abort(); + } + entry = new temp_entry(ir->var, + builtin_var_to_mesa_reg[i].file, + builtin_var_to_mesa_reg[i].index); + break; + case ir_var_auto: + entry = new temp_entry(ir->var, PROGRAM_TEMPORARY, this->next_temp); + this->variable_storage.push_tail(entry); - if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 && - !(var_in ^ in)) - break; + next_temp += type_size(ir->var->type); + break; } - if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) { - printf("Failed to find builtin for %s variable %s\n", - var_in ? "in" : "out", - ir->var->name); - abort(); + + if (!entry) { + printf("Failed to make storage for %s\n", ir->var->name); + exit(1); } - src_reg.file = builtin_var_to_mesa_reg[i].file; - src_reg.index = builtin_var_to_mesa_reg[i].index; - } else { - src_reg = get_temp_for_var(ir->var); } + src_reg.file = entry->file; + src_reg.index = entry->index; /* If the type is smaller than a vec4, replicate the last channel out. */ - src_reg.swizzle = swizzle_for_size(ir->type->vector_elements); + src_reg.swizzle = swizzle_for_size(ir->var->type->vector_elements); src_reg.reladdr = false; src_reg.negate = 0; @@ -836,7 +857,7 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, this->result); - this->result = get_temp(ir->type->vector_elements); + this->result = get_temp(ir->type); ir_to_mesa_emit_op1(ir, OPCODE_MOV, ir_to_mesa_dst_reg_from_src(this->result), src_reg); -- cgit v1.2.3