Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GOOS=wasip1 support #2911

Closed
11 tasks
mymmrac opened this issue Feb 19, 2024 · 8 comments
Closed
11 tasks

GOOS=wasip1 support #2911

mymmrac opened this issue Feb 19, 2024 · 8 comments

Comments

@mymmrac
Copy link
Contributor

mymmrac commented Feb 19, 2024

Operating System

  • Windows
  • macOS
  • Linux
  • FreeBSD
  • OpenBSD
  • Android
  • iOS
  • Nintendo Switch
  • PlayStation 5
  • Xbox
  • Web Browsers

What feature would you like to be added?

Support for builds for WASI (GOOS=wasip1 GOARCH=wasm)

Sine Go 1.21 it supports WASI, it would be nice to be able to use at least Ebiten's constants inside WASI

I know that implementing full Ebiten support in WASI might be really complicated (or most likely impossible due to WASI limitations), but it would be great to at least partially support it

Why is this needed?

I am right now playing with WASI & Ebiten and I got working "mod" system using WASI, but Ebiten can't be build for wasip1

Example:

package main

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/v2"
)

func main() {
	fmt.Println(ebiten.KeyA)
}

Build:

$ GOOS=wasip1 GOARCH=wasm go build .

package mod
        imports github.com/hajimehoshi/ebiten/v2
        imports github.com/hajimehoshi/ebiten/v2/internal/ui
        imports github.com/hajimehoshi/ebiten/v2/internal/devicescale
        imports github.com/hajimehoshi/ebiten/v2/internal/glfw
        imports github.com/hajimehoshi/ebiten/v2/internal/cglfw: build constraints exclude all Go files in /home/mymmrac/.go/pkg/mod/github.com/hajimehoshi/ebiten/v2@v2.6.6/internal/cglfw
$ GOOS=js GOARCH=wasm go build .

(builds fine)

@hajimehoshi
Copy link
Owner

Interesting, but how do we implement graphics with WASI..?

@mymmrac
Copy link
Contributor Author

mymmrac commented Feb 19, 2024

I know, it's most likely impossible with current state

@mymmrac
Copy link
Contributor Author

mymmrac commented Feb 19, 2024

What I have now is a simple example that can run updates and draw things, but all functions to draw are imported externally + it needs synchronization with sleeps (maybe there is more clever way to do that)

At this point, I only think about support for maybe constants and some functions that doesn't require any communication with host program

//go:generate env GOOS=wasip1 GOARCH=wasm go build -o ../bin/m2.wasm .

package main

import (
	"sync"
	"time"
)

//go:wasmimport env RegisterMod
func RegisterMod() int32

//go:wasmimport env IsClosed
func IsClosed() int32

//go:wasmimport env BeginUpdating
func BeginUpdating(modIndex int32) int32

//go:wasmimport env EndUpdating
func EndUpdating(modIndex int32)

//go:wasmimport env BeginDrawing
func BeginDrawing(modIndex int32) int32

//go:wasmimport env EndDrawing
func EndDrawing(modIndex int32)

//go:wasmimport env DrawRect
func DrawRect(x, y, w, h int32, cr, cg, cb uint32)

//go:wasmimport env DrawCircle
func DrawCircle(x, y, r int32, cr, cg, cb uint32)

//go:wasmimport env IsKeyJustPressed
func IsKeyJustPressed(key int32) int32

func main() {
	modIndex := RegisterMod()

	g := &Game{
		r: 32,
	}
	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		defer wg.Done()
		for IsClosed() != 1 {
			var s int32
			for s == 0 {
				s = BeginUpdating(modIndex)
				if s == 0 {
					time.Sleep(time.Millisecond)
				}
			}
			if s != 1 {
				return
			}
			g.Update()
			EndUpdating(modIndex)
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for IsClosed() != 1 {
			var s int32
			for s == 0 {
				s = BeginDrawing(modIndex)
				if s == 0 {
					time.Sleep(time.Millisecond)
				}
			}
			if s != 1 {
				return
			}
			g.Draw()
			EndDrawing(modIndex)
		}
	}()

	wg.Wait()
}

type Game struct {
	r int32
}

func (g *Game) Update() {
	if IsKeyJustPressed(85) == 1 {
		g.r += 32
		g.r %= 256
	}
}

func (g *Game) Draw() {
	DrawCircle(200, 200, g.r, 255, 255, 0)
}

@hajimehoshi
Copy link
Owner

Desigining a layer that communicates between Ebitengine and WASI seems challenging and pretty difficult. This has to consider backward compatibility of course, and designing this causes some risks to expose low-level APIs and increase maintenance burden. So, I tend not to want to implement this, though this seems a pretty interesting idea. What about waiting for a new WASI version so that we might be able to do more things?

@mymmrac
Copy link
Contributor Author

mymmrac commented Feb 19, 2024

Yep, I agree with you that as of right now it is not very clear how to do a lot of things

There are two active proposals for //go:wasmexport [name] which might simplify things a lot and wasip2, so we can wait

golang/go#42372
golang/go#65199

golang/go#65333

@mymmrac
Copy link
Contributor Author

mymmrac commented Feb 19, 2024

Most likely for now I will create a wrapper library that will not depend on Ebiten itself, but in future, it would be great to have WASI support in Ebiten since I suppose we have only two ways to create "mods" for games (WASM or interpreters of other languages build for Go)

Btw, thanks for quick response!

@mymmrac
Copy link
Contributor Author

mymmrac commented Feb 19, 2024

Just in case for anyone who will be interested in example of Ebiten + WASI: https://gist.github.com/mymmrac/c2fc10b07289650d1e65c1a781299bb4

@hajimehoshi
Copy link
Owner

As there is nothing we can do for now unfortunately, let me close this. Let's revisit this when the situation changes.

@hajimehoshi hajimehoshi closed this as not planned Won't fix, can't repro, duplicate, stale Feb 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants