mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
renderer/metal: initialize layer in init, handle iOS layer
This commit is contained in:
@ -488,6 +488,7 @@ pub fn init(
|
|||||||
.balance = config.@"window-padding-balance",
|
.balance = config.@"window-padding-balance",
|
||||||
},
|
},
|
||||||
.surface_mailbox = .{ .surface = self, .app = app_mailbox },
|
.surface_mailbox = .{ .surface = self, .app = app_mailbox },
|
||||||
|
.rt_surface = rt_surface,
|
||||||
});
|
});
|
||||||
errdefer renderer_impl.deinit();
|
errdefer renderer_impl.deinit();
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ buf_instance: InstanceBuffer, // MTLBuffer
|
|||||||
/// Metal objects
|
/// Metal objects
|
||||||
device: objc.Object, // MTLDevice
|
device: objc.Object, // MTLDevice
|
||||||
queue: objc.Object, // MTLCommandQueue
|
queue: objc.Object, // MTLCommandQueue
|
||||||
swapchain: objc.Object, // CAMetalLayer
|
layer: objc.Object, // CAMetalLayer
|
||||||
texture_greyscale: objc.Object, // MTLTexture
|
texture_greyscale: objc.Object, // MTLTexture
|
||||||
texture_color: objc.Object, // MTLTexture
|
texture_color: objc.Object, // MTLTexture
|
||||||
|
|
||||||
@ -262,20 +262,77 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const arena_alloc = arena.allocator();
|
const arena_alloc = arena.allocator();
|
||||||
|
|
||||||
|
const ViewInfo = struct {
|
||||||
|
view: objc.Object,
|
||||||
|
scaleFactor: f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the metadata about our underlying view that we'll be rendering to.
|
||||||
|
const info: ViewInfo = switch (apprt.runtime) {
|
||||||
|
apprt.glfw => info: {
|
||||||
|
// Everything in glfw is window-oriented so we grab the backing
|
||||||
|
// window, then derive everything from that.
|
||||||
|
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(
|
||||||
|
options.rt_surface.window,
|
||||||
|
).?);
|
||||||
|
|
||||||
|
const contentView = objc.Object.fromId(
|
||||||
|
nswindow.getProperty(?*anyopaque, "contentView").?,
|
||||||
|
);
|
||||||
|
const scaleFactor = nswindow.getProperty(
|
||||||
|
macos.graphics.c.CGFloat,
|
||||||
|
"backingScaleFactor",
|
||||||
|
);
|
||||||
|
|
||||||
|
break :info .{
|
||||||
|
.view = contentView,
|
||||||
|
.scaleFactor = scaleFactor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
apprt.embedded => .{
|
||||||
|
.scaleFactor = @floatCast(options.rt_surface.content_scale.x),
|
||||||
|
.view = switch (options.rt_surface.platform) {
|
||||||
|
.macos => |v| v.nsview,
|
||||||
|
.ios => |v| v.uiview,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
else => @compileError("unsupported apprt for metal"),
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize our metal stuff
|
// Initialize our metal stuff
|
||||||
const device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice());
|
const device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice());
|
||||||
const queue = device.msgSend(objc.Object, objc.sel("newCommandQueue"), .{});
|
const queue = device.msgSend(objc.Object, objc.sel("newCommandQueue"), .{});
|
||||||
const swapchain = swapchain: {
|
|
||||||
const CAMetalLayer = objc.getClass("CAMetalLayer").?;
|
|
||||||
const swapchain = CAMetalLayer.msgSend(objc.Object, objc.sel("layer"), .{});
|
|
||||||
swapchain.setProperty("device", device.value);
|
|
||||||
swapchain.setProperty("opaque", options.config.background_opacity >= 1);
|
|
||||||
|
|
||||||
// disable v-sync
|
// Get our CAMetalLayer
|
||||||
swapchain.setProperty("displaySyncEnabled", false);
|
const layer = switch (builtin.os.tag) {
|
||||||
|
.macos => layer: {
|
||||||
|
const CAMetalLayer = objc.getClass("CAMetalLayer").?;
|
||||||
|
break :layer CAMetalLayer.msgSend(objc.Object, objc.sel("layer"), .{});
|
||||||
|
},
|
||||||
|
|
||||||
break :swapchain swapchain;
|
// iOS is always layer-backed so we don't need to do anything here.
|
||||||
|
.ios => info.view.getProperty(objc.Object, "layer"),
|
||||||
|
|
||||||
|
else => @compileError("unsupported target for Metal"),
|
||||||
};
|
};
|
||||||
|
layer.setProperty("device", device.value);
|
||||||
|
layer.setProperty("opaque", options.config.background_opacity >= 1);
|
||||||
|
layer.setProperty("displaySyncEnabled", false); // disable v-sync
|
||||||
|
|
||||||
|
// Make our view layer-backed with our Metal layer. On iOS views are
|
||||||
|
// always layer backed so we don't need to do this. But on iOS the
|
||||||
|
// caller MUST be sure to set the layerClass to CAMetalLayer.
|
||||||
|
if (comptime builtin.os.tag == .macos) {
|
||||||
|
info.view.setProperty("layer", layer.value);
|
||||||
|
info.view.setProperty("wantsLayer", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that our metal layer has a content scale set to match the
|
||||||
|
// scale factor of the window. This avoids magnification issues leading
|
||||||
|
// to blurry rendering.
|
||||||
|
layer.setProperty("contentsScale", info.scaleFactor);
|
||||||
|
|
||||||
// Get our cell metrics based on a regular font ascii 'M'. Why 'M'?
|
// Get our cell metrics based on a regular font ascii 'M'. Why 'M'?
|
||||||
// Doesn't matter, any normal ASCII will do we're just trying to make
|
// Doesn't matter, any normal ASCII will do we're just trying to make
|
||||||
@ -401,7 +458,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
// Metal stuff
|
// Metal stuff
|
||||||
.device = device,
|
.device = device,
|
||||||
.queue = queue,
|
.queue = queue,
|
||||||
.swapchain = swapchain,
|
.layer = layer,
|
||||||
.texture_greyscale = texture_greyscale,
|
.texture_greyscale = texture_greyscale,
|
||||||
.texture_color = texture_color,
|
.texture_color = texture_color,
|
||||||
.custom_shader_state = custom_shader_state,
|
.custom_shader_state = custom_shader_state,
|
||||||
@ -445,50 +502,12 @@ pub fn deinit(self: *Metal) void {
|
|||||||
|
|
||||||
/// This is called just prior to spinning up the renderer thread for
|
/// This is called just prior to spinning up the renderer thread for
|
||||||
/// final main thread setup requirements.
|
/// final main thread setup requirements.
|
||||||
pub fn finalizeSurfaceInit(self: *const Metal, surface: *apprt.Surface) !void {
|
pub fn finalizeSurfaceInit(self: *Metal, surface: *apprt.Surface) !void {
|
||||||
const Info = struct {
|
_ = self;
|
||||||
view: objc.Object,
|
_ = surface;
|
||||||
scaleFactor: f64,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the view and scale factor for our surface.
|
// Metal doesn't have to do anything here. OpenGL has to do things
|
||||||
const info: Info = switch (apprt.runtime) {
|
// like release the context but Metal doesn't have anything like that.
|
||||||
apprt.glfw => info: {
|
|
||||||
// Everything in glfw is window-oriented so we grab the backing
|
|
||||||
// window, then derive everything from that.
|
|
||||||
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(surface.window).?);
|
|
||||||
const contentView = objc.Object.fromId(nswindow.getProperty(?*anyopaque, "contentView").?);
|
|
||||||
const scaleFactor = nswindow.getProperty(macos.graphics.c.CGFloat, "backingScaleFactor");
|
|
||||||
break :info .{
|
|
||||||
.view = contentView,
|
|
||||||
.scaleFactor = scaleFactor,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
apprt.embedded => .{
|
|
||||||
.view = switch (surface.platform) {
|
|
||||||
.macos => |v| v.nsview,
|
|
||||||
.ios => |v| v.uiview,
|
|
||||||
},
|
|
||||||
.scaleFactor = @floatCast(surface.content_scale.x),
|
|
||||||
},
|
|
||||||
|
|
||||||
else => @compileError("unsupported apprt for metal"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make our view layer-backed with our Metal layer. On iOS views are
|
|
||||||
// always layer backed so we don't need to do this. But on iOS the
|
|
||||||
// caller MUST be sure to set the layerClass to CAMetalLayer.
|
|
||||||
if (comptime builtin.os.tag == .macos) {
|
|
||||||
info.view.setProperty("layer", self.swapchain.value);
|
|
||||||
info.view.setProperty("wantsLayer", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that our metal layer has a content scale set to match the
|
|
||||||
// scale factor of the window. This avoids magnification issues leading
|
|
||||||
// to blurry rendering.
|
|
||||||
const layer = info.view.getProperty(objc.Object, "layer");
|
|
||||||
layer.setProperty("contentsScale", info.scaleFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Callback called by renderer.Thread when it begins.
|
/// Callback called by renderer.Thread when it begins.
|
||||||
@ -743,7 +762,7 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
|||||||
defer pool.deinit();
|
defer pool.deinit();
|
||||||
|
|
||||||
// Get our drawable (CAMetalDrawable)
|
// Get our drawable (CAMetalDrawable)
|
||||||
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
const drawable = self.layer.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
||||||
|
|
||||||
// Get our screen texture. If we don't have a dedicated screen texture
|
// Get our screen texture. If we don't have a dedicated screen texture
|
||||||
// then we just use the drawable texture.
|
// then we just use the drawable texture.
|
||||||
@ -1420,7 +1439,7 @@ pub fn setScreenSize(
|
|||||||
const padded_dim = dim.subPadding(padding);
|
const padded_dim = dim.subPadding(padding);
|
||||||
|
|
||||||
// Set the size of the drawable surface to the bounds
|
// Set the size of the drawable surface to the bounds
|
||||||
self.swapchain.setProperty("drawableSize", macos.graphics.Size{
|
self.layer.setProperty("drawableSize", macos.graphics.Size{
|
||||||
.width = @floatFromInt(dim.width),
|
.width = @floatFromInt(dim.width),
|
||||||
.height = @floatFromInt(dim.height),
|
.height = @floatFromInt(dim.height),
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,9 @@ padding: Padding,
|
|||||||
/// once the thread has started and should not be used outside of the thread.
|
/// once the thread has started and should not be used outside of the thread.
|
||||||
surface_mailbox: apprt.surface.Mailbox,
|
surface_mailbox: apprt.surface.Mailbox,
|
||||||
|
|
||||||
|
/// The apprt surface.
|
||||||
|
rt_surface: *apprt.Surface,
|
||||||
|
|
||||||
pub const Padding = struct {
|
pub const Padding = struct {
|
||||||
// Explicit padding options, in pixels. The surface thread is
|
// Explicit padding options, in pixels. The surface thread is
|
||||||
// expected to convert points to pixels for a given DPI.
|
// expected to convert points to pixels for a given DPI.
|
||||||
|
Reference in New Issue
Block a user