Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2012 Vincent Lejeune
  3.  * Copyright © 2012 Intel Corporation
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a
  6.  * copy of this software and associated documentation files (the "Software"),
  7.  * to deal in the Software without restriction, including without limitation
  8.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9.  * and/or sell copies of the Software, and to permit persons to whom the
  10.  * Software is furnished to do so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice (including the next
  13.  * paragraph) shall be included in all copies or substantial portions of the
  14.  * Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include "ir.h"
  26. #include "program/hash_table.h"
  27.  
  28. /**
  29.  * \file lower_output_reads.cpp
  30.  *
  31.  * In GLSL, shader output variables (such as varyings) can be both read and
  32.  * written.  However, on some hardware, reading an output register causes
  33.  * trouble.
  34.  *
  35.  * This pass creates temporary shadow copies of every (used) shader output,
  36.  * and replaces all accesses to use those instead.  It also adds code to the
  37.  * main() function to copy the final values to the actual shader outputs.
  38.  */
  39.  
  40. namespace {
  41.  
  42. class output_read_remover : public ir_hierarchical_visitor {
  43. protected:
  44.    /**
  45.     * A hash table mapping from the original ir_variable shader outputs
  46.     * (ir_var_shader_out mode) to the new temporaries to be used instead.
  47.     */
  48.    hash_table *replacements;
  49.  
  50.    void *mem_ctx;
  51. public:
  52.    output_read_remover();
  53.    ~output_read_remover();
  54.    virtual ir_visitor_status visit(class ir_dereference_variable *);
  55.    virtual ir_visitor_status visit_leave(class ir_emit_vertex *);
  56.    virtual ir_visitor_status visit_leave(class ir_return *);
  57.    virtual ir_visitor_status visit_leave(class ir_function_signature *);
  58. };
  59.  
  60. } /* anonymous namespace */
  61.  
  62. /**
  63.  * Hash function for the output variables - computes the hash of the name.
  64.  * NOTE: We're using the name string to ensure that the hash doesn't depend
  65.  * on any random factors, otherwise the output_read_remover could produce
  66.  * the random order of the assignments.
  67.  *
  68.  * NOTE: If you want to reuse this function please take into account that
  69.  * generally the names of the variables are non-unique.
  70.  */
  71. static unsigned
  72. hash_table_var_hash(const void *key)
  73. {
  74.    const ir_variable * var = static_cast<const ir_variable *>(key);
  75.    return hash_table_string_hash(var->name);
  76. }
  77.  
  78. output_read_remover::output_read_remover()
  79. {
  80.    mem_ctx = ralloc_context(NULL);
  81.    replacements =
  82.       hash_table_ctor(0, hash_table_var_hash, hash_table_pointer_compare);
  83. }
  84.  
  85. output_read_remover::~output_read_remover()
  86. {
  87.    hash_table_dtor(replacements);
  88.    ralloc_free(mem_ctx);
  89. }
  90.  
  91. ir_visitor_status
  92. output_read_remover::visit(ir_dereference_variable *ir)
  93. {
  94.    if (ir->var->data.mode != ir_var_shader_out)
  95.       return visit_continue;
  96.  
  97.    ir_variable *temp = (ir_variable *) hash_table_find(replacements, ir->var);
  98.  
  99.    /* If we don't have an existing temporary, create one. */
  100.    if (temp == NULL) {
  101.       void *var_ctx = ralloc_parent(ir->var);
  102.       temp = new(var_ctx) ir_variable(ir->var->type, ir->var->name,
  103.                                       ir_var_temporary);
  104.       hash_table_insert(replacements, temp, ir->var);
  105.       ir->var->insert_after(temp);
  106.    }
  107.  
  108.    /* Update the dereference to use the temporary */
  109.    ir->var = temp;
  110.  
  111.    return visit_continue;
  112. }
  113.  
  114. /**
  115.  * Create an assignment to copy a temporary value back to the actual output.
  116.  */
  117. static ir_assignment *
  118. copy(void *ctx, ir_variable *output, ir_variable *temp)
  119. {
  120.    ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(output);
  121.    ir_dereference_variable *rhs = new(ctx) ir_dereference_variable(temp);
  122.    return new(ctx) ir_assignment(lhs, rhs);
  123. }
  124.  
  125. /** Insert a copy-back assignment before a "return" statement or a call to
  126.  * EmitVertex().
  127.  */
  128. static void
  129. emit_return_copy(const void *key, void *data, void *closure)
  130. {
  131.    ir_return *ir = (ir_return *) closure;
  132.    ir->insert_before(copy(ir, (ir_variable *) key, (ir_variable *) data));
  133. }
  134.  
  135. /** Insert a copy-back assignment at the end of the main() function */
  136. static void
  137. emit_main_copy(const void *key, void *data, void *closure)
  138. {
  139.    ir_function_signature *sig = (ir_function_signature *) closure;
  140.    sig->body.push_tail(copy(sig, (ir_variable *) key, (ir_variable *) data));
  141. }
  142.  
  143. ir_visitor_status
  144. output_read_remover::visit_leave(ir_return *ir)
  145. {
  146.    hash_table_call_foreach(replacements, emit_return_copy, ir);
  147.    return visit_continue;
  148. }
  149.  
  150. ir_visitor_status
  151. output_read_remover::visit_leave(ir_emit_vertex *ir)
  152. {
  153.    hash_table_call_foreach(replacements, emit_return_copy, ir);
  154.    hash_table_clear(replacements);
  155.    return visit_continue;
  156. }
  157.  
  158. ir_visitor_status
  159. output_read_remover::visit_leave(ir_function_signature *sig)
  160. {
  161.    if (strcmp(sig->function_name(), "main") != 0)
  162.       return visit_continue;
  163.  
  164.    hash_table_call_foreach(replacements, emit_main_copy, sig);
  165.    return visit_continue;
  166. }
  167.  
  168. void
  169. lower_output_reads(exec_list *instructions)
  170. {
  171.    output_read_remover v;
  172.    visit_list_elements(&v, instructions);
  173. }
  174.