From 38ecde9da31742d7e77278a18b1a1fbbd8ba473d Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Wed, 9 Jul 2025 15:19:50 +0800 Subject: [PATCH] shader: fixed shader compile and linking errors --- src/imview/CMakeLists.txt | 1 + .../imview/opengl_capability_checker.hpp | 68 ++++++ src/imview/include/imview/viewer.hpp | 1 + src/imview/src/opengl_capability_checker.cpp | 213 ++++++++++++++++++ src/imview/src/viewer.cpp | 39 ++++ src/imview/src/window.cpp | 25 +- src/renderer/src/renderable/canvas.cpp | 12 + .../src/renderable/coordinate_frame.cpp | 12 + src/renderer/src/renderable/grid.cpp | 12 + src/renderer/src/renderable/point_cloud.cpp | 7 +- src/renderer/src/renderable/texture.cpp | 9 +- src/renderer/src/renderable/triangle.cpp | 12 + src/renderer/src/shader.cpp | 26 ++- src/renderer/src/shader_program.cpp | 52 ++++- 14 files changed, 475 insertions(+), 14 deletions(-) create mode 100644 src/imview/include/imview/opengl_capability_checker.hpp create mode 100644 src/imview/src/opengl_capability_checker.cpp diff --git a/src/imview/CMakeLists.txt b/src/imview/CMakeLists.txt index 5cfa797..79babdc 100644 --- a/src/imview/CMakeLists.txt +++ b/src/imview/CMakeLists.txt @@ -40,6 +40,7 @@ add_library(imview src/popup_manager.cpp src/logging/log_processor.cpp src/logging/app_log_handler.cpp + src/opengl_capability_checker.cpp ${AUTO_LAYOUT_SRC} # terminal ${TUI_COMP_SRC}) diff --git a/src/imview/include/imview/opengl_capability_checker.hpp b/src/imview/include/imview/opengl_capability_checker.hpp new file mode 100644 index 0000000..c94fcf5 --- /dev/null +++ b/src/imview/include/imview/opengl_capability_checker.hpp @@ -0,0 +1,68 @@ +/* + * opengl_capability_checker.hpp + * + * Created on: 2025-01-09 + * Description: OpenGL capability detection and validation utility + * + * Copyright (c) 2025 Ruixiang Du (rdu) + */ + +#pragma once + +#include +#include + +namespace quickviz { + +struct OpenGLCapabilities { + int major_version = 0; + int minor_version = 0; + std::string version_string; + std::string vendor; + std::string renderer; + std::string glsl_version; + bool core_profile = false; + bool supports_required_version = false; + std::vector available_extensions; + std::string error_message; +}; + +class OpenGLCapabilityChecker { +public: + /** + * @brief Check OpenGL capabilities and validate minimum requirements + * @param required_major Minimum required OpenGL major version (default: 3) + * @param required_minor Minimum required OpenGL minor version (default: 3) + * @return OpenGLCapabilities structure with detected capabilities + */ + static OpenGLCapabilities CheckCapabilities(int required_major = 3, + int required_minor = 3); + + /** + * @brief Print detailed OpenGL capability information to console + * @param capabilities OpenGL capabilities structure + */ + static void PrintCapabilities(const OpenGLCapabilities& capabilities); + + /** + * @brief Check if a specific OpenGL extension is supported + * @param extension_name Name of the extension to check + * @return True if extension is supported, false otherwise + */ + static bool IsExtensionSupported(const std::string& extension_name); + + /** + * @brief Validate that the OpenGL context supports required features + * @param capabilities OpenGL capabilities structure + * @return True if all required features are supported, false otherwise + */ + static bool ValidateRequiredFeatures(const OpenGLCapabilities& capabilities); + +private: + static std::vector GetAvailableExtensions(); + static bool IsIntelGPU(const std::string& vendor, const std::string& renderer); + static bool IsAMDGPU(const std::string& vendor, const std::string& renderer); + static bool IsNVIDIAGPU(const std::string& vendor, const std::string& renderer); +}; + +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/include/imview/viewer.hpp b/src/imview/include/imview/viewer.hpp index 3a33fbe..3025133 100644 --- a/src/imview/include/imview/viewer.hpp +++ b/src/imview/include/imview/viewer.hpp @@ -69,6 +69,7 @@ class Viewer : public Window { private: void LoadDefaultStyle(); void OnResize(GLFWwindow* window, int width, int height); + void CheckOpenGLCapabilities(); void EnumerateJoysticks(); void OnJoystickEvent(int id, int event); diff --git a/src/imview/src/opengl_capability_checker.cpp b/src/imview/src/opengl_capability_checker.cpp new file mode 100644 index 0000000..3201ab1 --- /dev/null +++ b/src/imview/src/opengl_capability_checker.cpp @@ -0,0 +1,213 @@ +/* + * opengl_capability_checker.cpp + * + * Created on: 2025-01-09 + * Description: OpenGL capability detection and validation utility + * + * Copyright (c) 2025 Ruixiang Du (rdu) + */ + +#include "imview/opengl_capability_checker.hpp" + +#include +#include +#include +#include + +#ifdef IMVIEW_WITH_GLAD +#include "glad/glad.h" +#else +#include +#endif + +namespace quickviz { + +OpenGLCapabilities OpenGLCapabilityChecker::CheckCapabilities(int required_major, + int required_minor) { + OpenGLCapabilities caps; + + try { + // Get OpenGL version string + const char* version_str = reinterpret_cast(glGetString(GL_VERSION)); + if (version_str) { + caps.version_string = version_str; + } else { + caps.error_message = "Failed to get OpenGL version string"; + return caps; + } + + // Get vendor information + const char* vendor_str = reinterpret_cast(glGetString(GL_VENDOR)); + if (vendor_str) { + caps.vendor = vendor_str; + } + + // Get renderer information + const char* renderer_str = reinterpret_cast(glGetString(GL_RENDERER)); + if (renderer_str) { + caps.renderer = renderer_str; + } + + // Get GLSL version + const char* glsl_version_str = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); + if (glsl_version_str) { + caps.glsl_version = glsl_version_str; + } + + // Parse OpenGL version numbers + if (sscanf(version_str, "%d.%d", &caps.major_version, &caps.minor_version) != 2) { + // Try alternative parsing for some drivers + if (sscanf(version_str, "OpenGL ES %d.%d", &caps.major_version, &caps.minor_version) != 2) { + caps.error_message = "Failed to parse OpenGL version numbers from: " + caps.version_string; + return caps; + } + } + + // Check if we have the required OpenGL version + if (caps.major_version > required_major || + (caps.major_version == required_major && caps.minor_version >= required_minor)) { + caps.supports_required_version = true; + } else { + std::stringstream ss; + ss << "OpenGL " << required_major << "." << required_minor + << " required, but only " << caps.major_version << "." << caps.minor_version + << " is available"; + caps.error_message = ss.str(); + } + + // Check for core profile (OpenGL 3.2+) + if (caps.major_version >= 3 && caps.minor_version >= 2) { + GLint profile = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); + caps.core_profile = (profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0; + } + + // Get available extensions + caps.available_extensions = GetAvailableExtensions(); + + // Check for common problematic configurations + if (IsIntelGPU(caps.vendor, caps.renderer)) { + // Intel GPUs sometimes have issues with OpenGL 3.3+ on older drivers + if (caps.major_version == 3 && caps.minor_version >= 3) { + std::cout << "WARNING: Intel GPU detected. If you experience shader issues, " + << "consider updating your graphics drivers." << std::endl; + } + } + + // Check for Mesa software rendering + if (caps.renderer.find("llvmpipe") != std::string::npos || + caps.renderer.find("softpipe") != std::string::npos) { + std::cout << "WARNING: Software rendering detected (" << caps.renderer + << "). Performance may be poor." << std::endl; + } + + } catch (const std::exception& e) { + caps.error_message = "Exception during OpenGL capability check: " + std::string(e.what()); + } + + return caps; +} + +void OpenGLCapabilityChecker::PrintCapabilities(const OpenGLCapabilities& capabilities) { + std::cout << "=== OpenGL Capabilities ===" << std::endl; + std::cout << "Version: " << capabilities.version_string << std::endl; + std::cout << "Vendor: " << capabilities.vendor << std::endl; + std::cout << "Renderer: " << capabilities.renderer << std::endl; + std::cout << "GLSL Version: " << capabilities.glsl_version << std::endl; + std::cout << "Parsed Version: " << capabilities.major_version << "." << capabilities.minor_version << std::endl; + std::cout << "Core Profile: " << (capabilities.core_profile ? "Yes" : "No") << std::endl; + std::cout << "Required Version Support: " << (capabilities.supports_required_version ? "Yes" : "No") << std::endl; + + if (!capabilities.error_message.empty()) { + std::cout << "Error: " << capabilities.error_message << std::endl; + } + + std::cout << "Available Extensions: " << capabilities.available_extensions.size() << std::endl; + std::cout << "=========================" << std::endl; +} + +bool OpenGLCapabilityChecker::IsExtensionSupported(const std::string& extension_name) { + auto extensions = GetAvailableExtensions(); + return std::find(extensions.begin(), extensions.end(), extension_name) != extensions.end(); +} + +bool OpenGLCapabilityChecker::ValidateRequiredFeatures(const OpenGLCapabilities& capabilities) { + if (!capabilities.supports_required_version) { + return false; + } + + // Check for essential OpenGL 3.3 features + if (capabilities.major_version >= 3 && capabilities.minor_version >= 3) { + // Vertex Array Objects should be available + if (!IsExtensionSupported("GL_ARB_vertex_array_object") && + !(capabilities.major_version > 3 || (capabilities.major_version == 3 && capabilities.minor_version >= 3))) { + std::cout << "WARNING: Vertex Array Objects may not be supported" << std::endl; + } + } + + return true; +} + +std::vector OpenGLCapabilityChecker::GetAvailableExtensions() { + std::vector extensions; + + // Try modern way first (OpenGL 3.0+) + GLint num_extensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + + if (num_extensions > 0) { + for (GLint i = 0; i < num_extensions; i++) { + const char* ext = reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); + if (ext) { + extensions.push_back(ext); + } + } + } else { + // Fallback to legacy method (OpenGL < 3.0) + const char* extensions_str = reinterpret_cast(glGetString(GL_EXTENSIONS)); + if (extensions_str) { + std::string ext_string(extensions_str); + std::istringstream iss(ext_string); + std::string ext; + while (iss >> ext) { + extensions.push_back(ext); + } + } + } + + return extensions; +} + +bool OpenGLCapabilityChecker::IsIntelGPU(const std::string& vendor, const std::string& renderer) { + std::string vendor_lower = vendor; + std::string renderer_lower = renderer; + std::transform(vendor_lower.begin(), vendor_lower.end(), vendor_lower.begin(), ::tolower); + std::transform(renderer_lower.begin(), renderer_lower.end(), renderer_lower.begin(), ::tolower); + + return vendor_lower.find("intel") != std::string::npos || + renderer_lower.find("intel") != std::string::npos; +} + +bool OpenGLCapabilityChecker::IsAMDGPU(const std::string& vendor, const std::string& renderer) { + std::string vendor_lower = vendor; + std::string renderer_lower = renderer; + std::transform(vendor_lower.begin(), vendor_lower.end(), vendor_lower.begin(), ::tolower); + std::transform(renderer_lower.begin(), renderer_lower.end(), renderer_lower.begin(), ::tolower); + + return vendor_lower.find("amd") != std::string::npos || + vendor_lower.find("ati") != std::string::npos || + renderer_lower.find("radeon") != std::string::npos; +} + +bool OpenGLCapabilityChecker::IsNVIDIAGPU(const std::string& vendor, const std::string& renderer) { + std::string vendor_lower = vendor; + std::string renderer_lower = renderer; + std::transform(vendor_lower.begin(), vendor_lower.end(), vendor_lower.begin(), ::tolower); + std::transform(renderer_lower.begin(), renderer_lower.end(), renderer_lower.begin(), ::tolower); + + return vendor_lower.find("nvidia") != std::string::npos || + renderer_lower.find("geforce") != std::string::npos || + renderer_lower.find("quadro") != std::string::npos; +} + +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/src/viewer.cpp b/src/imview/src/viewer.cpp index c1a7a8d..6df4de1 100644 --- a/src/imview/src/viewer.cpp +++ b/src/imview/src/viewer.cpp @@ -23,6 +23,7 @@ #include "implot/implot.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" +#include "imview/opengl_capability_checker.hpp" namespace quickviz { namespace { @@ -86,6 +87,9 @@ Viewer::Viewer(std::string title, uint32_t width, uint32_t height, #endif ImGui_ImplOpenGL3_Init(glsl_version); + // Check OpenGL capabilities after context creation + CheckOpenGLCapabilities(); + // set up callbacks // convert callback-function to c-pointer first FramebufferSizeCallback::func = @@ -411,6 +415,41 @@ void Viewer::OnResize(GLFWwindow *window, int width, int height) { } } +void Viewer::CheckOpenGLCapabilities() { + // Check OpenGL capabilities and validate requirements + auto capabilities = OpenGLCapabilityChecker::CheckCapabilities(3, 3); + + if (!capabilities.error_message.empty()) { + std::cerr << "[ERROR] OpenGL Capability Check Failed: " << capabilities.error_message << std::endl; + OpenGLCapabilityChecker::PrintCapabilities(capabilities); + + // Try to provide helpful error messages + if (!capabilities.supports_required_version) { + std::cerr << std::endl << "=== TROUBLESHOOTING ===" << std::endl; + std::cerr << "This application requires OpenGL 3.3 or higher." << std::endl; + std::cerr << "Your system only supports OpenGL " << capabilities.major_version + << "." << capabilities.minor_version << std::endl; + std::cerr << "Possible solutions:" << std::endl; + std::cerr << "1. Update your graphics drivers" << std::endl; + std::cerr << "2. Check if your GPU supports OpenGL 3.3+" << std::endl; + std::cerr << "3. For Intel GPUs, ensure you have the latest drivers" << std::endl; + std::cerr << "4. Try running with software rendering (slower performance)" << std::endl; + std::cerr << "===========================================" << std::endl; + } + + throw std::runtime_error("OpenGL capability check failed: " + capabilities.error_message); + } + + // Print capabilities for debugging + std::cout << "[INFO] OpenGL capabilities validated successfully" << std::endl; + OpenGLCapabilityChecker::PrintCapabilities(capabilities); + + // Validate required features + if (!OpenGLCapabilityChecker::ValidateRequiredFeatures(capabilities)) { + std::cerr << "[WARNING] Some required OpenGL features may not be fully supported" << std::endl; + } +} + void Viewer::Show() { // initialize layers int display_w, display_h; diff --git a/src/imview/src/window.cpp b/src/imview/src/window.cpp index 0d5ea4a..66b14c6 100644 --- a/src/imview/src/window.cpp +++ b/src/imview/src/window.cpp @@ -10,6 +10,7 @@ #include "imview/window.hpp" #include +#include namespace quickviz { namespace { @@ -34,7 +35,29 @@ Window::Window(std::string title, uint32_t width, uint32_t height, // create GLFW window win_ = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); if (win_ == NULL) { - throw std::runtime_error("Failed to create GLFW window"); + std::cerr << "Failed to create GLFW window with requested OpenGL version" << std::endl; + + // Try fallback to compatibility profile + std::cerr << "Attempting fallback to compatibility profile..." << std::endl; + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); + win_ = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); + + if (win_ == NULL) { + // Try even lower OpenGL version + std::cerr << "Attempting fallback to OpenGL 3.0..." << std::endl; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); + win_ = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); + + if (win_ == NULL) { + throw std::runtime_error("Failed to create GLFW window even with fallback options"); + } else { + std::cerr << "Successfully created window with OpenGL 3.0 compatibility profile" << std::endl; + } + } else { + std::cerr << "Successfully created window with compatibility profile" << std::endl; + } } glfwMakeContextCurrent(win_); glfwSwapInterval(1); diff --git a/src/renderer/src/renderable/canvas.cpp b/src/renderer/src/renderable/canvas.cpp index bdc127a..d7bf949 100644 --- a/src/renderer/src/renderable/canvas.cpp +++ b/src/renderer/src/renderable/canvas.cpp @@ -342,6 +342,18 @@ void Canvas::SetupBackgroundImage(int width, int height, int channels, Shader::Type::kVertex); Shader background_fragment_shader(background_fragment_shader_source.c_str(), Shader::Type::kFragment); + + // IMPORTANT: Compile shaders before linking + if (!background_vertex_shader.Compile()) { + std::cerr << "ERROR::CANVAS::BACKGROUND_VERTEX_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Background vertex shader compilation failed"); + } + + if (!background_fragment_shader.Compile()) { + std::cerr << "ERROR::CANVAS::BACKGROUND_FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Background fragment shader compilation failed"); + } + background_shader_.AttachShader(background_vertex_shader); background_shader_.AttachShader(background_fragment_shader); diff --git a/src/renderer/src/renderable/coordinate_frame.cpp b/src/renderer/src/renderable/coordinate_frame.cpp index 2ea2bbc..e8fcce1 100644 --- a/src/renderer/src/renderable/coordinate_frame.cpp +++ b/src/renderer/src/renderable/coordinate_frame.cpp @@ -161,6 +161,18 @@ void CoordinateFrame::AllocateGpuResources() { // Compile and link shaders Shader vertex_shader(vertex_shader_source.c_str(), Shader::Type::kVertex); Shader fragment_shader(fragment_shader_source.c_str(), Shader::Type::kFragment); + + // IMPORTANT: Compile shaders before linking + if (!vertex_shader.Compile()) { + std::cerr << "ERROR::COORDINATE_FRAME::VERTEX_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Vertex shader compilation failed"); + } + + if (!fragment_shader.Compile()) { + std::cerr << "ERROR::COORDINATE_FRAME::FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Fragment shader compilation failed"); + } + shader_.AttachShader(vertex_shader); shader_.AttachShader(fragment_shader); diff --git a/src/renderer/src/renderable/grid.cpp b/src/renderer/src/renderable/grid.cpp index 30c9719..bacbe93 100644 --- a/src/renderer/src/renderable/grid.cpp +++ b/src/renderer/src/renderable/grid.cpp @@ -97,6 +97,18 @@ void Grid::AllocateGpuResources() { Shader vertex_shader(vertex_shader_source.c_str(), Shader::Type::kVertex); Shader fragment_shader(fragment_shader_source.c_str(), Shader::Type::kFragment); + + // IMPORTANT: Compile shaders before linking + if (!vertex_shader.Compile()) { + std::cerr << "ERROR::GRID::VERTEX_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Vertex shader compilation failed"); + } + + if (!fragment_shader.Compile()) { + std::cerr << "ERROR::GRID::FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Fragment shader compilation failed"); + } + shader_.AttachShader(vertex_shader); shader_.AttachShader(fragment_shader); diff --git a/src/renderer/src/renderable/point_cloud.cpp b/src/renderer/src/renderable/point_cloud.cpp index e409b20..ff73465 100644 --- a/src/renderer/src/renderable/point_cloud.cpp +++ b/src/renderer/src/renderable/point_cloud.cpp @@ -62,12 +62,15 @@ void PointCloud::AllocateGpuResources() { Shader vertexShader(vertex_shader_source, Shader::Type::kVertex); Shader fragmentShader(fragment_shader_source, Shader::Type::kFragment); + // IMPORTANT: Compile shaders before linking if (!vertexShader.Compile()) { - throw std::runtime_error("Failed to compile vertex shader for point cloud"); + std::cerr << "ERROR::POINT_CLOUD::VERTEX_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Vertex shader compilation failed"); } if (!fragmentShader.Compile()) { - throw std::runtime_error("Failed to compile fragment shader for point cloud"); + std::cerr << "ERROR::POINT_CLOUD::FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Fragment shader compilation failed"); } // Create shader program diff --git a/src/renderer/src/renderable/texture.cpp b/src/renderer/src/renderable/texture.cpp index 4841eeb..5dcc5c8 100644 --- a/src/renderer/src/renderable/texture.cpp +++ b/src/renderer/src/renderable/texture.cpp @@ -129,15 +129,18 @@ void Texture::AllocateGpuResources() { std::cout << "Compiling texture vertex shader..." << std::endl; Shader vertex_shader(texture_vertex_shader_source.c_str(), Shader::Type::kVertex); + + std::cout << "Compiling texture fragment shader..." << std::endl; + Shader fragment_shader(texture_fragment_shader_source.c_str(), + Shader::Type::kFragment); + + // IMPORTANT: Compile shaders before linking if (!vertex_shader.Compile()) { std::cerr << "ERROR::TEXTURE::VERTEX_SHADER_COMPILATION_FAILED" << std::endl; throw std::runtime_error("Vertex shader compilation failed"); } - std::cout << "Compiling texture fragment shader..." << std::endl; - Shader fragment_shader(texture_fragment_shader_source.c_str(), - Shader::Type::kFragment); if (!fragment_shader.Compile()) { std::cerr << "ERROR::TEXTURE::FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; diff --git a/src/renderer/src/renderable/triangle.cpp b/src/renderer/src/renderable/triangle.cpp index 045e3d4..0cdbd55 100644 --- a/src/renderer/src/renderable/triangle.cpp +++ b/src/renderer/src/renderable/triangle.cpp @@ -91,6 +91,18 @@ void Triangle::AllocateGpuResources() { // Compile and link shaders Shader vertex_shader(vertex_shader_source.c_str(), Shader::Type::kVertex); Shader fragment_shader(fragment_shader_source.c_str(), Shader::Type::kFragment); + + // IMPORTANT: Compile shaders before linking + if (!vertex_shader.Compile()) { + std::cerr << "ERROR::TRIANGLE::VERTEX_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Vertex shader compilation failed"); + } + + if (!fragment_shader.Compile()) { + std::cerr << "ERROR::TRIANGLE::FRAGMENT_SHADER_COMPILATION_FAILED" << std::endl; + throw std::runtime_error("Fragment shader compilation failed"); + } + shader_.AttachShader(vertex_shader); shader_.AttachShader(fragment_shader); diff --git a/src/renderer/src/shader.cpp b/src/renderer/src/shader.cpp index 2a1e38b..9897834 100644 --- a/src/renderer/src/shader.cpp +++ b/src/renderer/src/shader.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "glad/glad.h" @@ -76,12 +77,29 @@ bool Shader::Compile() { glCompileShader(shader_id_); GLint success; - GLchar infoLog[512]; + GLchar infoLog[1024]; glGetShaderiv(shader_id_, GL_COMPILE_STATUS, &success); if (!success) { - glGetShaderInfoLog(shader_id_, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" - << infoLog << std::endl; + glGetShaderInfoLog(shader_id_, 1024, NULL, infoLog); + + // Provide more detailed error information + std::string shader_type_str = (type_ == Type::kVertex) ? "VERTEX" : "FRAGMENT"; + std::cerr << "ERROR::SHADER::" << shader_type_str << "::COMPILATION_FAILED" << std::endl; + std::cerr << "Shader source file: " << source_file_ << std::endl; + std::cerr << "Compilation error: " << infoLog << std::endl; + + // Print the shader source code with line numbers for debugging + std::cerr << "Shader source code:" << std::endl; + std::cerr << "===================" << std::endl; + std::istringstream iss(source_code_); + std::string line; + int line_number = 1; + while (std::getline(iss, line)) { + std::cerr << std::setfill('0') << std::setw(3) << line_number << ": " << line << std::endl; + line_number++; + } + std::cerr << "===================" << std::endl; + return false; } return success; diff --git a/src/renderer/src/shader_program.cpp b/src/renderer/src/shader_program.cpp index 58185d2..2b3f077 100644 --- a/src/renderer/src/shader_program.cpp +++ b/src/renderer/src/shader_program.cpp @@ -26,10 +26,54 @@ bool ShaderProgram::LinkProgram() { GLint success; glGetProgramiv(program_id_, GL_LINK_STATUS, &success); if (!success) { - GLchar infoLog[512]; - glGetProgramInfoLog(program_id_, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" - << infoLog << std::endl; + GLchar infoLog[1024]; + glGetProgramInfoLog(program_id_, 1024, NULL, infoLog); + + std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << std::endl; + std::cerr << "Program ID: " << program_id_ << std::endl; + std::cerr << "Linking error: " << infoLog << std::endl; + + // Check if shaders were properly compiled before linking + GLint num_shaders; + glGetProgramiv(program_id_, GL_ATTACHED_SHADERS, &num_shaders); + std::cerr << "Number of attached shaders: " << num_shaders << std::endl; + + if (num_shaders > 0) { + GLuint shaders[10]; + GLsizei count; + glGetAttachedShaders(program_id_, 10, &count, shaders); + + for (int i = 0; i < count; i++) { + GLint shader_type; + glGetShaderiv(shaders[i], GL_SHADER_TYPE, &shader_type); + + GLint compile_status; + glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &compile_status); + + std::string type_str = (shader_type == GL_VERTEX_SHADER) ? "VERTEX" : + (shader_type == GL_FRAGMENT_SHADER) ? "FRAGMENT" : "UNKNOWN"; + + std::cerr << "Shader " << i << " (ID: " << shaders[i] << ", Type: " << type_str + << ") - Compiled: " << (compile_status ? "YES" : "NO") << std::endl; + + if (!compile_status) { + GLchar shader_info[512]; + glGetShaderInfoLog(shaders[i], 512, NULL, shader_info); + std::cerr << "Shader " << i << " compilation error: " << shader_info << std::endl; + } + } + } + + // Additional troubleshooting information + std::cerr << std::endl << "=== SHADER LINKING TROUBLESHOOTING ===" << std::endl; + std::cerr << "Common causes of linking failures:" << std::endl; + std::cerr << "1. Shader compilation failed (see above)" << std::endl; + std::cerr << "2. Vertex shader output doesn't match fragment shader input" << std::endl; + std::cerr << "3. Missing main() function in shader" << std::endl; + std::cerr << "4. OpenGL version mismatch (#version directive)" << std::endl; + std::cerr << "5. Hardware/driver doesn't support required features" << std::endl; + std::cerr << "=========================================" << std::endl; + return false; } return true;