diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.cpp b/src/microsoft/spirv_to_dxil/dxil_validation.cpp deleted file mode 100644 index a8e012c0d11..00000000000 --- a/src/microsoft/spirv_to_dxil/dxil_validation.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright © 2021 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -#include "dxil_validation.h" - -#if DETECT_OS_WINDOWS - -#include "dxil_validator.h" - -bool -validate_dxil(dxil_spirv_object *dxil_obj) -{ - struct dxil_validator *val = dxil_create_validator(NULL); - - char *err; - bool res = dxil_validate_module(val, dxil_obj->binary.buffer, - dxil_obj->binary.size, &err); - if (!res && err) - fprintf(stderr, "DXIL: %s\n\n", err); - - dxil_destroy_validator(val); - return res; -} - -#else - -bool -validate_dxil(dxil_spirv_object *dxil_obj) -{ - fprintf(stderr, "DXIL validation only available in Windows.\n"); - return false; -} - -#endif diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.h b/src/microsoft/spirv_to_dxil/dxil_validation.h deleted file mode 100644 index 2405b806652..00000000000 --- a/src/microsoft/spirv_to_dxil/dxil_validation.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2021 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef DXIL_VALIDATION_H -#define DXIL_VALIDATION_H - -#include "spirv_to_dxil.h" -#include "util/detect_os.h" - -#ifdef __cplusplus -extern "C" { -#endif - -bool -validate_dxil(struct dxil_spirv_object *dxil_obj); - -#ifdef __cplusplus -} -#endif - -#endif /* DXIL_VALIDATION_H */ diff --git a/src/microsoft/spirv_to_dxil/meson.build b/src/microsoft/spirv_to_dxil/meson.build index 8f7c1b9a52f..c679936e29a 100644 --- a/src/microsoft/spirv_to_dxil/meson.build +++ b/src/microsoft/spirv_to_dxil/meson.build @@ -24,6 +24,7 @@ libspirv_to_dxil = both_libraries( [ files( 'dxil_spirv_nir.c', + 'dxil_spirv_nir.h', 'spirv_to_dxil.c', 'spirv_to_dxil.h', ), @@ -44,8 +45,6 @@ spirv_to_dxil = executable( 'spirv2dxil', files( 'spirv2dxil.c', - 'dxil_validation.h', - 'dxil_validation.cpp', ), dependencies : [idep_nir, idep_libdxil_compiler, idep_getopt, idep_libspirv_to_dxil], include_directories : [inc_include, inc_src, inc_compiler, inc_gallium], diff --git a/src/microsoft/spirv_to_dxil/spirv2dxil.c b/src/microsoft/spirv_to_dxil/spirv2dxil.c index 8bcdbcb4453..c5be7649b78 100644 --- a/src/microsoft/spirv_to_dxil/spirv2dxil.c +++ b/src/microsoft/spirv_to_dxil/spirv2dxil.c @@ -29,9 +29,10 @@ */ #include "nir_to_dxil.h" -#include "dxil_validation.h" +#include "dxil_validator.h" #include "spirv/nir_spirv.h" #include "spirv_to_dxil.h" +#include "dxil_spirv_nir.h" #include "util/os_file.h" #include @@ -56,8 +57,6 @@ stage_to_enum(char *stage) return MESA_SHADER_FRAGMENT; else if (!strcmp(stage, "compute")) return MESA_SHADER_COMPUTE; - else if (!strcmp(stage, "kernel")) - return MESA_SHADER_KERNEL; else return MESA_SHADER_NONE; } @@ -68,73 +67,32 @@ log_spirv_to_dxil_error(void *priv, const char *msg) fprintf(stderr, "spirv_to_dxil error: %s", msg); } -int -main(int argc, char **argv) +struct shader { + const char *entry_point; + const char *output_file; + nir_shader *nir; +}; + +bool validate = false, debug = false; +enum dxil_validator_version val_ver = DXIL_VALIDATOR_1_4; +enum dxil_shader_model shader_model = SHADER_MODEL_6_2; + +struct nir_shader_compiler_options nir_options; + +static bool +compile_shader(const char *filename, gl_shader_stage shader_stage, struct shader *shader) { - gl_shader_stage shader_stage = MESA_SHADER_FRAGMENT; - char *entry_point = "main"; - char *output_file = ""; - int ch; - bool validate = false, debug = false; - - static struct option long_options[] = { - {"stage", required_argument, 0, 's'}, - {"entry", required_argument, 0, 'e'}, - {"output", required_argument, 0, 'o'}, - {"validate", no_argument, 0, 'v'}, - {"debug", no_argument, 0, 'd'}, - {0, 0, 0, 0}}; - - - while ((ch = getopt_long(argc, argv, "s:e:o:vd", long_options, NULL)) != - -1) { - switch(ch) - { - case 's': - shader_stage = stage_to_enum(optarg); - if (shader_stage == MESA_SHADER_NONE) { - fprintf(stderr, "Unknown stage %s\n", optarg); - return 1; - } - break; - case 'e': - entry_point = optarg; - break; - case 'o': - output_file = optarg; - break; - case 'v': - validate = true; - break; - case 'd': - debug = true; - break; - default: - fprintf(stderr, "Unrecognized option.\n"); - return 1; - } - } - - if (optind != argc - 1) { - if (optind < argc) - fprintf(stderr, "Please specify only one input file."); - else - fprintf(stderr, "Please specify an input file."); - return 1; - } - - const char *filename = argv[optind]; size_t file_size; char *file_contents = os_read_file(filename, &file_size); if (!file_contents) { fprintf(stderr, "Failed to open %s\n", filename); - return 1; + return false; } if (file_size % WORD_SIZE != 0) { fprintf(stderr, "%s size == %zu is not a multiple of %d\n", filename, file_size, WORD_SIZE); - return 1; + return false; } size_t word_count = file_size / WORD_SIZE; @@ -145,46 +103,206 @@ main(int argc, char **argv) conf.runtime_data_cbv.register_space = 31; conf.zero_based_vertex_instance_id = true; - struct dxil_spirv_debug_options dbg_opts = { - .dump_nir = debug, - }; - const struct dxil_spirv_logger logger = { - .priv = NULL, - .log = log_spirv_to_dxil_error + struct spirv_to_nir_options spirv_opts = { + .caps = { + .draw_parameters = true, + }, + .ubo_addr_format = nir_address_format_32bit_index_offset, + .ssbo_addr_format = nir_address_format_32bit_index_offset, + .shared_addr_format = nir_address_format_32bit_offset_as_64bit, + + // use_deref_buffer_array_length + nir_lower_explicit_io force + // get_ssbo_size to take in the return from load_vulkan_descriptor + // instead of vulkan_resource_index. This makes it much easier to + // get the DXIL handle for the SSBO. + .use_deref_buffer_array_length = true }; - struct dxil_spirv_object obj; - memset(&obj, 0, sizeof(obj)); - if (spirv_to_dxil((uint32_t *)file_contents, word_count, NULL, 0, - (dxil_spirv_shader_stage)shader_stage, entry_point, - SHADER_MODEL_6_2, DXIL_VALIDATOR_1_4, - &dbg_opts, &conf, &logger, &obj)) { + shader->nir = spirv_to_nir( + (const uint32_t *)file_contents, word_count, NULL, + 0, (gl_shader_stage)shader_stage, shader->entry_point, + &spirv_opts, &nir_options); + free(file_contents); + if (!shader->nir) { + fprintf(stderr, "SPIR-V to NIR failed\n"); + return false; + } - if (validate && !validate_dxil(&obj)) { - fprintf(stderr, "Failed to validate DXIL\n"); - spirv_to_dxil_free(&obj); - free(file_contents); + nir_validate_shader(shader->nir, + "Validate before feeding NIR to the DXIL compiler"); + + dxil_spirv_nir_prep(shader->nir); + + bool requires_runtime_data; + dxil_spirv_nir_passes(shader->nir, &conf, &requires_runtime_data); + + if (debug) + nir_print_shader(shader->nir, stderr); + + return true; +} + +#if DETECT_OS_WINDOWS + +static bool +validate_dxil(struct blob *blob) +{ + struct dxil_validator *val = dxil_create_validator(NULL); + + char *err; + bool res = dxil_validate_module(val, blob->data, + blob->size, &err); + if (!res && err) + fprintf(stderr, "DXIL: %s\n\n", err); + + dxil_destroy_validator(val); + return res; +} + +#else + +static bool +validate_dxil(struct blob *blob) +{ + fprintf(stderr, "DXIL validation only available in Windows.\n"); + return false; +} + +#endif + +int +main(int argc, char **argv) +{ + glsl_type_singleton_init_or_ref(); + int ch; + + static struct option long_options[] = { + {"stage", required_argument, 0, 's'}, + {"entry", required_argument, 0, 'e'}, + {"output", required_argument, 0, 'o'}, + {"validate", no_argument, 0, 'v'}, + {"debug", no_argument, 0, 'd'}, + {"shadermodel", required_argument, 0, 'm'}, + {"validatorver", required_argument, 0, 'x'}, + {0, 0, 0, 0}}; + + struct shader shaders[MESA_SHADER_COMPUTE + 1]; + memset(shaders, 0, sizeof(shaders)); + struct shader cur_shader = { + .entry_point = "main", + .output_file = "", + }; + gl_shader_stage shader_stage = MESA_SHADER_FRAGMENT; + + nir_options = *dxil_get_nir_compiler_options(); + // We will manually handle base_vertex when vertex_id and instance_id have + // have been already converted to zero-base. + nir_options.lower_base_vertex = false; + + bool any_shaders = false; + while ((ch = getopt_long(argc, argv, "-s:e:o:m:x:vd", long_options, NULL)) != + -1) { + switch (ch) + { + case 's': + shader_stage = stage_to_enum(optarg); + if (shader_stage == MESA_SHADER_NONE) { + fprintf(stderr, "Unknown stage %s\n", optarg); + return 1; + } + break; + case 'e': + cur_shader.entry_point = optarg; + break; + case 'o': + cur_shader.output_file = optarg; + break; + case 'v': + validate = true; + break; + case 'd': + debug = true; + break; + case 'm': + shader_model = SHADER_MODEL_6_0 + atoi(optarg); + nir_options.lower_helper_invocation = shader_model < SHADER_MODEL_6_6; + break; + case 'x': + val_ver = DXIL_VALIDATOR_1_0 + atoi(optarg); + break; + case 1: + if (!compile_shader(optarg, shader_stage, &cur_shader)) + return 1; + shaders[shader_stage] = cur_shader; + any_shaders = true; + break; + default: + fprintf(stderr, "Unrecognized option.\n"); return 1; } + } - FILE *file = fopen(output_file, "wb"); - if (!file) { - fprintf(stderr, "Failed to open %s, %s\n", output_file, - strerror(errno)); - spirv_to_dxil_free(&obj); - free(file_contents); - return 1; - } - - fwrite(obj.binary.buffer, sizeof(char), obj.binary.size, file); - fclose(file); - spirv_to_dxil_free(&obj); - } else { - fprintf(stderr, "Compilation failed\n"); + if (!any_shaders) { + fprintf(stderr, "Specify a shader filename\n"); return 1; } - free(file_contents); + for (int32_t cur = MESA_SHADER_FRAGMENT; cur >= MESA_SHADER_VERTEX; --cur) { + if (!shaders[cur].nir) + continue; + for (int32_t prev = cur - 1; prev >= MESA_SHADER_VERTEX; --prev) { + if (!shaders[prev].nir) + continue; + dxil_spirv_nir_link(shaders[cur].nir, shaders[prev].nir); + break; + } + } + + struct nir_to_dxil_options opts = { + .environment = DXIL_ENVIRONMENT_VULKAN, + .shader_model_max = shader_model, + .validator_version_max = val_ver, + }; + + struct dxil_logger logger_inner = {.priv = NULL, + .log = log_spirv_to_dxil_error}; + + for (uint32_t i = 0; i <= MESA_SHADER_COMPUTE; ++i) { + if (!shaders[i].nir) + continue; + struct blob dxil_blob; + bool success = nir_to_dxil(shaders[i].nir, &opts, &logger_inner, &dxil_blob); + ralloc_free(shaders[i].nir); + + if (!success) { + fprintf(stderr, "Failed to convert to DXIL\n"); + if (dxil_blob.allocated) + blob_finish(&dxil_blob); + return false; + } + + if (validate && !validate_dxil(&dxil_blob)) { + fprintf(stderr, "Failed to validate DXIL\n"); + blob_finish(&dxil_blob); + return 1; + } + + if (shaders[i].output_file) { + FILE *file = fopen(shaders[i].output_file, "wb"); + if (!file) { + fprintf(stderr, "Failed to open %s, %s\n", shaders[i].output_file, + strerror(errno)); + blob_finish(&dxil_blob); + return 1; + } + + fwrite(dxil_blob.data, sizeof(char), dxil_blob.size, file); + fclose(file); + blob_finish(&dxil_blob); + } + } + + glsl_type_singleton_decref(); return 0; }