Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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. class output_read_remover : public ir_hierarchical_visitor {
  41. protected:
  42.    /**
  43.     * A hash table mapping from the original ir_variable shader outputs
  44.     * (ir_var_shader_out mode) to the new temporaries to be used instead.
  45.     */
  46.    hash_table *replacements;
  47.  
  48.    void *mem_ctx;
  49. public:
  50.    output_read_remover();
  51.    ~output_read_remover();
  52.    virtual ir_visitor_status visit(class ir_dereference_variable *);
  53.    virtual ir_visitor_status visit_leave(class ir_return *);
  54.    virtual ir_visitor_status visit_leave(class ir_function_signature *);
  55. };
  56.  
  57. /**
  58.  * Hash function for the output variables - computes the hash of the name.
  59.  * NOTE: We're using the name string to ensure that the hash doesn't depend
  60.  * on any random factors, otherwise the output_read_remover could produce
  61.  * the random order of the assignments.
  62.  *
  63.  * NOTE: If you want to reuse this function please take into account that
  64.  * generally the names of the variables are non-unique.
  65.  */
  66. static unsigned
  67. hash_table_var_hash(const void *key)
  68. {
  69.    const ir_variable * var = static_cast<const ir_variable *>(key);
  70.    return hash_table_string_hash(var->name);
  71. }
  72.  
  73. output_read_remover::output_read_remover()
  74. {
  75.    mem_ctx = ralloc_context(NULL);
  76.    replacements =
  77.       hash_table_ctor(0, hash_table_var_hash, hash_table_pointer_compare);
  78. }
  79.  
  80. output_read_remover::~output_read_remover()
  81. {
  82.    hash_table_dtor(replacements);
  83.    ralloc_free(mem_ctx);
  84. }
  85.  
  86. ir_visitor_status
  87. output_read_remover::visit(ir_dereference_variable *ir)
  88. {
  89.    if (ir->var->mode != ir_var_shader_out)
  90.       return visit_continue;
  91.  
  92.    ir_variable *temp = (ir_variable *) hash_table_find(replacements, ir->var);
  93.  
  94.    /* If we don't have an existing temporary, create one. */
  95.    if (temp == NULL) {
  96.       void *var_ctx = ralloc_parent(ir->var);
  97.       temp = new(var_ctx) ir_variable(ir->var->type, ir->var->name,
  98.                                       ir_var_temporary);
  99.       hash_table_insert(replacements, temp, ir->var);
  100.       ir->var->insert_after(temp);
  101.    }
  102.  
  103.    /* Update the dereference to use the temporary */
  104.    ir->var = temp;
  105.  
  106.    return visit_continue;
  107. }
  108.  
  109. /**
  110.  * Create an assignment to copy a temporary value back to the actual output.
  111.  */
  112. static ir_assignment *
  113. copy(void *ctx, ir_variable *output, ir_variable *temp)
  114. {
  115.    ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(output);
  116.    ir_dereference_variable *rhs = new(ctx) ir_dereference_variable(temp);
  117.    return new(ctx) ir_assignment(lhs, rhs);
  118. }
  119.  
  120. /** Insert a copy-back assignment before a "return" statement */
  121. static void
  122. emit_return_copy(const void *key, void *data, void *closure)
  123. {
  124.    ir_return *ir = (ir_return *) closure;
  125.    ir->insert_before(copy(ir, (ir_variable *) key, (ir_variable *) data));
  126. }
  127.  
  128. /** Insert a copy-back assignment at the end of the main() function */
  129. static void
  130. emit_main_copy(const void *key, void *data, void *closure)
  131. {
  132.    ir_function_signature *sig = (ir_function_signature *) closure;
  133.    sig->body.push_tail(copy(sig, (ir_variable *) key, (ir_variable *) data));
  134. }
  135.  
  136. ir_visitor_status
  137. output_read_remover::visit_leave(ir_return *ir)
  138. {
  139.    hash_table_call_foreach(replacements, emit_return_copy, ir);
  140.    return visit_continue;
  141. }
  142.  
  143. ir_visitor_status
  144. output_read_remover::visit_leave(ir_function_signature *sig)
  145. {
  146.    if (strcmp(sig->function_name(), "main") != 0)
  147.       return visit_continue;
  148.  
  149.    hash_table_call_foreach(replacements, emit_main_copy, sig);
  150.    return visit_continue;
  151. }
  152.  
  153. void
  154. lower_output_reads(exec_list *instructions)
  155. {
  156.    output_read_remover v;
  157.    visit_list_elements(&v, instructions);
  158. }
  159.