diff --git a/getrelease.goal b/getrelease.goal index 97023c7..b387f91 100755 --- a/getrelease.goal +++ b/getrelease.goal @@ -11,8 +11,8 @@ [mkdir release] cd release -[/bin/rm -rf wgpu-native] -[/bin/rm -rf zips] +[/usr/bin/env rm -rf wgpu-native] +[/usr/bin/env rm -rf zips] [mkdir zips] git clone https://github.com/gfx-rs/wgpu-native cd wgpu-native @@ -21,7 +21,7 @@ cd ../zips zips := goalib.SplitLines($ls -1 "*.zip"$) cd ../.. mv wgpu/lib wgpu/lib_old -[/bin/rm -rf wgpu/lib] +[/usr/bin/env rm -rf wgpu/lib] mkdir wgpu/lib cd wgpu/lib for _, f := range zips { @@ -37,7 +37,7 @@ for _, f := range zips { cd ../ } -/bin/cp ../lib_old/vendor.go . +/usr/bin/env cp ../lib_old/vendor.go . type files struct { zip, trg, arch string @@ -51,13 +51,12 @@ for _, f := range fls { cd {f.trg} [mkdir {f.arch}] cd {f.arch} - [/bin/cp -av {"../../" + f.zip + "/lib/libwgpu_native.a"} .] + [/usr/bin/env cp -av {"../../" + f.zip + "/lib/libwgpu_native.a"} .] if f.zip == "windows-aarch64" { - /bin/cp -av {"../../" + f.zip + "/lib/wgpu_native.lib"} libwgpu_native.a + /usr/bin/env cp -av {"../../" + f.zip + "/lib/wgpu_native.lib"} libwgpu_native.a } - /bin/cp -av {"../../" + f.zip + "/include/webgpu/*.h"} . + /usr/bin/env cp -av {"../../" + f.zip + "/include/webgpu/*.h"} . goalib.WriteFile("vendor.go", "package vendor") cd ../../ - /bin/rm -rf {f.zip} + /usr/bin/env rm -rf {f.zip} } - diff --git a/go.mod b/go.mod index 9834c9e..3fabae7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cogentcore/webgpu -go 1.22 +go 1.24 require ( github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a @@ -10,12 +10,40 @@ require ( ) require ( + cogentcore.org/core v0.3.12 // indirect + cogentcore.org/lab v0.1.2 // indirect + github.com/Bios-Marcel/wastebasket/v2 v2.0.3 // indirect + github.com/Masterminds/vcs v1.13.3 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bramvdbogaerde/go-scp v1.4.0 // indirect + github.com/chewxy/math32 v1.10.1 // indirect + github.com/cogentcore/readline v0.1.3 // indirect + github.com/cogentcore/yaegi v0.0.0-20250622201820-b7838bdd95eb // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/h2non/filetype v1.1.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-shellwords v1.0.12 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/pelletier/go-toml/v2 v2.1.2-0.20240227203013-2b69615b5d55 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/tools v0.23.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/image v0.25.0 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/tools v0.33.0 // indirect + gonum.org/v1/gonum v0.15.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect modernc.org/mathutil v1.5.0 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.1.0 // indirect ) + +tool cogentcore.org/lab/goal/cmd/goal diff --git a/go.sum b/go.sum index 753c436..8a83fed 100644 --- a/go.sum +++ b/go.sum @@ -1,25 +1,95 @@ +cogentcore.org/core v0.3.12 h1:wniqGY3wB+xDcJ3KfobR7VutWeiZafSQkjnbOW4nAXQ= +cogentcore.org/core v0.3.12/go.mod h1:Bwg3msVxqnfwvmQjpyJbyHMeox3UAcBcBitkGEdSYSE= +cogentcore.org/lab v0.1.2 h1:km5VUi3HVmP28maFnCvNgGXV4bGMjlPAXFIHchaRZ4k= +cogentcore.org/lab v0.1.2/go.mod h1:ilGaPEvvAVCHiUxpO83w01g1+Ix0tJxK+fnAmnLNOMk= +github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= +github.com/Bios-Marcel/wastebasket/v2 v2.0.3/go.mod h1:769oPCv6eH7ugl90DYIsWwjZh4hgNmMS3Zuhe1bH6KU= +github.com/Masterminds/vcs v1.13.3 h1:IIA2aBdXvfbIM+yl/eTnL4hb1XwdpvuQLglAix1gweE= +github.com/Masterminds/vcs v1.13.3/go.mod h1:TiE7xuEjl1N4j016moRd6vezp6e6Lz23gypeXfzXeW8= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bramvdbogaerde/go-scp v1.4.0 h1:jKMwpwCbcX1KyvDbm/PDJuXcMuNVlLGi0Q0reuzjyKY= +github.com/bramvdbogaerde/go-scp v1.4.0/go.mod h1:on2aH5AxaFb2G0N5Vsdy6B0Ml7k9HuHSwfo1y0QzAbQ= +github.com/chewxy/math32 v1.10.1 h1:LFpeY0SLJXeaiej/eIp2L40VYfscTvKh/FSEZ68uMkU= +github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= +github.com/cogentcore/readline v0.1.3 h1:tYmjP3XHvsGwhsDLkAp+vBhkERmLFENZfftyPOR/PBE= +github.com/cogentcore/readline v0.1.3/go.mod h1:IHVtJHSKXspK7CMg3OC/bbPEXxO++dFlug/vsPktvas= +github.com/cogentcore/yaegi v0.0.0-20250622201820-b7838bdd95eb h1:vXYqPLO36pRyyk1cVILVlk+slDI+Q7N4bgeWlh1sjA0= +github.com/cogentcore/yaegi v0.0.0-20250622201820-b7838bdd95eb/go.mod h1:+MGpZ0srBmeJ7aaOLTdVss8WLolt0/y/plVHLpxgd3A= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/pelletier/go-toml/v2 v2.1.2-0.20240227203013-2b69615b5d55 h1:CJwoX/v1ZWNj0Ofn62jvQDRuH3/hIHMqCQxbkzq2m5Y= +github.com/pelletier/go-toml/v2 v2.1.2-0.20240227203013-2b69615b5d55/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= +gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= diff --git a/jsx/jsx.go b/jsx/jsx.go index 6783e74..12473ff 100644 --- a/jsx/jsx.go +++ b/jsx/jsx.go @@ -5,21 +5,9 @@ package jsx import ( - "log/slog" "syscall/js" - "unsafe" ) -// BytesToJS converts the given bytes to a js Uint8ClampedArray -// by using the global wasm memory bytes. This avoids the -// copying present in [js.CopyBytesToJS]. -func BytesToJS(b []byte) js.Value { - ptr := uintptr(unsafe.Pointer(&b[0])) - // We directly pass the offset and length to the constructor to avoid calling subarray or slice, - // thereby improving performance and safety (this fixes a detached array buffer crash). - return js.Global().Get("Uint8ClampedArray").New(js.Global().Get("wasm").Get("instance").Get("exports").Get("mem").Get("buffer"), ptr, len(b)) -} - // Await is a helper function equivalent to await in JS. // It is copied from https://go-review.googlesource.com/c/go/+/150917/ func Await(promise js.Value) (result js.Value, ok bool) { @@ -40,7 +28,6 @@ func Await(promise js.Value) (result js.Value, ok bool) { onReject := js.FuncOf(func(this js.Value, args []js.Value) any { result = args[0] ok = false - slog.Error("wgpu.AwaitJS: promise rejected", "reason", result) close(done) return nil }) diff --git a/wgpu/adapter.go b/wgpu/adapter.go index 534ae7c..fdf86e5 100644 --- a/wgpu/adapter.go +++ b/wgpu/adapter.go @@ -14,7 +14,6 @@ extern void gowebgpu_device_lost_callback_c(WGPUDeviceLostReason reason, char co import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -109,7 +108,7 @@ type requestDeviceCb func(status RequestDeviceStatus, device *Device, message st //export gowebgpu_request_device_callback_go func gowebgpu_request_device_callback_go(status C.WGPURequestDeviceStatus, device C.WGPUDevice, message C.WGPUStringView, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) defer handle.Delete() cb, ok := handle.Value().(requestDeviceCb) @@ -120,7 +119,7 @@ func gowebgpu_request_device_callback_go(status C.WGPURequestDeviceStatus, devic //export gowebgpu_device_lost_callback_go func gowebgpu_device_lost_callback_go(reason C.WGPUDeviceLostReason, message *C.char, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) defer handle.Delete() cb, ok := handle.Value().(DeviceLostCallback) @@ -206,11 +205,11 @@ func (p *Adapter) RequestDevice(descriptor *DeviceDescriptor) (*Device, error) { } if descriptor.DeviceLostCallback != nil { - handle := cgo.NewHandle(descriptor.DeviceLostCallback) + handle := newHandle(descriptor.DeviceLostCallback) desc.deviceLostCallbackInfo = C.WGPUDeviceLostCallbackInfo{ callback: C.WGPUDeviceLostCallback(C.gowebgpu_device_lost_callback_c), - userdata1: unsafe.Pointer(&handle), + userdata1: handle.ToPointer(), } } @@ -238,10 +237,10 @@ func (p *Adapter) RequestDevice(descriptor *DeviceDescriptor) (*Device, error) { status = s device = d } - handle := cgo.NewHandle(cb) + handle := newHandle(cb) C.wgpuAdapterRequestDevice(p.ref, desc, C.WGPURequestDeviceCallbackInfo{ callback: C.WGPURequestDeviceCallback(C.gowebgpu_request_device_callback_c), - userdata1: unsafe.Pointer(&handle), + userdata1: handle.ToPointer(), }) if status != RequestDeviceStatusSuccess { diff --git a/wgpu/adapter_js.go b/wgpu/adapter_js.go index 4950770..2fa3249 100644 --- a/wgpu/adapter_js.go +++ b/wgpu/adapter_js.go @@ -27,8 +27,8 @@ func (g Adapter) GetInfo() AdapterInfo { return AdapterInfo{} // TODO(kai): implement? } -func (g Adapter) GetLimits() SupportedLimits { - return SupportedLimits{limitsFromJS(g.jsValue.Get("limits"))} +func (g Adapter) GetLimits() Limits { + return limitsFromJS(g.jsValue.Get("limits")) } func (g Adapter) Release() {} // no-op diff --git a/wgpu/buffer.go b/wgpu/buffer.go index eae43fc..46d126c 100644 --- a/wgpu/buffer.go +++ b/wgpu/buffer.go @@ -44,7 +44,6 @@ static inline void gowebgpu_buffer_release(WGPUBuffer buffer, WGPUDevice device) import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -72,7 +71,7 @@ func (p *Buffer) GetUsage() BufferUsage { //export gowebgpu_buffer_map_callback_go func gowebgpu_buffer_map_callback_go(status C.WGPUMapAsyncStatus, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) defer handle.Delete() cb, ok := handle.Value().(BufferMapCallback) @@ -82,12 +81,12 @@ func gowebgpu_buffer_map_callback_go(status C.WGPUMapAsyncStatus, userdata unsaf } func (p *Buffer) MapAsync(mode MapMode, offset uint64, size uint64, callback BufferMapCallback) (err error) { - callbackHandle := cgo.NewHandle(callback) + callbackHandle := newHandle(callback) var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Buffer).MapAsync(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_buffer_map_async( @@ -97,10 +96,10 @@ func (p *Buffer) MapAsync(mode MapMode, offset uint64, size uint64, callback Buf C.size_t(size), C.WGPUBufferMapCallbackInfo{ callback: C.WGPUBufferMapCallback(C.gowebgpu_buffer_map_callback_c), - userdata1: unsafe.Pointer(&callbackHandle), + userdata1: callbackHandle.ToPointer(), }, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -109,13 +108,13 @@ func (p *Buffer) Unmap() (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Buffer).Unmap(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_buffer_unmap( p.ref, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } diff --git a/wgpu/buffer_js.go b/wgpu/buffer_js.go index 49b14b7..9f06b96 100644 --- a/wgpu/buffer_js.go +++ b/wgpu/buffer_js.go @@ -36,8 +36,13 @@ func (g Buffer) GetMappedRange(offset, size uint) []byte { } func (g Buffer) MapAsync(mode MapMode, offset uint64, size uint64, callback BufferMapCallback) (err error) { - jsx.Await(g.jsValue.Call("mapAsync", uint32(mode), offset, size)) - callback(BufferMapAsyncStatusSuccess) // TODO(kai): is this the right thing to do? + _, ok := jsx.Await(g.jsValue.Call("mapAsync", uint32(mode), offset, size)) + if !ok { + callback(MapAsyncStatusError) + return + } + + callback(MapAsyncStatusSuccess) return } diff --git a/wgpu/command_encoder.go b/wgpu/command_encoder.go index 17db8e0..149ea59 100644 --- a/wgpu/command_encoder.go +++ b/wgpu/command_encoder.go @@ -153,7 +153,6 @@ static inline void gowebgpu_command_encoder_release(WGPUCommandEncoder commandEn import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -264,7 +263,7 @@ func (p *CommandEncoder) ClearBuffer(buffer *Buffer, offset uint64, size uint64) var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).ClearBuffer(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_clear_buffer( @@ -273,7 +272,7 @@ func (p *CommandEncoder) ClearBuffer(buffer *Buffer, offset uint64, size uint64) C.uint64_t(offset), C.uint64_t(size), p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -282,7 +281,7 @@ func (p *CommandEncoder) CopyBufferToBuffer(source *Buffer, sourceOffset uint64, var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).CopyBufferToBuffer(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_copy_buffer_to_buffer( @@ -293,7 +292,7 @@ func (p *CommandEncoder) CopyBufferToBuffer(source *Buffer, sourceOffset uint64, C.uint64_t(destinatonOffset), C.uint64_t(size), p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -339,7 +338,7 @@ func (p *CommandEncoder) CopyBufferToTexture(source *TexelCopyBufferInfo, destin var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).CopyBufferToTexture(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_copy_buffer_to_texture( @@ -348,7 +347,7 @@ func (p *CommandEncoder) CopyBufferToTexture(source *TexelCopyBufferInfo, destin &dst, &cpySize, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -394,7 +393,7 @@ func (p *CommandEncoder) CopyTextureToBuffer(source *TexelCopyTextureInfo, desti var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).CopyTextureToBuffer(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_copy_texture_to_buffer( @@ -403,7 +402,7 @@ func (p *CommandEncoder) CopyTextureToBuffer(source *TexelCopyTextureInfo, desti &dst, &cpySize, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -453,7 +452,7 @@ func (p *CommandEncoder) CopyTextureToTexture(source *TexelCopyTextureInfo, dest var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).CopyTextureToTexture(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_copy_texture_to_texture( @@ -462,7 +461,7 @@ func (p *CommandEncoder) CopyTextureToTexture(source *TexelCopyTextureInfo, dest &dst, &cpySize, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -483,14 +482,14 @@ func (p *CommandEncoder) Finish(descriptor *CommandBufferDescriptor) (*CommandBu var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).Finish(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_command_encoder_finish( p.ref, desc, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuCommandBufferRelease(ref) @@ -507,14 +506,14 @@ func (p *CommandEncoder) InsertDebugMarker(markerLabel string) (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).InsertDebugMarker(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_insert_debug_marker( p.ref, markerLabelStr, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -523,13 +522,13 @@ func (p *CommandEncoder) PopDebugGroup() (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).PopDebugGroup(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_pop_debug_group( p.ref, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -541,14 +540,14 @@ func (p *CommandEncoder) PushDebugGroup(groupLabel string) (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).PushDebugGroup(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_push_debug_group( p.ref, groupLabelStr, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -557,7 +556,7 @@ func (p *CommandEncoder) ResolveQuerySet(querySet *QuerySet, firstQuery uint32, var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).ResolveQuerySet(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_resolve_query_set( @@ -568,7 +567,7 @@ func (p *CommandEncoder) ResolveQuerySet(querySet *QuerySet, firstQuery uint32, destination.ref, C.uint64_t(destinationOffset), p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -577,7 +576,7 @@ func (p *CommandEncoder) WriteTimestamp(querySet *QuerySet, queryIndex uint32) ( var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*CommandEncoder).WriteTimestamp(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_command_encoder_write_timestamp( @@ -585,7 +584,7 @@ func (p *CommandEncoder) WriteTimestamp(querySet *QuerySet, queryIndex uint32) ( querySet.ref, C.uint32_t(queryIndex), p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } diff --git a/wgpu/command_encoder_js.go b/wgpu/command_encoder_js.go index 1df9555..1bc02fc 100644 --- a/wgpu/command_encoder_js.go +++ b/wgpu/command_encoder_js.go @@ -45,21 +45,21 @@ func (g CommandEncoder) CopyBufferToBuffer(source *Buffer, sourceOffset uint64, // CopyBufferToTexture as described: // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertotexture -func (g CommandEncoder) CopyBufferToTexture(source *ImageCopyBuffer, destination *ImageCopyTexture, copySize *Extent3D) (err error) { +func (g CommandEncoder) CopyBufferToTexture(source *TexelCopyBufferInfo, destination *TexelCopyTextureInfo, copySize *Extent3D) (err error) { g.jsValue.Call("copyBufferToTexture", pointerToJS(source), pointerToJS(destination), pointerToJS(copySize)) return nil } // CopyTextureToBuffer as described: // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copytexturetobuffer -func (g CommandEncoder) CopyTextureToBuffer(source *ImageCopyTexture, destination *ImageCopyBuffer, copySize *Extent3D) (err error) { +func (g CommandEncoder) CopyTextureToBuffer(source *TexelCopyTextureInfo, destination *TexelCopyBufferInfo, copySize *Extent3D) (err error) { g.jsValue.Call("copyTextureToBuffer", pointerToJS(source), pointerToJS(destination), pointerToJS(copySize)) return nil } // CopyTextureToTexture as described: // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copytexturetotexture -func (g CommandEncoder) CopyTextureToTexture(source *ImageCopyTexture, destination *ImageCopyTexture, copySize *Extent3D) (err error) { +func (g CommandEncoder) CopyTextureToTexture(source *TexelCopyTextureInfo, destination *TexelCopyTextureInfo, copySize *Extent3D) (err error) { g.jsValue.Call("copyTextureToTexture", pointerToJS(source), pointerToJS(destination), pointerToJS(copySize)) return nil } diff --git a/wgpu/common.go b/wgpu/common.go index a3386c1..2697e63 100644 --- a/wgpu/common.go +++ b/wgpu/common.go @@ -67,16 +67,17 @@ type Origin3D struct { X, Y, Z uint32 } -// SurfaceConfiguration, corresponding to GPUCanvasConfiguration: +// SurfaceConfiguration corresponding to GPUCanvasConfiguration: // https://gpuweb.github.io/gpuweb/#dictdef-gpucanvasconfiguration type SurfaceConfiguration struct { - Usage TextureUsage - Format TextureFormat - Width uint32 - Height uint32 - PresentMode PresentMode - AlphaMode CompositeAlphaMode - ViewFormats []TextureFormat + Usage TextureUsage + Format TextureFormat + Width uint32 + Height uint32 + PresentMode PresentMode + AlphaMode CompositeAlphaMode + ViewFormats []TextureFormat + DesiredMaximumFrameLatency uint32 } type TexelCopyTextureInfo struct { diff --git a/wgpu/compute_pass_encoder.go b/wgpu/compute_pass_encoder.go index abda77f..ec44c77 100644 --- a/wgpu/compute_pass_encoder.go +++ b/wgpu/compute_pass_encoder.go @@ -30,7 +30,6 @@ static inline void gowebgpu_compute_pass_encoder_release(WGPUComputePassEncoder import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -55,10 +54,10 @@ func (p *ComputePassEncoder) End() (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*ComputePassEncoder).End(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() - C.gowebgpu_compute_pass_encoder_end(p.ref, p.deviceRef, unsafe.Pointer(&errorCallbackHandle)) + C.gowebgpu_compute_pass_encoder_end(p.ref, p.deviceRef, errorCallbackHandle.ToPointer()) return } diff --git a/wgpu/compute_pass_js.go b/wgpu/compute_pass_js.go index ac3a09e..bae8b78 100644 --- a/wgpu/compute_pass_js.go +++ b/wgpu/compute_pass_js.go @@ -62,8 +62,9 @@ func (g ComputePassEncoder) DispatchWorkgroups(workgroupCountX, workgroupCountY, // End as described: // https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-end -func (g ComputePassEncoder) End() { +func (g ComputePassEncoder) End() error { g.jsValue.Call("end") + return nil } func (g ComputePassEncoder) Release() {} // no-op diff --git a/wgpu/compute_pipeline_js.go b/wgpu/compute_pipeline_js.go index 1bf895d..60b042e 100644 --- a/wgpu/compute_pipeline_js.go +++ b/wgpu/compute_pipeline_js.go @@ -15,7 +15,11 @@ type ComputePipelineDescriptor struct { func (g ComputePipelineDescriptor) toJS() any { result := make(map[string]any) - result["layout"] = pointerToJS(g.Layout) + if g.Layout != nil { + result["layout"] = pointerToJS(g.Layout) + } else { + result["layout"] = "auto" + } result["compute"] = g.Compute.toJS() return result } @@ -30,4 +34,9 @@ func (g ComputePipeline) toJS() any { return g.jsValue } -func (g ComputePipeline) Release() {} // no-op +func (g ComputePipeline) Release() {} + +func (g ComputePipeline) GetBindGroupLayout(idx int) *BindGroupLayout { + jsValue := g.jsValue.Call("getBindGroupLayout", idx) + return &BindGroupLayout{jsValue} +} diff --git a/wgpu/device.go b/wgpu/device.go index b91879e..18253ae 100644 --- a/wgpu/device.go +++ b/wgpu/device.go @@ -178,7 +178,6 @@ static inline WGPUTexture gowebgpu_device_create_texture(WGPUDevice device, WGPU import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -190,7 +189,7 @@ type errorCallback func(typ ErrorType, message string) //export gowebgpu_error_callback_go func gowebgpu_error_callback_go(_type C.WGPUErrorType, message C.WGPUStringView, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) cb, ok := handle.Value().(errorCallback) if ok { cb(ErrorType(_type), C.GoStringN(message.data, C.int(message.length))) @@ -251,13 +250,13 @@ func (p *Device) CreateBindGroup(descriptor *BindGroupDescriptor) (*BindGroup, e var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateBindGroup(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_bind_group( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuBindGroupRelease(ref) @@ -356,13 +355,13 @@ func (p *Device) CreateBindGroupLayout(descriptor *BindGroupLayoutDescriptor) (* var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateBindGroupLayout(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_bind_group_layout( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuBindGroupLayoutRelease(ref) @@ -393,13 +392,13 @@ func (p *Device) CreateBuffer(descriptor *BufferDescriptor) (*Buffer, error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateBuffer(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_buffer( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuBufferRelease(ref) @@ -429,13 +428,13 @@ func (p *Device) CreateCommandEncoder(descriptor *CommandEncoderDescriptor) (*Co var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateCommandEncoder(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_command_encoder( p.ref, desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuCommandEncoderRelease(ref) @@ -491,13 +490,13 @@ func (p *Device) CreateComputePipeline(descriptor *ComputePipelineDescriptor) (* var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateComputePipeline(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_compute_pipeline( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuComputePipelineRelease(ref) @@ -580,13 +579,13 @@ func (p *Device) CreatePipelineLayout(descriptor *PipelineLayoutDescriptor) (*Pi var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreatePipelineLayout(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_pipeline_layout( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuPipelineLayoutRelease(ref) @@ -636,13 +635,13 @@ func (p *Device) CreateQuerySet(descriptor *QuerySetDescriptor) (*QuerySet, erro var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateQuerySet(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_query_set( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuQuerySetRelease(ref) @@ -966,13 +965,13 @@ func (p *Device) CreateRenderPipeline(descriptor *RenderPipelineDescriptor) (*Re var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateRenderPipeline(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_render_pipeline( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuRenderPipelineRelease(ref) @@ -1012,13 +1011,13 @@ func (p *Device) CreateSampler(descriptor *SamplerDescriptor) (*Sampler, error) var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateSampler(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_sampler( p.ref, desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuSamplerRelease(ref) @@ -1150,13 +1149,13 @@ func (p *Device) CreateShaderModule(descriptor *ShaderModuleDescriptor) (*Shader var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateShaderModule(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_shader_module( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuShaderModuleRelease(ref) @@ -1196,13 +1195,13 @@ func (p *Device) CreateTexture(descriptor *TextureDescriptor) (*Texture, error) var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Device).CreateTexture(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_device_create_texture( p.ref, &desc, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuTextureRelease(ref) diff --git a/wgpu/device_js.go b/wgpu/device_js.go index 888f6f3..8f34b94 100644 --- a/wgpu/device_js.go +++ b/wgpu/device_js.go @@ -123,11 +123,11 @@ func (g Device) CreateSampler(descriptor *SamplerDescriptor) (*Sampler, error) { }, nil } -func (g Device) GetLimits() SupportedLimits { - return SupportedLimits{limitsFromJS(g.jsValue.Get("limits"))} +func (g Device) GetLimits() Limits { + return limitsFromJS(g.jsValue.Get("limits")) } -func (g Device) Poll(wait bool, wrappedSubmissionIndex *WrappedSubmissionIndex) (queueEmpty bool) { +func (g Device) Poll(wait bool, wrappedSubmissionIndex *uint64) (queueEmpty bool) { return false // no-op } diff --git a/wgpu/handle.go b/wgpu/handle.go new file mode 100644 index 0000000..a7cd759 --- /dev/null +++ b/wgpu/handle.go @@ -0,0 +1,91 @@ +package wgpu + +import ( + "sync" + "unsafe" +) + +var pointers []byte + +var handles = map[handle]any{} +var handlesMu sync.Mutex + +type handle struct { + pointer unsafe.Pointer +} + +// NewHandle returns a handle for a given value. +// +// The handle is valid until the program calls Delete on it. The handle +// uses resources, and this package assumes that C code may hold on to +// the handle, so a program must explicitly call Delete when the handle +// is no longer needed in C code. +// +// The intended use is to pass the returned handle to C code, which +// passes it back to Go, which calls Value. +// +// Compared to cgo.Handle, this handle can be converted to an unsafe.Pointer +// and be used in C as userdata when a void* value is required. +func newHandle(value any) handle { + handlesMu.Lock() + defer handlesMu.Unlock() + + if len(pointers) == 0 { + pointers = make([]byte, 1024*4) + } + + // get a unique pointer as the identifier of the newly created handle + h := handle{pointer: unsafe.Pointer(&pointers[0])} + pointers = pointers[1:] + + handles[h] = value + + return h +} + +// lookupHandle converts an unsafe.Pointer obtained by ToPointer back into +// a handle. It will not check if the handle is still valid. +func lookupHandle(p unsafe.Pointer) handle { + return handle{pointer: p} +} + +// Value returns the associated Go value for a valid handle. +// +// The method panics if the handle is invalid. +func (h handle) Value() any { + handlesMu.Lock() + defer handlesMu.Unlock() + + if !h.isValid() { + panic("invalid handle") + } + + return handles[h] +} + +// Delete invalidates a handle. This method should only be called once +// the program no longer needs to pass the handle to C and the C code +// no longer has a copy of the handle value. +// +// The method panics if the handle is invalid. +func (h handle) Delete() { + handlesMu.Lock() + defer handlesMu.Unlock() + + if !h.isValid() { + panic("invalid handle") + } + + delete(handles, h) +} + +// ToPointer converts the handle into a valid unsafe.Pointer +// that you can pass to C code. +func (h handle) ToPointer() unsafe.Pointer { + return h.pointer +} + +func (h handle) isValid() bool { + _, valid := handles[h] + return valid +} diff --git a/wgpu/instance.go b/wgpu/instance.go index d0dbf19..044d220 100644 --- a/wgpu/instance.go +++ b/wgpu/instance.go @@ -13,7 +13,6 @@ extern void gowebgpu_request_adapter_callback_c(WGPURequestAdapterStatus status, import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -185,7 +184,7 @@ type requestAdapterCb func(status RequestAdapterStatus, adapter *Adapter, messag //export gowebgpu_request_adapter_callback_go func gowebgpu_request_adapter_callback_go(status C.WGPURequestAdapterStatus, adapter C.WGPUAdapter, message C.WGPUStringView, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) defer handle.Delete() cb, ok := handle.Value().(requestAdapterCb) @@ -215,10 +214,10 @@ func (p *Instance) RequestAdapter(options *RequestAdapterOptions) (*Adapter, err status = s adapter = a } - handle := cgo.NewHandle(cb) + handle := newHandle(cb) C.wgpuInstanceRequestAdapter(p.ref, opts, C.WGPURequestAdapterCallbackInfo{ callback: C.WGPURequestAdapterCallback(C.gowebgpu_request_adapter_callback_c), - userdata1: unsafe.Pointer(&handle), + userdata1: handle.ToPointer(), }) if status != RequestAdapterStatusSuccess { diff --git a/wgpu/queue.go b/wgpu/queue.go index 985ba23..7f2efb9 100644 --- a/wgpu/queue.go +++ b/wgpu/queue.go @@ -43,7 +43,6 @@ static inline void gowebgpu_queue_release(WGPUQueue queue, WGPUDevice device) { import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -54,7 +53,7 @@ type Queue struct { //export gowebgpu_queue_work_done_callback_go func gowebgpu_queue_work_done_callback_go(status C.WGPUQueueWorkDoneStatus, userdata unsafe.Pointer) { - handle := *(*cgo.Handle)(userdata) + handle := lookupHandle(userdata) defer handle.Delete() cb, ok := handle.Value().(QueueWorkDoneCallback) @@ -64,11 +63,11 @@ func gowebgpu_queue_work_done_callback_go(status C.WGPUQueueWorkDoneStatus, user } func (p *Queue) OnSubmittedWorkDone(callback QueueWorkDoneCallback) { - handle := cgo.NewHandle(callback) + handle := newHandle(callback) C.wgpuQueueOnSubmittedWorkDone(p.ref, C.WGPUQueueWorkDoneCallbackInfo{ callback: C.WGPUQueueWorkDoneCallback(C.gowebgpu_queue_work_done_callback_c), - userdata1: unsafe.Pointer(&handle), + userdata1: handle.ToPointer(), }) } @@ -99,7 +98,7 @@ func (p *Queue) WriteBuffer(buffer *Buffer, bufferOffset uint64, data []byte) (e var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Queue).WriteBuffer(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() size := len(data) @@ -111,7 +110,7 @@ func (p *Queue) WriteBuffer(buffer *Buffer, bufferOffset uint64, data []byte) (e nil, 0, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -123,7 +122,7 @@ func (p *Queue) WriteBuffer(buffer *Buffer, bufferOffset uint64, data []byte) (e unsafe.Pointer(&data[0]), C.size_t(size), p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -166,7 +165,7 @@ func (p *Queue) WriteTexture(destination *TexelCopyTextureInfo, data []byte, dat var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Queue).WriteTexture(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() size := len(data) @@ -179,7 +178,7 @@ func (p *Queue) WriteTexture(destination *TexelCopyTextureInfo, data []byte, dat &layout, &writeExtent, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } @@ -192,7 +191,7 @@ func (p *Queue) WriteTexture(destination *TexelCopyTextureInfo, data []byte, dat &layout, &writeExtent, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } diff --git a/wgpu/queue_js.go b/wgpu/queue_js.go index 387a304..6e56f71 100644 --- a/wgpu/queue_js.go +++ b/wgpu/queue_js.go @@ -3,7 +3,9 @@ package wgpu import ( + "runtime" "syscall/js" + "unsafe" "github.com/cogentcore/webgpu/jsx" ) @@ -20,24 +22,31 @@ func (g Queue) toJS() any { // Submit as described: // https://gpuweb.github.io/gpuweb/#dom-gpuqueue-submit -func (g Queue) Submit(commandBuffers ...*CommandBuffer) { +func (g Queue) Submit(commandBuffers ...*CommandBuffer) SubmissionIndex { jsSequence := mapSlice(commandBuffers, func(buffer *CommandBuffer) any { return pointerToJS(buffer) }) g.jsValue.Call("submit", jsSequence) + return SubmissionIndex(0) } // WriteBuffer as described: // https://gpuweb.github.io/gpuweb/#dom-gpuqueue-writebuffer func (g Queue) WriteBuffer(buffer *Buffer, offset uint64, data []byte) (err error) { - g.jsValue.Call("writeBuffer", pointerToJS(buffer), offset, jsx.BytesToJS(data), uint64(0), len(data)) + defer runtime.KeepAlive(data) + + address := uintptr(unsafe.Pointer(&data[0])) + queueWriteBuffer.Invoke(g.jsValue, pointerToJS(buffer), offset, address, uint64(0), len(data)) return } // WriteTexture as described: // https://gpuweb.github.io/gpuweb/#dom-gpuqueue-writetexture -func (g Queue) WriteTexture(destination *ImageCopyTexture, data []byte, dataLayout *TextureDataLayout, writeSize *Extent3D) (err error) { - g.jsValue.Call("writeTexture", pointerToJS(destination), jsx.BytesToJS(data), pointerToJS(dataLayout), pointerToJS(writeSize)) +func (g Queue) WriteTexture(destination *TexelCopyTextureInfo, data []byte, dataLayout *TexelCopyBufferLayout, writeSize *Extent3D) (err error) { + defer runtime.KeepAlive(data) + + address := uintptr(unsafe.Pointer(&data[0])) + queueWriteTexture.Invoke(g.jsValue, pointerToJS(destination), address, len(data), pointerToJS(dataLayout), pointerToJS(writeSize)) return } @@ -49,3 +58,24 @@ func (g Queue) OnSubmittedWorkDone(callback QueueWorkDoneCallback) { } func (g Queue) Release() {} // no-op + +var queueWriteBuffer js.Value +var queueWriteTexture js.Value + +func init() { + queueWriteBuffer = js.Global().Call("eval", ` + (queue, buf, offset, addr, x, n) => { + const mem = wasm.instance.exports.mem.buffer; + const data = new Uint8ClampedArray(mem, addr, n); + return queue.writeBuffer(buf, offset, data, x, n); + } + `) + + queueWriteTexture = js.Global().Call("eval", ` + (queue, tex, addr, n, layout, writeSize) => { + const mem = wasm.instance.exports.mem.buffer; + const data = new Uint8ClampedArray(mem, addr, n); + return queue.writeTexture(tex, data, layout, writeSize); + } + `) +} diff --git a/wgpu/render_pass_encoder.go b/wgpu/render_pass_encoder.go index a8e3eb6..6f8833f 100644 --- a/wgpu/render_pass_encoder.go +++ b/wgpu/render_pass_encoder.go @@ -30,7 +30,6 @@ static inline void gowebgpu_render_pass_encoder_release(WGPURenderPassEncoder re import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -78,13 +77,13 @@ func (p *RenderPassEncoder) End() (err error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*RenderPassEncoder).End(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() C.gowebgpu_render_pass_encoder_end( p.ref, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) return } diff --git a/wgpu/render_pipeline.go b/wgpu/render_pipeline.go index 085e083..e08e828 100644 --- a/wgpu/render_pipeline.go +++ b/wgpu/render_pipeline.go @@ -17,7 +17,7 @@ type RenderPipeline struct { func (p *RenderPipeline) GetBindGroupLayout(groupIndex uint32) *BindGroupLayout { ref := C.wgpuRenderPipelineGetBindGroupLayout(p.ref, C.uint32_t(groupIndex)) if ref == nil { - panic("Failed to accquire BindGroupLayout") + panic("Failed to acquire BindGroupLayout") } return &BindGroupLayout{ref} diff --git a/wgpu/shader_js.go b/wgpu/shader_js.go index 9a1a96c..3b682fc 100644 --- a/wgpu/shader_js.go +++ b/wgpu/shader_js.go @@ -7,13 +7,13 @@ import "syscall/js" // ShaderModuleDescriptor as described: // https://gpuweb.github.io/gpuweb/#dictdef-gpushadermoduledescriptor type ShaderModuleDescriptor struct { - Label string - WGSLDescriptor *ShaderModuleWGSLDescriptor + Label string + WGSLSource *ShaderSourceWGSL } func (g ShaderModuleDescriptor) toJS() any { return map[string]any{ - "code": g.WGSLDescriptor.Code, + "code": g.WGSLSource.Code, } } diff --git a/wgpu/surface.go b/wgpu/surface.go index d39f663..c56aea7 100644 --- a/wgpu/surface.go +++ b/wgpu/surface.go @@ -28,7 +28,7 @@ static inline WGPUTexture gowebgpu_surface_get_current_texture(WGPUSurface surfa import "C" import ( "errors" - "runtime/cgo" + "runtime" "unsafe" ) @@ -81,8 +81,24 @@ func (p *Surface) GetCapabilities(adapter *Adapter) (ret SurfaceCapabilities) { func (p *Surface) Configure(adapter *Adapter, device *Device, config *SurfaceConfiguration) { p.deviceRef = device.ref + var pinner runtime.Pinner + defer pinner.Unpin() + var cfg *C.WGPUSurfaceConfiguration if config != nil { + var nextInChain *C.WGPUSurfaceConfigurationExtras + + if config.DesiredMaximumFrameLatency > 0 { + nextInChain = &C.WGPUSurfaceConfigurationExtras{ + chain: C.WGPUChainedStruct{ + sType: C.WGPUSType_SurfaceConfigurationExtras, + }, + desiredMaximumFrameLatency: 1, + } + + pinner.Pin(nextInChain) + } + cfg = &C.WGPUSurfaceConfiguration{ device: p.deviceRef, format: C.WGPUTextureFormat(config.Format), @@ -91,17 +107,14 @@ func (p *Surface) Configure(adapter *Adapter, device *Device, config *SurfaceCon width: C.uint32_t(config.Width), height: C.uint32_t(config.Height), presentMode: C.WGPUPresentMode(config.PresentMode), + nextInChain: (*C.WGPUChainedStruct)(unsafe.Pointer(nextInChain)), } - viewFormatCount := len(config.ViewFormats) - if viewFormatCount > 0 { - viewFormats := C.malloc(C.size_t(unsafe.Sizeof(C.WGPUTextureFormat(0))) * C.size_t(viewFormatCount)) - defer C.free(viewFormats) - viewFormatsSlice := unsafe.Slice((*TextureFormat)(viewFormats), viewFormatCount) - copy(viewFormatsSlice, config.ViewFormats) + if len(config.ViewFormats) > 0 { + pinner.Pin(&config.ViewFormats[0]) - cfg.viewFormatCount = C.size_t(viewFormatCount) - cfg.viewFormats = (*C.WGPUTextureFormat)(viewFormats) + cfg.viewFormatCount = C.size_t(len(config.ViewFormats)) + cfg.viewFormats = (*C.WGPUTextureFormat)(&config.ViewFormats[0]) } } @@ -115,13 +128,13 @@ func (p *Surface) GetCurrentTexture() (*Texture, error) { var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Surface).GetCurrentTexture(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_surface_get_current_texture( p.ref, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { if ref != nil { diff --git a/wgpu/texture.go b/wgpu/texture.go index fcdd984..c812432 100644 --- a/wgpu/texture.go +++ b/wgpu/texture.go @@ -33,7 +33,6 @@ static inline void gowebgpu_texture_release(WGPUTexture texture, WGPUDevice devi import "C" import ( "errors" - "runtime/cgo" "unsafe" ) @@ -69,14 +68,14 @@ func (p *Texture) CreateView(descriptor *TextureViewDescriptor) (*TextureView, e var cb errorCallback = func(_ ErrorType, message string) { err = errors.New("wgpu.(*Texture).CreateView(): " + message) } - errorCallbackHandle := cgo.NewHandle(cb) + errorCallbackHandle := newHandle(cb) defer errorCallbackHandle.Delete() ref := C.gowebgpu_texture_create_view( p.ref, desc, p.deviceRef, - unsafe.Pointer(&errorCallbackHandle), + errorCallbackHandle.ToPointer(), ) if err != nil { C.wgpuTextureViewRelease(ref) diff --git a/wgpu/texture_js.go b/wgpu/texture_js.go index d504269..f394dca 100644 --- a/wgpu/texture_js.go +++ b/wgpu/texture_js.go @@ -2,7 +2,10 @@ package wgpu -import "syscall/js" +import ( + "fmt" + "syscall/js" +) // TextureView as described: // https://gpuweb.github.io/gpuweb/#gputextureview @@ -29,8 +32,15 @@ func (g Texture) toJS() any { // GetFormat as described: // https://gpuweb.github.io/gpuweb/#dom-gputexture-format func (g Texture) GetFormat() TextureFormat { - jsFormat := g.jsValue.Get("format") - return TextureFormat(jsFormat.Int()) // TODO(kai): need to set from string + jsFormat := g.jsValue.Get("format").String() + + for tf := TextureFormatUndefined + 1; tf.String() != ""; tf++ { + if tf.String() == jsFormat { + return tf + } + } + + panic(fmt.Sprintf("unknown texture format %q", jsFormat)) } // GetDepthOrArrayLayers as described: @@ -45,6 +55,24 @@ func (g Texture) GetMipLevelCount() uint32 { return uint32(g.jsValue.Get("mipLevelCount").Int()) } +// GetWidth as described: +// https://gpuweb.github.io/gpuweb/#dom-gputexture-width +func (g Texture) GetWidth() uint32 { + return uint32(g.jsValue.Get("width").Int()) +} + +// GetWidth as described: +// https://gpuweb.github.io/gpuweb/#dom-gputexture-height +func (g Texture) GetHeight() uint32 { + return uint32(g.jsValue.Get("height").Int()) +} + +// GetWidth as described: +// https://gpuweb.github.io/gpuweb/#dom-gputexture-samplecount +func (g Texture) GetSampleCount() uint32 { + return uint32(g.jsValue.Get("sampleCount").Int()) +} + // CreateView as described: // https://gpuweb.github.io/gpuweb/#dom-gputexture-createview func (g Texture) CreateView(descriptor *TextureViewDescriptor) (*TextureView, error) { diff --git a/wgpu/to_js.go b/wgpu/to_js.go index d113dbb..9d801d0 100644 --- a/wgpu/to_js.go +++ b/wgpu/to_js.go @@ -128,7 +128,7 @@ func (g BufferDescriptor) toJS() any { } } -func (g *ImageCopyBuffer) toJS() any { +func (g *TexelCopyBufferInfo) toJS() any { return map[string]any{ "buffer": pointerToJS(g.Buffer), "offset": g.Layout.Offset, @@ -137,7 +137,7 @@ func (g *ImageCopyBuffer) toJS() any { } } -func (g *ImageCopyTexture) toJS() any { +func (g *TexelCopyTextureInfo) toJS() any { return map[string]any{ "texture": pointerToJS(g.Texture), "mipLevel": g.MipLevel, @@ -146,7 +146,7 @@ func (g *ImageCopyTexture) toJS() any { } } -func (g *TextureDataLayout) toJS() any { +func (g *TexelCopyBufferLayout) toJS() any { return map[string]any{ "offset": g.Offset, "bytesPerRow": g.BytesPerRow, diff --git a/wgpu/wgpu_ext.go b/wgpu/wgpu_ext.go index 41d124f..ab3d298 100644 --- a/wgpu/wgpu_ext.go +++ b/wgpu/wgpu_ext.go @@ -60,7 +60,19 @@ var ( func (v VertexFormat) Size() uint64 { switch v { - case VertexFormatUint8x2, + case VertexFormatUint8, + VertexFormatSint8, + VertexFormatUnorm8, + VertexFormatSnorm8: + return 1 + + case + VertexFormatUint16, + VertexFormatSint16, + VertexFormatUnorm16, + VertexFormatSnorm16, + VertexFormatFloat16, + VertexFormatUint8x2, VertexFormatSint8x2, VertexFormatUnorm8x2, VertexFormatSnorm8x2: