From 4f78c273307585a0cd3f0367f4d77b53dc4d45c5 Mon Sep 17 00:00:00 2001 From: Emma Anholt Date: Tue, 3 Oct 2023 12:53:24 -0700 Subject: [PATCH] i915: Do a test compile at glLinkShader() time. This lets us throw errors back to the app for shaders that are too complex. The X server would really like to have this instead of guessing based on renderer strings when shaders might be too complicated. Part-of: --- src/gallium/drivers/i915/i915_fpc.h | 3 ++ src/gallium/drivers/i915/i915_fpc_translate.c | 15 +++++--- src/gallium/drivers/i915/i915_screen.c | 7 +++- src/gallium/drivers/i915/i915_state.c | 38 +++++++++++++++++-- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/gallium/drivers/i915/i915_fpc.h b/src/gallium/drivers/i915/i915_fpc.h index a1d85604534..4762d54862a 100644 --- a/src/gallium/drivers/i915/i915_fpc.h +++ b/src/gallium/drivers/i915/i915_fpc.h @@ -281,6 +281,9 @@ struct i915_token_list { unsigned NumTokens; }; +char *i915_test_fragment_shader_compile(struct pipe_screen *screen, + struct nir_shader *s); + extern struct i915_token_list *i915_optimize(const struct tgsi_token *tokens); extern void i915_optimize_free(struct i915_token_list *tokens); diff --git a/src/gallium/drivers/i915/i915_fpc_translate.c b/src/gallium/drivers/i915/i915_fpc_translate.c index d6201cc45ae..72eb73ed3c2 100644 --- a/src/gallium/drivers/i915/i915_fpc_translate.c +++ b/src/gallium/drivers/i915/i915_fpc_translate.c @@ -1039,12 +1039,15 @@ i915_fini_compile(struct i915_context *i915, struct i915_fp_compile *p) memcpy(&ifs->program[decl_size], p->program, program_size * sizeof(uint32_t)); - util_debug_message( - &i915->debug, SHADER_INFO, - "%s shader: %d inst, %d tex, %d tex_indirect, %d temps, %d const", - _mesa_shader_stage_to_abbrev(MESA_SHADER_FRAGMENT), (int)program_size, - p->nr_tex_insn, p->nr_tex_indirect, - p->shader->info.file_max[TGSI_FILE_TEMPORARY] + 1, ifs->num_constants); + if (i915) { + util_debug_message( + &i915->debug, SHADER_INFO, + "%s shader: %d inst, %d tex, %d tex_indirect, %d temps, %d const", + _mesa_shader_stage_to_abbrev(MESA_SHADER_FRAGMENT), + (int)program_size, p->nr_tex_insn, p->nr_tex_indirect, + p->shader->info.file_max[TGSI_FILE_TEMPORARY] + 1, + ifs->num_constants); + } } if (strlen(p->error) != 0) diff --git a/src/gallium/drivers/i915/i915_screen.c b/src/gallium/drivers/i915/i915_screen.c index 6462ced9992..8c81bd7c588 100644 --- a/src/gallium/drivers/i915/i915_screen.c +++ b/src/gallium/drivers/i915/i915_screen.c @@ -27,6 +27,7 @@ #include "compiler/nir/nir.h" #include "draw/draw_context.h" +#include "nir/nir_to_tgsi.h" #include "util/format/u_format.h" #include "util/format/u_format_s3tc.h" #include "util/os_misc.h" @@ -37,6 +38,7 @@ #include "i915_context.h" #include "i915_debug.h" +#include "i915_fpc.h" #include "i915_public.h" #include "i915_reg.h" #include "i915_resource.h" @@ -277,7 +279,10 @@ i915_finalize_nir(struct pipe_screen *pscreen, void *nir) if (msg) return strdup(msg); - return NULL; + if (s->info.stage == MESA_SHADER_FRAGMENT) + return i915_test_fragment_shader_compile(pscreen, s); + else + return NULL; } static int diff --git a/src/gallium/drivers/i915/i915_state.c b/src/gallium/drivers/i915/i915_state.c index 151d1c7928e..8d8c3527823 100644 --- a/src/gallium/drivers/i915/i915_state.c +++ b/src/gallium/drivers/i915/i915_state.c @@ -534,6 +534,10 @@ i915_set_polygon_stipple(struct pipe_context *pipe, { } +static const struct nir_to_tgsi_options ntt_options = { + .lower_fabs = true, +}; + static void * i915_create_fs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ) @@ -549,9 +553,6 @@ i915_create_fs_state(struct pipe_context *pipe, nir_shader *s = templ->ir.nir; ifs->internal = s->info.internal; - static const struct nir_to_tgsi_options ntt_options = { - .lower_fabs = true, - }; ifs->state.tokens = nir_to_tgsi_options(s, pipe->screen, &ntt_options); } else { assert(templ->type == PIPE_SHADER_IR_TGSI); @@ -606,6 +607,37 @@ i915_delete_fs_state(struct pipe_context *pipe, void *shader) FREE(ifs); } +/* Does a test compile at link time to see if we'll be able to run this shader + * at runtime. Return a string to the GLSL compiler for anything we should + * report as link failure. + */ +char * +i915_test_fragment_shader_compile(struct pipe_screen *screen, nir_shader *s) +{ + struct i915_fragment_shader *ifs = CALLOC_STRUCT(i915_fragment_shader); + if (!ifs) + return NULL; + + /* NTT takes ownership of the shader, give it a clone. */ + s = nir_shader_clone(NULL, s); + + ifs->internal = s->info.internal; + ifs->state.tokens = nir_to_tgsi_options(s, screen, &ntt_options); + ifs->state.type = PIPE_SHADER_IR_TGSI; + + tgsi_scan_shader(ifs->state.tokens, &ifs->info); + + i915_translate_fragment_program(NULL, ifs); + + char *msg = NULL; + if (ifs->error) + msg = strdup(ifs->error); + + i915_delete_fs_state(NULL, ifs); + + return msg; +} + static void * i915_create_vs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ)