i965/vec4: Simplify opt_reduce_swizzle() using the swizzle utils.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_lower_texture_gradients.cpp
index dfbb983b726c55a3c67082e3988b4c1da48a4530..0424003ffd504948cb6bbacb30d9ab961130ce36 100644 (file)
 
 #include "glsl/ir.h"
 #include "glsl/ir_builder.h"
+#include "program/prog_instruction.h"
+#include "brw_context.h"
 
 using namespace ir_builder;
 
 class lower_texture_grad_visitor : public ir_hierarchical_visitor {
 public:
-   lower_texture_grad_visitor()
+   lower_texture_grad_visitor(bool has_sample_d_c)
+      : has_sample_d_c(has_sample_d_c)
    {
       progress = false;
    }
@@ -41,6 +44,7 @@ public:
 
 
    bool progress;
+   bool has_sample_d_c;
 
 private:
    void emit(ir_variable *, ir_rvalue *);
@@ -73,7 +77,7 @@ txs_type(const glsl_type *type)
       dims = 3;
       break;
    default:
-      assert(!"Should not get here: invalid sampler dimensionality");
+      unreachable("Should not get here: invalid sampler dimensionality");
    }
 
    if (type->sampler_array)
@@ -89,8 +93,20 @@ lower_texture_grad_visitor::visit_leave(ir_texture *ir)
    if (ir->op != ir_txd || !ir->shadow_comparitor)
       return visit_continue;
 
-   /* Cubes are broken.  Avoid assertion failures when swizzling. */
-   if (ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE)
+   /* Lower textureGrad() with samplerCubeShadow even if we have the sample_d_c
+    * message.  GLSL provides gradients for the 'r' coordinate.  Unfortunately:
+    *
+    * From the Ivybridge PRM, Volume 4, Part 1, sample_d message description:
+    * "The r coordinate contains the faceid, and the r gradients are ignored
+    *  by hardware."
+    *
+    * We likely need to do a similar treatment for samplerCube and
+    * samplerCubeArray, but we have insufficient testing for that at the moment.
+    */
+   bool need_lowering = !has_sample_d_c ||
+      ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE;
+
+   if (!need_lowering)
       return visit_continue;
 
    void *mem_ctx = ralloc_parent(ir);
@@ -106,8 +122,16 @@ lower_texture_grad_visitor::visit_leave(ir_texture *ir)
    txs->lod_info.lod = new(mem_ctx) ir_constant(0);
    ir_variable *size =
       new(mem_ctx) ir_variable(grad_type, "size", ir_var_temporary);
-   emit(size, expr(ir_unop_i2f,
-                  swizzle_for_size(txs, grad_type->vector_elements)));
+   if (ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE) {
+      base_ir->insert_before(size);
+      base_ir->insert_before(assign(size,
+                                    swizzle_for_size(expr(ir_unop_i2f, txs), 2),
+                                    WRITEMASK_XY));
+      base_ir->insert_before(assign(size, new(mem_ctx) ir_constant(1.0f), WRITEMASK_Z));
+   } else {
+      emit(size, expr(ir_unop_i2f,
+                      swizzle_for_size(txs, grad_type->vector_elements)));
+   }
 
    /* Scale the gradients by width and height.  Effectively, the incoming
     * gradients are s'(x,y), t'(x,y), and r'(x,y) from equation 3.19 in the
@@ -142,9 +166,11 @@ lower_texture_grad_visitor::visit_leave(ir_texture *ir)
 extern "C" {
 
 bool
-brw_lower_texture_gradients(struct exec_list *instructions)
+brw_lower_texture_gradients(struct brw_context *brw,
+                            struct exec_list *instructions)
 {
-   lower_texture_grad_visitor v;
+   bool has_sample_d_c = brw->gen >= 8 || brw->is_haswell;
+   lower_texture_grad_visitor v(has_sample_d_c);
 
    visit_list_elements(&v, instructions);