diff --git a/docs/test_error_handling.md b/docs/test_error_handling.md index bd5ffca..27c82c1 100644 --- a/docs/test_error_handling.md +++ b/docs/test_error_handling.md @@ -65,7 +65,7 @@ Now validates before attempting to read: **Example error messages**: ``` -File not found: /path/to/shader.spv +File not found: /path/to/shader.vert Please ensure the file exists at this location. ``` @@ -79,15 +79,15 @@ The file exists but cannot be opened. Check file permissions. #### Shader File Validation - Checks both vertex and fragment shader files exist before loading - Provides the shader key to help identify which pipeline failed -- Suggests checking that shaders are compiled and in the correct directory +- Suggests checking that shader sources are present in the correct directory **Example error message**: ``` -Vertex shader not found: shaders/cube.vert.spv +Vertex shader not found: shaders/cube.vert Shader key: default -Please ensure shader files are compiled and present in the shaders directory. +Please ensure shader source files are present in the shaders directory. ``` ### 4. Structured Vulkan Initialization ([sdl3_app_core.cpp](src/app/sdl3_app_core.cpp)) @@ -160,14 +160,14 @@ Plus a message box with the same error. ### Test Case 2: Missing Shader File ```bash cd build/Release -mv shaders/cube.vert.spv shaders/cube.vert.spv.backup +mv shaders/cube.vert shaders/cube.vert.backup ./sdl3_app --json-file-in ./config/seed_runtime.json ``` **Expected Result**: Message box showing: ``` -Vertex shader not found: shaders/cube.vert.spv +Vertex shader not found: shaders/cube.vert Shader key: default @@ -226,4 +226,3 @@ Application runs normally. If any errors occur during initialization, they will ## Conclusion The application now provides comprehensive error feedback instead of failing silently with a "see-through window". Every potential failure point has been wrapped with validation and clear error messages, making it much easier to diagnose and fix issues. - diff --git a/src/services/impl/gui_renderer.cpp b/src/services/impl/gui_renderer.cpp index 37dd73c..0ff44f0 100644 --- a/src/services/impl/gui_renderer.cpp +++ b/src/services/impl/gui_renderer.cpp @@ -247,18 +247,6 @@ shaderc_shader_kind ShadercKindFromStage(VkShaderStageFlagBits stage) { } } -std::vector ReadBinaryFile(const std::filesystem::path& path) { - std::ifstream file(path, std::ios::binary | std::ios::ate); - if (!file) { - throw std::runtime_error("Failed to read file: " + path.string()); - } - size_t fileSize = static_cast(file.tellg()); - std::vector buffer(fileSize); - file.seekg(0); - file.read(reinterpret_cast(buffer.data()), static_cast(fileSize)); - return buffer; -} - std::vector ReadShaderFile(const std::filesystem::path& path, VkShaderStageFlagBits stage, ILogger* logger) { @@ -273,36 +261,25 @@ std::vector ReadShaderFile(const std::filesystem::path& path, } std::filesystem::path shaderPath = path; - if (!std::filesystem::exists(shaderPath) && shaderPath.extension() == ".spv") { + if (shaderPath.extension() == ".spv") { std::filesystem::path sourcePath = shaderPath; sourcePath.replace_extension(); - if (std::filesystem::exists(sourcePath)) { - if (logger) { - logger->Trace("GuiRenderer", "ReadShaderFile", - "usingSource=" + sourcePath.string()); - } - shaderPath = sourcePath; + if (logger) { + logger->Trace("GuiRenderer", "ReadShaderFile", + "usingSource=" + sourcePath.string()); } + shaderPath = sourcePath; } if (!std::filesystem::exists(shaderPath)) { throw std::runtime_error("Shader file not found: " + shaderPath.string() + - "\n\nPlease ensure the source (.vert/.frag/etc.) or compiled .spv exists."); + "\n\nPlease ensure the shader source (.vert/.frag/etc.) exists."); } if (!std::filesystem::is_regular_file(shaderPath)) { throw std::runtime_error("Path is not a regular file: " + shaderPath.string()); } - if (shaderPath.extension() == ".spv") { - auto buffer = ReadBinaryFile(shaderPath); - if (logger) { - logger->Trace("GuiRenderer", "ReadShaderFile", - "loadedSpirvBytes=" + std::to_string(buffer.size())); - } - return buffer; - } - std::ifstream sourceFile(shaderPath); if (!sourceFile) { throw std::runtime_error("Failed to open shader source: " + shaderPath.string()); @@ -689,9 +666,9 @@ const std::vector& GuiRenderer::LoadShaderBytes(const std::filesystem:: void GuiRenderer::CreatePipeline(VkRenderPass renderPass, VkExtent2D extent) { // Load shader modules const std::filesystem::path vertexShaderPath = - scriptDirectory_.parent_path() / "shaders" / "gui_2d.vert.spv"; + scriptDirectory_.parent_path() / "shaders" / "gui_2d.vert"; const std::filesystem::path fragmentShaderPath = - scriptDirectory_.parent_path() / "shaders" / "gui_2d.frag.spv"; + scriptDirectory_.parent_path() / "shaders" / "gui_2d.frag"; if (logger_) { logger_->Trace("GuiRenderer", "CreatePipeline", "renderPassIsNull=" + std::string(renderPass == VK_NULL_HANDLE ? "true" : "false") + diff --git a/src/services/impl/pipeline_service.cpp b/src/services/impl/pipeline_service.cpp index 2dbc120..1364c0d 100644 --- a/src/services/impl/pipeline_service.cpp +++ b/src/services/impl/pipeline_service.cpp @@ -265,7 +265,7 @@ void PipelineService::CreatePipelinesInternal(VkRenderPass renderPass, VkExtent2 throw std::runtime_error( label + " shader not found: " + path + "\n\nShader key: " + key + - "\n\nPlease ensure the shader source (.vert/.frag/etc.) or compiled .spv exists."); + "\n\nPlease ensure the shader source (.vert/.frag/etc.) exists."); } }; @@ -393,15 +393,10 @@ bool PipelineService::HasShaderSource(const std::string& path) const { return false; } std::filesystem::path shaderPath(path); - if (std::filesystem::exists(shaderPath)) { - return true; - } if (shaderPath.extension() == ".spv") { - std::filesystem::path sourcePath = shaderPath; - sourcePath.replace_extension(); - return std::filesystem::exists(sourcePath); + shaderPath.replace_extension(); } - return false; + return std::filesystem::exists(shaderPath); } const std::vector& PipelineService::ReadShaderFile(const std::string& path, VkShaderStageFlagBits stage) { @@ -413,19 +408,17 @@ const std::vector& PipelineService::ReadShaderFile(const std::string& path } std::filesystem::path shaderPath(path); - if (!std::filesystem::exists(shaderPath) && shaderPath.extension() == ".spv") { + if (shaderPath.extension() == ".spv") { std::filesystem::path sourcePath = shaderPath; sourcePath.replace_extension(); - if (std::filesystem::exists(sourcePath)) { - logger_->Trace("PipelineService", "ReadShaderFile", - "usingSource=" + sourcePath.string()); - shaderPath = sourcePath; - } + logger_->Trace("PipelineService", "ReadShaderFile", + "usingSource=" + sourcePath.string()); + shaderPath = sourcePath; } if (!std::filesystem::exists(shaderPath)) { throw std::runtime_error("Shader file not found: " + shaderPath.string() + - "\n\nPlease ensure the source (.vert/.frag/etc.) or compiled .spv exists."); + "\n\nPlease ensure the shader source (.vert/.frag/etc.) exists."); } if (!std::filesystem::is_regular_file(shaderPath)) { @@ -441,53 +434,34 @@ const std::vector& PipelineService::ReadShaderFile(const std::string& path return cached->second; } - std::vector buffer; - if (shaderPath.extension() == ".spv") { - std::ifstream file(shaderPath, std::ios::ate | std::ios::binary); - if (!file) { - throw std::runtime_error("Failed to open shader file: " + shaderPath.string() + - "\n\nCheck file permissions."); - } - - size_t fileSize = static_cast(file.tellg()); - buffer.resize(fileSize); - - file.seekg(0); - file.read(buffer.data(), static_cast(fileSize)); - file.close(); - - logger_->Debug("Read shader file: " + shaderPath.string() + - " (" + std::to_string(fileSize) + " bytes)"); - } else { - std::ifstream sourceFile(shaderPath); - if (!sourceFile) { - throw std::runtime_error("Failed to open shader source: " + shaderPath.string()); - } - std::string source((std::istreambuf_iterator(sourceFile)), - std::istreambuf_iterator()); - sourceFile.close(); - - shaderc::Compiler compiler; - shaderc::CompileOptions options; - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); - - shaderc_shader_kind kind = ShadercKindFromStage(stage); - auto result = compiler.CompileGlslToSpv(source, kind, shaderPath.string().c_str(), options); - if (result.GetCompilationStatus() != shaderc_compilation_status_success) { - std::string error = result.GetErrorMessage(); - logger_->Error("Shader compilation failed: " + shaderPath.string() + "\n" + error); - throw std::runtime_error("Shader compilation failed: " + shaderPath.string() + "\n" + error); - } - - std::vector spirv(result.cbegin(), result.cend()); - buffer.resize(spirv.size() * sizeof(uint32_t)); - if (!buffer.empty()) { - std::memcpy(buffer.data(), spirv.data(), buffer.size()); - } - - logger_->Debug("Compiled shader: " + shaderPath.string() + - " (" + std::to_string(buffer.size()) + " bytes)"); + std::ifstream sourceFile(shaderPath); + if (!sourceFile) { + throw std::runtime_error("Failed to open shader source: " + shaderPath.string()); } + std::string source((std::istreambuf_iterator(sourceFile)), + std::istreambuf_iterator()); + sourceFile.close(); + + shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); + + shaderc_shader_kind kind = ShadercKindFromStage(stage); + auto result = compiler.CompileGlslToSpv(source, kind, shaderPath.string().c_str(), options); + if (result.GetCompilationStatus() != shaderc_compilation_status_success) { + std::string error = result.GetErrorMessage(); + logger_->Error("Shader compilation failed: " + shaderPath.string() + "\n" + error); + throw std::runtime_error("Shader compilation failed: " + shaderPath.string() + "\n" + error); + } + + std::vector spirv(result.cbegin(), result.cend()); + std::vector buffer(spirv.size() * sizeof(uint32_t)); + if (!buffer.empty()) { + std::memcpy(buffer.data(), spirv.data(), buffer.size()); + } + + logger_->Debug("Compiled shader: " + shaderPath.string() + + " (" + std::to_string(buffer.size()) + " bytes)"); auto inserted = shaderSpirvCache_.emplace(cacheKey, std::move(buffer)); logger_->Trace("PipelineService", "ReadShaderFile",