mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-29 20:07:55 +00:00
The GLSL to MSL conversion process uses a passed-in sampler state for the `iChannel0` parameter and we weren't providing it. This magically worked on Apple Silicon for unknown reasons but failed on Intel GPUs. In normal, hand-written MSL, we'd explicitly create the sampler state as a normal variable (we do this in `shaders.metal` already!), but the Shadertoy conversion stuff doesn't do this, probably because the exact sampler parameters can't be safely known. This fixes a Metal validation error when using custom shaders: ``` -[MTLDebugRenderCommandEncoder validateCommonDrawErrors:]:5970: failed assertion `Draw Errors Validation Fragment Function(main0): missing Sampler binding at index 0 for iChannel0Smplr[0]. ```
67 lines
1.7 KiB
Zig
67 lines
1.7 KiB
Zig
//! Wrapper for handling samplers.
|
|
const Self = @This();
|
|
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const assert = std.debug.assert;
|
|
const builtin = @import("builtin");
|
|
const objc = @import("objc");
|
|
|
|
const mtl = @import("api.zig");
|
|
const Metal = @import("../Metal.zig");
|
|
|
|
const log = std.log.scoped(.metal);
|
|
|
|
/// Options for initializing a sampler.
|
|
pub const Options = struct {
|
|
/// MTLDevice
|
|
device: objc.Object,
|
|
min_filter: mtl.MTLSamplerMinMagFilter,
|
|
mag_filter: mtl.MTLSamplerMinMagFilter,
|
|
s_address_mode: mtl.MTLSamplerAddressMode,
|
|
t_address_mode: mtl.MTLSamplerAddressMode,
|
|
};
|
|
|
|
/// The underlying MTLSamplerState Object.
|
|
sampler: objc.Object,
|
|
|
|
pub const Error = error{
|
|
/// A Metal API call failed.
|
|
MetalFailed,
|
|
};
|
|
|
|
/// Initialize a sampler
|
|
pub fn init(
|
|
opts: Options,
|
|
) Error!Self {
|
|
// Create our descriptor
|
|
const desc = init: {
|
|
const Class = objc.getClass("MTLSamplerDescriptor").?;
|
|
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;
|
|
};
|
|
defer desc.release();
|
|
|
|
// Properties
|
|
desc.setProperty("minFilter", opts.min_filter);
|
|
desc.setProperty("magFilter", opts.mag_filter);
|
|
desc.setProperty("sAddressMode", opts.s_address_mode);
|
|
desc.setProperty("tAddressMode", opts.t_address_mode);
|
|
|
|
// Create the sampler state
|
|
const id = opts.device.msgSend(
|
|
?*anyopaque,
|
|
objc.sel("newSamplerStateWithDescriptor:"),
|
|
.{desc},
|
|
) orelse return error.MetalFailed;
|
|
|
|
return .{
|
|
.sampler = objc.Object.fromId(id),
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: Self) void {
|
|
self.sampler.release();
|
|
}
|