mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-23 20:26:09 +03:00
renderer/metal: use a semaphore to protect deinit while waiting for GPU
This commit is contained in:
@ -126,6 +126,11 @@ custom_shader_state: ?CustomShaderState = null,
|
|||||||
/// this will have to be part of the frame state.
|
/// this will have to be part of the frame state.
|
||||||
health: std.atomic.Value(Health) = .{ .raw = .healthy },
|
health: std.atomic.Value(Health) = .{ .raw = .healthy },
|
||||||
|
|
||||||
|
/// Sempahore blocking our in-flight buffer updates. For now this is just
|
||||||
|
/// one but in the future if we implement double/triple-buffering this
|
||||||
|
/// will be incremented.
|
||||||
|
inflight: std.Thread.Semaphore = .{ .permits = 1 },
|
||||||
|
|
||||||
pub const CustomShaderState = struct {
|
pub const CustomShaderState = struct {
|
||||||
/// The screen texture that we render the terminal to. If we don't have
|
/// The screen texture that we render the terminal to. If we don't have
|
||||||
/// custom shaders, we render directly to the drawable.
|
/// custom shaders, we render directly to the drawable.
|
||||||
@ -404,6 +409,12 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Metal) void {
|
pub fn deinit(self: *Metal) void {
|
||||||
|
// If we have inflight buffers, wait for completion. This ensures that
|
||||||
|
// any pending GPU operations are completed before we start deallocating
|
||||||
|
// everything. This is important because our completion callbacks access
|
||||||
|
// "self"
|
||||||
|
self.inflight.wait();
|
||||||
|
|
||||||
self.cells.deinit(self.alloc);
|
self.cells.deinit(self.alloc);
|
||||||
self.cells_bg.deinit(self.alloc);
|
self.cells_bg.deinit(self.alloc);
|
||||||
|
|
||||||
@ -708,6 +719,10 @@ pub fn updateFrame(
|
|||||||
pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
|
||||||
_ = surface;
|
_ = surface;
|
||||||
|
|
||||||
|
// Wait for a buffer to be available.
|
||||||
|
self.inflight.wait();
|
||||||
|
errdefer self.inflight.post();
|
||||||
|
|
||||||
// If we have custom shaders, update the animation time.
|
// If we have custom shaders, update the animation time.
|
||||||
if (self.custom_shader_state) |*state| {
|
if (self.custom_shader_state) |*state| {
|
||||||
const now = std.time.Instant.now() catch state.last_frame_time;
|
const now = std.time.Instant.now() catch state.last_frame_time;
|
||||||
@ -901,14 +916,18 @@ fn bufferCompleted(
|
|||||||
|
|
||||||
// If our health value hasn't changed, then we do nothing. We don't
|
// If our health value hasn't changed, then we do nothing. We don't
|
||||||
// do a cmpxchg here because strict atomicity isn't important.
|
// do a cmpxchg here because strict atomicity isn't important.
|
||||||
if (self.health.load(.SeqCst) == health) return;
|
if (self.health.load(.SeqCst) != health) {
|
||||||
self.health.store(health, .SeqCst);
|
self.health.store(health, .SeqCst);
|
||||||
|
|
||||||
// Our health value changed, so we notify the surface so that it
|
// Our health value changed, so we notify the surface so that it
|
||||||
// can do something about it.
|
// can do something about it.
|
||||||
_ = self.surface_mailbox.push(.{
|
_ = self.surface_mailbox.push(.{
|
||||||
.renderer_health = health,
|
.renderer_health = health,
|
||||||
}, .{ .forever = {} });
|
}, .{ .forever = {} });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always release our semaphore
|
||||||
|
self.inflight.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawPostShader(
|
fn drawPostShader(
|
||||||
|
Reference in New Issue
Block a user