1/* 2 * Copyright © 2010 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24/** @file lower_discard_flow.cpp 25 * 26 * Implements the GLSL 1.30 revision 9 rule for fragment shader 27 * discard handling: 28 * 29 * "Control flow exits the shader, and subsequent implicit or 30 * explicit derivatives are undefined when this control flow is 31 * non-uniform (meaning different fragments within the primitive 32 * take different control paths)." 33 * 34 * There seem to be two conflicting things here. "Control flow exits 35 * the shader" sounds like the discarded fragments should effectively 36 * jump to the end of the shader, but that breaks derivatives in the 37 * case of uniform control flow and causes rendering failure in the 38 * bushes in Unigine Tropics. 39 * 40 * The question, then, is whether the intent was "loops stop at the 41 * point that the only active channels left are discarded pixels" or 42 * "discarded pixels become inactive at the point that control flow 43 * returns to the top of a loop". This implements the second 44 * interpretation. 45 */ 46 47#include "glsl_types.h" 48#include "ir.h" 49#include "program/hash_table.h" 50 51class lower_discard_flow_visitor : public ir_hierarchical_visitor { 52public: 53 lower_discard_flow_visitor(ir_variable *discarded) 54 : discarded(discarded) 55 { 56 mem_ctx = ralloc_parent(discarded); 57 } 58 59 ~lower_discard_flow_visitor() 60 { 61 } 62 63 ir_visitor_status visit_enter(ir_discard *ir); 64 ir_visitor_status visit_enter(ir_loop_jump *ir); 65 ir_visitor_status visit_enter(ir_loop *ir); 66 ir_visitor_status visit_enter(ir_function_signature *ir); 67 68 ir_if *generate_discard_break(); 69 70 ir_variable *discarded; 71 void *mem_ctx; 72}; 73 74ir_visitor_status 75lower_discard_flow_visitor::visit_enter(ir_loop_jump *ir) 76{ 77 if (ir->mode != ir_loop_jump::jump_continue) 78 return visit_continue; 79 80 ir->insert_before(generate_discard_break()); 81 82 return visit_continue; 83} 84 85ir_visitor_status 86lower_discard_flow_visitor::visit_enter(ir_discard *ir) 87{ 88 ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(discarded); 89 ir_rvalue *rhs = new(mem_ctx) ir_constant(true); 90 ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, rhs); 91 ir->insert_before(assign); 92 93 return visit_continue; 94} 95 96ir_visitor_status 97lower_discard_flow_visitor::visit_enter(ir_loop *ir) 98{ 99 ir->body_instructions.push_tail(generate_discard_break()); 100 101 return visit_continue; 102} 103 104ir_visitor_status 105lower_discard_flow_visitor::visit_enter(ir_function_signature *ir) 106{ 107 if (strcmp(ir->function_name(), "main") != 0) 108 return visit_continue; 109 110 ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(discarded); 111 ir_rvalue *rhs = new(mem_ctx) ir_constant(false); 112 ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, rhs); 113 ir->body.push_head(assign); 114 115 return visit_continue; 116} 117 118ir_if * 119lower_discard_flow_visitor::generate_discard_break() 120{ 121 ir_rvalue *if_condition = new(mem_ctx) ir_dereference_variable(discarded); 122 ir_if *if_inst = new(mem_ctx) ir_if(if_condition); 123 124 ir_instruction *br = new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break); 125 if_inst->then_instructions.push_tail(br); 126 127 return if_inst; 128} 129 130void 131lower_discard_flow(exec_list *ir) 132{ 133 void *mem_ctx = ir; 134 135 ir_variable *var = new(mem_ctx) ir_variable(glsl_type::bool_type, 136 "discarded", 137 ir_var_temporary); 138 139 ir->push_head(var); 140 141 lower_discard_flow_visitor v(var); 142 143 visit_list_elements(&v, ir); 144} 145