mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
wasm: use shared, imported memory
This switches our wasm build to use "shared" memory. Shared memory can be shared across multiple web workers, which is something we'll want to support for our multi-threaded behaviors later. Shared memory has a number of different restrictions so this updates zig-js to support it as well as updates some of our functions that need to be aware of it.
This commit is contained in:
32
build.zig
32
build.zig
@ -112,16 +112,44 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
|
||||
// wasm
|
||||
{
|
||||
// Build our Wasm target.
|
||||
const wasm_target: std.zig.CrossTarget = .{
|
||||
.cpu_arch = .wasm32,
|
||||
.os_tag = .freestanding,
|
||||
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
|
||||
.cpu_features_add = std.Target.wasm.featureSet(&.{
|
||||
// We use this to explicitly request shared memory.
|
||||
.atomics,
|
||||
|
||||
// Not explicitly used but compiler could use them if they want.
|
||||
.bulk_memory,
|
||||
.reference_types,
|
||||
.sign_ext,
|
||||
}),
|
||||
};
|
||||
|
||||
// Whether we're using wasm shared memory. Some behaviors change.
|
||||
// For now we require this but I wanted to make the code handle both
|
||||
// up front.
|
||||
const wasm_shared: bool = true;
|
||||
exe_options.addOption(bool, "wasm_shared", wasm_shared);
|
||||
|
||||
const wasm = b.addSharedLibrary(
|
||||
"ghostty-wasm",
|
||||
"src/main_wasm.zig",
|
||||
.{ .unversioned = {} },
|
||||
);
|
||||
wasm.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
|
||||
wasm.setTarget(wasm_target);
|
||||
wasm.setBuildMode(mode);
|
||||
wasm.setOutputDir("zig-out");
|
||||
wasm.addOptions("build_options", exe_options);
|
||||
|
||||
// So that we can use web workers with our wasm binary
|
||||
wasm.import_memory = true;
|
||||
wasm.initial_memory = 65536 * 25;
|
||||
wasm.max_memory = 65536 * 65536; // Maximum number of pages in wasm32
|
||||
wasm.shared_memory = wasm_shared;
|
||||
|
||||
// Stack protector adds extern requirements that we don't satisfy.
|
||||
wasm.stack_protector = false;
|
||||
|
||||
@ -136,7 +164,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
// it lets us test some basic functionality.
|
||||
const test_step = b.step("test-wasm", "Run all tests for wasm");
|
||||
const main_test = b.addTest("src/main_wasm.zig");
|
||||
main_test.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi });
|
||||
main_test.setTarget(wasm_target);
|
||||
main_test.addOptions("build_options", exe_options);
|
||||
try addDeps(b, main_test, true);
|
||||
test_step.dependOn(&main_test.step);
|
||||
|
@ -4,9 +4,11 @@ const zjs = new ZigJS();
|
||||
const importObject = {
|
||||
module: {},
|
||||
env: {
|
||||
memory: new WebAssembly.Memory({ initial: 25, maximum: 65536, shared: true }),
|
||||
log: (ptr: number, len: number) => {
|
||||
const view = new DataView(zjs.memory.buffer, ptr, Number(len));
|
||||
const str = new TextDecoder('utf-8').decode(view);
|
||||
const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len);
|
||||
const data = arr.slice();
|
||||
const str = new TextDecoder('utf-8').decode(data);
|
||||
console.log(str);
|
||||
},
|
||||
},
|
||||
@ -20,8 +22,8 @@ fetch(url.href).then(response =>
|
||||
).then(bytes =>
|
||||
WebAssembly.instantiate(bytes, importObject)
|
||||
).then(results => {
|
||||
const memory = importObject.env.memory;
|
||||
const {
|
||||
memory,
|
||||
malloc,
|
||||
free,
|
||||
face_new,
|
||||
|
@ -423,9 +423,17 @@ pub const Wasm = struct {
|
||||
defer mem_buf.deinit();
|
||||
|
||||
// Create an array that points to our buffer
|
||||
const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray");
|
||||
defer Uint8ClampedArray.deinit();
|
||||
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len });
|
||||
const arr = arr: {
|
||||
const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray");
|
||||
defer Uint8ClampedArray.deinit();
|
||||
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len });
|
||||
if (!wasm.shared_mem) break :arr arr;
|
||||
|
||||
// If we're sharing memory then we have to copy the data since
|
||||
// we can't set ImageData directly using a SharedArrayBuffer.
|
||||
defer arr.deinit();
|
||||
break :arr try arr.call(js.Object, "slice", .{});
|
||||
};
|
||||
defer arr.deinit();
|
||||
|
||||
// Create the image data from our array
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This file contains helpers for wasm compilation.
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const options = @import("build_options");
|
||||
|
||||
comptime {
|
||||
if (!builtin.target.isWasm()) {
|
||||
@ -8,6 +9,10 @@ comptime {
|
||||
}
|
||||
}
|
||||
|
||||
/// True if we're in shared memory mode. If true, then the memory buffer
|
||||
/// in JS will be backed by a SharedArrayBuffer and some behaviors change.
|
||||
pub const shared_mem = options.wasm_shared;
|
||||
|
||||
/// The allocator to use in wasm environments.
|
||||
///
|
||||
/// The return values of this should NOT be sent to the host environment
|
||||
|
2
vendor/zig-js
vendored
2
vendor/zig-js
vendored
@ -1 +1 @@
|
||||
Subproject commit 5e3a5ce776f7b424022494a830f66ace224fe7ff
|
||||
Subproject commit c89c1965cc6bf6ede97c1b891b624ce5282853d1
|
Reference in New Issue
Block a user