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
dxil_container_init(struct dxil_container * c)34 dxil_container_init(struct dxil_container *c)
35 {
36    blob_init(&c->parts);
37    c->num_parts = 0;
38 }
39 
40 void
dxil_container_finish(struct dxil_container * c)41 dxil_container_finish(struct dxil_container *c)
42 {
43    blob_finish(&c->parts);
44 }
45 
46 static bool
add_part_header(struct dxil_container * c,enum dxil_part_fourcc fourcc,uint32_t part_size)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
add_part(struct dxil_container * c,enum dxil_part_fourcc fourcc,const void * part_data,uint32_t part_size)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
dxil_container_add_features(struct dxil_container * c,const struct dxil_features * features)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
get_semantic_name_offset(name_offset_cache_t * cache,const char * name,struct _mesa_string_buffer * buf,uint32_t buf_offset)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
collect_semantic_names(unsigned num_records,struct dxil_signature_record * io_data,struct _mesa_string_buffer * buf,uint32_t buf_offset)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
dxil_container_add_io_signature(struct dxil_container * c,enum dxil_part_fourcc part,unsigned num_records,struct dxil_signature_record * io_data)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
dxil_container_add_state_validation(struct dxil_container * c,const struct dxil_module * m,struct dxil_validation_state * state)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
dxil_container_add_module(struct dxil_container * c,const struct dxil_module * m)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
dxil_container_write(struct dxil_container * c,struct blob * blob)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