Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c
4570 views
1
/*
2
* Copyright © 2014 Broadcom
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 DEALINGS
21
* IN THE SOFTWARE.
22
*/
23
24
/**
25
* @file vc4_qir_lower_uniforms.c
26
*
27
* This is the pre-code-generation pass for fixing up instructions that try to
28
* read from multiple uniform values.
29
*/
30
31
#include "vc4_qir.h"
32
#include "util/hash_table.h"
33
#include "util/u_math.h"
34
35
static inline uint32_t
36
index_hash(const void *key)
37
{
38
return (uintptr_t)key;
39
}
40
41
static inline bool
42
index_compare(const void *a, const void *b)
43
{
44
return a == b;
45
}
46
47
static void
48
add_uniform(struct hash_table *ht, struct qreg reg)
49
{
50
struct hash_entry *entry;
51
void *key = (void *)(uintptr_t)(reg.index + 1);
52
53
entry = _mesa_hash_table_search(ht, key);
54
if (entry) {
55
entry->data++;
56
} else {
57
_mesa_hash_table_insert(ht, key, (void *)(uintptr_t)1);
58
}
59
}
60
61
static void
62
remove_uniform(struct hash_table *ht, struct qreg reg)
63
{
64
struct hash_entry *entry;
65
void *key = (void *)(uintptr_t)(reg.index + 1);
66
67
entry = _mesa_hash_table_search(ht, key);
68
assert(entry);
69
entry->data = (void *)(((uintptr_t) entry->data) - 1);
70
if (entry->data == NULL)
71
_mesa_hash_table_remove(ht, entry);
72
}
73
74
static bool
75
is_lowerable_uniform(struct qinst *inst, int i)
76
{
77
if (inst->src[i].file != QFILE_UNIF)
78
return false;
79
if (qir_is_tex(inst))
80
return i != qir_get_tex_uniform_src(inst);
81
return true;
82
}
83
84
/* Returns the number of different uniform values referenced by the
85
* instruction.
86
*/
87
static uint32_t
88
qir_get_instruction_uniform_count(struct qinst *inst)
89
{
90
uint32_t count = 0;
91
92
for (int i = 0; i < qir_get_nsrc(inst); i++) {
93
if (inst->src[i].file != QFILE_UNIF)
94
continue;
95
96
bool is_duplicate = false;
97
for (int j = 0; j < i; j++) {
98
if (inst->src[j].file == QFILE_UNIF &&
99
inst->src[j].index == inst->src[i].index) {
100
is_duplicate = true;
101
break;
102
}
103
}
104
if (!is_duplicate)
105
count++;
106
}
107
108
return count;
109
}
110
111
void
112
qir_lower_uniforms(struct vc4_compile *c)
113
{
114
struct hash_table *ht =
115
_mesa_hash_table_create(c, index_hash, index_compare);
116
117
/* Walk the instruction list, finding which instructions have more
118
* than one uniform referenced, and add those uniform values to the
119
* ht.
120
*/
121
qir_for_each_inst_inorder(inst, c) {
122
uint32_t nsrc = qir_get_nsrc(inst);
123
124
if (qir_get_instruction_uniform_count(inst) <= 1)
125
continue;
126
127
for (int i = 0; i < nsrc; i++) {
128
if (is_lowerable_uniform(inst, i))
129
add_uniform(ht, inst->src[i]);
130
}
131
}
132
133
while (ht->entries) {
134
/* Find the most commonly used uniform in instructions that
135
* need a uniform lowered.
136
*/
137
uint32_t max_count = 0;
138
uint32_t max_index = 0;
139
hash_table_foreach(ht, entry) {
140
uint32_t count = (uintptr_t)entry->data;
141
uint32_t index = (uintptr_t)entry->key - 1;
142
if (count > max_count) {
143
max_count = count;
144
max_index = index;
145
}
146
}
147
148
struct qreg unif = qir_reg(QFILE_UNIF, max_index);
149
150
/* Now, find the instructions using this uniform and make them
151
* reference a temp instead.
152
*/
153
qir_for_each_block(block, c) {
154
struct qinst *mov = NULL;
155
156
qir_for_each_inst(inst, block) {
157
uint32_t nsrc = qir_get_nsrc(inst);
158
159
uint32_t count = qir_get_instruction_uniform_count(inst);
160
161
if (count <= 1)
162
continue;
163
164
/* If the block doesn't have a load of hte
165
* uniform yet, add it. We could potentially
166
* do better and CSE MOVs from multiple blocks
167
* into dominating blocks, except that may
168
* cause troubles for register allocation.
169
*/
170
if (!mov) {
171
mov = qir_inst(QOP_MOV, qir_get_temp(c),
172
unif, c->undef);
173
list_add(&mov->link,
174
&block->instructions);
175
c->defs[mov->dst.index] = mov;
176
}
177
178
bool removed = false;
179
for (int i = 0; i < nsrc; i++) {
180
if (is_lowerable_uniform(inst, i) &&
181
inst->src[i].index == max_index) {
182
inst->src[i] = mov->dst;
183
remove_uniform(ht, unif);
184
removed = true;
185
}
186
}
187
if (removed)
188
count--;
189
190
/* If the instruction doesn't need lowering any more,
191
* then drop it from the list.
192
*/
193
if (count <= 1) {
194
for (int i = 0; i < nsrc; i++) {
195
if (is_lowerable_uniform(inst, i))
196
remove_uniform(ht, inst->src[i]);
197
}
198
}
199
}
200
}
201
}
202
203
_mesa_hash_table_destroy(ht, NULL);
204
}
205
206