mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
renderer/metal: reuse an intermediate texture for custom shaders
This commit is contained in:
@ -116,6 +116,10 @@ swapchain: objc.Object, // CAMetalLayer
|
|||||||
texture_greyscale: objc.Object, // MTLTexture
|
texture_greyscale: objc.Object, // MTLTexture
|
||||||
texture_color: objc.Object, // MTLTexture
|
texture_color: objc.Object, // MTLTexture
|
||||||
|
|
||||||
|
/// The screen texture. This is only set if we have custom shaders. If
|
||||||
|
/// we don't have custom shaders, we render directly to the drawable.
|
||||||
|
texture_screen: ?objc.Object, // MTLTexture
|
||||||
|
|
||||||
/// The configuration for this renderer that is derived from the main
|
/// The configuration for this renderer that is derived from the main
|
||||||
/// configuration. This must be exported so that we don't need to
|
/// configuration. This must be exported so that we don't need to
|
||||||
/// pass around Config pointers which makes memory management a pain.
|
/// pass around Config pointers which makes memory management a pain.
|
||||||
@ -332,6 +336,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
.swapchain = swapchain,
|
.swapchain = swapchain,
|
||||||
.texture_greyscale = texture_greyscale,
|
.texture_greyscale = texture_greyscale,
|
||||||
.texture_color = texture_color,
|
.texture_color = texture_color,
|
||||||
|
.texture_screen = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,6 +360,7 @@ pub fn deinit(self: *Metal) void {
|
|||||||
self.buf_instance.deinit();
|
self.buf_instance.deinit();
|
||||||
deinitMTLResource(self.texture_greyscale);
|
deinitMTLResource(self.texture_greyscale);
|
||||||
deinitMTLResource(self.texture_color);
|
deinitMTLResource(self.texture_color);
|
||||||
|
if (self.texture_screen) |tex| deinitMTLResource(tex);
|
||||||
self.queue.msgSend(void, objc.sel("release"), .{});
|
self.queue.msgSend(void, objc.sel("release"), .{});
|
||||||
|
|
||||||
self.shaders.deinit(self.alloc);
|
self.shaders.deinit(self.alloc);
|
||||||
@ -613,36 +619,13 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
|||||||
// Get our drawable (CAMetalDrawable)
|
// Get our drawable (CAMetalDrawable)
|
||||||
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
||||||
|
|
||||||
// Make our intermediate texture
|
// Get our screen texture. If we don't have a dedicated screen texture
|
||||||
const target = target: {
|
// then we just use the drawable texture.
|
||||||
const desc = init: {
|
const screen_texture = self.texture_screen orelse tex: {
|
||||||
const Class = objc.getClass("MTLTextureDescriptor").?;
|
const texture = drawable.msgSend(objc.c.id, objc.sel("texture"), .{});
|
||||||
const id_alloc = Class.msgSend(objc.Object, objc.sel("alloc"), .{});
|
break :tex objc.Object.fromId(texture);
|
||||||
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
|
||||||
break :init id_init;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set our properties
|
|
||||||
desc.setProperty("pixelFormat", @intFromEnum(mtl.MTLPixelFormat.bgra8unorm));
|
|
||||||
desc.setProperty("width", @as(c_ulong, @intCast(self.screen_size.?.width)));
|
|
||||||
desc.setProperty("height", @as(c_ulong, @intCast(self.screen_size.?.height)));
|
|
||||||
desc.setProperty(
|
|
||||||
"usage",
|
|
||||||
@intFromEnum(mtl.MTLTextureUsage.render_target) |
|
|
||||||
@intFromEnum(mtl.MTLTextureUsage.shader_read) |
|
|
||||||
@intFromEnum(mtl.MTLTextureUsage.shader_write),
|
|
||||||
);
|
|
||||||
|
|
||||||
const id = self.device.msgSend(
|
|
||||||
?*anyopaque,
|
|
||||||
objc.sel("newTextureWithDescriptor:"),
|
|
||||||
.{desc},
|
|
||||||
) orelse return error.MetalFailed;
|
|
||||||
|
|
||||||
break :target objc.Object.fromId(id);
|
|
||||||
};
|
|
||||||
defer target.msgSend(void, objc.sel("release"), .{});
|
|
||||||
|
|
||||||
// If our font atlas changed, sync the texture data
|
// If our font atlas changed, sync the texture data
|
||||||
if (self.font_group.atlas_greyscale.modified) {
|
if (self.font_group.atlas_greyscale.modified) {
|
||||||
try syncAtlasTexture(self.device, &self.font_group.atlas_greyscale, &self.texture_greyscale);
|
try syncAtlasTexture(self.device, &self.font_group.atlas_greyscale, &self.texture_greyscale);
|
||||||
@ -682,7 +665,7 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
|||||||
//const texture = drawable.msgSend(objc.c.id, objc.sel("texture"), .{});
|
//const texture = drawable.msgSend(objc.c.id, objc.sel("texture"), .{});
|
||||||
attachment.setProperty("loadAction", @intFromEnum(mtl.MTLLoadAction.clear));
|
attachment.setProperty("loadAction", @intFromEnum(mtl.MTLLoadAction.clear));
|
||||||
attachment.setProperty("storeAction", @intFromEnum(mtl.MTLStoreAction.store));
|
attachment.setProperty("storeAction", @intFromEnum(mtl.MTLStoreAction.store));
|
||||||
attachment.setProperty("texture", target.value);
|
attachment.setProperty("texture", screen_texture.value);
|
||||||
attachment.setProperty("clearColor", mtl.MTLClearColor{
|
attachment.setProperty("clearColor", mtl.MTLClearColor{
|
||||||
.red = @as(f32, @floatFromInt(self.current_background_color.r)) / 255,
|
.red = @as(f32, @floatFromInt(self.current_background_color.r)) / 255,
|
||||||
.green = @as(f32, @floatFromInt(self.current_background_color.g)) / 255,
|
.green = @as(f32, @floatFromInt(self.current_background_color.g)) / 255,
|
||||||
@ -718,6 +701,10 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
|||||||
try self.drawImagePlacements(encoder, self.image_placements.items[self.image_text_end..]);
|
try self.drawImagePlacements(encoder, self.image_placements.items[self.image_text_end..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have custom shaders AND we have a screen texture, then we
|
||||||
|
// render the custom shaders.
|
||||||
|
if (self.config.custom_shaders.items.len > 0 and
|
||||||
|
self.texture_screen != null)
|
||||||
{
|
{
|
||||||
// MTLRenderPassDescriptor
|
// MTLRenderPassDescriptor
|
||||||
const desc = desc: {
|
const desc = desc: {
|
||||||
@ -764,15 +751,13 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
|||||||
);
|
);
|
||||||
defer encoder.msgSend(void, objc.sel("endEncoding"), .{});
|
defer encoder.msgSend(void, objc.sel("endEncoding"), .{});
|
||||||
|
|
||||||
try self.drawPostShader(encoder, target.value);
|
try self.drawPostShader(encoder, screen_texture.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});
|
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});
|
||||||
buffer.msgSend(void, objc.sel("commit"), .{});
|
buffer.msgSend(void, objc.sel("commit"), .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
var post_time: f32 = 1;
|
|
||||||
|
|
||||||
fn drawPostShader(
|
fn drawPostShader(
|
||||||
self: *Metal,
|
self: *Metal,
|
||||||
encoder: objc.Object,
|
encoder: objc.Object,
|
||||||
@ -789,7 +774,7 @@ fn drawPostShader(
|
|||||||
@floatFromInt(self.screen_size.?.height),
|
@floatFromInt(self.screen_size.?.height),
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
.time = post_time,
|
.time = 1,
|
||||||
.time_delta = 1,
|
.time_delta = 1,
|
||||||
.frame_rate = 1,
|
.frame_rate = 1,
|
||||||
.frame = 1,
|
.frame = 1,
|
||||||
@ -800,7 +785,6 @@ fn drawPostShader(
|
|||||||
.sample_rate = 1,
|
.sample_rate = 1,
|
||||||
}});
|
}});
|
||||||
defer buf.deinit();
|
defer buf.deinit();
|
||||||
post_time += 1;
|
|
||||||
|
|
||||||
// Use our custom shader pipeline
|
// Use our custom shader pipeline
|
||||||
encoder.msgSend(
|
encoder.msgSend(
|
||||||
@ -1264,6 +1248,45 @@ pub fn setScreenSize(
|
|||||||
self.cells.clearAndFree(self.alloc);
|
self.cells.clearAndFree(self.alloc);
|
||||||
self.cells_bg.clearAndFree(self.alloc);
|
self.cells_bg.clearAndFree(self.alloc);
|
||||||
|
|
||||||
|
// Setup our screen texture
|
||||||
|
const screen_texture: ?objc.Object = screen_texture: {
|
||||||
|
// If we have no custom shaders then we don't need a screen texture.
|
||||||
|
if (self.config.custom_shaders.items.len == 0) break :screen_texture null;
|
||||||
|
|
||||||
|
// This texture is the size of our drawable but supports being a
|
||||||
|
// render target AND reading so that the custom shaders can read from it.
|
||||||
|
const desc = init: {
|
||||||
|
const Class = objc.getClass("MTLTextureDescriptor").?;
|
||||||
|
const id_alloc = Class.msgSend(objc.Object, objc.sel("alloc"), .{});
|
||||||
|
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
||||||
|
break :init id_init;
|
||||||
|
};
|
||||||
|
desc.setProperty("pixelFormat", @intFromEnum(mtl.MTLPixelFormat.bgra8unorm));
|
||||||
|
desc.setProperty("width", @as(c_ulong, @intCast(dim.width)));
|
||||||
|
desc.setProperty("height", @as(c_ulong, @intCast(dim.height)));
|
||||||
|
desc.setProperty(
|
||||||
|
"usage",
|
||||||
|
@intFromEnum(mtl.MTLTextureUsage.render_target) |
|
||||||
|
@intFromEnum(mtl.MTLTextureUsage.shader_read) |
|
||||||
|
@intFromEnum(mtl.MTLTextureUsage.shader_write),
|
||||||
|
);
|
||||||
|
|
||||||
|
// If we fail to create the texture, then we just don't have a screen
|
||||||
|
// texture and our custom shaders won't run.
|
||||||
|
const id = self.device.msgSend(
|
||||||
|
?*anyopaque,
|
||||||
|
objc.sel("newTextureWithDescriptor:"),
|
||||||
|
.{desc},
|
||||||
|
) orelse break :screen_texture null;
|
||||||
|
|
||||||
|
break :screen_texture objc.Object.fromId(id);
|
||||||
|
};
|
||||||
|
errdefer if (screen_texture) |tex| tex.msgSend(void, objc.sel("release"), .{});
|
||||||
|
|
||||||
|
// Set our new screen texture
|
||||||
|
if (self.texture_screen) |tex| tex.msgSend(void, objc.sel("release"), .{});
|
||||||
|
self.texture_screen = screen_texture;
|
||||||
|
|
||||||
log.debug("screen size screen={} grid={}, cell={}", .{ dim, grid_size, self.cell_size });
|
log.debug("screen size screen={} grid={}, cell={}", .{ dim, grid_size, self.cell_size });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user