Misc Go interop fixes

This commit is contained in:
Pyrex 2024-04-27 12:16:04 -07:00
parent 042f2dca79
commit c124e60168
13 changed files with 77 additions and 58 deletions

7
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// "go.lintTool": "golint"
"go.toolsEnvVars": {
"GOOS": "wasip1",
"GOARCH": "wasm"
}
}

View File

@ -3,8 +3,7 @@ use std::{fs::File, io::Read, path::{Path, PathBuf}, process::Command};
use viperid::VResult; use viperid::VResult;
pub struct GoBuilder { pub struct GoBuilder {
project_directory: PathBuf, project_directory: PathBuf
entry_point: PathBuf
} }
impl GoBuilder { impl GoBuilder {
@ -27,15 +26,9 @@ impl GoBuilder {
anyhow::bail!("project directory must exist: {}", project_directory.to_string_lossy()) anyhow::bail!("project directory must exist: {}", project_directory.to_string_lossy())
} }
let entry_point = project_directory.join("main.go");
if !entry_point.exists() {
anyhow::bail!("entry point must exist: {}", entry_point.to_string_lossy())
}
// OK, we should be able to do things with Go without any errors // OK, we should be able to do things with Go without any errors
Ok(GoBuilder { Ok(GoBuilder {
project_directory: PathBuf::from(project_directory), project_directory: PathBuf::from(project_directory),
entry_point
}) })
} }
@ -47,24 +40,17 @@ impl GoBuilder {
self.project_directory.to_string_lossy() self.project_directory.to_string_lossy()
); );
} }
if !self.entry_point.exists() {
anyhow::bail!(
"entry point disappeared: {}",
self.entry_point.to_string_lossy()
);
}
let project_directory = &self.project_directory; let build_directory = self.project_directory.join("build");
let entry_point = &self.entry_point;
let build_directory = project_directory.join("build");
let wasm_name = build_directory.join("game.wasm"); let wasm_name = build_directory.join("game.wasm");
let mut child = Command::new("go") let mut child = Command::new("go")
.args(["build", "-o"]).arg(&wasm_name) .arg("-C").arg(self.project_directory.clone())
.args(["build", "-o"]).arg("build/game.wasm")
.env("GOOS", "wasip1") .env("GOOS", "wasip1")
.env("GOARCH", "wasm") .env("GOARCH", "wasm")
.arg("-trimpath") .arg("-trimpath")
.arg(entry_point) .arg(".")
.spawn()?; .spawn()?;
let status = child.wait()?; let status = child.wait()?;
if !status.success() { if !status.success() {

View File

@ -1,6 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use viperid::{Device, VResult}; use player::HOSTED_DEVICE;
use viperid::VResult;
use crate::go_builder::GoBuilder; use crate::go_builder::GoBuilder;
@ -10,11 +11,10 @@ fn main() -> VResult<()> {
let builder = GoBuilder::new( let builder = GoBuilder::new(
&PathBuf::from("example_project"))?; &PathBuf::from("example_project"))?;
let wasm = builder.build()?; let wasm = builder.build()?;
let device = Device::new();
let mut executor = player::Executor::new(device.share(), &wasm)?; let mut executor = player::Executor::new(&wasm)?;
minifb_host::host(device, || { minifb_host::host(HOSTED_DEVICE.with(|d| d.share()), || {
executor.update(); executor.update();
executor.get_error()?; executor.get_error()?;
Ok(()) Ok(())

View File

@ -1,9 +1,9 @@
use std::fmt::Display; use std::fmt::Display;
use viperid::VResult; use viperid::VResult;
use wasmi::{core::{HostError, Trap}, Caller, Extern, Linker}; use wasmi::{core::{HostError, Trap}, Caller, Linker};
use crate::executor::ExecutorState; use crate::{executor::ExecutorState, HOSTED_DEVICE};
pub(crate) fn integrate(linker: &mut Linker<ExecutorState>) -> VResult<()> { pub(crate) fn integrate(linker: &mut Linker<ExecutorState>) -> VResult<()> {
linker.func_wrap("viperid", "Pset", pset)?; linker.func_wrap("viperid", "Pset", pset)?;
@ -13,14 +13,11 @@ pub(crate) fn integrate(linker: &mut Linker<ExecutorState>) -> VResult<()> {
Ok(()) Ok(())
} }
fn pset(mut caller: Caller<ExecutorState>, x: i32, y: i32, color: i32) -> Result<(), Trap> { fn pset(mut _caller: Caller<ExecutorState>, x: i32, y: i32, color: i32) -> Result<(), Trap> {
let memory = match caller.get_export("memory") { HOSTED_DEVICE.with(|dev| {
Some(Extern::Memory(m)) => m, dev.shared.screen.pset(x, y, (color & 0xff) as u8);
_ => return Err(wasmi::core::Trap::new(String::from("missing required memory export"))),
};
let(_, ctx) = memory.data_and_store_mut(&mut caller);
ctx.device.shared.screen.pset(x, y, (color & 0xff) as u8);
Ok(()) Ok(())
})
} }
fn yield_frame(_caller: Caller<ExecutorState>) -> Result<(), Trap> { fn yield_frame(_caller: Caller<ExecutorState>) -> Result<(), Trap> {

View File

@ -1,6 +1,6 @@
use std::mem; use std::mem;
use viperid::{Device, VResult}; use viperid::VResult;
use wasmi::{core::Trap, Engine, Linker, Module, Store, TypedFunc, TypedResumableCall, TypedResumableInvocation}; use wasmi::{core::Trap, Engine, Linker, Module, Store, TypedFunc, TypedResumableCall, TypedResumableInvocation};
use crate::{engine_api::{self, YieldFrame}, wasi::{self, StockWasi}}; use crate::{engine_api::{self, YieldFrame}, wasi::{self, StockWasi}};
@ -12,14 +12,12 @@ pub struct Executor {
pub(crate) struct ExecutorState { pub(crate) struct ExecutorState {
wasi: wasi::StockWasi, wasi: wasi::StockWasi,
pub(crate) device: Device
} }
impl ExecutorState { impl ExecutorState {
fn new(device: Device) -> Self { fn new() -> Self {
ExecutorState { ExecutorState {
wasi: StockWasi::new(), wasi: StockWasi::new(),
device
} }
} }
@ -27,12 +25,12 @@ impl ExecutorState {
impl Executor { impl Executor {
pub fn new(device: Device, wasm: &[u8]) -> VResult<Self> { pub fn new(wasm: &[u8]) -> VResult<Self> {
let engine = Engine::default(); let engine = Engine::default();
let module = Module::new(&engine, wasm)?; let module = Module::new(&engine, wasm)?;
let mut store = Store::new(&engine, ExecutorState::new(device)); let mut store = Store::new(&engine, ExecutorState::new());
let mut linker = <Linker<ExecutorState>>::new(&engine); let mut linker = <Linker<ExecutorState>>::new(&engine);
wasi::integrate(&mut linker, |hs| &mut hs.wasi)?; wasi::integrate(&mut linker, |hs| &mut hs.wasi)?;

View File

@ -0,0 +1,7 @@
use std::thread_local;
use viperid::Device;
thread_local! {
pub static HOSTED_DEVICE: Device = Device::new();
}

View File

@ -1,5 +1,7 @@
mod engine_api; mod engine_api;
mod executor; mod executor;
mod wasi; mod wasi;
mod hosted_device;
pub use executor::Executor; pub use executor::Executor;
pub use hosted_device::HOSTED_DEVICE;

View File

@ -1,5 +1,3 @@
use std::time::SystemTime;
use wasmi::core::Trap; use wasmi::core::Trap;
use super::MinimalPreview1; use super::MinimalPreview1;

View File

@ -3,6 +3,7 @@ use std::rc::Rc;
use error_iter::ErrorIter as _; use error_iter::ErrorIter as _;
use log::error; use log::error;
use pixels::{Pixels, SurfaceTexture}; use pixels::{Pixels, SurfaceTexture};
use player::HOSTED_DEVICE;
use viperid::{Device, VResult, SCREEN_H, SCREEN_W}; use viperid::{Device, VResult, SCREEN_H, SCREEN_W};
// https://github.com/parasyte/pixels/blob/main/examples/minimal-web/src/main.rs // https://github.com/parasyte/pixels/blob/main/examples/minimal-web/src/main.rs
use winit::{dpi::LogicalSize, event::Event, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder}; use winit::{dpi::LogicalSize, event::Event, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder};
@ -15,12 +16,11 @@ fn main() {
async fn run() { async fn run() {
let wasm = include_bytes!("../../../example_project/build/game.wasm"); let wasm = include_bytes!("../../../example_project/build/game.wasm");
let device = Device::new();
let mut executor = let mut executor =
player::Executor::new(device.share(), wasm) player::Executor::new(wasm)
.expect("should have been able to create executor"); .expect("should have been able to create executor");
host(device, move || { host(HOSTED_DEVICE.with(|d| d.share()), move || {
executor.update(); executor.update();
executor.get_error()?; executor.get_error()?;
Ok(()) Ok(())

View File

@ -1 +1,3 @@
go 1.21.5 go 1.21.5
use .

View File

@ -1,14 +1,16 @@
package main package main
import "example_project/viperid"
func main() { func main() {
t := 0 t := 0
for { for {
for y := 0; y < 120; y++ { for y := 0; y < 120; y++ {
for x := 0; x < 160; x++ { for x := 0; x < 160; x++ {
Pset( viperid.Pset(
int32(x), x,
int32(y), y,
int32((x+y+t)%64), (x+y+t)%64,
) )
} }
} }
@ -17,15 +19,7 @@ func main() {
/* /*
debug.PrintStack() debug.PrintStack()
*/ */
YieldFrame() viperid.YieldFrame()
t += 1 t += 1
} }
} }
//go:wasmimport viperid Pset
//go:noescape
func Pset(x int32, y int32, color int32)
//go:wasmimport viperid YieldFrame
//go:noescape
func YieldFrame()

View File

@ -0,0 +1,13 @@
package viperid
func YieldFrame() {
yieldFrame()
}
func Pset(x int, y int, color int) {
pset(int32(x), int32(y), int32(color))
}
func Pget(x int, y int) int {
return int(pget(int32(x), int32(y)))
}

View File

@ -0,0 +1,15 @@
//lint:file-ignore U1000 Ignore all unused code, it's generated
package viperid
//go:wasmimport viperid YieldFrame
//go:noescape
func yieldFrame()
//go:wasmimport viperid Pset
//go:noescape
func pset(x int32, y int32, color int32)
//go:wasmimport viperid Pget
//go:noescape
func pget(x int32, y int32) int32