Support for user-defined structures.
authorBrian <brian@yutani.localnet.net>
Wed, 21 Mar 2007 21:40:39 +0000 (15:40 -0600)
committerBrian <brian@yutani.localnet.net>
Wed, 21 Mar 2007 21:40:39 +0000 (15:40 -0600)
struct == and != operators not finished yet.  Struct assignment works though.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.h

index 45868c725d8045e195ed942a92c9e4157af0bca2..89a891562eaa77000d456d81e17a628680e05aa0 100644 (file)
@@ -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;
 
index 25c107d1cccfd5d7be9880c2779ebb031f6e17ec..e578c8299540413596c57d5ec20e083f91eff489 100644 (file)
@@ -770,6 +770,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.
  */
@@ -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);
 
index b733d100ddc3e979662e2eecd938d3bdac0e7d8d..3c5526e3c547ad2c5a8e1b4175c15c042c064e45 100644 (file)
@@ -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 */