diff options
author | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2017-06-19 21:46:42 +0200 |
---|---|---|
committer | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2017-07-13 13:27:41 +0200 |
commit | 9d150731a0f810381f6a2cc882b4d2f127afd09c (patch) | |
tree | 066e4ba854ee8fac0bed34a5e5544ef16ec37b73 | |
parent | 4226dae01d212ede86c3e6d39040ee67593a5f26 (diff) |
glsl/linker: start linking NIR shaders for SPIR-V
Create shadow IR variables for compatibility with existing linking
steps.
-rw-r--r-- | src/compiler/Makefile.sources | 2 | ||||
-rw-r--r-- | src/compiler/glsl/linker.cpp | 43 | ||||
-rw-r--r-- | src/compiler/glsl/nir_linker.cpp | 178 | ||||
-rw-r--r-- | src/compiler/glsl/nir_linker.h | 38 |
4 files changed, 251 insertions, 10 deletions
diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index a0a0d62e84..0726a43956 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -112,6 +112,8 @@ LIBGLSL_FILES = \ glsl/lower_output_reads.cpp \ glsl/lower_shared_reference.cpp \ glsl/lower_ubo_reference.cpp \ + glsl/nir_linker.cpp \ + glsl/nir_linker.h \ glsl/opt_algebraic.cpp \ glsl/opt_array_splitting.cpp \ glsl/opt_conditional_discard.cpp \ diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index cc4a9291d9..a051c9d7e3 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -82,6 +82,7 @@ #include "ir_rvalue_visitor.h" #include "ir_uniform.h" #include "builtin_functions.h" +#include "nir_linker.h" #include "shader_cache.h" #include "main/shaderobj.h" @@ -4674,6 +4675,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) */ struct gl_shader **shader_list[MESA_SHADER_STAGES]; unsigned num_shaders[MESA_SHADER_STAGES]; + bool spirv = false; for (int i = 0; i < MESA_SHADER_STAGES; i++) { shader_list[i] = (struct gl_shader **) @@ -4684,17 +4686,27 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) unsigned min_version = UINT_MAX; unsigned max_version = 0; for (unsigned i = 0; i < prog->NumShaders; i++) { - min_version = MIN2(min_version, prog->Shaders[i]->Version); - max_version = MAX2(max_version, prog->Shaders[i]->Version); - - if (prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) { - linker_error(prog, "all shaders must use same shading " - "language version\n"); + if (prog->Shaders[i]->SpirVBinary != prog->Shaders[0]->SpirVBinary) { + linker_error(prog, "all shaders must have the same SPIR_V_BINARY_ARB " + "state\n"); goto done; } - if (prog->Shaders[i]->ARB_fragment_coord_conventions_enable) { - prog->ARB_fragment_coord_conventions_enable = true; + if (prog->Shaders[i]->SpirVBinary) { + spirv = true; + } else { + min_version = MIN2(min_version, prog->Shaders[i]->Version); + max_version = MAX2(max_version, prog->Shaders[i]->Version); + + if (prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) { + linker_error(prog, "all shaders must use same shading " + "language version\n"); + goto done; + } + + if (prog->Shaders[i]->ARB_fragment_coord_conventions_enable) { + prog->ARB_fragment_coord_conventions_enable = true; + } } gl_shader_stage shader_type = prog->Shaders[i]->Stage; @@ -4789,9 +4801,20 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) */ for (int stage = 0; stage < MESA_SHADER_STAGES; stage++) { if (num_shaders[stage] > 0) { - gl_linked_shader *const sh = - link_intrastage_shaders(mem_ctx, ctx, prog, shader_list[stage], + gl_linked_shader *sh; + + if (!spirv) { + sh = link_intrastage_shaders(mem_ctx, ctx, prog, shader_list[stage], num_shaders[stage], false); + } else { + if (num_shaders[stage] != 1) { + linker_error(prog, "more than one SPIR-V shader per stage\n"); + goto done; + } + + sh = create_linked_nir_shader(mem_ctx, ctx, prog, + shader_list[stage][0]); + } if (prog->data->LinkStatus) { if (!prog->data->cache_fallback) { diff --git a/src/compiler/glsl/nir_linker.cpp b/src/compiler/glsl/nir_linker.cpp new file mode 100644 index 0000000000..c9f248aa5f --- /dev/null +++ b/src/compiler/glsl/nir_linker.cpp @@ -0,0 +1,178 @@ +/* + * Copyright © 2010 Intel Corporation + * Copyright © 2017 Advanced Micro Devices, Inc. + * + * 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 "nir_linker.h" + +#include "main/mtypes.h" +#include "main/shaderobj.h" +#include "program/program.h" + +#include "nir.h" +#include "compiler/glsl/glsl_symbol_table.h" +#include "compiler/glsl/linker.h" + +#define validate(prog, cond, msg) \ + if (!(cond)) \ + validate_error(prog, __FILE__, __LINE__, #cond, msg); + +static void +validate_error(gl_shader_program *prog, const char *filename, unsigned line, + const char *cond, const char *msg) +{ + linker_error(prog, "SPIR-V link-time validation error:\n%s\nin %s:%u: %s", + msg, filename, line, cond); +} + +static ir_depth_layout +ir_from_nir_depth_layout(nir_depth_layout depth_layout) +{ + switch (depth_layout) { + default: + assert(false); + /* fall-through */ + case nir_depth_layout_none: return ir_depth_layout_none; + case nir_depth_layout_any: return ir_depth_layout_any; + case nir_depth_layout_greater: return ir_depth_layout_greater; + case nir_depth_layout_less: return ir_depth_layout_less; + case nir_depth_layout_unchanged: return ir_depth_layout_unchanged; + } +} + +static void +nir_to_ir_variable(void *mem_ctx, gl_shader_program *prog, + gl_linked_shader *linked, nir_variable *nir_var) +{ + ir_variable_mode mode; + + switch (nir_var->data.mode) { + case nir_var_shader_in: mode = ir_var_shader_in; break; + case nir_var_shader_out: mode = ir_var_shader_out; break; + case nir_var_uniform: mode = ir_var_uniform; break; + default: + assert(!"not implemented"); + } + + const char *name = nir_var->name; + + validate(prog, + nir_var->data.location >= 0 || + (nir_var->data.mode != nir_var_shader_in && nir_var->data.mode != nir_var_shader_out), + "Input and output variables must be decorated with a Location"); + + if (!name) { + /* Need spec clarification: Is this allowed for default-block uniforms? + * https://gitlab.khronos.org/opengl/API/issues/35 + */ + validate(prog, nir_var->data.location >= 0, + "Default-block uniforms without Name must have a Location"); + name = ""; + } + + ir_variable *ir_var = new(linked) ir_variable(nir_var->type, name, mode); + linked->ir->push_tail(ir_var); + + ir_var->data.read_only = nir_var->data.read_only; + ir_var->data.centroid = nir_var->data.centroid; + ir_var->data.sample = nir_var->data.sample; + ir_var->data.patch = nir_var->data.patch; + ir_var->data.invariant = nir_var->data.invariant; + ir_var->data.interpolation = nir_var->data.interpolation; + ir_var->data.origin_upper_left = nir_var->data.origin_upper_left; + ir_var->data.pixel_center_integer = nir_var->data.pixel_center_integer; + ir_var->data.location_frac = nir_var->data.location_frac; + ir_var->data.fb_fetch_output = nir_var->data.fb_fetch_output; + ir_var->data.depth_layout = ir_from_nir_depth_layout(nir_var->data.depth_layout); + ir_var->data.location = nir_var->data.location; + ir_var->data.index = nir_var->data.index; + assert(nir_var->data.descriptor_set == 0); + ir_var->data.binding = nir_var->data.binding; + ir_var->data.offset = nir_var->data.offset; + ir_var->data.memory_read_only = nir_var->data.image.read_only; + ir_var->data.memory_write_only = nir_var->data.image.write_only; + ir_var->data.memory_coherent = nir_var->data.image.coherent; + ir_var->data.memory_volatile = nir_var->data.image._volatile; + ir_var->data.memory_restrict = nir_var->data.image.restrict_flag; + ir_var->data.image_format = nir_var->data.image.format; + + if (ir_var->data.location >= 0) + ir_var->data.explicit_location = 1; +} + +/** + * Create and fill in a gl_linked_shader for a given shader which has already + * been converted to NIR. + * + * We populate the IR with a shadow copy of all linker-relevant variables. + * The linking steps themselves will then operate on the shadow copies. + */ +struct gl_linked_shader * +create_linked_nir_shader(void *mem_ctx, + struct gl_context *ctx, + struct gl_shader_program *prog, + struct gl_shader *shader) +{ + gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader); + if (!linked) { + linker_error(prog, "out of memory\n"); + return NULL; + } + + linked->Stage = shader->Stage; + + /* Create program and attach it to the linked shader */ + struct gl_program *gl_prog = + ctx->Driver.NewProgram(ctx, + _mesa_shader_stage_to_program(shader->Stage), + prog->Name, false); + if (!gl_prog) { + prog->data->LinkStatus = linking_failure; + _mesa_delete_linked_shader(ctx, linked); + return NULL; + } + + if (!prog->data->cache_fallback) + _mesa_reference_shader_program_data(ctx, &gl_prog->sh.data, prog->data); + + /* Don't use _mesa_reference_program() just take ownership */ + linked->Program = gl_prog; + + linked->nir = nir_shader_clone(linked, shader->nir); + linked->ir = new(linked) exec_list; + linked->symbols = new(linked) glsl_symbol_table; + + nir_foreach_variable(var, &linked->nir->inputs) + nir_to_ir_variable(mem_ctx, prog, linked, var); + + nir_foreach_variable(var, &linked->nir->outputs) + nir_to_ir_variable(mem_ctx, prog, linked, var); + + nir_foreach_variable(var, &linked->nir->uniforms) + nir_to_ir_variable(mem_ctx, prog, linked, var); + + _mesa_print_ir(stdout, linked->ir, NULL); + nir_print_shader(linked->nir, stdout); + fflush(stdout); + + return linked; +} diff --git a/src/compiler/glsl/nir_linker.h b/src/compiler/glsl/nir_linker.h new file mode 100644 index 0000000000..6396ffba78 --- /dev/null +++ b/src/compiler/glsl/nir_linker.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2017 Advanced Micro Devices, Inc. + * + * 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 NIR_LINKER_H +#define NIR_LINKER_H + +struct gl_context; +struct gl_linked_shader; +struct gl_shader; +struct gl_shader_program; + +struct gl_linked_shader * +create_linked_nir_shader(void *mem_ctx, + struct gl_context *ctx, + struct gl_shader_program *prog, + struct gl_shader *shader); + +#endif /* NIR_LINKER_H */ |