Skip to content

Commit

Permalink
Main branch targets Godot 4 (#39)
Browse files Browse the repository at this point in the history
Godot 4 support
Class documentation
Update examples
  • Loading branch information
ashtonmeuser authored May 22, 2023
1 parent eea765c commit 0d423b8
Show file tree
Hide file tree
Showing 23 changed files with 1,095 additions and 559 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/build-addon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ jobs:
path: |
${{ github.workspace }}/godot-cpp/bin
${{ github.workspace }}/godot-cpp/include
${{ github.workspace }}/godot-cpp/godot-headers/**/*.h
${{ github.workspace }}/godot-cpp/gen
key: ${{ runner.os }}-${{ env.SUBMODULE_HASH }}-${{ secrets.GODOT_CPP_CACHE_VERSION }}

- name: Compile Godot Library
if: steps.cache-godot-cpp.outputs.cache-hit != 'true'
run: |
cd ${{ github.workspace }}/godot-cpp
scons platform=linux target=release generate_bindings=yes
scons platform=linux
- name: Compile Addon
run: scons platform=linux
Expand Down Expand Up @@ -89,23 +89,23 @@ jobs:
path: |
${{ github.workspace }}/godot-cpp/bin
${{ github.workspace }}/godot-cpp/include
${{ github.workspace }}/godot-cpp/godot-headers/**/*.h
${{ github.workspace }}/godot-cpp/gen
key: ${{ runner.os }}-${{ env.SUBMODULE_HASH }}-${{ secrets.GODOT_CPP_CACHE_VERSION }}

- name: Compile Godot Library
if: steps.cache-godot-cpp.outputs.cache-hit != 'true'
run: |
cd ${{ github.workspace }}/godot-cpp
scons platform=osx target=release generate_bindings=yes
scons platform=macos
- name: Compile Addon
run: scons platform=macos

- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: osx
path: ${{ github.workspace }}/${{ env.LIBRARY_PATH }}/osx
name: macos
path: ${{ github.workspace }}/${{ env.LIBRARY_PATH }}/macos
if-no-files-found: error

build-windows:
Expand Down Expand Up @@ -135,14 +135,14 @@ jobs:
path: |
${{ github.workspace }}/godot-cpp/bin
${{ github.workspace }}/godot-cpp/include
${{ github.workspace }}/godot-cpp/godot-headers/**/*.h
${{ github.workspace }}/godot-cpp/gen
key: ${{ runner.os }}-${{ env.SUBMODULE_HASH }}-${{ secrets.GODOT_CPP_CACHE_VERSION }}

- name: Compile Godot Library
if: steps.cache-godot-cpp.outputs.cache-hit != 'true'
run: |
cd ${{ github.workspace }}\godot-cpp
scons platform=windows target=release generate_bindings=yes
scons platform=windows
- name: MSVC Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
Expand Down
50 changes: 9 additions & 41 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,18 @@ from utils import download_wasmer, VERSION_DEFAULT
opts = Variables([], ARGUMENTS)

# Define options
opts.Add(EnumVariable("target", "Compilation target", "release", ["debug", "release"], {"d": "debug"}))
opts.Add(EnumVariable("platform", "Platform", "", ["", "windows", "linux", "osx"], {"x11": "linux", "macos": "osx"}))
opts.Add(BoolVariable("use_llvm", "Use LLVM/Clang compiler", "no"))
opts.Add(BoolVariable("download_wasmer", "Download Wasmer library", "no"))
opts.Add("wasmer_version", "Wasmer library version", VERSION_DEFAULT)

# Standard flags CC, CCX, etc. with options
env = DefaultEnvironment(variables=opts)

# Process some arguments
if env["platform"] == "":
exit("Invalid platform selected")

if env["use_llvm"]:
env["CC"] = "clang"
env["CXX"] = "clang++"
# SConstruct environment from Godot CPP
env = SConscript("godot-cpp/SConstruct")
opts.Update(env)

# Download Wasmer if required
download_wasmer(env, env["download_wasmer"], env["wasmer_version"])

# Check platform specifics
if env["platform"] in ["osx", "macos"]:
env.Prepend(CFLAGS=["-std=gnu11"])
env.Prepend(CXXFLAGS=["-std=gnu++14"])
env.Append(CCFLAGS=["-arch", "x86_64", "-Wall", "-g", "-O3"])
env.Append(LINKFLAGS=["-arch", "x86_64", "-framework", "Security"])
elif env["platform"] == "linux":
env.Prepend(CFLAGS=["-std=gnu11"])
env.Prepend(CXXFLAGS=["-std=gnu++14"])
env.Append(CCFLAGS=["-fPIC", "-g", "-O3"])
elif env["platform"] == "windows":
env.Prepend(CCFLAGS=["/std:c++14", "-W3", "-GR", "-O2", "-EHsc", "-MD"])
env.Append(ENV=os.environ) # Keep session env variables to support VS 2017 prompt
env.Append(CPPDEFINES=["WIN32", "_WIN32", "_WINDOWS", "_CRT_SECURE_NO_WARNINGS", "NDEBUG"])
if env["platform"] == "windows":
if env.get("use_mingw"): # MinGW
env["LIBWASMERSUFFIX"] = ".a"
env.Append(LIBS=["userenv"])
Expand All @@ -48,28 +26,18 @@ elif env["platform"] == "windows":
# Force Windows SDK library suffix (see https://github.com/godotengine/godot/issues/23687)
env.Append(LINKFLAGS=["bcrypt.lib", "userenv.lib", "ws2_32.lib", "advapi32.lib"])

# Defines for GDNative specific API
env.Append(CPPDEFINES=["GDNATIVE"])
# Defines for GDExtension specific API
env.Append(CPPDEFINES=["GDEXTENSION"])

# Explicit static libraries
cpp_lib = env.File("godot-cpp/bin/libgodot-cpp.{}.{}.64{}".format(env["platform"], env["target"], env["LIBSUFFIX"]))
wasmer_lib = env.File("wasmer/lib/{}wasmer{}".format(env["LIBPREFIX"], env.get("LIBWASMERSUFFIX", env["LIBSUFFIX"])))

# CPP includes and libraries
env.Append(
CPPPATH=[
".",
"godot-cpp/godot-headers",
"godot-cpp/include",
"wasmer/include",
"godot-cpp/include/core",
"godot-cpp/include/gen",
]
)
env.Append(LIBS=[cpp_lib, wasmer_lib])
env.Append(CPPPATH=[".", "wasmer/include"])
env.Append(LIBS=[wasmer_lib])

# Godot Wasm sources
source = [env.Glob("src/*.cpp")]
source = ["register_types.cpp", env.Glob("src/*.cpp")]

# Builders
library = env.SharedLibrary(target="addons/godot-wasm/bin/{}/godot-wasm".format(env["platform"]), source=source)
Expand Down
8 changes: 0 additions & 8 deletions addons/godot-wasm/Wasm.gdns

This file was deleted.

14 changes: 14 additions & 0 deletions addons/godot-wasm/godot-wasm.gdextension
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[configuration]
entry_symbol = "wasm_library_init"

[libraries]
windows.debug.x86_64 = "bin/windows/godot-wasm.dll"
windows.release.x86_64 = "bin/windows/godot-wasm.dll"
windows.debug.x86_32 = "bin/windows/godot-wasm.dll"
windows.release.x86_32 = "bin/windows/godot-wasm.dll"
linux.debug.x86_64 = "bin/linux/libgodot-wasm.so"
linux.release.x86_64 = "bin/linux/libgodot-wasm.so"
linux.debug.x86_32 = "bin/linux/libgodot-wasm.so"
linux.release.x86_32 = "bin/linux/libgodot-wasm.so"
macos.debug = "bin/macos/libgodot-wasm.dylib"
macos.release = "bin/macos/libgodot-wasm.dylib"
18 changes: 0 additions & 18 deletions addons/godot-wasm/godot-wasm.gdnlib

This file was deleted.

4 changes: 2 additions & 2 deletions doc_classes/StreamPeerWasm.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="StreamPeerWasm" inherits="StreamPeer" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="StreamPeerWasm" inherits="StreamPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A [StreamPeer] interface for interacting with the memory of an instantiated Wasm module.
</brief_description>
Expand All @@ -18,7 +18,7 @@
</method>
<method name="seek">
<return type="StreamPeerWasm" />
<argument index="0" name="p_pos" type="int" />
<param index="0" name="p_pos" type="int" />
<description>
Set the memory offset of the [StreamPeer].
Values will be read from and written to this position.
Expand Down
16 changes: 8 additions & 8 deletions doc_classes/Wasm.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Wasm" inherits="Reference" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="Wasm" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
An instance of a Wasm module.
Before being able to be used, the module must be compiled and instantiated.
Expand All @@ -13,16 +13,16 @@
<methods>
<method name="compile">
<return type="int" enum="Error" />
<argument index="0" name="bytecode" type="PoolByteArray" />
<param index="0" name="bytecode" type="PackedByteArray" />
<description>
Compile the Wasm module provided Wasm binary [code]bytecode[/code].
This must be called before instantiating the module. Alternatively, the module can be compiled and instantiated in a single step with [method load].
</description>
</method>
<method name="function">
<return type="Variant" />
<argument index="0" name="name" type="String" />
<argument index="1" name="args" type="Array" />
<param index="0" name="name" type="String" />
<param index="1" name="args" type="Array" />
<description>
Call an exported function of the instantiated Wasm module.
The [code]args[/code] argument array must be provided even if no arguments are required.
Expand All @@ -31,7 +31,7 @@
</method>
<method name="global">
<return type="Variant" />
<argument index="0" name="name" type="String" />
<param index="0" name="name" type="String" />
<description>
Access an exported global of the instantiated Wasm module.
Returns either a single float or integer.
Expand All @@ -46,7 +46,7 @@
</method>
<method name="instantiate">
<return type="int" enum="Error" />
<argument index="0" name="import_map" type="Dictionary" />
<param index="0" name="import_map" type="Dictionary" />
<description>
Instantiate a compiled Wasm module.
Before this can be called, the module must be compiled via [method compile].
Expand All @@ -57,8 +57,8 @@
</method>
<method name="load">
<return type="int" enum="Error" />
<argument index="0" name="bytecode" type="PoolByteArray" />
<argument index="1" name="import_map" type="Dictionary" />
<param index="0" name="bytecode" type="PackedByteArray" />
<param index="1" name="import_map" type="Dictionary" />
<description>
Compile and instantiate a Wasm module in a single step.
Equivalent to calling [method compile] and [method instantiate].
Expand Down
2 changes: 1 addition & 1 deletion examples/wasm-consume/Benchmark.gd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
extends Reference
extends RefCounted
class_name Benchmark

static func fibonacci(n: int):
Expand Down
51 changes: 26 additions & 25 deletions examples/wasm-consume/Main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ extends Control

const info_template = "[b]Import Globals[/b]\n%s[b]Imports Functions[/b]\n%s[b]Export Globals[/b]\n%s[b]Export Functions[/b]\n%s[b]Memory[/b]\n[indent]Min %s\nMax %s%s[/indent]"
var callback_count: int
onready var wasm: Wasm = Wasm.new()
@onready var wasm: Wasm = Wasm.new()

func _ready():
$"%PrimeLimit".connect("value_changed", self, "_benchmark")
$"%MemoryType".connect("item_selected", self, "_update_memory_type")
$"%CallbackButton".connect("pressed", wasm, "function", ["invoke_callback", []])
$"%PrimeLimit".connect("value_changed", Callable(self, "_benchmark"))
$"%MemoryType".connect("item_selected", Callable(self, "_update_memory_type"))
$"%CallbackButton".connect("pressed", Callable(wasm, "function").bind("invoke_callback", []))
for node in $"%MemoryInput".get_children() + [$"%MemoryOffset"]:
node.connect("value_changed" if node is Range else "text_changed", self, "_update_memory")
node.connect("value_changed" if node is Range else "text_changed", Callable(self, "_update_memory"))
for item in ["Int", "Float", "String"]: $"%MemoryType".add_item(item)

_load_wasm("res://example.wasm")
Expand All @@ -18,13 +18,12 @@ func _ready():

func _gui_input(event: InputEvent): # Unfocus input
if event is InputEventMouseButton and event.pressed:
var focus_owner = get_focus_owner()
var focus_owner = get_viewport().gui_get_focus_owner()
if focus_owner: focus_owner.release_focus()

func _load_wasm(path: String):
var file = File.new()
file.open(path, File.READ)
var buffer = file.get_buffer(file.get_len())
var file = FileAccess.open(path, FileAccess.READ)
var buffer = file.get_buffer(file.get_length())
var imports = { # Import format module.name
"functions": { "index.callback": [self, "callback"] },
}
Expand All @@ -40,8 +39,10 @@ func callback(value: int):

func _update_info():
var info = wasm.inspect()
if !info: return $"%InfoText".set("text", "Error")
$"%InfoText".bbcode_text = info_template % [
if info.is_empty():
$"%InfoText".set("text", "Error")
return
$"%InfoText".text = info_template % [
_pretty_signatures({}),
_pretty_signatures(info.import_functions),
_pretty_signatures(info.export_globals),
Expand All @@ -63,7 +64,7 @@ func _update_memory(_value = 0):
match(input.get_index()):
0: wasm.stream.put_64(int(input.value))
1: wasm.stream.put_double(input.value)
2: wasm.stream.put_data(input.text.to_utf8())
2: wasm.stream.put_data(input.text.to_utf8_buffer())
wasm.function("update_memory", [])
$"%GlobalValue".text = _hex(wasm.global("memory_value"))
$"%ReadValue".text = _hex(wasm.stream.seek(0).get_64()) # Seek allows chaining
Expand All @@ -74,22 +75,22 @@ func _hex(i: int) -> String: # Format bytes without leading negative sign
return "%X%015X" % [(i >> 60) | 0x8, i & 0x0FFFFFFFFFFFFFFF]

func _pretty_signatures(signatures: Dictionary) -> String: # Indented, line-separated string
if !signatures.keys(): return ""
var rows = PoolStringArray()
if signatures.keys().is_empty(): return ""
var rows = PackedStringArray()
for key in signatures.keys():
var signature = signatures[key]
assert(signature is Array and len(signature) == 2, "Invalid signature")
assert(signature is Array and len(signature) == 2) #,"Invalid signature")
if signature[0] is Array and signature[1] is Array: # Function signature (param and result types)
var func_signature = ""
if !signature[0]: func_signature += "V"
if signature[0].is_empty(): func_signature += "V"
else: for type in signature[0]: func_signature += "I" if type == TYPE_INT else "F"
func_signature += "→"
if !signature[1]: func_signature += "V"
if signature[1].is_empty(): func_signature += "V"
else: for type in signature[1]: func_signature += "I" if type == TYPE_INT else "F"
rows.append("%s [code][color=#5FFF]%s[/color][/code]" % [key, func_signature])
rows.append("%s [code][color=#FFF5]%s[/color][/code]" % [key, func_signature])
elif signature[0] is int and signature[1] is bool: # Global signature (type and mutability)
rows.append("%s [code][color=#5FFF]%s(%s)[/color][/code]" % [key, "I" if signature[0] == TYPE_INT else "F", "M" if signature[1] else "C"])
return "[indent]%s[/indent]\n" % rows.join("\n")
rows.append("%s [code][color=#FFF5]%s(%s)[/color][/code]" % [key, "I" if signature[0] == TYPE_INT else "F", "M" if signature[1] else "C"])
return "[indent]%s[/indent]\n" % "\n".join(rows)

func _pretty_bytes(i: int) -> String: # Format bytes without leading negative sign
for unit in ["", "Ki", "Mi"]:
Expand All @@ -99,12 +100,12 @@ func _pretty_bytes(i: int) -> String: # Format bytes without leading negative si

func _benchmark(_value = 0):
var limit: int = $"%PrimeLimit".value
var t_gdscript = OS.get_ticks_usec()
var t_gdscript = Time.get_ticks_usec()
var v_gdscript = Benchmark.sieve(limit)
t_gdscript = OS.get_ticks_usec() - t_gdscript
var t_wasm = OS.get_ticks_usec()
t_gdscript = Time.get_ticks_usec() - t_gdscript
var t_wasm = Time.get_ticks_usec()
var v_wasm = wasm.function("sieve", [limit])
t_wasm = OS.get_ticks_usec() - t_wasm
$"%PrimeAnswer".text = String(v_gdscript) if v_gdscript == v_wasm else "?"
t_wasm = Time.get_ticks_usec() - t_wasm
$"%PrimeAnswer".text = ("%d" % v_gdscript) if v_gdscript == v_wasm else "?"
$"%TimeGDScript".text = "%.3f ms" % (t_gdscript / 1000.0)
$"%TimeWasm".text = "%.3f ms" % (t_wasm / 1000.0)
Loading

0 comments on commit 0d423b8

Please sign in to comment.