Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 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(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
}