Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  51. class lower_discard_flow_visitor : public ir_hierarchical_visitor {
  52. public:
  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.  
  74. ir_visitor_status
  75. lower_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.  
  85. ir_visitor_status
  86. lower_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.  
  96. ir_visitor_status
  97. lower_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.  
  104. ir_visitor_status
  105. lower_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.  
  118. ir_if *
  119. lower_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.  
  130. void
  131. lower_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.