Revert "remove fbo entirely"

This reverts commit 9b10363f27c2a34bd067254c0eed39448594fc27.
This commit is contained in:
julia
2025-01-23 19:43:13 +11:00
committed by Mitchell Hashimoto
parent 93806df469
commit b9b0451c61
2 changed files with 50 additions and 19 deletions

View File

@ -2363,6 +2363,9 @@ fn drawCustomPrograms(self: *OpenGL, custom_state: *custom.State) !void {
// Setup the new frame // Setup the new frame
try custom_state.newFrame(); try custom_state.newFrame();
// const fbobind = try custom_state.fbo.bind(.framebuffer);
// defer fbobind.unbind();
// Go through each custom shader and draw it. // Go through each custom shader and draw it.
for (custom_state.programs) |program| { for (custom_state.programs) |program| {
// Bind our cell program state, buffers // Bind our cell program state, buffers
@ -2370,7 +2373,7 @@ fn drawCustomPrograms(self: *OpenGL, custom_state: *custom.State) !void {
defer bind.unbind(); defer bind.unbind();
try bind.draw(); try bind.draw();
// copy backbuffers // copy main and custom fbo
try custom_state.copy(); try custom_state.copy();
} }
} }
@ -2384,6 +2387,14 @@ fn drawCellProgram(
// are changes to the atlas. // are changes to the atlas.
try self.flushAtlas(); try self.flushAtlas();
// If we have custom shaders, then we draw to the custom
// shader framebuffer.
const fbobind: ?gl.Framebuffer.Binding = fbobind: {
const state = gl_state.custom orelse break :fbobind null;
break :fbobind try state.fbo.bind(.framebuffer);
};
defer if (fbobind) |v| v.unbind();
// Clear the surface // Clear the surface
gl.clearColor( gl.clearColor(
@floatCast(@as(f32, @floatFromInt(self.draw_background.r)) / 255 * self.config.background_opacity), @floatCast(@as(f32, @floatFromInt(self.draw_background.r)) / 255 * self.config.background_opacity),

View File

@ -27,19 +27,20 @@ pub const Uniforms = extern struct {
/// The state associated with custom shaders. This should only be initialized /// The state associated with custom shaders. This should only be initialized
/// if there is at least one custom shader. /// if there is at least one custom shader.
/// ///
/// To use this, each shader should be rendererd to the screen and then /// To use this, the main terminal shader should render to the framebuffer
/// copied to the "backbuffer" texture. This texture, which acts as a /// specified by "fbo". The resulting "fb_texture" will contain the color
/// mirror of the screen, can then be sampled from iChannel0 in consecutive /// attachment. This is then used as the iChannel0 input to the custom
/// shaders. /// shader.
pub const State = struct { pub const State = struct {
/// The uniform data /// The uniform data
uniforms: Uniforms, uniforms: Uniforms,
/// The OpenGL buffers /// The OpenGL buffers
fbo: gl.Framebuffer,
ubo: gl.Buffer, ubo: gl.Buffer,
vao: gl.VertexArray, vao: gl.VertexArray,
ebo: gl.Buffer, ebo: gl.Buffer,
backbuffer: gl.Texture, fb_texture: gl.Texture,
/// The set of programs for the custom shaders. /// The set of programs for the custom shaders.
programs: []const Program, programs: []const Program,
@ -66,11 +67,11 @@ pub const State = struct {
try programs.append(try Program.init(src)); try programs.append(try Program.init(src));
} }
// Create the texture for the backbuffer mirror // Create the texture for the framebuffer
const bb_tex = try gl.Texture.create(); const fb_tex = try gl.Texture.create();
errdefer bb_tex.destroy(); errdefer fb_tex.destroy();
{ {
const texbind = try bb_tex.bind(.@"2D"); const texbind = try fb_tex.bind(.@"2D");
try texbind.parameter(.WrapS, gl.c.GL_CLAMP_TO_EDGE); try texbind.parameter(.WrapS, gl.c.GL_CLAMP_TO_EDGE);
try texbind.parameter(.WrapT, gl.c.GL_CLAMP_TO_EDGE); try texbind.parameter(.WrapT, gl.c.GL_CLAMP_TO_EDGE);
try texbind.parameter(.MinFilter, gl.c.GL_LINEAR); try texbind.parameter(.MinFilter, gl.c.GL_LINEAR);
@ -87,6 +88,23 @@ pub const State = struct {
); );
} }
// Create our framebuffer for rendering off screen.
// The shader prior to custom shaders should use this
// framebuffer.
const fbo = try gl.Framebuffer.create();
errdefer fbo.destroy();
const fbbind = try fbo.bind(.framebuffer);
defer fbbind.unbind();
try fbbind.texture2D(.color0, .@"2D", fb_tex, 0);
const fbstatus = fbbind.checkStatus();
if (fbstatus != .complete) {
log.warn(
"framebuffer is not complete state={}",
.{fbstatus},
);
return error.InvalidFramebuffer;
}
// Create our uniform buffer that is shared across all // Create our uniform buffer that is shared across all
// custom shaders // custom shaders
const ubo = try gl.Buffer.create(); const ubo = try gl.Buffer.create();
@ -116,10 +134,11 @@ pub const State = struct {
return .{ return .{
.programs = try programs.toOwnedSlice(), .programs = try programs.toOwnedSlice(),
.uniforms = .{}, .uniforms = .{},
.fbo = fbo,
.ubo = ubo, .ubo = ubo,
.vao = vao, .vao = vao,
.ebo = ebo, .ebo = ebo,
.backbuffer = bb_tex, .fb_texture = fb_tex,
.first_frame_time = try std.time.Instant.now(), .first_frame_time = try std.time.Instant.now(),
.last_frame_time = try std.time.Instant.now(), .last_frame_time = try std.time.Instant.now(),
}; };
@ -131,7 +150,8 @@ pub const State = struct {
self.ubo.destroy(); self.ubo.destroy();
self.ebo.destroy(); self.ebo.destroy();
self.vao.destroy(); self.vao.destroy();
self.backbuffer.destroy(); self.fb_texture.destroy();
self.fbo.destroy();
} }
pub fn setScreenSize(self: *State, size: Size) !void { pub fn setScreenSize(self: *State, size: Size) !void {
@ -144,7 +164,7 @@ pub const State = struct {
try self.syncUniforms(); try self.syncUniforms();
// Update our texture // Update our texture
const texbind = try self.backbuffer.bind(.@"2D"); const texbind = try self.fb_texture.bind(.@"2D");
try texbind.image2D( try texbind.image2D(
0, 0,
.rgb, .rgb,
@ -194,7 +214,7 @@ pub const State = struct {
// Bind our texture that is shared amongst all // Bind our texture that is shared amongst all
try gl.Texture.active(gl.c.GL_TEXTURE0); try gl.Texture.active(gl.c.GL_TEXTURE0);
var texbind = try self.backbuffer.bind(.@"2D"); var texbind = try self.fb_texture.bind(.@"2D");
errdefer texbind.unbind(); errdefer texbind.unbind();
const vao = try self.vao.bind(); const vao = try self.vao.bind();
@ -206,13 +226,13 @@ pub const State = struct {
return .{ return .{
.vao = vao, .vao = vao,
.ebo = ebo, .ebo = ebo,
.backbuffer = texbind, .fb_texture = texbind,
}; };
} }
/// copy the main backbuffer to our backbuffer copy texture /// copy the fbo's attached texture to the backbuffer
pub fn copy(self: *State) !void { pub fn copy(self: *State) !void {
const texbind = try self.backbuffer.bind(.@"2D"); const texbind = try self.fb_texture.bind(.@"2D");
errdefer texbind.unbind(); errdefer texbind.unbind();
try texbind.copySubImage2D(0, 0, 0, 0, 0, @intFromFloat(self.uniforms.resolution[0]), @intFromFloat(self.uniforms.resolution[1])); try texbind.copySubImage2D(0, 0, 0, 0, 0, @intFromFloat(self.uniforms.resolution[0]), @intFromFloat(self.uniforms.resolution[1]));
@ -221,12 +241,12 @@ pub const State = struct {
pub const Binding = struct { pub const Binding = struct {
vao: gl.VertexArray.Binding, vao: gl.VertexArray.Binding,
ebo: gl.Buffer.Binding, ebo: gl.Buffer.Binding,
backbuffer: gl.Texture.Binding, fb_texture: gl.Texture.Binding,
pub fn unbind(self: Binding) void { pub fn unbind(self: Binding) void {
self.ebo.unbind(); self.ebo.unbind();
self.vao.unbind(); self.vao.unbind();
self.backbuffer.unbind(); self.fb_texture.unbind();
} }
}; };
}; };