diff options
Diffstat (limited to 'src/microsoft/compiler/dxil_container.c')
-rw-r--r-- | src/microsoft/compiler/dxil_container.c | 122 |
1 files changed, 78 insertions, 44 deletions
diff --git a/src/microsoft/compiler/dxil_container.c b/src/microsoft/compiler/dxil_container.c index e8373fb93ab..936bf9a792f 100644 --- a/src/microsoft/compiler/dxil_container.c +++ b/src/microsoft/compiler/dxil_container.c @@ -72,11 +72,12 @@ bool dxil_container_add_features(struct dxil_container *c, const struct dxil_features *features) { - union { - struct dxil_features flags; - uint64_t bits; - } u = { .flags = *features }; - return add_part(c, DXIL_SFI0, &u.bits, sizeof(u.bits)); + /* DXIL feature info is a bitfield packed into a uint64_t. */ + static_assert(sizeof(struct dxil_features) <= sizeof(uint64_t), + "Expected dxil_features to fit into a uint64_t"); + uint64_t bits = 0; + memcpy(&bits, features, sizeof(struct dxil_features)); + return add_part(c, DXIL_SFI0, &bits, sizeof(uint64_t)); } typedef struct { @@ -89,12 +90,13 @@ typedef struct { static uint32_t get_semantic_name_offset(name_offset_cache_t *cache, const char *name, - struct _mesa_string_buffer *buf, uint32_t buf_offset) + struct _mesa_string_buffer *buf, uint32_t buf_offset, + bool validator_7) { uint32_t offset = buf->length + buf_offset; - // DXC doesn't de-duplicate arbitrary semantic names, only SVs. - if (strncmp(name, "SV_", 3) == 0) { + /* DXC doesn't de-duplicate arbitrary semantic names until validator 1.7, only SVs. */ + if (validator_7 || strncmp(name, "SV_", 3) == 0) { /* consider replacing this with a binary search using rb_tree */ for (unsigned i = 0; i < cache->num_entries; ++i) { if (!strcmp(name, cache->entries[i].name)) @@ -114,17 +116,23 @@ static uint32_t collect_semantic_names(unsigned num_records, struct dxil_signature_record *io_data, struct _mesa_string_buffer *buf, - uint32_t buf_offset) + uint32_t buf_offset, + bool validator_7) { name_offset_cache_t cache; cache.num_entries = 0; for (unsigned i = 0; i < num_records; ++i) { struct dxil_signature_record *io = &io_data[i]; - uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset); + uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset, validator_7); for (unsigned j = 0; j < io->num_elements; ++j) io->elements[j].semantic_name_offset = offset; } + if (validator_7 && buf->length % sizeof(uint32_t) != 0) { + unsigned padding_to_add = sizeof(uint32_t) - (buf->length % sizeof(uint32_t)); + char padding[sizeof(uint32_t)] = { 0 }; + _mesa_string_buffer_append_len(buf, padding, padding_to_add); + } return buf_offset + buf->length; } @@ -132,7 +140,8 @@ bool dxil_container_add_io_signature(struct dxil_container *c, enum dxil_part_fourcc part, unsigned num_records, - struct dxil_signature_record *io_data) + struct dxil_signature_record *io_data, + bool validator_7) { struct { uint32_t param_count; @@ -156,7 +165,8 @@ dxil_container_add_io_signature(struct dxil_container *c, _mesa_string_buffer_create(NULL, 1024); uint32_t last_offset = collect_semantic_names(num_records, io_data, - names, fixed_size); + names, fixed_size, + validator_7); if (!add_part_header(c, part, last_offset) || @@ -190,12 +200,15 @@ dxil_container_add_state_validation(struct dxil_container *c, const struct dxil_module *m, struct dxil_validation_state *state) { - uint32_t psv1_size = sizeof(struct dxil_psv_runtime_info_1); - uint32_t resource_bind_info_size = 4 * sizeof(uint32_t); + uint32_t psv_size = m->minor_validator >= 6 ? + sizeof(struct dxil_psv_runtime_info_2) : + sizeof(struct dxil_psv_runtime_info_1); + uint32_t resource_bind_info_size = m->minor_validator >= 6 ? + sizeof(struct dxil_resource_v1) : sizeof(struct dxil_resource_v0); uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element); uint32_t resource_count = state->num_resources; - uint32_t size = psv1_size + 2 * sizeof(uint32_t); + uint32_t size = psv_size + 2 * sizeof(uint32_t); if (resource_count > 0) { size += sizeof (uint32_t) + resource_bind_info_size * resource_count; @@ -203,43 +216,36 @@ dxil_container_add_state_validation(struct dxil_container *c, uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u; size += sizeof(uint32_t) + string_table_size; - // Semantic index table size, currently always 0 size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t); - if (m->num_sig_inputs || m->num_sig_outputs) { + if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) { size += sizeof(uint32_t); } size += dxil_pvs_sig_size * m->num_sig_inputs; size += dxil_pvs_sig_size * m->num_sig_outputs; - // size += dxil_pvs_sig_size * m->num_sig_patch_const...; - - state->state.sig_input_vectors = (uint8_t)m->num_psv_inputs; + size += dxil_pvs_sig_size * m->num_sig_patch_consts; - // TODO: check proper stream - state->state.sig_output_vectors[0] = (uint8_t)m->num_psv_outputs; + state->state.psv1.sig_input_vectors = (uint8_t)m->num_psv_inputs; - // TODO: Add viewID records size + for (unsigned i = 0; i < 4; ++i) + state->state.psv1.sig_output_vectors[i] = (uint8_t)m->num_psv_outputs[i]; - // TODO: Add sig input output dependency table size - uint32_t dependency_table_size = 0; - if (state->state.sig_input_vectors > 0) { - for (unsigned i = 0; i < 4; ++i) { - if (state->state.sig_output_vectors[i] > 0) - dependency_table_size += sizeof(uint32_t) * ((state->state.sig_output_vectors[i] + 7) >> 3) * - state->state.sig_input_vectors * 4; - } + if (state->state.psv1.uses_view_id) { + for (unsigned i = 0; i < 4; ++i) + size += m->dependency_table_dwords_per_input[i] * sizeof(uint32_t); } - size += dependency_table_size; - // TODO: Domain shader table goes here + + for (unsigned i = 0; i < 4; ++i) + size += m->io_dependency_table_size[i] * sizeof(uint32_t); if (!add_part_header(c, DXIL_PSV0, size)) return false; - if (!blob_write_bytes(&c->parts, &psv1_size, sizeof(psv1_size))) + if (!blob_write_bytes(&c->parts, &psv_size, sizeof(psv_size))) return false; - if (!blob_write_bytes(&c->parts, &state->state, psv1_size)) + if (!blob_write_bytes(&c->parts, &state->state, psv_size)) return false; if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count))) @@ -247,7 +253,7 @@ dxil_container_add_state_validation(struct dxil_container *c, if (resource_count > 0) { if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) || - !blob_write_bytes(&c->parts, state->resources, resource_bind_info_size * state->num_resources)) + !blob_write_bytes(&c->parts, state->resources.v0, resource_bind_info_size * state->num_resources)) return false; } @@ -258,7 +264,6 @@ dxil_container_add_state_validation(struct dxil_container *c, !blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length)) return false; - // TODO: write the correct semantic index table. Currently it is empty if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t))) return false; @@ -268,7 +273,7 @@ dxil_container_add_state_validation(struct dxil_container *c, return false; } - if (m->num_sig_inputs || m->num_sig_outputs) { + if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) { if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size))) return false; @@ -277,16 +282,45 @@ dxil_container_add_state_validation(struct dxil_container *c, if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs)) return false; - } - // TODO: Write PatchConst... + if (!blob_write_bytes(&c->parts, &m->psv_patch_consts, dxil_pvs_sig_size * m->num_sig_patch_consts)) + return false; + } - // TODO: Handle case when ViewID is used + /* This was a bug in the DXIL validation logic prior to 1.8. When replicating these I/O dependency + * tables from the metadata to the container, the pointer is advanced for each stream, + * and then copied for all streams... meaning that the first streams have zero data, since the + * pointer is advanced and then never written to. The last stream (that has data) then has the + * data from all streams written to it. However, if any stream before the last one has a larger + * size, this will cause corruption, since it's writing to the smaller space that was allocated + * for the last stream. We assume that never happens, and just zero all earlier streams. */ + if (m->shader_kind == DXIL_GEOMETRY_SHADER && m->minor_validator < 8) { + bool zero_view_id_deps = false, zero_io_deps = false; + for (int i = 3; i >= 0; --i) { + if (state->state.psv1.uses_view_id && m->dependency_table_dwords_per_input[i]) { + if (zero_view_id_deps) + memset(m->viewid_dependency_table[i], 0, sizeof(uint32_t) * m->dependency_table_dwords_per_input[i]); + zero_view_id_deps = true; + } + if (m->io_dependency_table_size[i]) { + if (zero_io_deps) + memset(m->io_dependency_table[i], 0, sizeof(uint32_t) * m->io_dependency_table_size[i]); + zero_io_deps = true; + } + } + } - // TODO: Handle sig input output dependency table + if (state->state.psv1.uses_view_id) { + for (unsigned i = 0; i < 4; ++i) + if (!blob_write_bytes(&c->parts, m->viewid_dependency_table[i], + sizeof(uint32_t) * m->dependency_table_dwords_per_input[i])) + return false; + } - for (uint32_t i = 0; i < dependency_table_size; ++i) - blob_write_uint8(&c->parts, 0); + for (unsigned i = 0; i < 4; ++i) + if (!blob_write_bytes(&c->parts, m->io_dependency_table[i], + sizeof(uint32_t) * m->io_dependency_table_size[i])) + return false; return true; } |