make opengl loader context-aware

This commit is contained in:
Mitchell Hashimoto 2022-10-23 19:39:02 -07:00
parent de9731da1f
commit 89a4c59f3c
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
12 changed files with 909 additions and 1559 deletions

View File

@ -242,12 +242,12 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
// Culling, probably not necessary. We have to change the winding
// order since our 0,0 is top-left.
gl.c.glEnable(gl.c.GL_CULL_FACE);
gl.c.glFrontFace(gl.c.GL_CW);
try gl.enable(gl.c.GL_CULL_FACE);
try gl.frontFace(gl.c.GL_CW);
// Blending for text
gl.c.glEnable(gl.c.GL_BLEND);
gl.c.glBlendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
try gl.enable(gl.c.GL_BLEND);
try gl.blendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
// The font size we desire along with the DPI determiend for the window
const font_size: font.face.DesiredSize = .{

View File

@ -3,6 +3,7 @@ const Buffer = @This();
const std = @import("std");
const c = @import("c.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
id: c.GLuint,
@ -41,7 +42,7 @@ pub const Binding = struct {
usage: Usage,
) !void {
const info = dataInfo(&data);
c.glBufferData(@enumToInt(b.target), info.size, info.ptr, @enumToInt(usage));
glad.context.BufferData.?(@enumToInt(b.target), info.size, info.ptr, @enumToInt(usage));
try errors.getError();
}
@ -53,7 +54,7 @@ pub const Binding = struct {
data: anytype,
) !void {
const info = dataInfo(data);
c.glBufferSubData(@enumToInt(b.target), @intCast(c_long, offset), info.size, info.ptr);
glad.context.BufferSubData.?(@enumToInt(b.target), @intCast(c_long, offset), info.size, info.ptr);
try errors.getError();
}
@ -65,7 +66,7 @@ pub const Binding = struct {
comptime T: type,
usage: Usage,
) !void {
c.glBufferData(@enumToInt(b.target), @sizeOf(T), null, @enumToInt(usage));
glad.context.BufferData.?(@enumToInt(b.target), @sizeOf(T), null, @enumToInt(usage));
try errors.getError();
}
@ -75,7 +76,7 @@ pub const Binding = struct {
size: usize,
usage: Usage,
) !void {
c.glBufferData(@enumToInt(b.target), @intCast(c_long, size), null, @enumToInt(usage));
glad.context.BufferData.?(@enumToInt(b.target), @intCast(c_long, size), null, @enumToInt(usage));
try errors.getError();
}
@ -106,7 +107,7 @@ pub const Binding = struct {
}
pub inline fn enableAttribArray(_: Binding, idx: c.GLuint) !void {
c.glEnableVertexAttribArray(idx);
glad.context.EnableVertexAttribArray.?(idx);
}
/// Shorthand for vertexAttribPointer that is specialized towards the
@ -153,7 +154,7 @@ pub const Binding = struct {
/// VertexAttribDivisor
pub fn attributeDivisor(_: Binding, idx: c.GLuint, divisor: c.GLuint) !void {
c.glVertexAttribDivisor(idx, divisor);
glad.context.VertexAttribDivisor.?(idx, divisor);
try errors.getError();
}
@ -172,7 +173,7 @@ pub const Binding = struct {
else
null;
c.glVertexAttribPointer(idx, size, typ, normalized_c, stride, offsetPtr);
glad.context.VertexAttribPointer.?(idx, size, typ, normalized_c, stride, offsetPtr);
try errors.getError();
}
@ -189,12 +190,12 @@ pub const Binding = struct {
else
null;
c.glVertexAttribIPointer(idx, size, typ, stride, offsetPtr);
glad.context.VertexAttribIPointer.?(idx, size, typ, stride, offsetPtr);
try errors.getError();
}
pub inline fn unbind(b: *Binding) void {
c.glBindBuffer(@enumToInt(b.target), 0);
glad.context.BindBuffer.?(@enumToInt(b.target), 0);
b.* = undefined;
}
};
@ -202,16 +203,16 @@ pub const Binding = struct {
/// Create a single buffer.
pub inline fn create() !Buffer {
var vbo: c.GLuint = undefined;
c.glGenBuffers(1, &vbo);
glad.context.GenBuffers.?(1, &vbo);
return Buffer{ .id = vbo };
}
/// glBindBuffer
pub inline fn bind(v: Buffer, target: Target) !Binding {
c.glBindBuffer(@enumToInt(target), v.id);
glad.context.BindBuffer.?(@enumToInt(target), v.id);
return Binding{ .target = target };
}
pub inline fn destroy(v: Buffer) void {
c.glDeleteBuffers(1, &v.id);
glad.context.DeleteBuffers.?(1, &v.id);
}

View File

@ -7,17 +7,18 @@ const log = std.log.scoped(.opengl);
const c = @import("c.zig");
const Shader = @import("Shader.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
id: c.GLuint,
const Binding = struct {
pub inline fn unbind(_: Binding) void {
c.glUseProgram(0);
glad.context.UseProgram.?(0);
}
};
pub inline fn create() !Program {
const id = c.glCreateProgram();
const id = glad.context.CreateProgram.?();
if (id == 0) try errors.mustError();
log.debug("program created id={}", .{id});
@ -44,16 +45,16 @@ pub inline fn createVF(vsrc: [:0]const u8, fsrc: [:0]const u8) !Program {
}
pub inline fn attachShader(p: Program, s: Shader) !void {
c.glAttachShader(p.id, s.id);
glad.context.AttachShader.?(p.id, s.id);
try errors.getError();
}
pub inline fn link(p: Program) !void {
c.glLinkProgram(p.id);
glad.context.LinkProgram.?(p.id);
// Check if linking succeeded
var success: c_int = undefined;
c.glGetProgramiv(p.id, c.GL_LINK_STATUS, &success);
glad.context.GetProgramiv.?(p.id, c.GL_LINK_STATUS, &success);
if (success == c.GL_TRUE) {
log.debug("program linked id={}", .{p.id});
return;
@ -67,7 +68,7 @@ pub inline fn link(p: Program) !void {
}
pub inline fn use(p: Program) !Binding {
c.glUseProgram(p.id);
glad.context.UseProgram.?(p.id);
return Binding{};
}
@ -77,7 +78,7 @@ pub inline fn setUniform(
n: [:0]const u8,
value: anytype,
) !void {
const loc = c.glGetUniformLocation(
const loc = glad.context.GetUniformLocation.?(
p.id,
@ptrCast([*c]const u8, n.ptr),
);
@ -88,12 +89,12 @@ pub inline fn setUniform(
// Perform the correct call depending on the type of the value.
switch (@TypeOf(value)) {
comptime_int => c.glUniform1i(loc, value),
f32 => c.glUniform1f(loc, value),
@Vector(2, f32) => c.glUniform2f(loc, value[0], value[1]),
@Vector(3, f32) => c.glUniform3f(loc, value[0], value[1], value[2]),
@Vector(4, f32) => c.glUniform4f(loc, value[0], value[1], value[2], value[3]),
[4]@Vector(4, f32) => c.glUniformMatrix4fv(
comptime_int => glad.context.Uniform1i.?(loc, value),
f32 => glad.context.Uniform1f.?(loc, value),
@Vector(2, f32) => glad.context.Uniform2f.?(loc, value[0], value[1]),
@Vector(3, f32) => glad.context.Uniform3f.?(loc, value[0], value[1], value[2]),
@Vector(4, f32) => glad.context.Uniform4f.?(loc, value[0], value[1], value[2], value[3]),
[4]@Vector(4, f32) => glad.context.UniformMatrix4fv.?(
loc,
1,
c.GL_FALSE,
@ -112,12 +113,12 @@ pub inline fn setUniform(
// if we ever need it.
pub inline fn getInfoLog(s: Program) [512]u8 {
var msg: [512]u8 = undefined;
c.glGetProgramInfoLog(s.id, msg.len, null, &msg);
glad.context.GetProgramInfoLog.?(s.id, msg.len, null, &msg);
return msg;
}
pub inline fn destroy(p: Program) void {
assert(p.id != 0);
c.glDeleteProgram(p.id);
glad.context.DeleteProgram.?(p.id);
log.debug("program destroyed id={}", .{p.id});
}

View File

@ -6,11 +6,12 @@ const log = std.log.scoped(.opengl);
const c = @import("c.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
id: c.GLuint,
pub inline fn create(typ: c.GLenum) errors.Error!Shader {
const id = c.glCreateShader(typ);
const id = glad.context.CreateShader.?(typ);
if (id == 0) {
try errors.mustError();
unreachable;
@ -22,12 +23,12 @@ pub inline fn create(typ: c.GLenum) errors.Error!Shader {
/// Set the source and compile a shader.
pub inline fn setSourceAndCompile(s: Shader, source: [:0]const u8) !void {
c.glShaderSource(s.id, 1, &@ptrCast([*c]const u8, source), null);
c.glCompileShader(s.id);
glad.context.ShaderSource.?(s.id, 1, &@ptrCast([*c]const u8, source), null);
glad.context.CompileShader.?(s.id);
// Check if compilation succeeded
var success: c_int = undefined;
c.glGetShaderiv(s.id, c.GL_COMPILE_STATUS, &success);
glad.context.GetShaderiv.?(s.id, c.GL_COMPILE_STATUS, &success);
if (success == c.GL_TRUE) return;
log.err("shader compilation failure id={} message={s}", .{
s.id,
@ -44,12 +45,12 @@ pub inline fn setSourceAndCompile(s: Shader, source: [:0]const u8) !void {
// if we ever need it.
pub inline fn getInfoLog(s: Shader) [512]u8 {
var msg: [512]u8 = undefined;
c.glGetShaderInfoLog(s.id, msg.len, null, &msg);
glad.context.GetShaderInfoLog.?(s.id, msg.len, null, &msg);
return msg;
}
pub inline fn destroy(s: Shader) void {
assert(s.id != 0);
c.glDeleteShader(s.id);
glad.context.DeleteShader.?(s.id);
log.debug("shader destroyed id={}", .{s.id});
}

View File

@ -3,11 +3,12 @@ const Texture = @This();
const std = @import("std");
const c = @import("c.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
id: c.GLuint,
pub inline fn active(target: c.GLenum) !void {
c.glActiveTexture(target);
glad.context.ActiveTexture.?(target);
}
/// Enun for possible texture binding targets.
@ -74,17 +75,17 @@ pub const Binding = struct {
target: Target,
pub inline fn unbind(b: *Binding) void {
c.glBindTexture(@enumToInt(b.target), 0);
glad.context.BindTexture.?(@enumToInt(b.target), 0);
b.* = undefined;
}
pub fn generateMipmap(b: Binding) void {
c.glGenerateMipmap(@enumToInt(b.target));
glad.context.GenerateMipmap.?(@enumToInt(b.target));
}
pub fn parameter(b: Binding, name: Parameter, value: anytype) !void {
switch (@TypeOf(value)) {
c.GLint => c.glTexParameteri(
c.GLint => glad.context.TexParameteri.?(
@enumToInt(b.target),
@enumToInt(name),
value,
@ -104,7 +105,7 @@ pub const Binding = struct {
typ: DataType,
data: ?*const anyopaque,
) !void {
c.glTexImage2D(
glad.context.TexImage2D.?(
@enumToInt(b.target),
level,
@enumToInt(internal_format),
@ -128,7 +129,7 @@ pub const Binding = struct {
typ: DataType,
data: ?*const anyopaque,
) !void {
c.glTexSubImage2D(
glad.context.TexSubImage2D.?(
@enumToInt(b.target),
level,
xoffset,
@ -145,16 +146,16 @@ pub const Binding = struct {
/// Create a single texture.
pub inline fn create() !Texture {
var id: c.GLuint = undefined;
c.glGenTextures(1, &id);
glad.context.GenTextures.?(1, &id);
return Texture{ .id = id };
}
/// glBindTexture
pub inline fn bind(v: Texture, target: Target) !Binding {
c.glBindTexture(@enumToInt(target), v.id);
glad.context.BindTexture.?(@enumToInt(target), v.id);
return Binding{ .target = target };
}
pub inline fn destroy(v: Texture) void {
c.glDeleteTextures(1, &v.id);
glad.context.DeleteTextures.?(1, &v.id);
}

View File

@ -1,26 +1,27 @@
const VertexArray = @This();
const c = @import("c.zig");
const glad = @import("glad.zig");
id: c.GLuint,
/// Create a single vertex array object.
pub inline fn create() !VertexArray {
var vao: c.GLuint = undefined;
c.glGenVertexArrays(1, &vao);
glad.context.GenVertexArrays.?(1, &vao);
return VertexArray{ .id = vao };
}
// Unbind any active vertex array.
pub inline fn unbind() !void {
c.glBindVertexArray(0);
glad.context.BindVertexArray.?(0);
}
/// glBindVertexArray
pub inline fn bind(v: VertexArray) !void {
c.glBindVertexArray(v.id);
glad.context.BindVertexArray.?(v.id);
}
pub inline fn destroy(v: VertexArray) void {
c.glDeleteVertexArrays(1, &v.id);
glad.context.DeleteVertexArrays.?(1, &v.id);
}

View File

@ -1,22 +1,23 @@
const c = @import("c.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
pub fn clearColor(r: f32, g: f32, b: f32, a: f32) void {
c.glClearColor(r, g, b, a);
glad.context.ClearColor.?(r, g, b, a);
}
pub fn clear(mask: c.GLbitfield) void {
c.glClear(mask);
glad.context.Clear.?(mask);
}
pub fn drawArrays(mode: c.GLenum, first: c.GLint, count: c.GLsizei) !void {
c.glDrawArrays(mode, first, count);
glad.context.DrawArrays.?(mode, first, count);
try errors.getError();
}
pub fn drawElements(mode: c.GLenum, count: c.GLsizei, typ: c.GLenum, offset: usize) !void {
const offsetPtr = if (offset == 0) null else @intToPtr(*const anyopaque, offset);
c.glDrawElements(mode, count, typ, offsetPtr);
glad.context.DrawElements.?(mode, count, typ, offsetPtr);
try errors.getError();
}
@ -26,17 +27,32 @@ pub fn drawElementsInstanced(
typ: c.GLenum,
primcount: usize,
) !void {
c.glDrawElementsInstanced(mode, count, typ, null, @intCast(c.GLsizei, primcount));
glad.context.DrawElementsInstanced.?(mode, count, typ, null, @intCast(c.GLsizei, primcount));
try errors.getError();
}
pub fn enable(cap: c.GLenum) !void {
glad.context.Enable.?(cap);
try errors.getError();
}
pub fn frontFace(mode: c.GLenum) !void {
glad.context.FrontFace.?(mode);
try errors.getError();
}
pub fn blendFunc(sfactor: c.GLenum, dfactor: c.GLenum) !void {
glad.context.BlendFunc.?(sfactor, dfactor);
try errors.getError();
}
pub fn viewport(x: c.GLint, y: c.GLint, width: c.GLsizei, height: c.GLsizei) !void {
c.glViewport(x, y, width, height);
glad.context.Viewport.?(x, y, width, height);
}
pub fn pixelStore(mode: c.GLenum, value: anytype) !void {
switch (@typeInfo(@TypeOf(value))) {
.ComptimeInt, .Int => c.glPixelStorei(mode, value),
.ComptimeInt, .Int => glad.context.PixelStorei.?(mode, value),
else => unreachable,
}
try errors.getError();

View File

@ -1,5 +1,6 @@
const std = @import("std");
const c = @import("c.zig");
const glad = @import("glad.zig");
pub const Error = error{
InvalidEnum,
@ -13,7 +14,7 @@ pub const Error = error{
/// getError returns the error (if any) from the last OpenGL operation.
pub fn getError() Error!void {
return switch (c.glGetError()) {
return switch (glad.context.GetError.?()) {
c.GL_NO_ERROR => {},
c.GL_INVALID_ENUM => Error.InvalidEnum,
c.GL_INVALID_VALUE => Error.InvalidValue,

View File

@ -1,11 +1,12 @@
const std = @import("std");
const c = @import("c.zig");
const errors = @import("errors.zig");
const glad = @import("glad.zig");
/// Returns the number of extensions.
pub fn len() !u32 {
var n: c.GLint = undefined;
c.glGetIntegerv(c.GL_NUM_EXTENSIONS, &n);
glad.context.GetIntegerv.?(c.GL_NUM_EXTENSIONS, &n);
try errors.getError();
return @intCast(u32, n);
}
@ -23,7 +24,7 @@ pub const Iterator = struct {
pub fn next(self: *Iterator) !?[]const u8 {
if (self.i >= self.len) return null;
const res = c.glGetStringi(c.GL_EXTENSIONS, self.i);
const res = glad.context.GetStringi.?(c.GL_EXTENSIONS, self.i);
try errors.getError();
self.i += 1;
return std.mem.sliceTo(res, 0);

View File

@ -1,6 +1,14 @@
const std = @import("std");
const c = @import("c.zig");
pub const Context = c.GladGLContext;
/// This is the current context. Set this var manually prior to calling
/// any of this package's functions. I know its nasty to have a global but
/// this makes it match OpenGL API styles where it also operates on a
/// threadlocal global.
pub threadlocal var context: Context = undefined;
/// Initialize Glad. This is guaranteed to succeed if no errors are returned.
/// The getProcAddress param is an anytype so that we can accept multiple
/// forms of the function depending on what we're interfacing with.
@ -10,18 +18,23 @@ pub fn load(getProcAddress: anytype) !c_int {
const res = switch (@TypeOf(getProcAddress)) {
// glfw
GlfwFn => c.gladLoadGL(@ptrCast(
GlfwFn => c.gladLoadGLContext(&context, @ptrCast(
std.meta.FnPtr(fn ([*c]const u8) callconv(.C) ?GlProc),
getProcAddress,
)),
// try as-is. If this introduces a compiler error, then add a new case.
else => c.gladLoadGL(getProcAddress),
else => c.gladLoadGLContext(&context, getProcAddress),
};
if (res == 0) return error.GLInitFailed;
return res;
}
pub fn unload() void {
c.gladLoaderUnloadGLContext(&context);
context = undefined;
}
pub fn versionMajor(res: c_int) c_uint {
// https://github.com/ziglang/zig/issues/13162
// return c.GLAD_VERSION_MAJOR(res);

File diff suppressed because it is too large Load Diff

1220
vendor/glad/src/gl.c vendored

File diff suppressed because it is too large Load Diff