Misc Go interop fixes
This commit is contained in:
parent
042f2dca79
commit
c124e60168
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
// "go.lintTool": "golint"
|
||||||
|
"go.toolsEnvVars": {
|
||||||
|
"GOOS": "wasip1",
|
||||||
|
"GOARCH": "wasm"
|
||||||
|
}
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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(())
|
||||||
|
@ -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> {
|
||||||
|
@ -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)?;
|
||||||
|
7
crates/player/src/hosted_device.rs
Normal file
7
crates/player/src/hosted_device.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use std::thread_local;
|
||||||
|
|
||||||
|
use viperid::Device;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static HOSTED_DEVICE: Device = Device::new();
|
||||||
|
}
|
@ -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;
|
@ -1,5 +1,3 @@
|
|||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
use wasmi::core::Trap;
|
use wasmi::core::Trap;
|
||||||
|
|
||||||
use super::MinimalPreview1;
|
use super::MinimalPreview1;
|
||||||
|
@ -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(())
|
||||||
|
@ -1 +1,3 @@
|
|||||||
go 1.21.5
|
go 1.21.5
|
||||||
|
|
||||||
|
use .
|
@ -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()
|
|
||||||
|
13
example_project/viperid/exports.go
Normal file
13
example_project/viperid/exports.go
Normal 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)))
|
||||||
|
}
|
15
example_project/viperid/imports.go
Normal file
15
example_project/viperid/imports.go
Normal 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
|
Loading…
Reference in New Issue
Block a user