Skip to content

Commit 56d4f9f

Browse files
committed
Implement FFI for GDScript.
1 parent a372214 commit 56d4f9f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+26542
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,4 @@ $RECYCLE.BIN/
380380
*.msp
381381
*.lnk
382382
*.generated.props
383+
*.obj.i

COPYRIGHT.txt

+5
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ Comment: libbacktrace
304304
Copyright: 2012-2021, Free Software Foundation, Inc.
305305
License: BSD-3-clause
306306

307+
Files: ./thirdparty/libffi/
308+
Comment: libffi
309+
Copyright: 1996-2022 Anthony Green, Red Hat, Inc and others.
310+
License: Expat
311+
307312
Files: ./thirdparty/libktx/
308313
Comment: KTX
309314
Copyright: 2013-2020, Mark Callow

SConstruct

+1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundle
279279
opts.Add(BoolVariable("builtin_clipper2", "Use the built-in Clipper2 library", True))
280280
opts.Add(BoolVariable("builtin_embree", "Use the built-in Embree library", True))
281281
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
282+
opts.Add(BoolVariable("builtin_libffi", "Use the built-in FFI library", True))
282283
opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
283284
opts.Add(BoolVariable("builtin_msdfgen", "Use the built-in MSDFgen library", True))
284285
opts.Add(BoolVariable("builtin_glslang", "Use the built-in glslang library", True))

core/variant/variant_call.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,15 @@ struct _VariantCall {
674674
VARCALL_PACKED_GETTER(PackedVector3Array, Vector3)
675675
VARCALL_PACKED_GETTER(PackedVector4Array, Vector4)
676676

677+
static uint64_t func_PackedByteArray_unsafe_get_ptr(PackedByteArray *p_instance) {
678+
return (uint64_t)(void *)(p_instance->ptrw());
679+
}
680+
681+
static void func_PackedByteArray_unsafe_from_ptr(PackedByteArray *p_instance, uint64_t p_ptr, uint64_t p_size) {
682+
p_instance->resize(p_size);
683+
memcpy(p_instance->ptrw(), (void *)p_ptr, p_size);
684+
}
685+
677686
static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
678687
String s;
679688
if (p_instance->size() > 0) {
@@ -2431,6 +2440,9 @@ static void _register_variant_builtin_methods_array() {
24312440
bind_function(PackedByteArray, decompress, _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0));
24322441
bind_function(PackedByteArray, decompress_dynamic, _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0));
24332442

2443+
bind_functionnc(PackedByteArray, unsafe_get_ptr, _VariantCall::func_PackedByteArray_unsafe_get_ptr, sarray(), varray());
2444+
bind_functionnc(PackedByteArray, unsafe_from_ptr, _VariantCall::func_PackedByteArray_unsafe_from_ptr, sarray("ptr", "size"), varray());
2445+
24342446
bind_function(PackedByteArray, decode_u8, _VariantCall::func_PackedByteArray_decode_u8, sarray("byte_offset"), varray());
24352447
bind_function(PackedByteArray, decode_s8, _VariantCall::func_PackedByteArray_decode_s8, sarray("byte_offset"), varray());
24362448
bind_function(PackedByteArray, decode_u16, _VariantCall::func_PackedByteArray_decode_u16, sarray("byte_offset"), varray());

doc/classes/PackedByteArray.xml

+14
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,20 @@
486486
If the original data can't be converted to signed 64-bit integers, the resulting data is undefined.
487487
</description>
488488
</method>
489+
<method name="unsafe_from_ptr">
490+
<return type="void" />
491+
<param index="0" name="ptr" type="int" />
492+
<param index="1" name="size" type="int" />
493+
<description>
494+
Resizes array and copies data for the unsafe pointer.
495+
</description>
496+
</method>
497+
<method name="unsafe_get_ptr">
498+
<return type="int" />
499+
<description>
500+
Returns unsafe raw pointer to the array data.
501+
</description>
502+
</method>
489503
</methods>
490504
<operators>
491505
<operator name="operator !=">

modules/ffi/SCsub

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
#!/usr/bin/env python
2+
3+
Import("env")
4+
Import("env_modules")
5+
6+
import subprocess
7+
from SCons.Defaults import _defines, _concat
8+
9+
env_ffi = env_modules.Clone()
10+
11+
# Thirdparty source files
12+
13+
thirdparty_obj = []
14+
15+
16+
def mscv_preprocess_and_assemble_file_x86(target, source, env):
17+
for x in range(len(source)):
18+
try:
19+
defs = _defines(env["CPPDEFPREFIX"], env["CPPDEFINES"], env["CPPDEFSUFFIX"], env, target, source)
20+
incs = _concat(env["INCPREFIX"], env["CPPPATH"], env["INCSUFFIX"], env)
21+
22+
cmd = str(env["CC"]) + " /FA /P /EP /nologo"
23+
for d in defs:
24+
cmd += " " + d
25+
for i in incs:
26+
cmd += " " + i.replace("#", "./")
27+
cmd += " " + str(source[x]) + " /Fi" + str(target[x]) + ".i"
28+
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
29+
30+
cmd = str(env["AS"])
31+
for i in incs:
32+
cmd += " " + i.replace("#", "./")
33+
cmd += " /Fo" + str(target[x]) + " /c " + str(target[x]) + ".i"
34+
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
35+
except Exception:
36+
return -1
37+
38+
return 0
39+
40+
41+
def mscv_preprocess_and_assemble_file_arm(target, source, env):
42+
for x in range(len(source)):
43+
defs = _defines(env["CPPDEFPREFIX"], env["CPPDEFINES"], env["CPPDEFSUFFIX"], env, target, source)
44+
incs = _concat(env["INCPREFIX"], env["CPPPATH"], env["INCSUFFIX"], env)
45+
46+
cmd = str(env["CC"]) + " /FA /P /EP /nologo"
47+
for d in defs:
48+
cmd += " " + d
49+
for i in incs:
50+
cmd += " " + i.replace("#", "./")
51+
cmd += " " + str(source[x]) + " /Fi" + str(target[x]) + ".i"
52+
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
53+
54+
cmd = str(env["AS"])
55+
cmd += " " + str(target[x]) + ".i" + " -o " + str(target[x])
56+
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
57+
58+
return 0
59+
60+
61+
if env["builtin_libffi"]:
62+
thirdparty_dir = "#thirdparty/libffi/"
63+
thirdparty_sources = [
64+
"src/closures.c",
65+
"src/prep_cif.c",
66+
"src/types.c",
67+
"src/tramp.c",
68+
]
69+
70+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "include/"])
71+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/"])
72+
env_ffi.Append(CPPDEFINES=["FFI_STATIC_BUILD"])
73+
74+
if env["platform"] == "web":
75+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/wasm32/"])
76+
thirdparty_sources += ["src/wasm32/ffi.c"]
77+
elif env["arch"] == "arm64":
78+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/aarch64/"])
79+
thirdparty_sources += ["src/aarch64/ffi.c"]
80+
if env["platform"] == "windows":
81+
if env.msvc:
82+
env_ffi_asm = env_ffi.Clone()
83+
env_ffi_asm["AS"] = "armasm64"
84+
env_ffi_asm.Append(CPPDEFINES=["_M_ARM64", "_MSC_VER"])
85+
env_ffi_asm.Append(
86+
BUILDERS={
87+
"ASPP": env.Builder(action=mscv_preprocess_and_assemble_file_arm, suffix=".o", src_suffix=".S")
88+
}
89+
)
90+
env.modules_sources += env_ffi_asm.ASPP(
91+
thirdparty_dir + "src/aarch64/win64_armasm" + env["OBJSUFFIX"],
92+
thirdparty_dir + "src/aarch64/win64_armasm.S",
93+
)
94+
else:
95+
env_ffi["AS"] = env["CC"]
96+
env_ffi["ASFLAGS"] += [
97+
"-c",
98+
"-Ithirdparty/libffi/src/aarch64/",
99+
"-Ithirdparty/libffi/src/",
100+
"-Ithirdparty/libffi/include/",
101+
]
102+
thirdparty_sources += ["src/aarch64/win64_armasm.S"]
103+
else:
104+
if env["platform"] == "macos" or env["platform"] == "ios":
105+
env_ffi.Append(CPPDEFINES=["FFI_EXEC_TRAMPOLINE_TABLE"])
106+
thirdparty_sources += ["src/aarch64/sysv.S"]
107+
elif env["arch"] == "arm32":
108+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/arm/"])
109+
thirdparty_sources += ["src/arm/ffi.c"]
110+
if env["platform"] == "windows":
111+
if env.msvc:
112+
env_ffi_asm = env_ffi.Clone()
113+
env_ffi_asm["AS"] = "armasm"
114+
env_ffi_asm.Append(CPPDEFINES=["_M_ARM", "_MSC_VER"])
115+
env_ffi_asm.Append(
116+
BUILDERS={
117+
"ASPP": env.Builder(action=mscv_preprocess_and_assemble_file_arm, suffix=".o", src_suffix=".S")
118+
}
119+
)
120+
env.modules_sources += env_ffi_asm.ASPP(
121+
thirdparty_dir + "src/arm/sysv_msvc_arm32" + env["OBJSUFFIX"],
122+
thirdparty_dir + "src/arm/sysv_msvc_arm32.S",
123+
)
124+
else:
125+
env_ffi["AS"] = env["CC"]
126+
env_ffi["ASFLAGS"] += [
127+
"-c",
128+
"-Ithirdparty/libffi/src/arm/",
129+
"-Ithirdparty/libffi/src/",
130+
"-Ithirdparty/libffi/include/",
131+
]
132+
thirdparty_sources += ["src/arm/sysv_msvc_arm32.S"]
133+
else:
134+
thirdparty_sources += ["src/arm/sysv.S"]
135+
elif env["arch"] == "x86_64":
136+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/x86/"])
137+
if env["platform"] == "windows":
138+
env_ffi.Append(CPPDEFINES=["X86_WIN64"])
139+
else:
140+
if env["platform"] == "macos" or env["platform"] == "ios":
141+
env_ffi.Append(CPPDEFINES=["X86_DARWIN"])
142+
else:
143+
env_ffi.Append(CPPDEFINES=["X86_64"])
144+
thirdparty_sources += ["src/x86/ffi64.c"]
145+
thirdparty_sources += ["src/x86/unix64.S"]
146+
thirdparty_sources += ["src/x86/ffiw64.c"]
147+
if env.msvc:
148+
env_ffi_asm = env_ffi.Clone()
149+
env_ffi_asm["AS"] = "ml64"
150+
env_ffi_asm.Append(CPPDEFINES=["__x86_64__", "_MSC_VER"])
151+
env_ffi_asm.Append(
152+
BUILDERS={
153+
"ASPP": env.Builder(action=mscv_preprocess_and_assemble_file_x86, suffix=".o", src_suffix=".S")
154+
}
155+
)
156+
env.modules_sources += env_ffi_asm.ASPP(
157+
thirdparty_dir + "src/x86/win64" + env["OBJSUFFIX"], thirdparty_dir + "src/x86/win64_intel.S"
158+
)
159+
else:
160+
env_ffi.Append(CPPDEFINES=["HAVE_AS_X86_PCREL"])
161+
env_ffi["AS"] = env["CC"]
162+
env_ffi["ASFLAGS"] += [
163+
"-c",
164+
"-Ithirdparty/libffi/src/x86/",
165+
"-Ithirdparty/libffi/src/",
166+
"-Ithirdparty/libffi/include/",
167+
]
168+
thirdparty_sources += ["src/x86/win64.S"]
169+
elif env["arch"] == "x86_32":
170+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/x86/"])
171+
env_ffi.Append(CPPDEFINES=[("EH_FRAME_FLAGS", '\\"a\\"')])
172+
if env["platform"] == "windows":
173+
env_ffi.Append(CPPDEFINES=["X86_WIN32"])
174+
thirdparty_sources += ["src/x86/ffi.c"]
175+
if env.msvc:
176+
env_ffi_asm = env_ffi.Clone()
177+
env_ffi_asm["AS"] = "ml"
178+
env_ffi_asm.Append(CPPDEFINES=["__i386__", "_MSC_VER"])
179+
env_ffi_asm.Append(
180+
BUILDERS={
181+
"ASPP": env.Builder(action=mscv_preprocess_and_assemble_file_x86, suffix=".o", src_suffix=".S")
182+
}
183+
)
184+
env.modules_sources += env_ffi_asm.ASPP(
185+
thirdparty_dir + "src/x86/sysv" + env["OBJSUFFIX"], thirdparty_dir + "src/x86/sysv_intel.S"
186+
)
187+
else:
188+
env_ffi.Append(CPPDEFINES=["HAVE_AS_X86_PCREL"])
189+
env_ffi["AS"] = env["CC"]
190+
env_ffi["ASFLAGS"] += [
191+
"-c",
192+
"-Ithirdparty/libffi/src/x86/",
193+
"-Ithirdparty/libffi/src/",
194+
"-Ithirdparty/libffi/include/",
195+
]
196+
thirdparty_sources += ["src/x86/sysv.S"]
197+
elif env["arch"] == "rv64":
198+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/riscv/"])
199+
thirdparty_sources += ["src/riscv/ffi.c"]
200+
env_ffi["AS"] = env["CC"]
201+
env_ffi["ASFLAGS"] += [
202+
"-c",
203+
"-Ithirdparty/libffi/src/riscv/",
204+
"-Ithirdparty/libffi/src/",
205+
"-Ithirdparty/libffi/include/",
206+
]
207+
thirdparty_sources += ["src/riscv/sysv.S"]
208+
elif env["arch"] == "ppc32" or env["arch"] == "ppc64":
209+
env_ffi.Prepend(CPPPATH=[thirdparty_dir + "src/powerpc/"])
210+
thirdparty_sources += ["src/powerpc/ffi.c"]
211+
thirdparty_sources += ["src/powerpc/ffi_sysv.c"]
212+
thirdparty_sources += ["src/powerpc/ffi_linux64.c"]
213+
env_ffi["AS"] = env["CC"]
214+
env_ffi["ASFLAGS"] += [
215+
"-c",
216+
"-Ithirdparty/libffi/src/powerpc/",
217+
"-Ithirdparty/libffi/src/",
218+
"-Ithirdparty/libffi/include/",
219+
]
220+
thirdparty_sources += ["src/powerpc/sysv.S"]
221+
thirdparty_sources += ["src/powerpc/linux64.S"]
222+
223+
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
224+
225+
env_thirdparty = env_ffi.Clone()
226+
env_thirdparty.disable_warnings()
227+
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
228+
env.modules_sources += thirdparty_obj
229+
230+
# Godot source files
231+
232+
module_obj = []
233+
234+
env_ffi.add_source_files(module_obj, "*.cpp")
235+
env.modules_sources += module_obj
236+
237+
# Needed to force rebuilding the module files when the thirdparty library is updated.
238+
env.Depends(module_obj, thirdparty_obj)

modules/ffi/config.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
def can_build(env, platform):
2+
return True
3+
4+
5+
def configure(env):
6+
pass
7+
8+
9+
def get_doc_classes():
10+
return [
11+
"FFILibrary",
12+
]
13+
14+
15+
def get_doc_path():
16+
return "doc_classes"

0 commit comments

Comments
 (0)