mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-21 11:16:08 +03:00
add first pass metal shader
This commit is contained in:
@ -5,6 +5,7 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const glfw = @import("glfw");
|
const glfw = @import("glfw");
|
||||||
const objc = @import("objc");
|
const objc = @import("objc");
|
||||||
|
const macos = @import("macos");
|
||||||
const font = @import("../font/main.zig");
|
const font = @import("../font/main.zig");
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
@ -46,6 +47,8 @@ font_shaper: font.Shaper,
|
|||||||
device: objc.Object, // MTLDevice
|
device: objc.Object, // MTLDevice
|
||||||
queue: objc.Object, // MTLCommandQueue
|
queue: objc.Object, // MTLCommandQueue
|
||||||
swapchain: objc.Object, // CAMetalLayer
|
swapchain: objc.Object, // CAMetalLayer
|
||||||
|
library: objc.Object, // MTLLibrary
|
||||||
|
buf_instance: objc.Object, // MTLBuffer
|
||||||
|
|
||||||
const GPUCell = extern struct {
|
const GPUCell = extern struct {
|
||||||
foo: f64,
|
foo: f64,
|
||||||
@ -99,6 +102,61 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !Metal {
|
|||||||
var font_shaper = try font.Shaper.init(shape_buf);
|
var font_shaper = try font.Shaper.init(shape_buf);
|
||||||
errdefer font_shaper.deinit();
|
errdefer font_shaper.deinit();
|
||||||
|
|
||||||
|
// Initialize our Metal buffers
|
||||||
|
const buf_instance = buffer: {
|
||||||
|
const data = [6]u8{
|
||||||
|
0, 1, 3, // Top-left triangle
|
||||||
|
1, 2, 3, // Bottom-right triangle
|
||||||
|
};
|
||||||
|
|
||||||
|
break :buffer device.msgSend(
|
||||||
|
objc.Object,
|
||||||
|
objc.sel("newBufferWithBytes:length:options:"),
|
||||||
|
.{
|
||||||
|
@ptrCast(*const anyopaque, &data),
|
||||||
|
@intCast(c_ulong, data.len * @sizeOf(u8)),
|
||||||
|
MTLResourceStorageModeShared,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize our shader (MTLLibrary)
|
||||||
|
const library = library: {
|
||||||
|
// Load our source into a CFString
|
||||||
|
const source = try macos.foundation.String.createWithBytes(
|
||||||
|
@embedFile("../shaders/cell.metal"),
|
||||||
|
.utf8,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
defer source.release();
|
||||||
|
|
||||||
|
// Compile
|
||||||
|
var err: ?*anyopaque = null;
|
||||||
|
const library = device.msgSend(
|
||||||
|
objc.Object,
|
||||||
|
objc.sel("newLibraryWithSource:options:error:"),
|
||||||
|
.{
|
||||||
|
source,
|
||||||
|
@as(?*anyopaque, null),
|
||||||
|
&err,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// If there is an error (shouldn't since we test), report it and exit.
|
||||||
|
if (err != null) {
|
||||||
|
const nserr = objc.Object.fromId(err);
|
||||||
|
const str = @ptrCast(
|
||||||
|
*macos.foundation.String,
|
||||||
|
nserr.getProperty(?*anyopaque, "localizedDescription").?,
|
||||||
|
);
|
||||||
|
|
||||||
|
log.err("shader error={s}", .{str.cstringPtr(.ascii).?});
|
||||||
|
return error.MetalFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :library library;
|
||||||
|
};
|
||||||
|
|
||||||
return Metal{
|
return Metal{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
||||||
@ -117,6 +175,8 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !Metal {
|
|||||||
.device = device,
|
.device = device,
|
||||||
.queue = queue,
|
.queue = queue,
|
||||||
.swapchain = swapchain,
|
.swapchain = swapchain,
|
||||||
|
.library = library,
|
||||||
|
.buf_instance = buf_instance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,6 +475,18 @@ const MTLStoreAction = enum(c_ulong) {
|
|||||||
store = 1,
|
store = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/metal/mtlstoragemode?language=objc
|
||||||
|
const MTLStorageMode = enum(c_ulong) {
|
||||||
|
shared = 0,
|
||||||
|
managed = 1,
|
||||||
|
private = 2,
|
||||||
|
memoryless = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/metal/mtlresourceoptions?language=objc
|
||||||
|
/// (incomplete, we only use this mode so we just hardcode it)
|
||||||
|
const MTLResourceStorageModeShared: c_ulong = @enumToInt(MTLStorageMode.shared) << 4;
|
||||||
|
|
||||||
const MTLClearColor = extern struct {
|
const MTLClearColor = extern struct {
|
||||||
red: f64,
|
red: f64,
|
||||||
green: f64,
|
green: f64,
|
||||||
|
35
src/shaders/cell.metal
Normal file
35
src/shaders/cell.metal
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
vertex float4 basic_vertex(unsigned int vid [[ vertex_id ]]) {
|
||||||
|
// Where we are in the grid (x, y) where top-left is origin
|
||||||
|
float2 grid_coord = float2(0.0f, 0.0f);
|
||||||
|
|
||||||
|
// The size of a single cell in pixels
|
||||||
|
float2 cell_size = float2(75.0f, 100.0f);
|
||||||
|
|
||||||
|
// Convert the grid x,y into world space x, y by accounting for cell size
|
||||||
|
float2 cell_pos = cell_size * grid_coord;
|
||||||
|
|
||||||
|
// Turn the cell position into a vertex point depending on the
|
||||||
|
// vertex ID. Since we use instanced drawing, we have 4 vertices
|
||||||
|
// for each corner of the cell. We can use vertex ID to determine
|
||||||
|
// which one we're looking at. Using this, we can use 1 or 0 to keep
|
||||||
|
// or discard the value for the vertex.
|
||||||
|
//
|
||||||
|
// 0 = top-right
|
||||||
|
// 1 = bot-right
|
||||||
|
// 2 = bot-left
|
||||||
|
// 3 = top-left
|
||||||
|
float2 position;
|
||||||
|
position.x = (vid == 0 || vid == 1) ? 1.0f : 0.0f;
|
||||||
|
position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f;
|
||||||
|
|
||||||
|
// Calculate the final position of our cell in world space.
|
||||||
|
// We have to add our cell size since our vertices are offset
|
||||||
|
// one cell up and to the left. (Do the math to verify yourself)
|
||||||
|
cell_pos = cell_pos + cell_size * position;
|
||||||
|
|
||||||
|
return float4(cell_pos.x, cell_pos.y, 0.5f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 basic_fragment() {
|
||||||
|
return half4(1.0);
|
||||||
|
}
|
Reference in New Issue
Block a user