feat(cpp/gfx): GPU compute primitives for Monte Carlo (G1-G7)
Stack base de compute shaders OpenGL 4.3 para cargas Monte Carlo intensivas en GPU. Reutiliza el patron de graph_force_layout_gpu (SSBO + compute) y se integra con el resto del registry sin nuevos simbolos en gl_loader (todo lo que se necesita ya estaba expuesto). - gpu_ssbo: lifecycle de Shader Storage Buffer Objects. - gpu_compute_program: compila compute GLSL 4.3 con preamble inyectable (mismo pattern de gl_shader::compile_fragment). - gpu_dispatch: dispatch_1d/2d/3d con ceil(N/local) automatico + barrier helpers (storage, uniform, image, buffer_update, all). - gpu_rng_glsl: PCG32 GLSL (uniform/normal/below) + SplitMix64 seed walkers para sembrar deterministicamente N walkers desde un master seed. - gpu_histogram_1d: SSBO float[N] -> uint[nbins] via atomicAdd. - gpu_histogram_2d: SSBO float[2N] xy-interleaved -> uint[nx*ny] + to_density helper para alimentar heatmap_cpp_viz. - gpu_reduce: workgroup-shared sum/min/max/mean (local 256, partials CPU). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#include "gfx/gl_loader.h"
|
||||
#include "gfx/gpu_compute_program.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
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<std::size_t>(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<std::size_t>(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
|
||||
Reference in New Issue
Block a user