diff options
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 69 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 72 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_ir.h | 1 |
3 files changed, 119 insertions, 23 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 45868c725d8..89a891562ea 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -78,6 +78,35 @@ is_sampler_type(const slang_fully_specified_type *t) } +/** + * Return the offset (in floats or ints) of the named field within + * the given struct. Return -1 if field not found. + * If field is NULL, return the size of the struct instead. + */ +static GLint +_slang_field_offset(const slang_type_specifier *spec, slang_atom field) +{ + GLint offset = 0; + GLuint i; + for (i = 0; i < spec->_struct->fields->num_variables; i++) { + const slang_variable *v = spec->_struct->fields->variables[i]; + const GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier); + if (sz > 1) { + /* types larger than 1 float are register (4-float) aligned */ + offset = (offset + 3) & ~3; + } + if (field && v->a_name == field) { + return offset; + } + offset += sz; + } + if (field) + return -1; /* field not found */ + else + return offset; /* struct size */ +} + + GLuint _slang_sizeof_type_specifier(const slang_type_specifier *spec) { @@ -122,20 +151,9 @@ _slang_sizeof_type_specifier(const slang_type_specifier *spec) case SLANG_SPEC_SAMPLER2DSHADOW: case SLANG_SPEC_SAMPLER2DRECT: case SLANG_SPEC_SAMPLER2DRECTSHADOW: - return 1; /* special case */ + return 1; /* a sampler is basically just an integer index */ case SLANG_SPEC_STRUCT: - { - GLuint sum = 0, i; - for (i = 0; i < spec->_struct->fields->num_variables; i++) { - slang_variable *v = spec->_struct->fields->variables[i]; - GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier); - /* XXX verify padding */ - if (sz < 4) - sz = 4; - sum += sz; - } - return sum; - } + return _slang_field_offset(spec, 0); /* special use */ case SLANG_SPEC_ARRAY: return _slang_sizeof_type_specifier(spec->_array); default: @@ -2034,6 +2052,7 @@ _slang_gen_field(slang_assemble_ctx * A, slang_operation *oper) { slang_typeinfo ti; + /* type of struct */ slang_typeinfo_construct(&ti); _slang_typeof_operation(A, &oper->children[0], &ti); @@ -2079,20 +2098,38 @@ _slang_gen_field(slang_assemble_ctx * A, slang_operation *oper) /* oper->children[0] is the base */ /* oper->a_id is the field name */ slang_ir_node *base, *n; - GLint size = 4; /* XXX fix? */ + slang_typeinfo field_ti; + GLint fieldSize, fieldOffset; + /* type of field */ + slang_typeinfo_construct(&field_ti); + _slang_typeof_operation(A, oper, &field_ti); + + fieldSize = _slang_sizeof_type_specifier(&field_ti.spec); + fieldOffset = _slang_field_offset(&ti.spec, oper->a_id); + + if (fieldOffset < 0) { + slang_info_log_error(A->log, + "\"%s\" is not a member of struct \"%s\"", + (char *) oper->a_id, + (char *) ti.spec._struct->a_name); + return NULL; + } + assert(fieldSize >= 0); base = _slang_gen_operation(A, &oper->children[0]); if (!base) { - /* error previously found */ + /* error msg should have already been logged */ return NULL; } n = new_node1(IR_FIELD, base); if (n) { n->Field = (char *) oper->a_id; + n->FieldOffset = fieldOffset; + assert(n->FieldOffset >= 0); n->Store = _slang_new_ir_storage(base->Store->File, base->Store->Index, - size); + fieldSize); } return n; diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 25c107d1ccc..e578c829954 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -771,6 +771,53 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) /** + * Emit code for == and != operators. These could normally be handled + * by emit_arith() except we need to be able to handle structure comparisons. + */ +static struct prog_instruction * +emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_SEQUAL || n->Opcode == IR_SNEQUAL); + + /* gen code for children */ + emit(emitInfo, n->Children[0]); + emit(emitInfo, n->Children[1]); + + assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size); + + /* gen this instruction and src registers */ + inst = new_instruction(emitInfo, + (n->Opcode == IR_SEQUAL) ? OPCODE_SEQ : OPCODE_SNE); + if (n->Children[0]->Store->Size > 4) { + /* struct compare */ + _mesa_problem(NULL, "struct compare not implemented!"); + return NULL; + } + else { + /* small/simple types */ + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); + storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store); + } + + /* free temps */ + free_temp_storage(emitInfo->vt, n->Children[0]); + free_temp_storage(emitInfo->vt, n->Children[1]); + + /* result storage */ + if (!n->Store) { + if (!alloc_temp_storage(emitInfo, n, 1)) /* 1 bool */ + return NULL; + } + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); + + return inst; +} + + + +/** * Generate code for an IR_CLAMP instruction. */ static struct prog_instruction * @@ -1337,7 +1384,6 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) return NULL; } - if (n->Children[1]->Opcode == IR_FLOAT) { /* Constant index */ const GLint arrayAddr = n->Children[0]->Store->Index; @@ -1365,7 +1411,16 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); } else { - _mesa_problem(NULL, "structs/fields not supported yet"); + GLint offset = n->FieldOffset / 4; + assert(n->Children[0]->Store->Index >= 0); + n->Store->Index = n->Children[0]->Store->Index + offset; + if (n->Store->Size == 1) { + GLint swz = n->FieldOffset % 4; + n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); + } + else { + n->Store->Swizzle = SWIZZLE_XYZW; + } } return NULL; /* no instruction */ } @@ -1427,10 +1482,10 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) if (emitInfo->EmitComments) { /* emit NOP with comment describing the variable's storage location */ char s[1000]; - sprintf(s, "TEMP[%d]%s = %s (size %d)", + sprintf(s, "TEMP[%d]%s = variable %s (size %d)", n->Store->Index, _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), - (char *) n->Var->a_name, + (n->Var ? (char *) n->Var->a_name : "anonymous"), n->Store->Size); inst = new_instruction(emitInfo, OPCODE_NOP); inst->Comment = _mesa_strdup(s); @@ -1503,8 +1558,6 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) case IR_CROSS: case IR_MIN: case IR_MAX: - case IR_SEQUAL: - case IR_SNEQUAL: case IR_SGE: case IR_SGT: case IR_SLE: @@ -1515,6 +1568,11 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) /* trinary operators */ case IR_LRP: return emit_arith(emitInfo, n); + + case IR_SEQUAL: + case IR_SNEQUAL: + return emit_compare(emitInfo, n); + case IR_CLAMP: return emit_clamp(emitInfo, n); case IR_TEX: @@ -1600,7 +1658,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt, emitInfo.prog = prog; emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; - emitInfo.EmitComments = ctx->Shader.EmitComments; + emitInfo.EmitComments = 1+ctx->Shader.EmitComments; (void) emit(&emitInfo, n); diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index b733d100ddc..3c5526e3c54 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -152,6 +152,7 @@ typedef struct slang_ir_node_ /** special fields depending on Opcode: */ const char *Field; /**< If Opcode == IR_FIELD */ + int FieldOffset; /**< If Opcode == IR_FIELD */ GLuint Writemask; /**< If Opcode == IR_MOVE */ GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ |