Path: blob/21.2-virgl/src/microsoft/compiler/dxil_container.c
4564 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "dxil_container.h"24#include "dxil_module.h"2526#include "util/u_debug.h"2728#include <assert.h>2930const uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C');3132void33dxil_container_init(struct dxil_container *c)34{35blob_init(&c->parts);36c->num_parts = 0;37}3839void40dxil_container_finish(struct dxil_container *c)41{42blob_finish(&c->parts);43}4445static bool46add_part_header(struct dxil_container *c,47enum dxil_part_fourcc fourcc,48uint32_t part_size)49{50assert(c->parts.size < UINT_MAX);51unsigned offset = (unsigned)c->parts.size;52if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) ||53!blob_write_bytes(&c->parts, &part_size, sizeof(part_size)))54return false;5556assert(c->num_parts < DXIL_MAX_PARTS);57c->part_offsets[c->num_parts++] = offset;58return true;59}6061static bool62add_part(struct dxil_container *c,63enum dxil_part_fourcc fourcc,64const void *part_data, uint32_t part_size)65{66return add_part_header(c, fourcc, part_size) &&67blob_write_bytes(&c->parts, part_data, part_size);68}6970bool71dxil_container_add_features(struct dxil_container *c,72const struct dxil_features *features)73{74union {75struct dxil_features flags;76uint64_t bits;77} u = { .flags = *features };78return add_part(c, DXIL_SFI0, &u.bits, sizeof(u.bits));79}8081typedef struct {82struct {83const char *name;84uint32_t offset;85} entries[DXIL_SHADER_MAX_IO_ROWS];86uint32_t num_entries;87} name_offset_cache_t;8889static uint32_t90get_semantic_name_offset(name_offset_cache_t *cache, const char *name,91struct _mesa_string_buffer *buf, uint32_t buf_offset)92{93uint32_t offset = buf->length + buf_offset;9495// DXC doesn't de-duplicate arbitrary semantic names, only SVs.96if (strncmp(name, "SV_", 3) == 0) {97/* consider replacing this with a binary search using rb_tree */98for (unsigned i = 0; i < cache->num_entries; ++i) {99if (!strcmp(name, cache->entries[i].name))100return cache->entries[i].offset;101}102103cache->entries[cache->num_entries].name = name;104cache->entries[cache->num_entries].offset = offset;105++cache->num_entries;106}107_mesa_string_buffer_append_len(buf, name, strlen(name) + 1);108109return offset;110}111112static uint32_t113collect_semantic_names(unsigned num_records,114struct dxil_signature_record *io_data,115struct _mesa_string_buffer *buf,116uint32_t buf_offset)117{118name_offset_cache_t cache;119cache.num_entries = 0;120121for (unsigned i = 0; i < num_records; ++i) {122struct dxil_signature_record *io = &io_data[i];123uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset);124for (unsigned j = 0; j < io->num_elements; ++j)125io->elements[j].semantic_name_offset = offset;126}127return buf_offset + buf->length;128}129130bool131dxil_container_add_io_signature(struct dxil_container *c,132enum dxil_part_fourcc part,133unsigned num_records,134struct dxil_signature_record *io_data)135{136struct {137uint32_t param_count;138uint32_t param_offset;139} header;140header.param_count = 0;141uint32_t fixed_size = sizeof(header);142header.param_offset = fixed_size;143144bool retval = true;145146for (unsigned i = 0; i < num_records; ++i) {147/* TODO:148* - Here we need to check whether the value is actually part of the149* signature */150fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements;151header.param_count += io_data[i].num_elements;152}153154struct _mesa_string_buffer *names =155_mesa_string_buffer_create(NULL, 1024);156157uint32_t last_offset = collect_semantic_names(num_records, io_data,158names, fixed_size);159160161if (!add_part_header(c, part, last_offset) ||162!blob_write_bytes(&c->parts, &header, sizeof(header))) {163retval = false;164goto cleanup;165}166167/* write all parts */168for (unsigned i = 0; i < num_records; ++i)169for (unsigned j = 0; j < io_data[i].num_elements; ++j) {170if (!blob_write_bytes(&c->parts, &io_data[i].elements[j],171sizeof(io_data[i].elements[j]))) {172retval = false;173goto cleanup;174}175}176177/* write all names */178179if (!blob_write_bytes(&c->parts, names->buf, names->length))180retval = false;181182cleanup:183_mesa_string_buffer_destroy(names);184return retval;185}186187bool188dxil_container_add_state_validation(struct dxil_container *c,189const struct dxil_module *m,190struct dxil_validation_state *state)191{192uint32_t psv1_size = sizeof(struct dxil_psv_runtime_info_1);193uint32_t resource_bind_info_size = 4 * sizeof(uint32_t);194uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element);195uint32_t resource_count = state->num_resources;196197uint32_t size = psv1_size + 2 * sizeof(uint32_t);198if (resource_count > 0) {199size += sizeof (uint32_t) +200resource_bind_info_size * resource_count;201}202uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u;203size += sizeof(uint32_t) + string_table_size;204205// Semantic index table size, currently always 0206size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t);207208if (m->num_sig_inputs || m->num_sig_outputs) {209size += sizeof(uint32_t);210}211212size += dxil_pvs_sig_size * m->num_sig_inputs;213size += dxil_pvs_sig_size * m->num_sig_outputs;214// size += dxil_pvs_sig_size * m->num_sig_patch_const...;215216state->state.sig_input_vectors = (uint8_t)m->num_psv_inputs;217218// TODO: check proper stream219state->state.sig_output_vectors[0] = (uint8_t)m->num_psv_outputs;220221// TODO: Add viewID records size222223// TODO: Add sig input output dependency table size224uint32_t dependency_table_size = 0;225if (state->state.sig_input_vectors > 0) {226for (unsigned i = 0; i < 4; ++i) {227if (state->state.sig_output_vectors[i] > 0)228dependency_table_size += sizeof(uint32_t) * ((state->state.sig_output_vectors[i] + 7) >> 3) *229state->state.sig_input_vectors * 4;230}231}232size += dependency_table_size;233// TODO: Domain shader table goes here234235if (!add_part_header(c, DXIL_PSV0, size))236return false;237238if (!blob_write_bytes(&c->parts, &psv1_size, sizeof(psv1_size)))239return false;240241if (!blob_write_bytes(&c->parts, &state->state, psv1_size))242return false;243244if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count)))245return false;246247if (resource_count > 0) {248if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) ||249!blob_write_bytes(&c->parts, state->resources, resource_bind_info_size * state->num_resources))250return false;251}252253254uint32_t fill = 0;255if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) ||256!blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) ||257!blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length))258return false;259260// TODO: write the correct semantic index table. Currently it is empty261if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t)))262return false;263264if (m->sem_index_table.size > 0) {265if (!blob_write_bytes(&c->parts, m->sem_index_table.data,266m->sem_index_table.size * sizeof(uint32_t)))267return false;268}269270if (m->num_sig_inputs || m->num_sig_outputs) {271if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size)))272return false;273274if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs))275return false;276277if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs))278return false;279}280281// TODO: Write PatchConst...282283// TODO: Handle case when ViewID is used284285// TODO: Handle sig input output dependency table286287for (uint32_t i = 0; i < dependency_table_size; ++i)288blob_write_uint8(&c->parts, 0);289290return true;291}292293bool294dxil_container_add_module(struct dxil_container *c,295const struct dxil_module *m)296{297assert(m->buf.buf_bits == 0); // make sure the module is fully flushed298uint32_t version = (m->shader_kind << 16) |299(m->major_version << 4) |300m->minor_version;301uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size;302assert(size % sizeof(uint32_t) == 0);303uint32_t uint32_size = size / sizeof(uint32_t);304uint32_t magic = 0x4C495844;305uint32_t dxil_version = 1 << 8; // I have no idea...306uint32_t bitcode_offset = 16;307uint32_t bitcode_size = m->buf.blob.size;308309return add_part_header(c, DXIL_DXIL, size) &&310blob_write_bytes(&c->parts, &version, sizeof(version)) &&311blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) &&312blob_write_bytes(&c->parts, &magic, sizeof(magic)) &&313blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) &&314blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) &&315blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) &&316blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size);317}318319bool320dxil_container_write(struct dxil_container *c, struct blob *blob)321{322assert(blob->size == 0);323if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC)))324return false;325326const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned327if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest)))328return false;329330uint16_t major_version = 1;331uint16_t minor_version = 0;332if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) ||333!blob_write_bytes(blob, &minor_version, sizeof(minor_version)))334return false;335336size_t header_size = 32 + 4 * c->num_parts;337size_t size = header_size + c->parts.size;338assert(size <= UINT32_MAX);339uint32_t container_size = (uint32_t)size;340if (!blob_write_bytes(blob, &container_size, sizeof(container_size)))341return false;342343uint32_t part_offsets[DXIL_MAX_PARTS];344for (int i = 0; i < c->num_parts; ++i) {345size_t offset = header_size + c->part_offsets[i];346assert(offset <= UINT32_MAX);347part_offsets[i] = (uint32_t)offset;348}349350if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) ||351!blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) ||352!blob_write_bytes(blob, c->parts.data, c->parts.size))353return false;354355return true;356}357358359