mesa: capture shaders to disk before invoking the linker

If there is an infinite loop in the GLSL linker, we want to write shaders
to disk before that.

Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32175>
This commit is contained in:
Marek Olšák 2024-11-17 04:08:30 -05:00 committed by Marge Bot
parent 3179c65a5a
commit 237ed6fd08

View file

@ -1276,6 +1276,60 @@ update_programs_in_pipeline(void *data, void *userData)
}
}
static void
capture_shader_program(struct gl_context *ctx,
struct gl_shader_program *shProg)
{
#ifndef CUSTOM_SHADER_REPLACEMENT
/* Capture .shader_test files. */
const char *capture_path = _mesa_get_shader_capture_path();
if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
/* Find an unused filename. */
FILE *file = NULL;
char *filename = NULL;
for (unsigned i = 0;; i++) {
if (i) {
filename = ralloc_asprintf(NULL, "%s/%u-%u.shader_test",
capture_path, shProg->Name, i);
} else {
filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
capture_path, shProg->Name);
}
file = os_file_create_unique(filename, 0644);
if (file)
break;
/* If we are failing for another reason than "this filename already
* exists", we are likely to fail again with another filename, so
* let's just give up */
if (errno != EEXIST)
break;
ralloc_free(filename);
}
if (file) {
fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
shProg->IsES ? " ES" : "", shProg->GLSL_Version / 100,
shProg->GLSL_Version % 100);
if (shProg->SeparateShader)
fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n");
fprintf(file, "\n");
for (unsigned i = 0; i < shProg->NumShaders; i++) {
fprintf(file, "[%s shader]\n%s\n",
_mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
shProg->Shaders[i]->Source);
}
fclose(file);
} else {
_mesa_warning(ctx, "Failed to open %s", filename);
}
ralloc_free(filename);
}
#endif
}
/**
* Link a program's shaders.
@ -1302,6 +1356,8 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
}
}
capture_shader_program(ctx, shProg);
unsigned programs_in_use = 0;
if (ctx->_Shader)
for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
@ -1345,53 +1401,6 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
&params);
}
#ifndef CUSTOM_SHADER_REPLACEMENT
/* Capture .shader_test files. */
const char *capture_path = _mesa_get_shader_capture_path();
if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
/* Find an unused filename. */
FILE *file = NULL;
char *filename = NULL;
for (unsigned i = 0;; i++) {
if (i) {
filename = ralloc_asprintf(NULL, "%s/%u-%u.shader_test",
capture_path, shProg->Name, i);
} else {
filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
capture_path, shProg->Name);
}
file = os_file_create_unique(filename, 0644);
if (file)
break;
/* If we are failing for another reason than "this filename already
* exists", we are likely to fail again with another filename, so
* let's just give up */
if (errno != EEXIST)
break;
ralloc_free(filename);
}
if (file) {
fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
shProg->IsES ? " ES" : "", shProg->GLSL_Version / 100,
shProg->GLSL_Version % 100);
if (shProg->SeparateShader)
fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n");
fprintf(file, "\n");
for (unsigned i = 0; i < shProg->NumShaders; i++) {
fprintf(file, "[%s shader]\n%s\n",
_mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
shProg->Shaders[i]->Source);
}
fclose(file);
} else {
_mesa_warning(ctx, "Failed to open %s", filename);
}
ralloc_free(filename);
}
#endif
if (shProg->data->LinkStatus == LINKING_FAILURE &&
(ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
_mesa_debug(ctx, "Error linking program %u:\n%s\n",