i965: Add support for builtin uniforms to the new FS backend.
authorEric Anholt <eric@anholt.net>
Tue, 28 Sep 2010 23:23:04 +0000 (16:23 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 28 Sep 2010 23:31:10 +0000 (16:31 -0700)
Fixes 8 piglit tests.

src/mesa/drivers/dri/i965/brw_fs.cpp

index 4f5ca4e9fe65ec64f84e7935c6d9c11a357b1d46..2ecacb564646f188fbacf2af0365364ecc22d57f 100644 (file)
@@ -31,6 +31,7 @@ extern "C" {
 
 #include "main/macros.h"
 #include "main/shaderobj.h"
+#include "main/uniforms.h"
 #include "program/prog_parameter.h"
 #include "program/prog_print.h"
 #include "program/prog_optimize.h"
@@ -461,6 +462,7 @@ public:
 
    struct brw_reg interp_reg(int location, int channel);
    int setup_uniform_values(int loc, const glsl_type *type);
+   void setup_builtin_uniform_values(ir_variable *ir);
 
    struct brw_context *brw;
    const struct gl_fragment_program *fp;
@@ -607,6 +609,69 @@ fs_visitor::setup_uniform_values(int loc, const glsl_type *type)
    }
 }
 
+
+/* Our support for builtin uniforms is even scarier than non-builtin.
+ * It sits on top of the PROG_STATE_VAR parameters that are
+ * automatically updated from GL context state.
+ */
+void
+fs_visitor::setup_builtin_uniform_values(ir_variable *ir)
+{
+   const struct gl_builtin_uniform_desc *statevar = NULL;
+
+   for (unsigned int i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
+      statevar = &_mesa_builtin_uniform_desc[i];
+      if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
+        break;
+   }
+
+   if (!statevar->name) {
+      this->fail = true;
+      printf("Failed to find builtin uniform `%s'\n", ir->name);
+      return;
+   }
+
+   int array_count;
+   if (ir->type->is_array()) {
+      array_count = ir->type->length;
+   } else {
+      array_count = 1;
+   }
+
+   for (int a = 0; a < array_count; a++) {
+      for (unsigned int i = 0; i < statevar->num_elements; i++) {
+        struct gl_builtin_uniform_element *element = &statevar->elements[i];
+        int tokens[STATE_LENGTH];
+
+        memcpy(tokens, element->tokens, sizeof(element->tokens));
+        if (ir->type->is_array()) {
+           tokens[1] = a;
+        }
+
+        /* This state reference has already been setup by ir_to_mesa,
+         * but we'll get the same index back here.
+         */
+        int index = _mesa_add_state_reference(this->fp->Base.Parameters,
+                                              (gl_state_index *)tokens);
+        float *vec_values = this->fp->Base.Parameters->ParameterValues[index];
+
+        /* Add each of the unique swizzles of the element as a
+         * parameter.  This'll end up matching the expected layout of
+         * the array/matrix/structure we're trying to fill in.
+         */
+        int last_swiz = -1;
+        for (unsigned int i = 0; i < 4; i++) {
+           int this_swiz = GET_SWZ(element->swizzle, i);
+           if (this_swiz == last_swiz)
+              break;
+           last_swiz = this_swiz;
+
+           c->prog_data.param[c->prog_data.nr_params++] = &vec_values[i];
+        }
+      }
+   }
+}
+
 void
 fs_visitor::emit_fragcoord_interpolation(ir_variable *ir)
 {
@@ -751,7 +816,11 @@ fs_visitor::visit(ir_variable *ir)
    if (ir->mode == ir_var_uniform) {
       int param_index = c->prog_data.nr_params;
 
-      setup_uniform_values(ir->location, ir->type);
+      if (!strncmp(ir->name, "gl_", 3)) {
+        setup_builtin_uniform_values(ir);
+      } else {
+        setup_uniform_values(ir->location, ir->type);
+      }
 
       reg = new(this->mem_ctx) fs_reg(UNIFORM, param_index);
    }