From 9c36e9f8626fb2b02736abbd11e783b61a40959c Mon Sep 17 00:00:00 2001 From: Eduardo Lima Mitev Date: Tue, 10 Oct 2017 10:46:29 +0200 Subject: [PATCH] mesa/glspirv: Add _mesa_spirv_link_shaders() function This is the equivalent to link_shaders() from src/compiler/glsl/linker.cpp, but for SPIR-V programs. It just creates the program and its gl_linked_shader objects, giving drivers the opportunity to implement any linking of SPIR-V shaders they choose, at a later stage. v2: Bail out if we see more that one shader for the same stage, and add a corresponding comment. (Timothy Arceri) v3: * Adds also a linker error log to the condition above, with a reference to the specification issue. (Timothy Arceri) * Squash with the patch adding the function boilerplate (Timothy Arceri) Reviewed-by: Timothy Arceri --- src/mesa/main/glspirv.c | 71 +++++++++++++++++++++++++++++++++++++++++ src/mesa/main/glspirv.h | 4 +++ 2 files changed, 75 insertions(+) diff --git a/src/mesa/main/glspirv.c b/src/mesa/main/glspirv.c index b1185ca5fdf..7aa06f8e8c0 100644 --- a/src/mesa/main/glspirv.c +++ b/src/mesa/main/glspirv.c @@ -28,6 +28,8 @@ #include "compiler/nir/nir.h" #include "compiler/spirv/nir_spirv.h" +#include "program/program.h" + #include "util/u_atomic.h" void @@ -103,6 +105,75 @@ _mesa_spirv_shader_binary(struct gl_context *ctx, } } +/** + * This is the equivalent to compiler/glsl/linker.cpp::link_shaders() + * but for SPIR-V programs. + * + * This method just creates the gl_linked_shader structs with a reference to + * the SPIR-V data collected during previous steps. + * + * The real linking happens later in the driver-specifc call LinkShader(). + * This is so backends can implement different linking strategies for + * SPIR-V programs. + */ +void +_mesa_spirv_link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) +{ + prog->data->LinkStatus = LINKING_SUCCESS; + prog->data->Validated = false; + + for (unsigned i = 0; i < prog->NumShaders; i++) { + struct gl_shader *shader = prog->Shaders[i]; + gl_shader_stage shader_type = shader->Stage; + + /* We only support one shader per stage. The gl_spirv spec doesn't seem + * to prevent this, but the way the API is designed, requiring all shaders + * to be specialized with an entry point, makes supporting this quite + * undefined. + * + * TODO: Turn this into a proper error once the spec bug + * is resolved. + */ + if (prog->_LinkedShaders[shader_type]) { + ralloc_strcat(&prog->data->InfoLog, + "\nError trying to link more than one SPIR-V shader " + "per stage.\n"); + prog->data->LinkStatus = LINKING_FAILURE; + return; + } + + assert(shader->spirv_data); + + struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader); + linked->Stage = shader_type; + + /* Create program and attach it to the linked shader */ + struct gl_program *gl_prog = + ctx->Driver.NewProgram(ctx, + _mesa_shader_stage_to_program(shader_type), + prog->Name, false); + if (!gl_prog) { + prog->data->LinkStatus = LINKING_FAILURE; + _mesa_delete_linked_shader(ctx, linked); + return; + } + + _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; + + /* Reference the SPIR-V data from shader to the linked shader */ + _mesa_shader_spirv_data_reference(&linked->spirv_data, + shader->spirv_data); + + prog->_LinkedShaders[shader_type] = linked; + prog->data->linked_stages |= 1 << shader_type; + } +} + void GLAPIENTRY _mesa_SpecializeShaderARB(GLuint shader, const GLchar *pEntryPoint, diff --git a/src/mesa/main/glspirv.h b/src/mesa/main/glspirv.h index ba281f68bef..0f03b75c111 100644 --- a/src/mesa/main/glspirv.h +++ b/src/mesa/main/glspirv.h @@ -76,6 +76,10 @@ _mesa_spirv_shader_binary(struct gl_context *ctx, unsigned n, struct gl_shader **shaders, const void* binary, size_t length); +void +_mesa_spirv_link_shaders(struct gl_context *ctx, + struct gl_shader_program *prog); + /** * \name API functions */ -- 2.30.2