17ec681f3Smrg/* 27ec681f3Smrg * Copyright © Microsoft Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "dxil_container.h" 257ec681f3Smrg#include "dxil_module.h" 267ec681f3Smrg 277ec681f3Smrg#include "util/u_debug.h" 287ec681f3Smrg 297ec681f3Smrg#include <assert.h> 307ec681f3Smrg 317ec681f3Smrgconst uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C'); 327ec681f3Smrg 337ec681f3Smrgvoid 347ec681f3Smrgdxil_container_init(struct dxil_container *c) 357ec681f3Smrg{ 367ec681f3Smrg blob_init(&c->parts); 377ec681f3Smrg c->num_parts = 0; 387ec681f3Smrg} 397ec681f3Smrg 407ec681f3Smrgvoid 417ec681f3Smrgdxil_container_finish(struct dxil_container *c) 427ec681f3Smrg{ 437ec681f3Smrg blob_finish(&c->parts); 447ec681f3Smrg} 457ec681f3Smrg 467ec681f3Smrgstatic bool 477ec681f3Smrgadd_part_header(struct dxil_container *c, 487ec681f3Smrg enum dxil_part_fourcc fourcc, 497ec681f3Smrg uint32_t part_size) 507ec681f3Smrg{ 517ec681f3Smrg assert(c->parts.size < UINT_MAX); 527ec681f3Smrg unsigned offset = (unsigned)c->parts.size; 537ec681f3Smrg if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) || 547ec681f3Smrg !blob_write_bytes(&c->parts, &part_size, sizeof(part_size))) 557ec681f3Smrg return false; 567ec681f3Smrg 577ec681f3Smrg assert(c->num_parts < DXIL_MAX_PARTS); 587ec681f3Smrg c->part_offsets[c->num_parts++] = offset; 597ec681f3Smrg return true; 607ec681f3Smrg} 617ec681f3Smrg 627ec681f3Smrgstatic bool 637ec681f3Smrgadd_part(struct dxil_container *c, 647ec681f3Smrg enum dxil_part_fourcc fourcc, 657ec681f3Smrg const void *part_data, uint32_t part_size) 667ec681f3Smrg{ 677ec681f3Smrg return add_part_header(c, fourcc, part_size) && 687ec681f3Smrg blob_write_bytes(&c->parts, part_data, part_size); 697ec681f3Smrg} 707ec681f3Smrg 717ec681f3Smrgbool 727ec681f3Smrgdxil_container_add_features(struct dxil_container *c, 737ec681f3Smrg const struct dxil_features *features) 747ec681f3Smrg{ 757ec681f3Smrg union { 767ec681f3Smrg struct dxil_features flags; 777ec681f3Smrg uint64_t bits; 787ec681f3Smrg } u = { .flags = *features }; 797ec681f3Smrg return add_part(c, DXIL_SFI0, &u.bits, sizeof(u.bits)); 807ec681f3Smrg} 817ec681f3Smrg 827ec681f3Smrgtypedef struct { 837ec681f3Smrg struct { 847ec681f3Smrg const char *name; 857ec681f3Smrg uint32_t offset; 867ec681f3Smrg } entries[DXIL_SHADER_MAX_IO_ROWS]; 877ec681f3Smrg uint32_t num_entries; 887ec681f3Smrg} name_offset_cache_t; 897ec681f3Smrg 907ec681f3Smrgstatic uint32_t 917ec681f3Smrgget_semantic_name_offset(name_offset_cache_t *cache, const char *name, 927ec681f3Smrg struct _mesa_string_buffer *buf, uint32_t buf_offset) 937ec681f3Smrg{ 947ec681f3Smrg uint32_t offset = buf->length + buf_offset; 957ec681f3Smrg 967ec681f3Smrg // DXC doesn't de-duplicate arbitrary semantic names, only SVs. 977ec681f3Smrg if (strncmp(name, "SV_", 3) == 0) { 987ec681f3Smrg /* consider replacing this with a binary search using rb_tree */ 997ec681f3Smrg for (unsigned i = 0; i < cache->num_entries; ++i) { 1007ec681f3Smrg if (!strcmp(name, cache->entries[i].name)) 1017ec681f3Smrg return cache->entries[i].offset; 1027ec681f3Smrg } 1037ec681f3Smrg 1047ec681f3Smrg cache->entries[cache->num_entries].name = name; 1057ec681f3Smrg cache->entries[cache->num_entries].offset = offset; 1067ec681f3Smrg ++cache->num_entries; 1077ec681f3Smrg } 1087ec681f3Smrg _mesa_string_buffer_append_len(buf, name, strlen(name) + 1); 1097ec681f3Smrg 1107ec681f3Smrg return offset; 1117ec681f3Smrg} 1127ec681f3Smrg 1137ec681f3Smrgstatic uint32_t 1147ec681f3Smrgcollect_semantic_names(unsigned num_records, 1157ec681f3Smrg struct dxil_signature_record *io_data, 1167ec681f3Smrg struct _mesa_string_buffer *buf, 1177ec681f3Smrg uint32_t buf_offset) 1187ec681f3Smrg{ 1197ec681f3Smrg name_offset_cache_t cache; 1207ec681f3Smrg cache.num_entries = 0; 1217ec681f3Smrg 1227ec681f3Smrg for (unsigned i = 0; i < num_records; ++i) { 1237ec681f3Smrg struct dxil_signature_record *io = &io_data[i]; 1247ec681f3Smrg uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset); 1257ec681f3Smrg for (unsigned j = 0; j < io->num_elements; ++j) 1267ec681f3Smrg io->elements[j].semantic_name_offset = offset; 1277ec681f3Smrg } 1287ec681f3Smrg return buf_offset + buf->length; 1297ec681f3Smrg} 1307ec681f3Smrg 1317ec681f3Smrgbool 1327ec681f3Smrgdxil_container_add_io_signature(struct dxil_container *c, 1337ec681f3Smrg enum dxil_part_fourcc part, 1347ec681f3Smrg unsigned num_records, 1357ec681f3Smrg struct dxil_signature_record *io_data) 1367ec681f3Smrg{ 1377ec681f3Smrg struct { 1387ec681f3Smrg uint32_t param_count; 1397ec681f3Smrg uint32_t param_offset; 1407ec681f3Smrg } header; 1417ec681f3Smrg header.param_count = 0; 1427ec681f3Smrg uint32_t fixed_size = sizeof(header); 1437ec681f3Smrg header.param_offset = fixed_size; 1447ec681f3Smrg 1457ec681f3Smrg bool retval = true; 1467ec681f3Smrg 1477ec681f3Smrg for (unsigned i = 0; i < num_records; ++i) { 1487ec681f3Smrg /* TODO: 1497ec681f3Smrg * - Here we need to check whether the value is actually part of the 1507ec681f3Smrg * signature */ 1517ec681f3Smrg fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements; 1527ec681f3Smrg header.param_count += io_data[i].num_elements; 1537ec681f3Smrg } 1547ec681f3Smrg 1557ec681f3Smrg struct _mesa_string_buffer *names = 1567ec681f3Smrg _mesa_string_buffer_create(NULL, 1024); 1577ec681f3Smrg 1587ec681f3Smrg uint32_t last_offset = collect_semantic_names(num_records, io_data, 1597ec681f3Smrg names, fixed_size); 1607ec681f3Smrg 1617ec681f3Smrg 1627ec681f3Smrg if (!add_part_header(c, part, last_offset) || 1637ec681f3Smrg !blob_write_bytes(&c->parts, &header, sizeof(header))) { 1647ec681f3Smrg retval = false; 1657ec681f3Smrg goto cleanup; 1667ec681f3Smrg } 1677ec681f3Smrg 1687ec681f3Smrg /* write all parts */ 1697ec681f3Smrg for (unsigned i = 0; i < num_records; ++i) 1707ec681f3Smrg for (unsigned j = 0; j < io_data[i].num_elements; ++j) { 1717ec681f3Smrg if (!blob_write_bytes(&c->parts, &io_data[i].elements[j], 1727ec681f3Smrg sizeof(io_data[i].elements[j]))) { 1737ec681f3Smrg retval = false; 1747ec681f3Smrg goto cleanup; 1757ec681f3Smrg } 1767ec681f3Smrg } 1777ec681f3Smrg 1787ec681f3Smrg /* write all names */ 1797ec681f3Smrg 1807ec681f3Smrg if (!blob_write_bytes(&c->parts, names->buf, names->length)) 1817ec681f3Smrg retval = false; 1827ec681f3Smrg 1837ec681f3Smrgcleanup: 1847ec681f3Smrg _mesa_string_buffer_destroy(names); 1857ec681f3Smrg return retval; 1867ec681f3Smrg} 1877ec681f3Smrg 1887ec681f3Smrgbool 1897ec681f3Smrgdxil_container_add_state_validation(struct dxil_container *c, 1907ec681f3Smrg const struct dxil_module *m, 1917ec681f3Smrg struct dxil_validation_state *state) 1927ec681f3Smrg{ 1937ec681f3Smrg uint32_t psv1_size = sizeof(struct dxil_psv_runtime_info_1); 1947ec681f3Smrg uint32_t resource_bind_info_size = 4 * sizeof(uint32_t); 1957ec681f3Smrg uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element); 1967ec681f3Smrg uint32_t resource_count = state->num_resources; 1977ec681f3Smrg 1987ec681f3Smrg uint32_t size = psv1_size + 2 * sizeof(uint32_t); 1997ec681f3Smrg if (resource_count > 0) { 2007ec681f3Smrg size += sizeof (uint32_t) + 2017ec681f3Smrg resource_bind_info_size * resource_count; 2027ec681f3Smrg } 2037ec681f3Smrg uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u; 2047ec681f3Smrg size += sizeof(uint32_t) + string_table_size; 2057ec681f3Smrg 2067ec681f3Smrg // Semantic index table size, currently always 0 2077ec681f3Smrg size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t); 2087ec681f3Smrg 2097ec681f3Smrg if (m->num_sig_inputs || m->num_sig_outputs) { 2107ec681f3Smrg size += sizeof(uint32_t); 2117ec681f3Smrg } 2127ec681f3Smrg 2137ec681f3Smrg size += dxil_pvs_sig_size * m->num_sig_inputs; 2147ec681f3Smrg size += dxil_pvs_sig_size * m->num_sig_outputs; 2157ec681f3Smrg // size += dxil_pvs_sig_size * m->num_sig_patch_const...; 2167ec681f3Smrg 2177ec681f3Smrg state->state.sig_input_vectors = (uint8_t)m->num_psv_inputs; 2187ec681f3Smrg 2197ec681f3Smrg // TODO: check proper stream 2207ec681f3Smrg state->state.sig_output_vectors[0] = (uint8_t)m->num_psv_outputs; 2217ec681f3Smrg 2227ec681f3Smrg // TODO: Add viewID records size 2237ec681f3Smrg 2247ec681f3Smrg // TODO: Add sig input output dependency table size 2257ec681f3Smrg uint32_t dependency_table_size = 0; 2267ec681f3Smrg if (state->state.sig_input_vectors > 0) { 2277ec681f3Smrg for (unsigned i = 0; i < 4; ++i) { 2287ec681f3Smrg if (state->state.sig_output_vectors[i] > 0) 2297ec681f3Smrg dependency_table_size += sizeof(uint32_t) * ((state->state.sig_output_vectors[i] + 7) >> 3) * 2307ec681f3Smrg state->state.sig_input_vectors * 4; 2317ec681f3Smrg } 2327ec681f3Smrg } 2337ec681f3Smrg size += dependency_table_size; 2347ec681f3Smrg // TODO: Domain shader table goes here 2357ec681f3Smrg 2367ec681f3Smrg if (!add_part_header(c, DXIL_PSV0, size)) 2377ec681f3Smrg return false; 2387ec681f3Smrg 2397ec681f3Smrg if (!blob_write_bytes(&c->parts, &psv1_size, sizeof(psv1_size))) 2407ec681f3Smrg return false; 2417ec681f3Smrg 2427ec681f3Smrg if (!blob_write_bytes(&c->parts, &state->state, psv1_size)) 2437ec681f3Smrg return false; 2447ec681f3Smrg 2457ec681f3Smrg if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count))) 2467ec681f3Smrg return false; 2477ec681f3Smrg 2487ec681f3Smrg if (resource_count > 0) { 2497ec681f3Smrg if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) || 2507ec681f3Smrg !blob_write_bytes(&c->parts, state->resources, resource_bind_info_size * state->num_resources)) 2517ec681f3Smrg return false; 2527ec681f3Smrg } 2537ec681f3Smrg 2547ec681f3Smrg 2557ec681f3Smrg uint32_t fill = 0; 2567ec681f3Smrg if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) || 2577ec681f3Smrg !blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) || 2587ec681f3Smrg !blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length)) 2597ec681f3Smrg return false; 2607ec681f3Smrg 2617ec681f3Smrg // TODO: write the correct semantic index table. Currently it is empty 2627ec681f3Smrg if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t))) 2637ec681f3Smrg return false; 2647ec681f3Smrg 2657ec681f3Smrg if (m->sem_index_table.size > 0) { 2667ec681f3Smrg if (!blob_write_bytes(&c->parts, m->sem_index_table.data, 2677ec681f3Smrg m->sem_index_table.size * sizeof(uint32_t))) 2687ec681f3Smrg return false; 2697ec681f3Smrg } 2707ec681f3Smrg 2717ec681f3Smrg if (m->num_sig_inputs || m->num_sig_outputs) { 2727ec681f3Smrg if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size))) 2737ec681f3Smrg return false; 2747ec681f3Smrg 2757ec681f3Smrg if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs)) 2767ec681f3Smrg return false; 2777ec681f3Smrg 2787ec681f3Smrg if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs)) 2797ec681f3Smrg return false; 2807ec681f3Smrg } 2817ec681f3Smrg 2827ec681f3Smrg // TODO: Write PatchConst... 2837ec681f3Smrg 2847ec681f3Smrg // TODO: Handle case when ViewID is used 2857ec681f3Smrg 2867ec681f3Smrg // TODO: Handle sig input output dependency table 2877ec681f3Smrg 2887ec681f3Smrg for (uint32_t i = 0; i < dependency_table_size; ++i) 2897ec681f3Smrg blob_write_uint8(&c->parts, 0); 2907ec681f3Smrg 2917ec681f3Smrg return true; 2927ec681f3Smrg} 2937ec681f3Smrg 2947ec681f3Smrgbool 2957ec681f3Smrgdxil_container_add_module(struct dxil_container *c, 2967ec681f3Smrg const struct dxil_module *m) 2977ec681f3Smrg{ 2987ec681f3Smrg assert(m->buf.buf_bits == 0); // make sure the module is fully flushed 2997ec681f3Smrg uint32_t version = (m->shader_kind << 16) | 3007ec681f3Smrg (m->major_version << 4) | 3017ec681f3Smrg m->minor_version; 3027ec681f3Smrg uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size; 3037ec681f3Smrg assert(size % sizeof(uint32_t) == 0); 3047ec681f3Smrg uint32_t uint32_size = size / sizeof(uint32_t); 3057ec681f3Smrg uint32_t magic = 0x4C495844; 3067ec681f3Smrg uint32_t dxil_version = 1 << 8; // I have no idea... 3077ec681f3Smrg uint32_t bitcode_offset = 16; 3087ec681f3Smrg uint32_t bitcode_size = m->buf.blob.size; 3097ec681f3Smrg 3107ec681f3Smrg return add_part_header(c, DXIL_DXIL, size) && 3117ec681f3Smrg blob_write_bytes(&c->parts, &version, sizeof(version)) && 3127ec681f3Smrg blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) && 3137ec681f3Smrg blob_write_bytes(&c->parts, &magic, sizeof(magic)) && 3147ec681f3Smrg blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) && 3157ec681f3Smrg blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) && 3167ec681f3Smrg blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) && 3177ec681f3Smrg blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size); 3187ec681f3Smrg} 3197ec681f3Smrg 3207ec681f3Smrgbool 3217ec681f3Smrgdxil_container_write(struct dxil_container *c, struct blob *blob) 3227ec681f3Smrg{ 3237ec681f3Smrg assert(blob->size == 0); 3247ec681f3Smrg if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC))) 3257ec681f3Smrg return false; 3267ec681f3Smrg 3277ec681f3Smrg const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned 3287ec681f3Smrg if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest))) 3297ec681f3Smrg return false; 3307ec681f3Smrg 3317ec681f3Smrg uint16_t major_version = 1; 3327ec681f3Smrg uint16_t minor_version = 0; 3337ec681f3Smrg if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) || 3347ec681f3Smrg !blob_write_bytes(blob, &minor_version, sizeof(minor_version))) 3357ec681f3Smrg return false; 3367ec681f3Smrg 3377ec681f3Smrg size_t header_size = 32 + 4 * c->num_parts; 3387ec681f3Smrg size_t size = header_size + c->parts.size; 3397ec681f3Smrg assert(size <= UINT32_MAX); 3407ec681f3Smrg uint32_t container_size = (uint32_t)size; 3417ec681f3Smrg if (!blob_write_bytes(blob, &container_size, sizeof(container_size))) 3427ec681f3Smrg return false; 3437ec681f3Smrg 3447ec681f3Smrg uint32_t part_offsets[DXIL_MAX_PARTS]; 3457ec681f3Smrg for (int i = 0; i < c->num_parts; ++i) { 3467ec681f3Smrg size_t offset = header_size + c->part_offsets[i]; 3477ec681f3Smrg assert(offset <= UINT32_MAX); 3487ec681f3Smrg part_offsets[i] = (uint32_t)offset; 3497ec681f3Smrg } 3507ec681f3Smrg 3517ec681f3Smrg if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) || 3527ec681f3Smrg !blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) || 3537ec681f3Smrg !blob_write_bytes(blob, c->parts.data, c->parts.size)) 3547ec681f3Smrg return false; 3557ec681f3Smrg 3567ec681f3Smrg return true; 3577ec681f3Smrg} 358