From: Eric Anholt Date: Thu, 29 Apr 2010 16:02:09 +0000 (-0700) Subject: ir_to_mesa: Start building GLSL IR to Mesa IR conversion. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=84771df82ed2ed8718013795089edd38cf5bd84d;p=mesa.git 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. --- 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