chore: auto-commit (95 archivos)

- cmd/fn/doctor.go
- cmd/fn/main.go
- cpp/apps/primitives_gallery/playground/tables/CMakeLists.txt
- cpp/apps/primitives_gallery/playground/tables/data_table.cpp
- cpp/apps/primitives_gallery/playground/tables/data_table_logic.cpp
- cpp/apps/primitives_gallery/playground/tables/data_table_logic.h
- cpp/apps/primitives_gallery/playground/tables/self_test.cpp
- cpp/apps/primitives_gallery/playground/tables/tql.cpp
- cpp/apps/primitives_gallery/playground/tables/viz.cpp
- cpp/apps/primitives_gallery/playground/tables/viz.h
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 00:50:34 +02:00
parent ef60449e64
commit a802f59f55
189 changed files with 18964 additions and 330 deletions
+96
View File
@@ -0,0 +1,96 @@
#include "gfx/gpu_check.h"
#include "gfx/gl_loader.h"
#include <cstring>
#include <string>
// CUDA runtime version via compile-time macro.
// cuda_runtime.h define CUDART_VERSION como XXYYZZ (ej. 12040 para 12.4.0).
// Solo se incluye si el header esta disponible; si no, cuda_runtime_version = "".
#if defined(__has_include) && __has_include(<cuda_runtime.h>)
#include <cuda_runtime.h>
#define FN_HAS_CUDA_RUNTIME 1
#endif
namespace fn::gfx {
static std::string safe_gl_string(GLenum name) {
const GLubyte* s = glGetString(name);
if (!s) return "";
return std::string(reinterpret_cast<const char*>(s));
}
static bool check_gl_version_43() {
// GL_VERSION tiene formato "major.minor ..." o "OpenGL ES major.minor ..."
const GLubyte* ver = glGetString(GL_VERSION);
if (!ver) return false;
int major = 0, minor = 0;
// Saltar prefijo "OpenGL ES " si lo hay
const char* p = reinterpret_cast<const char*>(ver);
if (std::strncmp(p, "OpenGL ES ", 10) == 0) p += 10;
// sscanf con la forma "X.Y"
// NOLINTNEXTLINE(cert-err34-c)
std::sscanf(p, "%d.%d", &major, &minor);
return (major > 4) || (major == 4 && minor >= 3);
}
bool gpu_check_caps(GpuCaps& out) {
out = GpuCaps{}; // reset
out.gl_vendor = safe_gl_string(GL_VENDOR);
out.gl_renderer = safe_gl_string(GL_RENDERER);
out.gl_version = safe_gl_string(GL_VERSION);
if (out.gl_vendor.empty()) {
// No hay contexto GL activo.
return false;
}
// Compute shader support: GL 4.3+ o ARB_compute_shader
{
const GLubyte* exts = glGetString(GL_EXTENSIONS);
bool has_arb = exts &&
std::strstr(reinterpret_cast<const char*>(exts),
"GL_ARB_compute_shader") != nullptr;
out.has_compute_shader = check_gl_version_43() || has_arb;
}
// Shader storage buffer: GL 4.3+ o ARB_shader_storage_buffer_object
{
const GLubyte* exts = glGetString(GL_EXTENSIONS);
bool has_ssbo_arb = exts &&
std::strstr(reinterpret_cast<const char*>(exts),
"GL_ARB_shader_storage_buffer_object") != nullptr;
out.has_storage_buffer = check_gl_version_43() || has_ssbo_arb;
}
// Workgroup limits (solo si hay compute shader support)
if (out.has_compute_shader) {
// GL_MAX_COMPUTE_WORK_GROUP_COUNT — indexed query
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &out.max_compute_workgroup_count[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &out.max_compute_workgroup_count[1]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &out.max_compute_workgroup_count[2]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &out.max_compute_workgroup_size[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &out.max_compute_workgroup_size[1]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &out.max_compute_workgroup_size[2]);
}
// CUDA runtime version (compile-time detection)
#if defined(FN_HAS_CUDA_RUNTIME)
{
int cuda_ver = CUDART_VERSION; // ej. 12040 para CUDA 12.4.0
int major = cuda_ver / 1000;
int minor = (cuda_ver % 1000) / 10;
char buf[16];
std::snprintf(buf, sizeof(buf), "%d.%d", major, minor);
out.cuda_runtime_version = buf;
}
#else
out.cuda_runtime_version = "";
#endif
return true;
}
} // namespace fn::gfx
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <string>
namespace fn::gfx {
// GpuCaps recopila capacidades OpenGL y CUDA del contexto activo.
// Todos los campos de cadena estan vacios ("") si el dato no esta disponible.
struct GpuCaps {
// OpenGL — requieren contexto GL activo antes de llamar gpu_check_caps.
std::string gl_vendor; // glGetString(GL_VENDOR) ej. "NVIDIA Corporation"
std::string gl_renderer; // glGetString(GL_RENDERER) ej. "NVIDIA GeForce RTX 3080/PCIe/SSE2"
std::string gl_version; // glGetString(GL_VERSION) ej. "4.6.0 NVIDIA 550.54.15"
// Compute shader limits (GL_MAX_COMPUTE_WORK_GROUP_COUNT/SIZE)
// Indice 0=X 1=Y 2=Z. Valor 0 si compute shaders no disponibles.
int max_compute_workgroup_count[3] = {0, 0, 0};
int max_compute_workgroup_size[3] = {0, 0, 0};
bool has_compute_shader = false; // GL_VERSION >= 4.3 o extension ARB_compute_shader
bool has_storage_buffer = false; // GL_VERSION >= 4.3 o extension ARB_shader_storage_buffer_object
// CUDA — vacio si CUDA runtime no detectado en compile time.
// Formato: "12.4" (major.minor) o "" si no disponible.
std::string cuda_runtime_version;
};
// gpu_check_caps rellena out con las capacidades del contexto OpenGL activo.
//
// REQUISITO: debe llamarse despues de inicializar el contexto GL y, en Windows,
// despues de fn::gfx::gl_loader_init(). Si se llama sin contexto activo el
// comportamiento es indefinido (glGetString devuelve nullptr).
//
// Retorna true si se pudo leer al menos el vendor GL (contexto activo).
// Retorna false si gl_vendor queda vacio (contexto no activo o driver defectuoso).
bool gpu_check_caps(GpuCaps& out);
} // namespace fn::gfx
+86
View File
@@ -0,0 +1,86 @@
---
name: gpu_check
kind: function
lang: cpp
domain: gfx
version: "1.0.0"
purity: impure
signature: "bool fn_gfx::gpu_check_caps(GpuCaps& out)"
description: "Rellena GpuCaps con las capacidades del contexto OpenGL activo: vendor, renderer, version, limites de compute workgroup, flags has_compute_shader/has_storage_buffer, y version CUDA runtime (deteccion en compile-time via CUDART_VERSION). Requiere contexto GL activo. Retorna false si el contexto no esta disponible."
tags: [gpu, opengl, cuda, caps, hardware, probe, gfx, compute, infra]
uses_functions: ["gl_loader_cpp_gfx"]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [gfx/gpu_check.h, gfx/gl_loader.h, cuda_runtime.h, cstring, string]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/gfx/gpu_check.cpp"
framework: opengl
params:
- name: out
desc: "Referencia a GpuCaps que se rellena con las capacidades detectadas. Se resetea al inicio de la llamada."
output: "true si el contexto GL esta activo y gl_vendor no esta vacio; false si no hay contexto GL activo o el driver devuelve nullptr para GL_VENDOR."
---
# gpu_check
Probing de capacidades GPU en runtime: OpenGL strings, compute shader support y CUDA.
## Uso tipico
```cpp
#include "gfx/gpu_check.h"
#include "gfx/gl_loader.h"
// Dentro de render(), despues del primer frame (contexto GL activo):
fn::gfx::GpuCaps caps;
if (fn::gfx::gpu_check_caps(caps)) {
printf("GPU: %s\n", caps.gl_renderer.c_str());
printf("Compute shaders: %s\n", caps.has_compute_shader ? "yes" : "no");
if (!caps.cuda_runtime_version.empty())
printf("CUDA runtime: %s\n", caps.cuda_runtime_version.c_str());
} else {
printf("No GL context active\n");
}
```
## Estructura GpuCaps
```cpp
struct GpuCaps {
std::string gl_vendor; // "NVIDIA Corporation"
std::string gl_renderer; // "NVIDIA GeForce RTX 3080/PCIe/SSE2"
std::string gl_version; // "4.6.0 NVIDIA 550.54.15"
int max_compute_workgroup_count[3]; // [65535, 65535, 65535] tipico NVIDIA
int max_compute_workgroup_size[3]; // [1024, 1024, 64] tipico
bool has_compute_shader; // GL 4.3+ o ARB_compute_shader
bool has_storage_buffer; // GL 4.3+ o ARB_shader_storage_buffer_object
std::string cuda_runtime_version; // "12.4" o "" si no compilado con CUDA
};
```
## CUDA detection
La version CUDA se detecta en **compile time** via el macro `CUDART_VERSION` de `<cuda_runtime.h>`. Si la app no esta compilada con el CUDA toolkit, `cuda_runtime_version` sera `""`. Para detection en runtime del toolkit del sistema, usar `cuda_toolkit_check_bash_infra`.
## Requisito de contexto GL
Llamar siempre despues de crear el contexto GL. En apps que usan `fn::run_app`, el contexto esta activo desde el primer frame del `render()` callback. En Windows, `fn::gfx::gl_loader_init()` debe haberse llamado antes para que los punteros de funcion esten resueltos.
## Uso previsto (fn doctor cpp-apps)
Esta funcion sera invocada por el audit de `fn doctor cpp-apps` para verificar que las apps C++ del registry tienen acceso a compute shaders cuando declaran dependencias de `gpu_compute_program`, `gpu_dispatch`, etc.
## CMakeLists.txt
```cmake
add_imgui_app(mi_app
main.cpp
${CMAKE_SOURCE_DIR}/cpp/functions/gfx/gpu_check.cpp
)
# CUDA opcional: si la app compila con CUDA toolkit el header cuda_runtime.h
# estara disponible y FN_HAS_CUDA_RUNTIME se activara automaticamente.
```