summaryrefslogtreecommitdiff
path: root/glw
diff options
context:
space:
mode:
Diffstat (limited to 'glw')
-rw-r--r--glw/debug.ha34
-rw-r--r--glw/glw.ha91
2 files changed, 125 insertions, 0 deletions
diff --git a/glw/debug.ha b/glw/debug.ha
new file mode 100644
index 0000000..2ffe3c4
--- /dev/null
+++ b/glw/debug.ha
@@ -0,0 +1,34 @@
+use strings;
+use types::c;
+use trace;
+
+use gl::*;
+
+fn debug_callback(
+ source: gl_enum,
+ type_: gl_enum,
+ id: uint,
+ severity: gl_enum,
+ length: i32,
+ message: nullable *const c::char,
+ user_data: nullable *opaque,
+) void = {
+ // (2024 note): I'm painfully aware of the data race present here:
+ // The GL driver can call this from another thread, and the stdlib has
+ // some non-thread-safe stuff in it that we use, in particular strconv.
+ // I've seen it happen at times, but it's pretty rare.
+ const message = (message: *const [*]u8)[..length];
+ const message = strings::fromutf8(message)!;
+ const message = strings::trimsuffix(message, "\n");
+ trace::debug(&trace::root, "gl: {}", message);
+};
+
+export fn init_debug_logging() void = {
+ let ctxflags = 0i32;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &ctxflags);
+
+ if (ctxflags & GL_CONTEXT_FLAG_DEBUG_BIT: i32 != 0) {
+ trace::info(&trace::root, "opengl debugging is enabled");
+ glDebugMessageCallback(&debug_callback, null);
+ };
+};
diff --git a/glw/glw.ha b/glw/glw.ha
new file mode 100644
index 0000000..a3a2b65
--- /dev/null
+++ b/glw/glw.ha
@@ -0,0 +1,91 @@
+use strings;
+use trace;
+use types::c;
+
+use gl::*;
+
+export fn get_string(name: gl_enum) str = {
+ match (glGetString(name)) {
+ case null =>
+ return "";
+ case let s: *const u8 =>
+ return c::tostr(s: *const c::char)!;
+ };
+};
+
+export fn buffer_data(
+ target: gl_enum,
+ data: []opaque,
+ itemsz: size,
+ usage: gl_enum,
+) void = {
+ glBufferData(
+ target,
+ (len(data) * itemsz): uintptr,
+ data: nullable *[*]u8: nullable *opaque,
+ usage,
+ );
+};
+
+export fn compile_shader_src(type_: gl_enum, src: str) uint = {
+ const shader = glCreateShader(type_);
+ glShaderSource(
+ shader, 1,
+ &(strings::toutf8(src): *[*]i8: nullable *const i8),
+ &(len(src): i32),
+ );
+ glCompileShader(shader);
+
+ let status = 0i32;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+
+ if (status == 0) {
+ let log_len = 0i32;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
+
+ const log_buf = alloc([0u8...], log_len: size);
+ glGetShaderInfoLog(
+ shader, log_len,
+ null, log_buf: *[*]i8: *i8,
+ );
+
+ const log = strings::fromutf8(log_buf)!;
+
+ const type_str = switch (type_) {
+ case GL_VERTEX_SHADER => yield "vertex";
+ case GL_FRAGMENT_SHADER => yield "fragment";
+ case GL_GEOMETRY_SHADER => yield "geometry";
+ case => yield "(unknown)";
+ };
+
+ trace::error(&trace::root,
+ "{} shader compilation failed:\n{}",
+ type_str, log): void;
+ };
+
+ return shader;
+};
+
+export fn link_program(program: uint) void = {
+ glLinkProgram(program);
+
+ let status = 0i32;
+ glGetProgramiv(program, GL_LINK_STATUS, &status);
+
+ if (status == 0) {
+ let log_len = 0i32;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
+
+ const log_buf = alloc([0u8...], log_len: size);
+ glGetProgramInfoLog(
+ program, log_len,
+ null, log_buf: *[*]i8: *i8,
+ );
+
+ const log = strings::fromutf8(log_buf)!;
+
+ trace::error(&trace::root,
+ "program linking failed:\n{}",
+ log): void;
+ };
+};