Subversion Repositories Kolibri OS

Rev

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. namespace {
  52.  
  53. class lower_discard_flow_visitor : public ir_hierarchical_visitor {
  54. public:
  55.    lower_discard_flow_visitor(ir_variable *discarded)
  56.    : discarded(discarded)
  57.    {
  58.       mem_ctx = ralloc_parent(discarded);
  59.    }
  60.  
  61.    ~lower_discard_flow_visitor()
  62.    {
  63.    }
  64.  
  65.    ir_visitor_status visit_enter(ir_discard *ir);
  66.    ir_visitor_status visit_enter(ir_loop_jump *ir);
  67.    ir_visitor_status visit_enter(ir_loop *ir);
  68.    ir_visitor_status visit_enter(ir_function_signature *ir);
  69.  
  70.    ir_if *generate_discard_break();
  71.  
  72.    ir_variable *discarded;
  73.    void *mem_ctx;
  74. };
  75.  
  76. } /* anonymous namespace */
  77.  
  78. ir_visitor_status
  79. lower_discard_flow_visitor::visit_enter(ir_loop_jump *ir)
  80. {
  81.    if (ir->mode != ir_loop_jump::jump_continue)
  82.       return visit_continue;
  83.  
  84.    ir->insert_before(generate_discard_break());
  85.  
  86.    return visit_continue;
  87. }
  88.  
  89. ir_visitor_status
  90. lower_discard_flow_visitor::visit_enter(ir_discard *ir)
  91. {
  92.    ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(discarded);
  93.    ir_rvalue *rhs;
  94.    if (ir->condition) {
  95.       /* discarded <- condition, use (var_ref discarded) as the condition */
  96.       rhs = ir->condition;
  97.       ir->condition = new(mem_ctx) ir_dereference_variable(discarded);
  98.    } else {
  99.       rhs = new(mem_ctx) ir_constant(true);
  100.    }
  101.    ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, rhs);
  102.    ir->insert_before(assign);
  103.  
  104.    return visit_continue;
  105. }
  106.  
  107. ir_visitor_status
  108. lower_discard_flow_visitor::visit_enter(ir_loop *ir)
  109. {
  110.    ir->body_instructions.push_tail(generate_discard_break());
  111.  
  112.    return visit_continue;
  113. }
  114.  
  115. ir_visitor_status
  116. lower_discard_flow_visitor::visit_enter(ir_function_signature *ir)
  117. {
  118.    if (strcmp(ir->function_name(), "main") != 0)
  119.       return visit_continue;
  120.  
  121.    ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(discarded);
  122.    ir_rvalue *rhs = new(mem_ctx) ir_constant(false);
  123.    ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, rhs);
  124.    ir->body.push_head(assign);
  125.  
  126.    return visit_continue;
  127. }
  128.  
  129. ir_if *
  130. lower_discard_flow_visitor::generate_discard_break()
  131. {
  132.    ir_rvalue *if_condition = new(mem_ctx) ir_dereference_variable(discarded);
  133.    ir_if *if_inst = new(mem_ctx) ir_if(if_condition);
  134.  
  135.    ir_instruction *br = new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break);
  136.    if_inst->then_instructions.push_tail(br);
  137.  
  138.    return if_inst;
  139. }
  140.  
  141. void
  142. lower_discard_flow(exec_list *ir)
  143. {
  144.    void *mem_ctx = ir;
  145.  
  146.    ir_variable *var = new(mem_ctx) ir_variable(glsl_type::bool_type,
  147.                                                "discarded",
  148.                                                ir_var_temporary);
  149.  
  150.    ir->push_head(var);
  151.  
  152.    lower_discard_flow_visitor v(var);
  153.  
  154.    visit_list_elements(&v, ir);
  155. }
  156.