mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 08:50:13 +01:00
spirv2dxil: Support linking multiple shaders
This probably could/should be split up into multiple commits, but it's simpler to make this a monolithic change. This change inlines a bunch of logic from spirv_to_dxil into the spirv2dxil tool so that linking can be done on the nir shaders. Probably the linking functionality should be exposed in the lib/dll form too, which means that a helper for freeing intermediate nir would be needed too. That's TODO for now. The tool now requires arguments to be in-order, and once a filename is encountered, will use the previous arguments to compile the shader. If multiple graphics shaders are passed, they're linked as if they were forming a pipeline together. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20440>
This commit is contained in:
parent
ac7abf0483
commit
531d17c334
4 changed files with 210 additions and 190 deletions
|
|
@ -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 <cstdio>
|
||||
|
||||
#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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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 <errno.h>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue