diff --git a/source/blender/blenkernel/BKE_global.hh b/source/blender/blenkernel/BKE_global.hh index 76d7d967abe..812682141ff 100644 --- a/source/blender/blenkernel/BKE_global.hh +++ b/source/blender/blenkernel/BKE_global.hh @@ -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; }; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index feffad2075e..cd9dbf96b77 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -38,6 +38,7 @@ #include +#include #include #include #include @@ -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 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) { diff --git a/source/blender/gpu/vulkan/vk_shader_compiler.cc b/source/blender/gpu/vulkan/vk_shader_compiler.cc index c9ea8e19413..cac4065b5a2 100644 --- a/source/blender/gpu/vulkan/vk_shader_compiler.cc +++ b/source/blender/gpu/vulkan/vk_shader_compiler.cc @@ -19,6 +19,11 @@ #include "vk_shader.hh" #include "vk_shader_compiler.hh" +#include +#include +#include +#include + namespace blender::gpu { static std::optional 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() == diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc index 28c8486bbad..f46d089174a 100644 --- a/source/creator/creator_args.cc +++ b/source/creator/creator_args.cc @@ -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,