renderer/metal: move more metal objects into GPUState

This commit is contained in:
Mitchell Hashimoto
2024-04-21 19:32:17 -07:00
parent 20bfbd9b2e
commit 8093088515

View File

@ -108,11 +108,8 @@ image_text_end: u32 = 0,
/// Metal state /// Metal state
shaders: Shaders, // Compiled shaders shaders: Shaders, // Compiled shaders
buf_instance: InstanceBuffer, // MTLBuffer
/// Metal objects /// Metal objects
device: objc.Object, // MTLDevice
queue: objc.Object, // MTLCommandQueue
layer: objc.Object, // CAMetalLayer layer: objc.Object, // CAMetalLayer
/// Custom shader state. This is only set if we have custom shaders. /// Custom shader state. This is only set if we have custom shaders.
@ -141,10 +138,26 @@ pub const GPUState = struct {
frame_sema: std.Thread.Semaphore = .{ .permits = BufferCount }, frame_sema: std.Thread.Semaphore = .{ .permits = BufferCount },
device: objc.Object, // MTLDevice device: objc.Object, // MTLDevice
queue: objc.Object, // MTLCommandQueue
/// This buffer is written exactly once so we can use it globally.
instance: InstanceBuffer, // MTLBuffer
pub fn init() !GPUState { pub fn init() !GPUState {
const device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice());
const queue = device.msgSend(objc.Object, objc.sel("newCommandQueue"), .{});
errdefer queue.msgSend(void, objc.sel("release"), .{});
var instance = try InstanceBuffer.initFill(device, &.{
0, 1, 3, // Top-left triangle
1, 2, 3, // Bottom-right triangle
});
errdefer instance.deinit();
var result: GPUState = .{ var result: GPUState = .{
.device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice()), .device = device,
.queue = queue,
.instance = instance,
.frames = undefined, .frames = undefined,
}; };
@ -161,6 +174,8 @@ pub const GPUState = struct {
// we can cleanly deinit our GPU state. // we can cleanly deinit our GPU state.
for (0..BufferCount) |_| self.frame_sema.wait(); for (0..BufferCount) |_| self.frame_sema.wait();
for (&self.frames) |*frame| frame.deinit(); for (&self.frames) |*frame| frame.deinit();
self.instance.deinit();
self.queue.msgSend(void, objc.sel("release"), .{});
} }
/// Get the next frame state to draw to. This will wait on the /// Get the next frame state to draw to. This will wait on the
@ -423,8 +438,8 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
}; };
// Initialize our metal stuff // Initialize our metal stuff
const device = objc.Object.fromId(mtl.MTLCreateSystemDefaultDevice()); var gpu_state = try GPUState.init();
const queue = device.msgSend(objc.Object, objc.sel("newCommandQueue"), .{}); errdefer gpu_state.deinit();
// Get our CAMetalLayer // Get our CAMetalLayer
const layer = switch (builtin.os.tag) { const layer = switch (builtin.os.tag) {
@ -438,7 +453,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
else => @compileError("unsupported target for Metal"), else => @compileError("unsupported target for Metal"),
}; };
layer.setProperty("device", device.value); layer.setProperty("device", gpu_state.device.value);
layer.setProperty("opaque", options.config.background_opacity >= 1); layer.setProperty("opaque", options.config.background_opacity >= 1);
layer.setProperty("displaySyncEnabled", false); // disable v-sync layer.setProperty("displaySyncEnabled", false); // disable v-sync
@ -467,13 +482,6 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
}); });
errdefer font_shaper.deinit(); errdefer font_shaper.deinit();
// Vertex buffers
var buf_instance = try InstanceBuffer.initFill(device, &.{
0, 1, 3, // Top-left triangle
1, 2, 3, // Bottom-right triangle
});
errdefer buf_instance.deinit();
// Load our custom shaders // Load our custom shaders
const custom_shaders: []const [:0]const u8 = shadertoy.loadFromFiles( const custom_shaders: []const [:0]const u8 = shadertoy.loadFromFiles(
arena_alloc, arena_alloc,
@ -489,7 +497,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
if (custom_shaders.len == 0) break :state null; if (custom_shaders.len == 0) break :state null;
// Build our sampler for our texture // Build our sampler for our texture
var sampler = try mtl_sampler.Sampler.init(device); var sampler = try mtl_sampler.Sampler.init(gpu_state.device);
errdefer sampler.deinit(); errdefer sampler.deinit();
break :state .{ break :state .{
@ -517,7 +525,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
errdefer if (custom_shader_state) |*state| state.deinit(); errdefer if (custom_shader_state) |*state| state.deinit();
// Initialize our shaders // Initialize our shaders
var shaders = try Shaders.init(alloc, device, custom_shaders); var shaders = try Shaders.init(alloc, gpu_state.device, custom_shaders);
errdefer shaders.deinit(alloc); errdefer shaders.deinit(alloc);
// Initialize all the data that requires a critical font section. // Initialize all the data that requires a critical font section.
@ -532,10 +540,6 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
}; };
}; };
// Build our GPU state
var gpu_state = try GPUState.init();
errdefer gpu_state.deinit();
return Metal{ return Metal{
.alloc = alloc, .alloc = alloc,
.config = options.config, .config = options.config,
@ -564,11 +568,8 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
// Shaders // Shaders
.shaders = shaders, .shaders = shaders,
.buf_instance = buf_instance,
// Metal stuff // Metal stuff
.device = device,
.queue = queue,
.layer = layer, .layer = layer,
.custom_shader_state = custom_shader_state, .custom_shader_state = custom_shader_state,
.gpu_state = gpu_state, .gpu_state = gpu_state,
@ -592,9 +593,6 @@ pub fn deinit(self: *Metal) void {
} }
self.image_placements.deinit(self.alloc); self.image_placements.deinit(self.alloc);
self.buf_instance.deinit();
self.queue.msgSend(void, objc.sel("release"), .{});
if (self.custom_shader_state) |*state| state.deinit(); if (self.custom_shader_state) |*state| state.deinit();
self.shaders.deinit(self.alloc); self.shaders.deinit(self.alloc);
@ -797,7 +795,7 @@ pub fn updateFrame(
.replace_grey_alpha, .replace_grey_alpha,
.replace_rgb, .replace_rgb,
.replace_rgba, .replace_rgba,
=> try kv.value_ptr.image.upload(self.alloc, self.device), => try kv.value_ptr.image.upload(self.alloc, self.gpu_state.device),
.unload_pending, .unload_pending,
.unload_replace, .unload_replace,
@ -858,7 +856,7 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
self.font_grid.lock.lockShared(); self.font_grid.lock.lockShared();
defer self.font_grid.lock.unlockShared(); defer self.font_grid.lock.unlockShared();
frame.greyscale_modified = self.font_grid.atlas_greyscale.modified.load(.monotonic); frame.greyscale_modified = self.font_grid.atlas_greyscale.modified.load(.monotonic);
try syncAtlasTexture(self.device, &self.font_grid.atlas_greyscale, &frame.greyscale); try syncAtlasTexture(self.gpu_state.device, &self.font_grid.atlas_greyscale, &frame.greyscale);
} }
texture: { texture: {
const modified = self.font_grid.atlas_color.modified.load(.monotonic); const modified = self.font_grid.atlas_color.modified.load(.monotonic);
@ -866,11 +864,11 @@ pub fn drawFrame(self: *Metal, surface: *apprt.Surface) !void {
self.font_grid.lock.lockShared(); self.font_grid.lock.lockShared();
defer self.font_grid.lock.unlockShared(); defer self.font_grid.lock.unlockShared();
frame.color_modified = self.font_grid.atlas_color.modified.load(.monotonic); frame.color_modified = self.font_grid.atlas_color.modified.load(.monotonic);
try syncAtlasTexture(self.device, &self.font_grid.atlas_color, &frame.color); try syncAtlasTexture(self.gpu_state.device, &self.font_grid.atlas_color, &frame.color);
} }
// Command buffer (MTLCommandBuffer) // Command buffer (MTLCommandBuffer)
const buffer = self.queue.msgSend(objc.Object, objc.sel("commandBuffer"), .{}); const buffer = self.gpu_state.queue.msgSend(objc.Object, objc.sel("commandBuffer"), .{});
{ {
// MTLRenderPassDescriptor // MTLRenderPassDescriptor
@ -1150,7 +1148,7 @@ fn drawImagePlacement(
// Create our vertex buffer, which is always exactly one item. // Create our vertex buffer, which is always exactly one item.
// future(mitchellh): we can group rendering multiple instances of a single image // future(mitchellh): we can group rendering multiple instances of a single image
const Buffer = mtl_buffer.Buffer(mtl_shaders.Image); const Buffer = mtl_buffer.Buffer(mtl_shaders.Image);
var buf = try Buffer.initFill(self.device, &.{.{ var buf = try Buffer.initFill(self.gpu_state.device, &.{.{
.grid_pos = .{ .grid_pos = .{
@as(f32, @floatFromInt(p.x)), @as(f32, @floatFromInt(p.x)),
@as(f32, @floatFromInt(p.y)), @as(f32, @floatFromInt(p.y)),
@ -1208,7 +1206,7 @@ fn drawImagePlacement(
@intFromEnum(mtl.MTLPrimitiveType.triangle), @intFromEnum(mtl.MTLPrimitiveType.triangle),
@as(c_ulong, 6), @as(c_ulong, 6),
@intFromEnum(mtl.MTLIndexType.uint16), @intFromEnum(mtl.MTLIndexType.uint16),
self.buf_instance.buffer.value, self.gpu_state.instance.buffer.value,
@as(c_ulong, 0), @as(c_ulong, 0),
@as(c_ulong, 1), @as(c_ulong, 1),
}, },
@ -1271,7 +1269,7 @@ fn drawCells(
@intFromEnum(mtl.MTLPrimitiveType.triangle), @intFromEnum(mtl.MTLPrimitiveType.triangle),
@as(c_ulong, 6), @as(c_ulong, 6),
@intFromEnum(mtl.MTLIndexType.uint16), @intFromEnum(mtl.MTLIndexType.uint16),
self.buf_instance.buffer.value, self.gpu_state.instance.buffer.value,
@as(c_ulong, 0), @as(c_ulong, 0),
@as(c_ulong, len), @as(c_ulong, len),
}, },
@ -1573,7 +1571,7 @@ pub fn setScreenSize(
// If we fail to create the texture, then we just don't have a screen // If we fail to create the texture, then we just don't have a screen
// texture and our custom shaders won't run. // texture and our custom shaders won't run.
const id = self.device.msgSend( const id = self.gpu_state.device.msgSend(
?*anyopaque, ?*anyopaque,
objc.sel("newTextureWithDescriptor:"), objc.sel("newTextureWithDescriptor:"),
.{desc}, .{desc},