GPU: Add command line option to output shader source

This command line outputs only shaders whose name
matches the argument string.

Metal is missing as it waits until #147010 lands.

Pull Request: https://projects.blender.org/blender/blender/pulls/147970
This commit is contained in:
Clément Foucault
2025-10-13 14:37:54 +02:00
committed by Clément Foucault
parent 304461e761
commit 139fa532c1
4 changed files with 82 additions and 17 deletions

View File

@@ -170,7 +170,13 @@ struct Global {
* Triggers a GPU capture if the name matches a DebugScope.
* Set using `--debug-gpu-scope-capture "debug_scope"`.
*/
char gpu_debug_scope_name[200];
char gpu_debug_scope_name[100];
/**
* Save final shader string to disk.
* Set using `--debug-gpu-shader-source "shader_name"`.
*/
char gpu_debug_shader_source_name[100];
bool profile_gpu;
};

View File

@@ -38,6 +38,7 @@
#include <fmt/format.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
@@ -1218,6 +1219,21 @@ StringRefNull GLShader::glsl_patch_get(GLenum gl_stage)
return "";
}
static StringRefNull stage_name_get(GLenum gl_stage)
{
switch (gl_stage) {
case GL_VERTEX_SHADER:
return "vertex";
case GL_GEOMETRY_SHADER:
return "geometry";
case GL_FRAGMENT_SHADER:
return "fragment";
case GL_COMPUTE_SHADER:
return "compute";
}
return "";
}
GLuint GLShader::create_shader_stage(GLenum gl_stage,
MutableSpan<StringRefNull> sources,
GLSources &gl_sources,
@@ -1246,21 +1262,7 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage,
if (DEBUG_LOG_SHADER_SRC_ON_ERROR) {
/* Store the generated source for printing in case the link fails. */
StringRefNull source_type;
switch (gl_stage) {
case GL_VERTEX_SHADER:
source_type = "VertShader";
break;
case GL_GEOMETRY_SHADER:
source_type = "GeomShader";
break;
case GL_FRAGMENT_SHADER:
source_type = "FragShader";
break;
case GL_COMPUTE_SHADER:
source_type = "ComputeShader";
break;
}
StringRefNull source_type = stage_name_get(gl_stage);
debug_source += "\n\n----------" + source_type + "----------\n\n";
for (StringRefNull source : sources) {
@@ -1281,6 +1283,24 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage,
std::string concat_source = fmt::to_string(fmt::join(sources, ""));
std::string full_name = this->name_get() + "_" + stage_name_get(gl_stage);
if (this->name_get() == G.gpu_debug_shader_source_name) {
namespace fs = std::filesystem;
fs::path shader_dir = fs::current_path() / "Shaders";
fs::create_directories(shader_dir);
fs::path file_path = shader_dir / (full_name + ".glsl");
std::ofstream output_source_file(file_path);
if (output_source_file) {
output_source_file << concat_source;
output_source_file.close();
}
else {
std::cerr << "Shader Source Debug: Failed to open file: " << file_path << "\n";
}
}
/* Patch line directives so that we can make error reporting consistent. */
size_t start_pos = 0;
while ((start_pos = concat_source.find("#line ", start_pos)) != std::string::npos) {

View File

@@ -19,6 +19,11 @@
#include "vk_shader.hh"
#include "vk_shader_compiler.hh"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
namespace blender::gpu {
static std::optional<std::string> cache_dir_get()
@@ -212,10 +217,27 @@ static bool compile_ex(shaderc::Compiler &compiler,
options.SetGenerateDebugInfo();
}
std::string full_name = shader.name_get() + "_" + to_stage_name(stage);
if (shader.name_get() == G.gpu_debug_shader_source_name) {
namespace fs = std::filesystem;
fs::path shader_dir = fs::current_path() / "Shaders";
fs::create_directories(shader_dir);
fs::path file_path = shader_dir / (full_name + ".glsl");
std::ofstream output_source_file(file_path);
if (output_source_file) {
output_source_file << shader_module.combined_sources;
output_source_file.close();
}
else {
std::cerr << "Shader Source Debug: Failed to open file: " << file_path << "\n";
}
}
/* Removes line directive. */
std::string sources = patch_line_directives(shader_module.combined_sources);
std::string full_name = shader.name_get() + "_" + to_stage_name(stage);
shader_module.compilation_result = compiler.CompileGlslToSpv(
sources, stage, full_name.c_str(), options);
bool compilation_succeeded = shader_module.compilation_result.GetCompilationStatus() ==

View File

@@ -763,6 +763,7 @@ static void print_help(bArgs *ba, bool all)
BLI_args_print_arg_doc(ba, "--debug-gpu-force-workarounds");
BLI_args_print_arg_doc(ba, "--debug-gpu-compile-shaders");
BLI_args_print_arg_doc(ba, "--debug-gpu-shader-debug-info");
BLI_args_print_arg_doc(ba, "--debug-gpu-shader-source");
if (defs.with_renderdoc) {
BLI_args_print_arg_doc(ba, "--debug-gpu-scope-capture");
BLI_args_print_arg_doc(ba, "--debug-gpu-renderdoc");
@@ -1545,6 +1546,20 @@ static int arg_handle_debug_gpu_scope_capture_set(int argc, const char **argv, v
return 0;
}
static const char arg_handle_debug_gpu_shader_source_doc[] =
"\n"
"\tCapture the GPU commands issued inside the give scope name."
"\tFiles are saved in the current working directory inside a folder named \"Shaders\".";
static int arg_handle_debug_gpu_shader_source(int argc, const char **argv, void * /*data*/)
{
if (argc > 1) {
STRNCPY(G.gpu_debug_scope_name, argv[1]);
return 1;
}
fprintf(stderr, "\nError: you must specify a shader name to capture.\n");
return 0;
}
static const char arg_handle_debug_gpu_renderdoc_set_doc[] =
"\n"
"\tEnable RenderDoc integration for GPU frame grabbing and debugging.";
@@ -3014,6 +3029,8 @@ void main_args_setup(bContext *C, bArgs *ba, bool all)
"--debug-gpu-compile-shaders",
CB(arg_handle_debug_gpu_compile_shaders_set),
nullptr);
BLI_args_add(
ba, nullptr, "--debug-gpu-shader-source", CB(arg_handle_debug_gpu_shader_source), nullptr);
if (defs.with_renderdoc) {
BLI_args_add(ba,
nullptr,