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