summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Hähnle <nicolai.haehnle@amd.com>2017-06-19 21:46:42 +0200
committerNicolai Hähnle <nicolai.haehnle@amd.com>2017-07-13 13:27:41 +0200
commit9d150731a0f810381f6a2cc882b4d2f127afd09c (patch)
tree066e4ba854ee8fac0bed34a5e5544ef16ec37b73
parent4226dae01d212ede86c3e6d39040ee67593a5f26 (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.sources2
-rw-r--r--src/compiler/glsl/linker.cpp43
-rw-r--r--src/compiler/glsl/nir_linker.cpp178
-rw-r--r--src/compiler/glsl/nir_linker.h38
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 */