Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/bifrost/bi_opt_push_ubo.c
4564 views
1
/*
2
* Copyright (C) 2021 Collabora, Ltd.
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 FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
* SOFTWARE.
22
*/
23
24
#include "compiler.h"
25
#include "bi_builder.h"
26
27
/* This optimization pass, intended to run once after code emission but before
28
* copy propagation, analyzes direct word-aligned UBO reads and promotes a
29
* subset to moves from FAU. It is the sole populator of the UBO push data
30
* structure returned back to the command stream. */
31
32
static bool
33
bi_is_ubo(bi_instr *ins)
34
{
35
return (bi_opcode_props[ins->op].message == BIFROST_MESSAGE_LOAD) &&
36
(ins->seg == BI_SEG_UBO);
37
}
38
39
static bool
40
bi_is_direct_aligned_ubo(bi_instr *ins)
41
{
42
return bi_is_ubo(ins) &&
43
(ins->src[0].type == BI_INDEX_CONSTANT) &&
44
(ins->src[1].type == BI_INDEX_CONSTANT) &&
45
((ins->src[0].value & 0x3) == 0);
46
}
47
48
/* Represents use data for a single UBO */
49
50
#define MAX_UBO_WORDS (65536 / 16)
51
52
struct bi_ubo_block {
53
BITSET_DECLARE(pushed, MAX_UBO_WORDS);
54
uint8_t range[MAX_UBO_WORDS];
55
};
56
57
struct bi_ubo_analysis {
58
/* Per block analysis */
59
unsigned nr_blocks;
60
struct bi_ubo_block *blocks;
61
};
62
63
static struct bi_ubo_analysis
64
bi_analyze_ranges(bi_context *ctx)
65
{
66
struct bi_ubo_analysis res = {
67
.nr_blocks = ctx->nir->info.num_ubos + 1,
68
};
69
70
res.blocks = calloc(res.nr_blocks, sizeof(struct bi_ubo_block));
71
72
bi_foreach_instr_global(ctx, ins) {
73
if (!bi_is_direct_aligned_ubo(ins)) continue;
74
75
unsigned ubo = ins->src[1].value;
76
unsigned word = ins->src[0].value / 4;
77
unsigned channels = bi_opcode_props[ins->op].sr_count;
78
79
assert(ubo < res.nr_blocks);
80
assert(channels > 0 && channels <= 4);
81
82
if (word < MAX_UBO_WORDS)
83
res.blocks[ubo].range[word] = channels;
84
}
85
86
return res;
87
}
88
89
/* Select UBO words to push. A sophisticated implementation would consider the
90
* number of uses and perhaps the control flow to estimate benefit. This is not
91
* sophisticated. Select from the last UBO first to prioritize sysvals. */
92
93
static void
94
bi_pick_ubo(struct panfrost_ubo_push *push, struct bi_ubo_analysis *analysis)
95
{
96
for (signed ubo = analysis->nr_blocks - 1; ubo >= 0; --ubo) {
97
struct bi_ubo_block *block = &analysis->blocks[ubo];
98
99
for (unsigned r = 0; r < MAX_UBO_WORDS; ++r) {
100
unsigned range = block->range[r];
101
102
/* Don't push something we don't access */
103
if (range == 0) continue;
104
105
/* Don't push more than possible */
106
if (push->count > PAN_MAX_PUSH - range)
107
return;
108
109
for (unsigned offs = 0; offs < range; ++offs) {
110
struct panfrost_ubo_word word = {
111
.ubo = ubo,
112
.offset = (r + offs) * 4
113
};
114
115
push->words[push->count++] = word;
116
}
117
118
/* Mark it as pushed so we can rewrite */
119
BITSET_SET(block->pushed, r);
120
}
121
}
122
}
123
124
void
125
bi_opt_push_ubo(bi_context *ctx)
126
{
127
if (ctx->inputs->no_ubo_to_push) {
128
/* If nothing is pushed, all UBOs need to be uploaded */
129
ctx->ubo_mask = ~0;
130
return;
131
}
132
133
/* This pass only runs once */
134
assert(ctx->info->push.count == 0);
135
136
struct bi_ubo_analysis analysis = bi_analyze_ranges(ctx);
137
bi_pick_ubo(&ctx->info->push, &analysis);
138
139
ctx->ubo_mask = 0;
140
141
bi_foreach_instr_global_safe(ctx, ins) {
142
if (!bi_is_ubo(ins)) continue;
143
144
unsigned ubo = ins->src[1].value;
145
unsigned offset = ins->src[0].value;
146
147
if (!bi_is_direct_aligned_ubo(ins)) {
148
/* The load can't be pushed, so this UBO needs to be
149
* uploaded conventionally */
150
if (ins->src[1].type == BI_INDEX_CONSTANT)
151
ctx->ubo_mask |= BITSET_BIT(ubo);
152
else
153
ctx->ubo_mask = ~0;
154
155
continue;
156
}
157
158
/* Check if we decided to push this */
159
assert(ubo < analysis.nr_blocks);
160
if (!BITSET_TEST(analysis.blocks[ubo].pushed, offset / 4)) {
161
ctx->ubo_mask |= BITSET_BIT(ubo);
162
continue;
163
}
164
165
/* Replace the UBO load with moves from FAU */
166
bi_builder b = bi_init_builder(ctx, bi_after_instr(ins));
167
168
unsigned channels = bi_opcode_props[ins->op].sr_count;
169
170
for (unsigned w = 0; w < channels; ++w) {
171
/* FAU is grouped in pairs (2 x 4-byte) */
172
unsigned base =
173
pan_lookup_pushed_ubo(&ctx->info->push, ubo,
174
(offset + 4 * w));
175
176
unsigned fau_idx = (base >> 1);
177
unsigned fau_hi = (base & 1);
178
179
bi_mov_i32_to(&b,
180
bi_word(ins->dest[0], w),
181
bi_fau(BIR_FAU_UNIFORM | fau_idx, fau_hi));
182
}
183
184
bi_remove_instruction(ins);
185
}
186
187
free(analysis.blocks);
188
}
189
190