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