lower_distance.cpp revision 065da16508731f6b6a98865f392509be4f9ce07f
1c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/*
2c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Copyright © 2011 Intel Corporation
3c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
4c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Permission is hereby granted, free of charge, to any person obtaining a
5c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * copy of this software and associated documentation files (the "Software"),
6c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * to deal in the Software without restriction, including without limitation
7c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * and/or sell copies of the Software, and to permit persons to whom the
9c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Software is furnished to do so, subject to the following conditions:
10c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
11c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * The above copyright notice and this permission notice (including the next
12c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * paragraph) shall be included in all copies or substantial portions of the
13c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Software.
14c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
15c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * DEALINGS IN THE SOFTWARE.
22c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
23c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
24c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
25c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * \file lower_clip_distance.cpp
26c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
27c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * This pass accounts for the difference between the way
28c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * gl_ClipDistance is declared in standard GLSL (as an array of
29c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * floats), and the way it is frequently implemented in hardware (as
30c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * a pair of vec4s, with four clip distances packed into each).
31c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
32c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * The declaration of gl_ClipDistance is replaced with a declaration
33c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * of gl_ClipDistanceMESA, and any references to gl_ClipDistance are
34c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * translated to refer to gl_ClipDistanceMESA with the appropriate
35c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * swizzling of array indices.  For instance:
36c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
37c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *   gl_ClipDistance[i]
38c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
39c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * is translated into:
40c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
41c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *   gl_ClipDistanceMESA[i>>2][i&3]
42c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
43c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Since some hardware may not internally represent gl_ClipDistance as a pair
44c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * of vec4's, this lowering pass is optional.  To enable it, set the
45c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * LowerClipDistance flag in gl_shader_compiler_options to true.
46c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
47c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
4818392443d448e083187d085965375e7de910b18aPaul Berry#include "glsl_symbol_table.h"
49065da16508731f6b6a98865f392509be4f9ce07fIan Romanick#include "ir_rvalue_visitor.h"
50c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry#include "ir.h"
51c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
52065da16508731f6b6a98865f392509be4f9ce07fIan Romanickclass lower_clip_distance_visitor : public ir_rvalue_visitor {
53c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrypublic:
54c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   lower_clip_distance_visitor()
55c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      : progress(false), old_clip_distance_var(NULL),
56c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry        new_clip_distance_var(NULL)
57c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   {
58c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
59c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
60c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   virtual ir_visitor_status visit(ir_variable *);
61c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   void create_indices(ir_rvalue*, ir_rvalue *&, ir_rvalue *&);
62c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   virtual ir_visitor_status visit_leave(ir_assignment *);
63c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   void visit_new_assignment(ir_assignment *ir);
64c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   virtual ir_visitor_status visit_leave(ir_call *);
65c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
66065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   virtual void handle_rvalue(ir_rvalue **rvalue);
67065da16508731f6b6a98865f392509be4f9ce07fIan Romanick
68c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   bool progress;
69c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
70c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   /**
71c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    * Pointer to the declaration of gl_ClipDistance, if found.
72c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    */
73c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_variable *old_clip_distance_var;
74c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
75c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   /**
76c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    * Pointer to the newly-created gl_ClipDistanceMESA variable.
77c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    */
78c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_variable *new_clip_distance_var;
79c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry};
80c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
81c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
82c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
83c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Replace any declaration of gl_ClipDistance as an array of floats with a
84c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * declaration of gl_ClipDistanceMESA as an array of vec4's.
85c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
86c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berryir_visitor_status
87c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrylower_clip_distance_visitor::visit(ir_variable *ir)
88c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
89c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   /* No point in looking for the declaration of gl_ClipDistance if
90c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    * we've already found it.
91c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    */
92c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if (this->old_clip_distance_var)
93c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      return visit_continue;
94c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
95c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if (ir->name && strcmp(ir->name, "gl_ClipDistance") == 0) {
96c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->progress = true;
97c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->old_clip_distance_var = ir;
98c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      assert (ir->type->is_array());
99c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      assert (ir->type->element_type() == glsl_type::float_type);
100c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      unsigned new_size = (ir->type->array_size() + 3) / 4;
101c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
102c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* Clone the old var so that we inherit all of its properties */
103c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->new_clip_distance_var = ir->clone(ralloc_parent(ir), NULL);
104c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
105c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* And change the properties that we need to change */
106c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->new_clip_distance_var->name
107c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         = ralloc_strdup(this->new_clip_distance_var, "gl_ClipDistanceMESA");
108c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->new_clip_distance_var->type
109c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         = glsl_type::get_array_instance(glsl_type::vec4_type, new_size);
110c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->new_clip_distance_var->max_array_access = ir->max_array_access / 4;
111c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
112c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir->replace_with(this->new_clip_distance_var);
113c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
114c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   return visit_continue;
115c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
116c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
117c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
118c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
119c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Create the necessary GLSL rvalues to index into gl_ClipDistanceMESA based
120c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * on the rvalue previously used to index into gl_ClipDistance.
121c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *
122c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * \param array_index Selects one of the vec4's in gl_ClipDistanceMESA
123c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * \param swizzle_index Selects a component within the vec4 selected by
124c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry *        array_index.
125c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
126c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berryvoid
127c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrylower_clip_distance_visitor::create_indices(ir_rvalue *old_index,
128c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry                                            ir_rvalue *&array_index,
129c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry                                            ir_rvalue *&swizzle_index)
130c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
131c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   void *ctx = ralloc_parent(old_index);
132c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
133c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   /* Make sure old_index is a signed int so that the bitwise "shift" and
134c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    * "and" operations below type check properly.
135c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    */
136c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if (old_index->type != glsl_type::int_type) {
137c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      assert (old_index->type == glsl_type::uint_type);
138c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      old_index = new(ctx) ir_expression(ir_unop_u2i, old_index);
139c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
140c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
141c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_constant *old_index_constant = old_index->constant_expression_value();
142c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if (old_index_constant) {
143c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* gl_ClipDistance is being accessed via a constant index.  Don't bother
144c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * creating expressions to calculate the lowered indices.  Just create
145c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * constants.
146c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
147c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      int const_val = old_index_constant->get_int_component(0);
148c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      array_index = new(ctx) ir_constant(const_val / 4);
149c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      swizzle_index = new(ctx) ir_constant(const_val % 4);
150c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   } else {
151c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* Create a variable to hold the value of old_index (so that we
152c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * don't compute it twice).
153c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
154c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_variable *old_index_var = new(ctx) ir_variable(
155c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         glsl_type::int_type, "clip_distance_index", ir_var_temporary);
156c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->base_ir->insert_before(old_index_var);
157c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->base_ir->insert_before(new(ctx) ir_assignment(
158c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         new(ctx) ir_dereference_variable(old_index_var), old_index));
159c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
160c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* Create the expression clip_distance_index / 4.  Do this as a bit
161c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * shift because that's likely to be more efficient.
162c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
163c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      array_index = new(ctx) ir_expression(
164c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         ir_binop_rshift, new(ctx) ir_dereference_variable(old_index_var),
165c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         new(ctx) ir_constant(2));
166c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
167c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* Create the expression clip_distance_index % 4.  Do this as a bitwise
168c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * AND because that's likely to be more efficient.
169c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
170c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      swizzle_index = new(ctx) ir_expression(
171c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         ir_binop_bit_and, new(ctx) ir_dereference_variable(old_index_var),
172c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         new(ctx) ir_constant(3));
173c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
174c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
175c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
176c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
177065da16508731f6b6a98865f392509be4f9ce07fIan Romanickvoid
178065da16508731f6b6a98865f392509be4f9ce07fIan Romanicklower_clip_distance_visitor::handle_rvalue(ir_rvalue **rv)
179c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
180c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   /* If the gl_ClipDistance var hasn't been declared yet, then
181c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    * there's no way this deref can refer to it.
182c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry    */
183065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   if (!this->old_clip_distance_var || *rv == NULL)
184065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      return;
185c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
186065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   ir_dereference_array *const array_deref = (*rv)->as_dereference_array();
187065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   if (array_deref == NULL)
188065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      return;
189065da16508731f6b6a98865f392509be4f9ce07fIan Romanick
190065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   /* Replace any expression that indexes into the gl_ClipDistance array
191065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    * with an expression that indexes into one of the vec4's in
192065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    * gl_ClipDistanceMESA and accesses the appropriate component.
193065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    */
194065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   ir_dereference_variable *old_var_ref =
195065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      array_deref->array->as_dereference_variable();
196c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if (old_var_ref && old_var_ref->var == this->old_clip_distance_var) {
197c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      this->progress = true;
198c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_rvalue *array_index;
199c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_rvalue *swizzle_index;
200065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      this->create_indices(array_deref->array_index, array_index, swizzle_index);
201065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      void *mem_ctx = ralloc_parent(array_deref);
202065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      array_deref->array = new(mem_ctx) ir_dereference_array(
203c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         this->new_clip_distance_var, array_index);
204065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      array_deref->array_index = swizzle_index;
205c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
206c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
207c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
208c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
209c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
210c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Replace any assignment having gl_ClipDistance (undereferenced) as its LHS
211c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * or RHS with a sequence of assignments, one for each component of the array.
212c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Each of these assignments is lowered to refer to gl_ClipDistanceMESA as
213c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * appropriate.
214c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
215c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berryir_visitor_status
216c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrylower_clip_distance_visitor::visit_leave(ir_assignment *ir)
217c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
218c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_dereference_variable *lhs_var = ir->lhs->as_dereference_variable();
219c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_dereference_variable *rhs_var = ir->rhs->as_dereference_variable();
220c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   if ((lhs_var && lhs_var->var == this->old_clip_distance_var)
221c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       || (rhs_var && rhs_var->var == this->old_clip_distance_var)) {
222c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* LHS or RHS of the assignment is the entire gl_ClipDistance array.
223c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * Since we are reshaping gl_ClipDistance from an array of floats to an
224c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * array of vec4's, this isn't going to work as a bulk assignment
225c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * anymore, so unroll it to element-by-element assignments and lower
226c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * each of them.
227c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       *
228c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * Note: to unroll into element-by-element assignments, we need to make
229c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * clones of the LHS and RHS.  This is only safe if the LHS and RHS are
230c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * side-effect free.  Fortunately, we know that they are, because the
231c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * only kind of rvalue that can have side effects is an ir_call, and
232c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * ir_calls only appear (a) as a statement on their own, or (b) as the
233c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * RHS of an assignment that stores the result of the call in a
234c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * temporary variable.
235c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
236c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      void *ctx = ralloc_parent(ir);
237c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      int array_size = this->old_clip_distance_var->type->array_size();
238c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      for (int i = 0; i < array_size; ++i) {
239c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         ir_dereference_array *new_lhs = new(ctx) ir_dereference_array(
240c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            ir->lhs->clone(ctx, NULL), new(ctx) ir_constant(i));
241065da16508731f6b6a98865f392509be4f9ce07fIan Romanick         this->handle_rvalue((ir_rvalue **) &new_lhs);
242c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         ir_dereference_array *new_rhs = new(ctx) ir_dereference_array(
243c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            ir->rhs->clone(ctx, NULL), new(ctx) ir_constant(i));
244065da16508731f6b6a98865f392509be4f9ce07fIan Romanick         this->handle_rvalue((ir_rvalue **) &new_rhs);
245c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         this->base_ir->insert_before(
246c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            new(ctx) ir_assignment(new_lhs, new_rhs));
247c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      }
248c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir->remove();
249065da16508731f6b6a98865f392509be4f9ce07fIan Romanick
250065da16508731f6b6a98865f392509be4f9ce07fIan Romanick      return visit_continue;
251c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
252c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
253065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   /* Handle the LHS as if it were an r-value.  Normally
254065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    * rvalue_visit(ir_assignment *) only visits the RHS, but we need to lower
255065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    * expressions in the LHS as well.
256065da16508731f6b6a98865f392509be4f9ce07fIan Romanick    */
257065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   handle_rvalue((ir_rvalue **)&ir->lhs);
258065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   return rvalue_visit(ir);
259c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
260c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
261c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
262c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
263c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * Set up base_ir properly and call visit_leave() on a newly created
264c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * ir_assignment node.  This is used in cases where we have to insert an
265c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * ir_assignment in a place where we know the hierarchical visitor won't see
266c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * it.
267c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
268c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berryvoid
269c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrylower_clip_distance_visitor::visit_new_assignment(ir_assignment *ir)
270c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
271c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir_instruction *old_base_ir = this->base_ir;
272c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   this->base_ir = ir;
273c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   ir->accept(this);
274c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   this->base_ir = old_base_ir;
275c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
276c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
277c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
278c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry/**
279c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * If gl_ClipDistance appears as an argument in an ir_call expression, replace
280c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * it with a temporary variable, and make sure the ir_call is preceded and/or
281c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * followed by assignments that copy the contents of the temporary variable to
282c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * and/or from gl_ClipDistance.  Each of these assignments is then lowered to
283c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry * refer to gl_ClipDistanceMESA.
284c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry */
285c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berryir_visitor_status
286c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrylower_clip_distance_visitor::visit_leave(ir_call *ir)
287c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
288c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   void *ctx = ralloc_parent(ir);
289c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
29082065fa20ee3f2880a070f1f4f75509b910ceddeKenneth Graunke   const exec_node *formal_param_node = ir->callee->parameters.head;
291c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   const exec_node *actual_param_node = ir->actual_parameters.head;
292c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   while (!actual_param_node->is_tail_sentinel()) {
293c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_variable *formal_param = (ir_variable *) formal_param_node;
294c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_rvalue *actual_param = (ir_rvalue *) actual_param_node;
295c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
296c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      /* Advance formal_param_node and actual_param_node now so that we can
297c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       * safely replace actual_param with another node, if necessary, below.
298c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry       */
299c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      formal_param_node = formal_param_node->next;
300c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      actual_param_node = actual_param_node->next;
301c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
302c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      ir_dereference_variable *deref = actual_param->as_dereference_variable();
303c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      if (deref && deref->var == this->old_clip_distance_var) {
304c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         /* User is trying to pass the whole gl_ClipDistance array to a
305c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry          * function call.  Since we are reshaping gl_ClipDistance from an
306c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry          * array of floats to an array of vec4's, this isn't going to work
307c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry          * anymore, so use a temporary array instead.
308c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry          */
309c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         ir_variable *temp_clip_distance = new(ctx) ir_variable(
310c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            actual_param->type, "temp_clip_distance", ir_var_temporary);
311c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         this->base_ir->insert_before(temp_clip_distance);
312c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         actual_param->replace_with(
313c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            new(ctx) ir_dereference_variable(temp_clip_distance));
31442a29d89fd85c86387f0d119950e243b6de76d79Paul Berry         if (formal_param->mode == ir_var_function_in
31542a29d89fd85c86387f0d119950e243b6de76d79Paul Berry             || formal_param->mode == ir_var_function_inout) {
316c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            /* Copy from gl_ClipDistance to the temporary before the call.
317c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * Since we are going to insert this copy before the current
318c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * instruction, we need to visit it afterwards to make sure it
319c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * gets lowered.
320c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             */
321c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            ir_assignment *new_assignment = new(ctx) ir_assignment(
322c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry               new(ctx) ir_dereference_variable(temp_clip_distance),
323c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry               new(ctx) ir_dereference_variable(old_clip_distance_var));
324c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            this->base_ir->insert_before(new_assignment);
325c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            this->visit_new_assignment(new_assignment);
326c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         }
32742a29d89fd85c86387f0d119950e243b6de76d79Paul Berry         if (formal_param->mode == ir_var_function_out
32842a29d89fd85c86387f0d119950e243b6de76d79Paul Berry             || formal_param->mode == ir_var_function_inout) {
329c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            /* Copy from the temporary to gl_ClipDistance after the call.
330c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * Since visit_list_elements() has already decided which
331c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * instruction it's going to visit next, we need to visit
332c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             * afterwards to make sure it gets lowered.
333c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry             */
334c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            ir_assignment *new_assignment = new(ctx) ir_assignment(
335c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry               new(ctx) ir_dereference_variable(old_clip_distance_var),
336c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry               new(ctx) ir_dereference_variable(temp_clip_distance));
337c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            this->base_ir->insert_after(new_assignment);
338c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry            this->visit_new_assignment(new_assignment);
339c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry         }
340c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry      }
341c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   }
342c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
343065da16508731f6b6a98865f392509be4f9ce07fIan Romanick   return rvalue_visit(ir);
344c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
345c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
346c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
347c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berrybool
34818392443d448e083187d085965375e7de910b18aPaul Berrylower_clip_distance(gl_shader *shader)
349c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry{
350c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   lower_clip_distance_visitor v;
351c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
35218392443d448e083187d085965375e7de910b18aPaul Berry   visit_list_elements(&v, shader->ir);
35318392443d448e083187d085965375e7de910b18aPaul Berry
35418392443d448e083187d085965375e7de910b18aPaul Berry   if (v.new_clip_distance_var)
35518392443d448e083187d085965375e7de910b18aPaul Berry      shader->symbols->add_variable(v.new_clip_distance_var);
356c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry
357c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry   return v.progress;
358c06e32596735074536b0e613cbddb1c5fd7b367aPaul Berry}
359