#include "gfx/gl_loader.h" #include "gfx/gpu_compute_program.h" #include #include #include namespace fn::gfx { static int parse_err_line(const char* log) { std::regex re1(R"(ERROR:\s*\d+:(\d+):)"); std::regex re2(R"(\d+\((\d+)\))"); std::cmatch m; if (std::regex_search(log, m, re1)) return std::stoi(m[1].str()); if (std::regex_search(log, m, re2)) return std::stoi(m[1].str()); return -1; } static int count_lines(const std::string& s) { int n = 0; for (char c : s) if (c == '\n') ++n; return n; } static ComputeCompileResult compile_with_layout(const std::string& layout_line, const std::string& user_body, const std::string& preamble) { ComputeCompileResult r; // Header fijo. count = lineas que sumamos antes del user_body, para // restar al err_line del log. std::string header = "#version 430 core\n"; header += layout_line; if (!preamble.empty()) { header += preamble; if (preamble.back() != '\n') header += '\n'; } int header_lines = count_lines(header); const char* srcs[2] = { header.c_str(), user_body.c_str() }; GLuint sh = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(sh, 2, srcs, nullptr); glCompileShader(sh); GLint ok = 0; glGetShaderiv(sh, GL_COMPILE_STATUS, &ok); if (!ok) { GLint len = 0; glGetShaderiv(sh, GL_INFO_LOG_LENGTH, &len); r.err_msg.resize(static_cast(len)); if (len > 0) glGetShaderInfoLog(sh, len, nullptr, &r.err_msg[0]); int line = parse_err_line(r.err_msg.c_str()); r.err_line = (line > header_lines) ? (line - header_lines) : line; glDeleteShader(sh); return r; } GLuint prog = glCreateProgram(); glAttachShader(prog, sh); glLinkProgram(prog); glDeleteShader(sh); glGetProgramiv(prog, GL_LINK_STATUS, &ok); if (!ok) { GLint len = 0; glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); r.err_msg.resize(static_cast(len)); if (len > 0) glGetProgramInfoLog(prog, len, nullptr, &r.err_msg[0]); r.err_line = parse_err_line(r.err_msg.c_str()); glDeleteProgram(prog); return r; } r.program = prog; r.ok = true; return r; } ComputeCompileResult compile_compute(const std::string& user_body, int local_size_x, const std::string& preamble) { char buf[64]; std::snprintf(buf, sizeof(buf), "layout(local_size_x = %d) in;\n", local_size_x); return compile_with_layout(buf, user_body, preamble); } ComputeCompileResult compile_compute_2d(const std::string& user_body, int local_size_x, int local_size_y, const std::string& preamble) { char buf[96]; std::snprintf(buf, sizeof(buf), "layout(local_size_x = %d, local_size_y = %d) in;\n", local_size_x, local_size_y); return compile_with_layout(buf, user_body, preamble); } void delete_compute_program(unsigned int program) { if (program) glDeleteProgram(program); } } // namespace fn::gfx