Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/microsoft/compiler/dxil_container.c
4564 views
1
/*
2
* Copyright © Microsoft Corporation
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
#include "dxil_container.h"
25
#include "dxil_module.h"
26
27
#include "util/u_debug.h"
28
29
#include <assert.h>
30
31
const uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C');
32
33
void
34
dxil_container_init(struct dxil_container *c)
35
{
36
blob_init(&c->parts);
37
c->num_parts = 0;
38
}
39
40
void
41
dxil_container_finish(struct dxil_container *c)
42
{
43
blob_finish(&c->parts);
44
}
45
46
static bool
47
add_part_header(struct dxil_container *c,
48
enum dxil_part_fourcc fourcc,
49
uint32_t part_size)
50
{
51
assert(c->parts.size < UINT_MAX);
52
unsigned offset = (unsigned)c->parts.size;
53
if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) ||
54
!blob_write_bytes(&c->parts, &part_size, sizeof(part_size)))
55
return false;
56
57
assert(c->num_parts < DXIL_MAX_PARTS);
58
c->part_offsets[c->num_parts++] = offset;
59
return true;
60
}
61
62
static bool
63
add_part(struct dxil_container *c,
64
enum dxil_part_fourcc fourcc,
65
const void *part_data, uint32_t part_size)
66
{
67
return add_part_header(c, fourcc, part_size) &&
68
blob_write_bytes(&c->parts, part_data, part_size);
69
}
70
71
bool
72
dxil_container_add_features(struct dxil_container *c,
73
const struct dxil_features *features)
74
{
75
union {
76
struct dxil_features flags;
77
uint64_t bits;
78
} u = { .flags = *features };
79
return add_part(c, DXIL_SFI0, &u.bits, sizeof(u.bits));
80
}
81
82
typedef struct {
83
struct {
84
const char *name;
85
uint32_t offset;
86
} entries[DXIL_SHADER_MAX_IO_ROWS];
87
uint32_t num_entries;
88
} name_offset_cache_t;
89
90
static uint32_t
91
get_semantic_name_offset(name_offset_cache_t *cache, const char *name,
92
struct _mesa_string_buffer *buf, uint32_t buf_offset)
93
{
94
uint32_t offset = buf->length + buf_offset;
95
96
// DXC doesn't de-duplicate arbitrary semantic names, only SVs.
97
if (strncmp(name, "SV_", 3) == 0) {
98
/* consider replacing this with a binary search using rb_tree */
99
for (unsigned i = 0; i < cache->num_entries; ++i) {
100
if (!strcmp(name, cache->entries[i].name))
101
return cache->entries[i].offset;
102
}
103
104
cache->entries[cache->num_entries].name = name;
105
cache->entries[cache->num_entries].offset = offset;
106
++cache->num_entries;
107
}
108
_mesa_string_buffer_append_len(buf, name, strlen(name) + 1);
109
110
return offset;
111
}
112
113
static uint32_t
114
collect_semantic_names(unsigned num_records,
115
struct dxil_signature_record *io_data,
116
struct _mesa_string_buffer *buf,
117
uint32_t buf_offset)
118
{
119
name_offset_cache_t cache;
120
cache.num_entries = 0;
121
122
for (unsigned i = 0; i < num_records; ++i) {
123
struct dxil_signature_record *io = &io_data[i];
124
uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset);
125
for (unsigned j = 0; j < io->num_elements; ++j)
126
io->elements[j].semantic_name_offset = offset;
127
}
128
return buf_offset + buf->length;
129
}
130
131
bool
132
dxil_container_add_io_signature(struct dxil_container *c,
133
enum dxil_part_fourcc part,
134
unsigned num_records,
135
struct dxil_signature_record *io_data)
136
{
137
struct {
138
uint32_t param_count;
139
uint32_t param_offset;
140
} header;
141
header.param_count = 0;
142
uint32_t fixed_size = sizeof(header);
143
header.param_offset = fixed_size;
144
145
bool retval = true;
146
147
for (unsigned i = 0; i < num_records; ++i) {
148
/* TODO:
149
* - Here we need to check whether the value is actually part of the
150
* signature */
151
fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements;
152
header.param_count += io_data[i].num_elements;
153
}
154
155
struct _mesa_string_buffer *names =
156
_mesa_string_buffer_create(NULL, 1024);
157
158
uint32_t last_offset = collect_semantic_names(num_records, io_data,
159
names, fixed_size);
160
161
162
if (!add_part_header(c, part, last_offset) ||
163
!blob_write_bytes(&c->parts, &header, sizeof(header))) {
164
retval = false;
165
goto cleanup;
166
}
167
168
/* write all parts */
169
for (unsigned i = 0; i < num_records; ++i)
170
for (unsigned j = 0; j < io_data[i].num_elements; ++j) {
171
if (!blob_write_bytes(&c->parts, &io_data[i].elements[j],
172
sizeof(io_data[i].elements[j]))) {
173
retval = false;
174
goto cleanup;
175
}
176
}
177
178
/* write all names */
179
180
if (!blob_write_bytes(&c->parts, names->buf, names->length))
181
retval = false;
182
183
cleanup:
184
_mesa_string_buffer_destroy(names);
185
return retval;
186
}
187
188
bool
189
dxil_container_add_state_validation(struct dxil_container *c,
190
const struct dxil_module *m,
191
struct dxil_validation_state *state)
192
{
193
uint32_t psv1_size = sizeof(struct dxil_psv_runtime_info_1);
194
uint32_t resource_bind_info_size = 4 * sizeof(uint32_t);
195
uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element);
196
uint32_t resource_count = state->num_resources;
197
198
uint32_t size = psv1_size + 2 * sizeof(uint32_t);
199
if (resource_count > 0) {
200
size += sizeof (uint32_t) +
201
resource_bind_info_size * resource_count;
202
}
203
uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u;
204
size += sizeof(uint32_t) + string_table_size;
205
206
// Semantic index table size, currently always 0
207
size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t);
208
209
if (m->num_sig_inputs || m->num_sig_outputs) {
210
size += sizeof(uint32_t);
211
}
212
213
size += dxil_pvs_sig_size * m->num_sig_inputs;
214
size += dxil_pvs_sig_size * m->num_sig_outputs;
215
// size += dxil_pvs_sig_size * m->num_sig_patch_const...;
216
217
state->state.sig_input_vectors = (uint8_t)m->num_psv_inputs;
218
219
// TODO: check proper stream
220
state->state.sig_output_vectors[0] = (uint8_t)m->num_psv_outputs;
221
222
// TODO: Add viewID records size
223
224
// TODO: Add sig input output dependency table size
225
uint32_t dependency_table_size = 0;
226
if (state->state.sig_input_vectors > 0) {
227
for (unsigned i = 0; i < 4; ++i) {
228
if (state->state.sig_output_vectors[i] > 0)
229
dependency_table_size += sizeof(uint32_t) * ((state->state.sig_output_vectors[i] + 7) >> 3) *
230
state->state.sig_input_vectors * 4;
231
}
232
}
233
size += dependency_table_size;
234
// TODO: Domain shader table goes here
235
236
if (!add_part_header(c, DXIL_PSV0, size))
237
return false;
238
239
if (!blob_write_bytes(&c->parts, &psv1_size, sizeof(psv1_size)))
240
return false;
241
242
if (!blob_write_bytes(&c->parts, &state->state, psv1_size))
243
return false;
244
245
if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count)))
246
return false;
247
248
if (resource_count > 0) {
249
if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) ||
250
!blob_write_bytes(&c->parts, state->resources, resource_bind_info_size * state->num_resources))
251
return false;
252
}
253
254
255
uint32_t fill = 0;
256
if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) ||
257
!blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) ||
258
!blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length))
259
return false;
260
261
// TODO: write the correct semantic index table. Currently it is empty
262
if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t)))
263
return false;
264
265
if (m->sem_index_table.size > 0) {
266
if (!blob_write_bytes(&c->parts, m->sem_index_table.data,
267
m->sem_index_table.size * sizeof(uint32_t)))
268
return false;
269
}
270
271
if (m->num_sig_inputs || m->num_sig_outputs) {
272
if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size)))
273
return false;
274
275
if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs))
276
return false;
277
278
if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs))
279
return false;
280
}
281
282
// TODO: Write PatchConst...
283
284
// TODO: Handle case when ViewID is used
285
286
// TODO: Handle sig input output dependency table
287
288
for (uint32_t i = 0; i < dependency_table_size; ++i)
289
blob_write_uint8(&c->parts, 0);
290
291
return true;
292
}
293
294
bool
295
dxil_container_add_module(struct dxil_container *c,
296
const struct dxil_module *m)
297
{
298
assert(m->buf.buf_bits == 0); // make sure the module is fully flushed
299
uint32_t version = (m->shader_kind << 16) |
300
(m->major_version << 4) |
301
m->minor_version;
302
uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size;
303
assert(size % sizeof(uint32_t) == 0);
304
uint32_t uint32_size = size / sizeof(uint32_t);
305
uint32_t magic = 0x4C495844;
306
uint32_t dxil_version = 1 << 8; // I have no idea...
307
uint32_t bitcode_offset = 16;
308
uint32_t bitcode_size = m->buf.blob.size;
309
310
return add_part_header(c, DXIL_DXIL, size) &&
311
blob_write_bytes(&c->parts, &version, sizeof(version)) &&
312
blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) &&
313
blob_write_bytes(&c->parts, &magic, sizeof(magic)) &&
314
blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) &&
315
blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) &&
316
blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) &&
317
blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size);
318
}
319
320
bool
321
dxil_container_write(struct dxil_container *c, struct blob *blob)
322
{
323
assert(blob->size == 0);
324
if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC)))
325
return false;
326
327
const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned
328
if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest)))
329
return false;
330
331
uint16_t major_version = 1;
332
uint16_t minor_version = 0;
333
if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) ||
334
!blob_write_bytes(blob, &minor_version, sizeof(minor_version)))
335
return false;
336
337
size_t header_size = 32 + 4 * c->num_parts;
338
size_t size = header_size + c->parts.size;
339
assert(size <= UINT32_MAX);
340
uint32_t container_size = (uint32_t)size;
341
if (!blob_write_bytes(blob, &container_size, sizeof(container_size)))
342
return false;
343
344
uint32_t part_offsets[DXIL_MAX_PARTS];
345
for (int i = 0; i < c->num_parts; ++i) {
346
size_t offset = header_size + c->part_offsets[i];
347
assert(offset <= UINT32_MAX);
348
part_offsets[i] = (uint32_t)offset;
349
}
350
351
if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) ||
352
!blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) ||
353
!blob_write_bytes(blob, c->parts.data, c->parts.size))
354
return false;
355
356
return true;
357
}
358
359