diff options
-rw-r--r-- | Makefile.am | 15 | ||||
-rw-r--r-- | ir_to_mesa.cpp | 548 | ||||
-rw-r--r-- | ir_to_mesa.h | 170 | ||||
-rw-r--r-- | main/mtypes.h | 32 | ||||
-rw-r--r-- | mesa/shader/prog_instruction.h | 437 | ||||
-rw-r--r-- | mesa_codegen.brg | 173 | ||||
-rw-r--r-- | program.h | 2 |
7 files changed, 1375 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index a88bf0022a..88d8f0587c 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 0000000000..5cbd451b21 --- /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 0000000000..6154c1ca58 --- /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 f168b6605b..cab5ffde6c 100644 --- a/main/mtypes.h +++ b/main/mtypes.h @@ -36,6 +36,8 @@ #define MAX_DRAW_BUFFERS 8 #define MAX_VARYING 16 +#include <GL/gl.h> + /** * 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 0000000000..2c95d274ca --- /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 <idr@us.ibm.com> + */ + + +#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 0000000000..1f6ccfaf0c --- /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 <eric@anholt.net> + * + */ + +/* DO NOT EDIT mesa_codegen.h. It is a generated file produced + * from mesa_codegen.brg and will be overwritten. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> + +/* 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); +} + +%% @@ -22,6 +22,7 @@ */ #include <GL/gl.h> +#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 |