Compare commits
206
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65864190cc | ||
|
|
292e431748 | ||
|
|
f0cb78e082 | ||
|
|
55484ef023 | ||
|
|
020664bd10 | ||
|
|
b836ad4d4f | ||
|
|
a88105784f | ||
|
|
f868408a3a | ||
|
|
cbdc93b17f | ||
|
|
8a7beca122 | ||
|
|
ee5f5c9172 | ||
|
|
6e4193b743 | ||
|
|
60c65f9fa4 | ||
|
|
b8c2bc143e | ||
|
|
7ab1412e20 | ||
|
|
725af6ad16 | ||
|
|
ef23ebfb5a | ||
|
|
c682599448 | ||
|
|
ea513fd47c | ||
|
|
87b1c9736f | ||
|
|
a44107540d | ||
|
|
9a802797d2 | ||
|
|
54c7aa9c90 | ||
|
|
35e8cf8ee6 | ||
|
|
281f0fae1c | ||
|
|
d09bf56818 | ||
|
|
edaf447678 | ||
|
|
7b9036bea6 | ||
|
|
f7cadcba84 | ||
|
|
b3336c5a73 | ||
|
|
2b784b5bf6 | ||
|
|
eb89d0c8c3 | ||
|
|
1ea99bc904 | ||
|
|
56e2955b6a | ||
|
|
cc984c9735 | ||
|
|
ba88b6aa06 | ||
|
|
66ecdc69ac | ||
|
|
fab52b578f | ||
|
|
9464aaa8af | ||
|
|
cf819ca818 | ||
|
|
e012573766 | ||
|
|
34c3734953 | ||
|
|
049a7a04de | ||
|
|
f0f593f04b | ||
|
|
bb748ef2d9 | ||
|
|
38a73a1783 | ||
|
|
85a302550d | ||
|
|
29df99ee38 | ||
|
|
2f77558bad | ||
|
|
44f1ec35c4 | ||
|
|
1c2189c7c9 | ||
|
|
ffdca343fb | ||
|
|
ac5fca4ae5 | ||
|
|
fc365e945a | ||
|
|
ad840e8796 | ||
|
|
bb8dcf08e7 | ||
|
|
6980325310 | ||
|
|
e6a24fcbb5 | ||
|
|
db4e6c1931 | ||
|
|
0a592b78c1 | ||
|
|
58388e8db4 | ||
|
|
db817a37f4 | ||
|
|
a7bc6c5e08 | ||
|
|
60b7faa987 | ||
|
|
2990d142c4 | ||
|
|
a0086a5cc4 | ||
|
|
35544df838 | ||
|
|
deadfe0c98 | ||
|
|
0815637cf0 | ||
|
|
ea77472d75 | ||
|
|
ad11c6988c | ||
|
|
8bfde6755e | ||
|
|
52af81ea17 | ||
|
|
1a0a94b501 | ||
|
|
52e64f816c | ||
|
|
7224b40407 | ||
|
|
945da099ae | ||
|
|
70f657e520 | ||
|
|
e50db698e2 | ||
|
|
1ddba3ad55 | ||
|
|
fdf72d1e45 | ||
|
|
a811e0ef0f | ||
|
|
bc85c55350 | ||
|
|
75bbcbf87b | ||
|
|
5c214e5e9c | ||
|
|
03e00cd347 | ||
|
|
fcd41c1d2c | ||
|
|
b5297de56f | ||
|
|
911e53dece | ||
|
|
3b8cb62283 | ||
|
|
9a607e886e | ||
|
|
9d06145d6c | ||
|
|
fa380a4004 | ||
|
|
2a1b617fb2 | ||
|
|
69e03094bd | ||
|
|
c70f54e28b | ||
|
|
2e346d7166 | ||
|
|
5d776c070a | ||
|
|
3293eb1a16 | ||
|
|
7855842306 | ||
|
|
71d1de5d96 | ||
|
|
28f0867948 | ||
|
|
8d3db06ff2 | ||
|
|
c153f83df0 | ||
|
|
52ee0c1058 | ||
|
|
9267930fea | ||
|
|
f24f9d3bed | ||
|
|
2e89c53ebc | ||
|
|
06602f4e80 | ||
|
|
a792434a37 | ||
|
|
baf69edfc7 | ||
|
|
fdf8e5a704 | ||
|
|
9784414ddd | ||
|
|
b48de48efb | ||
|
|
6e0264d38e | ||
|
|
1a38960eee | ||
|
|
8f4c5e15f1 | ||
|
|
1a853973ab | ||
|
|
a40b2de946 | ||
|
|
523e6530a8 | ||
|
|
9e4c657ed8 | ||
|
|
7500a758b8 | ||
|
|
a7f01cd73c | ||
|
|
1fd626939f | ||
|
|
31f9cb4806 | ||
|
|
057c3602e9 | ||
|
|
5c79f4cae1 | ||
|
|
70d23b2349 | ||
|
|
6aef6ae9a8 | ||
|
|
3b4cfc11f0 | ||
|
|
fadb261b66 | ||
|
|
6ef687c864 | ||
|
|
de12cb92dc | ||
|
|
a513168902 | ||
|
|
045a4492f1 | ||
|
|
da2460f9e7 | ||
|
|
7ea0ffb748 | ||
|
|
06eb10c518 | ||
|
|
dea99e54fd | ||
|
|
1754943596 | ||
|
|
e3d9f1172c | ||
|
|
831fc70923 | ||
|
|
c6a3b5b6ef | ||
|
|
84a236c92e | ||
|
|
4a9b579195 | ||
|
|
ba45256940 | ||
|
|
fd4e6d2949 | ||
|
|
6f3b14a6df | ||
|
|
5b98c4a524 | ||
|
|
8a648dfd9b | ||
|
|
c16b7bcb7a | ||
|
|
ed0a03e9b5 | ||
|
|
5dce8c748f | ||
|
|
cedf53bbc2 | ||
|
|
3de975884a | ||
|
|
b9d018f2a2 | ||
|
|
041894a523 | ||
|
|
3be67ced64 | ||
|
|
1354affd28 | ||
|
|
d2b7a84651 | ||
|
|
ca29304ce1 | ||
|
|
f67c644649 | ||
|
|
1b35ca9c32 | ||
|
|
706de78a9e | ||
|
|
715c18739b | ||
|
|
ce69e98989 | ||
|
|
55fd205ba4 | ||
|
|
e6029401d9 | ||
|
|
b03332b68d | ||
|
|
5dd2492645 | ||
|
|
78f816d74e | ||
|
|
99cf16287a | ||
|
|
6c37971521 | ||
|
|
9b18e8438f | ||
|
|
0bce19cf15 | ||
|
|
3cfa476d3f | ||
|
|
5ccee77190 | ||
|
|
cf41ccc6ce | ||
|
|
9308404e9a | ||
|
|
5e31bbf05e | ||
|
|
84b0c13c44 | ||
|
|
3bc53b9ade | ||
|
|
c032586262 | ||
|
|
b63d3afc18 | ||
|
|
0bc1f87120 | ||
|
|
da464e9e5f | ||
|
|
bf01cc8ce7 | ||
|
|
ecd089bb69 | ||
|
|
4fd0b2a85c | ||
|
|
f6126e9ea1 | ||
|
|
d35bef64e9 | ||
|
|
9bd6d36471 | ||
|
|
78721d720c | ||
|
|
7aba6c4c73 | ||
|
|
e29ebb9f18 | ||
|
|
ca9a044b3e | ||
|
|
69d28027ad | ||
|
|
a0b6c0fd8f | ||
|
|
864bb65ce9 | ||
|
|
006605c3bf | ||
|
|
dc035c5ca6 | ||
|
|
5d1bbd9b27 | ||
|
|
7c12c63f63 | ||
|
|
2ced6b09fc | ||
|
|
7af17f874c | ||
|
|
982094c85c |
No files matched your search
@@ -28,7 +28,6 @@ class JobOs(Enum):
|
||||
WindowsLatest = "windows-latest"
|
||||
UbuntuLatest = "ubuntu-latest"
|
||||
MacosLatest = "macos-latest"
|
||||
Ubuntu20_04 = "ubuntu-20.04"
|
||||
Ubuntu22_04 = "ubuntu-22.04"
|
||||
Ubuntu24_04 = "ubuntu-24.04"
|
||||
Ubuntu24_04_arm = "ubuntu-24.04-arm"
|
||||
@@ -60,7 +59,6 @@ class SdlPlatform(Enum):
|
||||
class Msys2Platform(Enum):
|
||||
Mingw32 = "mingw32"
|
||||
Mingw64 = "mingw64"
|
||||
Clang32 = "clang32"
|
||||
Clang64 = "clang64"
|
||||
Ucrt64 = "ucrt64"
|
||||
|
||||
@@ -104,7 +102,6 @@ class JobSpec:
|
||||
JOB_SPECS = {
|
||||
"msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ),
|
||||
"msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ),
|
||||
"msys2-clang32": JobSpec(name="Windows (msys2, clang32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32-clang", msys2_platform=Msys2Platform.Clang32, ),
|
||||
"msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ),
|
||||
"msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ),
|
||||
"msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ),
|
||||
@@ -114,12 +111,11 @@ JOB_SPECS = {
|
||||
"msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ),
|
||||
"msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ),
|
||||
"msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
|
||||
"ubuntu-20.04": JobSpec(name="Ubuntu 20.04", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04", ),
|
||||
"ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ),
|
||||
"ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ),
|
||||
"steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-slrsniper", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ),
|
||||
"ubuntu-intel-icx": JobSpec(name="Ubuntu 20.04 (Intel oneAPI)", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04-oneapi", intel=IntelCompiler.Icx, ),
|
||||
"ubuntu-intel-icc": JobSpec(name="Ubuntu 20.04 (Intel Compiler)", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04-icc", intel=IntelCompiler.Icc, ),
|
||||
"ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
|
||||
"ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ),
|
||||
"macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
|
||||
"macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ),
|
||||
"macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ),
|
||||
@@ -166,6 +162,7 @@ class JobDetails:
|
||||
platform: str
|
||||
artifact: str
|
||||
no_cmake: bool
|
||||
ccache: bool = False
|
||||
build_tests: bool = True
|
||||
container: str = ""
|
||||
cmake_build_type: str = "RelWithDebInfo"
|
||||
@@ -231,6 +228,7 @@ class JobDetails:
|
||||
"name": self.name,
|
||||
"key": self.key,
|
||||
"os": self.os,
|
||||
"ccache": self.ccache,
|
||||
"container": self.container if self.container else "",
|
||||
"platform": self.platform,
|
||||
"artifact": self.artifact,
|
||||
@@ -343,7 +341,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
case IntelCompiler.Icc:
|
||||
job.cc = "icc"
|
||||
job.cxx = "icpc"
|
||||
# Disable deprecation warning
|
||||
job.cppflags.append("-diag-disable=10441")
|
||||
# Avoid 'Catastrophic error: cannot open precompiled header file'
|
||||
job.cmake_arguments.append("-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON")
|
||||
job.clang_tidy = False
|
||||
case _:
|
||||
raise ValueError(f"Invalid intel={spec.intel}")
|
||||
@@ -421,6 +422,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
if spec.name.startswith("Ubuntu"):
|
||||
assert spec.os.value.startswith("ubuntu-")
|
||||
job.apt_packages.extend((
|
||||
"ccache",
|
||||
"gnome-desktop-testing",
|
||||
"libasound2-dev",
|
||||
"libpulse-dev",
|
||||
@@ -454,6 +456,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.apt_packages.extend((
|
||||
"libunwind-dev", # For SDL_test memory tracking
|
||||
))
|
||||
job.ccache = True
|
||||
if trackmem_symbol_names:
|
||||
# older libunwind is slow
|
||||
job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2")
|
||||
@@ -462,8 +465,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
fpic = True
|
||||
case SdlPlatform.Ios | SdlPlatform.Tvos:
|
||||
job.brew_packages.extend([
|
||||
"ccache",
|
||||
"ninja",
|
||||
])
|
||||
job.ccache = True
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.test_pkg_config = False
|
||||
@@ -506,8 +511,12 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
))
|
||||
job.shared_lib = SharedLibType.DYLIB
|
||||
job.static_lib = StaticLibType.A
|
||||
job.ccache = True
|
||||
job.apt_packages = []
|
||||
job.brew_packages.append("ninja")
|
||||
job.brew_packages.extend((
|
||||
"ccache",
|
||||
"ninja",
|
||||
))
|
||||
if job.clang_tidy:
|
||||
job.brew_packages.append("llvm")
|
||||
if spec.xcode:
|
||||
@@ -515,6 +524,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
case SdlPlatform.Android:
|
||||
job.android_gradle = spec.android_gradle
|
||||
job.android_mk = spec.android_mk
|
||||
job.apt_packages.append("ccache")
|
||||
job.run_tests = False
|
||||
job.shared_lib = SharedLibType.SO
|
||||
job.static_lib = StaticLibType.A
|
||||
@@ -525,6 +535,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
if spec.android_mk or spec.android_gradle:
|
||||
job.apt_packages = []
|
||||
if not spec.no_cmake:
|
||||
job.ccache = True
|
||||
job.cmake_arguments.extend((
|
||||
f"-DANDROID_PLATFORM={spec.android_platform}",
|
||||
f"-DANDROID_ABI={spec.android_abi}",
|
||||
@@ -542,6 +553,8 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
case SdlPlatform.Emscripten:
|
||||
job.clang_tidy = False # clang-tidy does not understand -gsource-map
|
||||
job.shared = False
|
||||
job.ccache = True
|
||||
job.apt_packages.append("ccache")
|
||||
job.cmake_config_emulator = "emcmake"
|
||||
job.cmake_build_type = "Debug"
|
||||
job.test_pkg_config = False
|
||||
@@ -567,11 +580,12 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.setup_python = True
|
||||
job.pypi_packages.append("selenium")
|
||||
case SdlPlatform.Ps2:
|
||||
job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
|
||||
build_parallel = False
|
||||
job.shared = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ]
|
||||
job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ]
|
||||
job.cmake_toolchain_file = "${PS2DEV}/ps2sdk/ps2dev.cmake"
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
@@ -580,10 +594,11 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.ldflags = ["-L${PS2DEV}/ps2sdk/ee/lib", "-L${PS2DEV}/gsKit/lib", "-L${PS2DEV}/ps2sdk/ports/lib", ]
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Psp:
|
||||
job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
|
||||
build_parallel = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ]
|
||||
job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ]
|
||||
job.cmake_toolchain_file = "${PSPDEV}/psp/share/pspdev.cmake"
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
@@ -593,9 +608,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.pollute_directories = ["${PSPDEV}/include", "${PSPDEV}/psp/include", "${PSPDEV}/psp/sdk/include", ]
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Vita:
|
||||
job.ccache = True
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "ninja", "pkgconf", "bash", "tar"]
|
||||
job.apk_packages = ["ccache", "cmake", "ninja", "pkgconf", "bash", "tar"]
|
||||
job.cmake_toolchain_file = "${VITASDK}/share/vita.toolchain.cmake"
|
||||
assert spec.vita_gles is not None
|
||||
job.setup_vita_gles_type = {
|
||||
@@ -616,8 +632,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.cc = "arm-vita-eabi-gcc"
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Haiku:
|
||||
job.ccache = True
|
||||
fpic = False
|
||||
job.run_tests = False
|
||||
job.apt_packages.append("ccache")
|
||||
job.cc = "x86_64-unknown-haiku-gcc"
|
||||
job.cxx = "x86_64-unknown-haiku-g++"
|
||||
job.sudo = ""
|
||||
@@ -629,19 +647,23 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.PowerPC64 | SdlPlatform.PowerPC:
|
||||
job.ccache = True
|
||||
# FIXME: Enable SDL_WERROR
|
||||
job.werror = False
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apt_packages = ["ccache"]
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
job.cmake_arguments.extend((
|
||||
"-DSDL_UNIX_CONSOLE_BUILD=ON",
|
||||
))
|
||||
case SdlPlatform.LoongArch64:
|
||||
job.ccache = True
|
||||
fpic = True
|
||||
job.run_tests = False
|
||||
job.apt_packages.append("ccache")
|
||||
job.cc = "${LOONGARCH64_CC}"
|
||||
job.cxx = "${LOONGARCH64_CXX}"
|
||||
job.cmake_arguments.extend((
|
||||
@@ -653,31 +675,33 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.N3ds:
|
||||
job.ccache = True
|
||||
job.shared = False
|
||||
job.apt_packages = ["ninja-build", "binutils"]
|
||||
job.apt_packages = ["ccache", "ninja-build", "binutils"]
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.cc_from_cmake = True
|
||||
job.cmake_toolchain_file = "${DEVKITPRO}/cmake/3DS.cmake"
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Msys2:
|
||||
job.ccache = True
|
||||
job.shell = "msys2 {0}"
|
||||
assert spec.msys2_platform
|
||||
job.msys2_msystem = spec.msys2_platform.value
|
||||
job.msys2_env = {
|
||||
"mingw32": "mingw-w64-i686",
|
||||
"mingw64": "mingw-w64-x86_64",
|
||||
"clang32": "mingw-w64-clang-i686",
|
||||
"clang64": "mingw-w64-clang-x86_64",
|
||||
"ucrt64": "mingw-w64-ucrt-x86_64",
|
||||
}[spec.msys2_platform.value]
|
||||
job.msys2_no_perl = spec.msys2_platform in (Msys2Platform.Mingw32, Msys2Platform.Clang32)
|
||||
job.msys2_no_perl = spec.msys2_platform in (Msys2Platform.Mingw32, )
|
||||
job.shared_lib = SharedLibType.WIN32
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Riscos:
|
||||
job.ccache = False # FIXME: enable when container gets upgrade
|
||||
# FIXME: Enable SDL_WERROR
|
||||
job.werror = False
|
||||
job.apt_packages = ["cmake", "ninja-build"]
|
||||
job.apt_packages = ["ccache", "cmake", "ninja-build"]
|
||||
job.test_pkg_config = False
|
||||
job.shared = False
|
||||
job.run_tests = False
|
||||
@@ -720,12 +744,17 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.check_sources = True
|
||||
job.setup_python = True
|
||||
|
||||
if job.ccache:
|
||||
job.cmake_arguments.extend((
|
||||
"-DCMAKE_C_COMPILER_LAUNCHER=ccache",
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
|
||||
))
|
||||
if not build_parallel:
|
||||
job.cmake_build_arguments.append("-j1")
|
||||
if job.cflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags)}\"")
|
||||
if job.cxxflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags)}\"")
|
||||
if job.cflags or job.cppflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags + job.cppflags)}\"")
|
||||
if job.cxxflags or job.cppflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags + job.cppflags)}\"")
|
||||
if job.ldflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_SHARED_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
|
||||
job.cmake_arguments.append(f"-DCMAKE_EXE_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
|
||||
|
||||
@@ -34,6 +34,7 @@ jobs:
|
||||
${{ (!matrix.platform.msys2-no-perl && format('{0}-perl', matrix.platform.msys2-env)) || '' }}
|
||||
${{ matrix.platform.msys2-env }}-pkg-config
|
||||
${{ matrix.platform.msys2-env }}-clang-tools-extra
|
||||
${{ (matrix.platform.ccache && format('{0}-ccache', matrix.platform.msys2-env)) || '' }}
|
||||
- name: 'About this job'
|
||||
run: |
|
||||
echo "key=${{ matrix.platform.key }}"
|
||||
@@ -165,6 +166,36 @@ jobs:
|
||||
done
|
||||
done
|
||||
|
||||
- name: 'Calculate ccache key'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
id: prepare-restore-ccache
|
||||
run: |
|
||||
echo "timestamp=$(date -u "+%Y%m%d%H%M_%S")" >> "$GITHUB_OUTPUT"
|
||||
- name: 'Restore ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
uses: actions/cache/restore@v4
|
||||
id: restore-ccache
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ccache-${{ matrix.platform.key }}-${{ steps.prepare-restore-ccache.outputs.timestamp }}
|
||||
restore-keys: |
|
||||
ccache-${{matrix.platform.key}}
|
||||
- name: 'Configure ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
run: |
|
||||
echo 'CCACHE_DIR=${{ runner.temp }}/ccache' >>${GITHUB_ENV}
|
||||
- name: 'Prepare ccache'
|
||||
if: ${{ matrix.platform.ccache && steps.restore-ccache.outputs.cache-hit }}
|
||||
run: |
|
||||
if [ "x${{ runner.os }}" = "xmacOS" ]; then
|
||||
touch_date="2025-02-01T12:00:00Z"
|
||||
else
|
||||
touch_date="2025-02-01"
|
||||
fi
|
||||
find "${CCACHE_DIR}" -type f -exec touch -a -m -d "$touch_date" {} +
|
||||
ccache -s
|
||||
ccache -z
|
||||
|
||||
- name: 'Configure (CMake)'
|
||||
if: ${{ !matrix.platform.no-cmake }}
|
||||
#shell: ${{ matrix.platform.shell }}
|
||||
@@ -357,6 +388,17 @@ jobs:
|
||||
if: ${{ matrix.platform.xcode-sdk != '' }}
|
||||
run: |
|
||||
xcodebuild -project Xcode/SDL/SDL.xcodeproj -target SDL3 -configuration Release -sdk ${{ matrix.platform.xcode-sdk }} clean build
|
||||
- name: 'Prune old ccache files'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
run: |
|
||||
ccache --evict-older-than=1d
|
||||
ccache -s
|
||||
- name: 'Save ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ${{ steps.restore-ccache.outputs.cache-primary-key }}
|
||||
- name: 'Check Sources'
|
||||
if: ${{ matrix.platform.check-sources }}
|
||||
run: |
|
||||
|
||||
+15
-12
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# See docs/release_checklist.md
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.4")
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.6")
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(SDL3_MAINPROJECT ON)
|
||||
@@ -243,6 +243,8 @@ if(SDL_SHARED_DEFAULT AND SDL_STATIC_DEFAULT AND SDL_SHARED_AVAILABLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
dep_option(SDL_DEPS_SHARED "Load dependencies dynamically" ON SDL_SHARED_AVAILABLE OFF)
|
||||
|
||||
set(SDL_SUBSYSTEMS )
|
||||
|
||||
macro(define_sdl_subsystem _name)
|
||||
@@ -334,19 +336,19 @@ set_option(SDL_PTHREADS "Use POSIX threads for multi-threading" ${SDL
|
||||
dep_option(SDL_PTHREADS_SEM "Use pthread semaphores" ON "SDL_PTHREADS" OFF)
|
||||
dep_option(SDL_OSS "Support the OSS audio API" ${SDL_OSS_DEFAULT} "UNIX_SYS OR RISCOS;SDL_AUDIO" OFF)
|
||||
dep_option(SDL_ALSA "Support the ALSA audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA" OFF)
|
||||
dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_JACK "Support the JACK audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK" OFF)
|
||||
dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_PIPEWIRE "Use Pipewire audio" ${UNIX_SYS})
|
||||
dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE" OFF)
|
||||
dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_PULSEAUDIO "Use PulseAudio" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO" OFF)
|
||||
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_SNDIO "Support the sndio audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO" OFF)
|
||||
dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_RPATH "Use an rpath when linking SDL" ${SDL_RPATH_DEFAULT})
|
||||
set_option(SDL_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_DEFAULT})
|
||||
dep_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11" OFF)
|
||||
dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_X11_XCURSOR "Enable Xcursor support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XDBE "Enable Xdbe support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XINPUT "Enable XInput support" ON SDL_X11 OFF)
|
||||
@@ -356,9 +358,9 @@ dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND" OFF)
|
||||
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_RPI "Use Raspberry Pi video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF)
|
||||
dep_option(SDL_ROCKCHIP "Use ROCKCHIP Hardware Acceleration video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF)
|
||||
dep_option(SDL_COCOA "Use Cocoa video driver" ON "APPLE" OFF)
|
||||
@@ -376,14 +378,14 @@ dep_option(SDL_RENDER_VULKAN "Enable the Vulkan render driver" ON "SDL_REN
|
||||
dep_option(SDL_METAL "Enable Metal support" ON "APPLE" OFF)
|
||||
set_option(SDL_OPENVR "Use OpenVR video driver" OFF)
|
||||
dep_option(SDL_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM" OFF)
|
||||
dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_OFFSCREEN "Use offscreen video driver" ON)
|
||||
dep_option(SDL_DUMMYCAMERA "Support the dummy camera driver" ON SDL_CAMERA OFF)
|
||||
option_string(SDL_BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" OFF)
|
||||
option_string(SDL_FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" OFF)
|
||||
dep_option(SDL_HIDAPI "Enable the HIDAPI subsystem" ON "NOT VISIONOS" OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB "Use libusb for low level joystick drivers" ON SDL_HIDAPI_LIBUSB_AVAILABLE OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON SDL_HIDAPI_LIBUSB OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON "SDL_HIDAPI_LIBUSB;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_HIDAPI_JOYSTICK "Use HIDAPI for low level joystick drivers" ON SDL_HIDAPI OFF)
|
||||
dep_option(SDL_VIRTUAL_JOYSTICK "Enable the virtual-joystick driver" ON SDL_HIDAPI OFF)
|
||||
set_option(SDL_LIBUDEV "Enable libudev support" ON)
|
||||
@@ -751,7 +753,7 @@ if(SDL_ASSEMBLY)
|
||||
if(SDL_SSE4_2)
|
||||
cmake_push_check_state()
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.2")
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.2 -mcrc32")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
#include <nmmintrin.h>
|
||||
@@ -2887,6 +2889,7 @@ elseif(N3DS)
|
||||
set(SDL_THREAD_N3DS 1)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c")
|
||||
sdl_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c"
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c"
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c"
|
||||
)
|
||||
|
||||
@@ -425,6 +425,7 @@
|
||||
<ClInclude Include="..\..\src\camera\SDL_syscamera.h" />
|
||||
<ClInclude Include="..\..\src\core\gdk\SDL_gdk.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -441,6 +442,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -594,6 +596,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
@@ -640,6 +643,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c"/>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -673,6 +677,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -868,6 +873,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -38,6 +39,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -175,6 +177,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
@@ -314,6 +317,7 @@
|
||||
<ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
|
||||
<ClInclude Include="..\..\src\core\gdk\SDL_gdk.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -330,6 +334,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -434,6 +439,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
|
||||
@@ -336,6 +336,7 @@
|
||||
<ClInclude Include="..\..\src\camera\SDL_camera_c.h" />
|
||||
<ClInclude Include="..\..\src\camera\SDL_syscamera.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -353,6 +354,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -492,6 +494,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
@@ -538,6 +541,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -555,6 +559,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -703,6 +708,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
|
||||
@@ -486,6 +486,12 @@
|
||||
<ClInclude Include="..\..\src\audio\SDL_audioresample.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
@@ -528,6 +534,9 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\events\SDL_eventfilter_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
@@ -666,6 +675,9 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_egl_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\SDL_yuv_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
@@ -1028,6 +1040,9 @@
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClCompile>
|
||||
@@ -1064,6 +1079,9 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\events\SDL_eventfilter.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
@@ -1283,6 +1301,9 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.4</string>
|
||||
<string>3.2.6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>SDLX</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.2.4</string>
|
||||
<string>3.2.6</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -512,10 +512,16 @@
|
||||
F3D46B122D20625800D9CBDF /* SDL_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A8E2D20625800D9CBDF /* SDL_egl.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F3D46B132D20625800D9CBDF /* SDL_filesystem.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A922D20625800D9CBDF /* SDL_filesystem.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F3D60A8328C16A1900788A3A /* SDL_hidapi_wii.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */; };
|
||||
F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */; };
|
||||
F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */; };
|
||||
F3DDCC562AFD42B600B0842B /* SDL_clipboard_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */; };
|
||||
F3DDCC5B2AFD42B600B0842B /* SDL_video_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC522AFD42B600B0842B /* SDL_video_c.h */; };
|
||||
F3DDCC5D2AFD42B600B0842B /* SDL_rect_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */; };
|
||||
F3E5A6EB2AD5E0E600293D83 /* SDL_properties.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */; };
|
||||
F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */; };
|
||||
F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EC2D5AB97300BCF22F /* stb_image.h */; };
|
||||
F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */; };
|
||||
F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */ = {isa = PBXBuildFile; fileRef = F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */; };
|
||||
F3F07D5A269640160074468B /* SDL_hidapi_luna.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F07D59269640160074468B /* SDL_hidapi_luna.c */; };
|
||||
F3F15D7F2D011912007AE210 /* SDL_dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F15D7D2D011912007AE210 /* SDL_dialog.c */; };
|
||||
F3F15D802D011912007AE210 /* SDL_dialog_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = F3F15D7E2D011912007AE210 /* SDL_dialog_utils.h */; };
|
||||
@@ -1075,10 +1081,16 @@
|
||||
F3D46AC82D20625800D9CBDF /* SDL_video.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_video.h; sourceTree = "<group>"; };
|
||||
F3D46AC92D20625800D9CBDF /* SDL_vulkan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = "<group>"; };
|
||||
F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_wii.c; sourceTree = "<group>"; };
|
||||
F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_eventwatch.c; sourceTree = "<group>"; };
|
||||
F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_eventwatch_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_clipboard_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC522AFD42B600B0842B /* SDL_video_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_video_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_rect_impl.h; sourceTree = "<group>"; };
|
||||
F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_properties.c; sourceTree = "<group>"; };
|
||||
F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_stb.c; sourceTree = "<group>"; };
|
||||
F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_stb_c.h; sourceTree = "<group>"; };
|
||||
F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_surface_c.h; sourceTree = "<group>"; };
|
||||
F3EFA5EC2D5AB97300BCF22F /* stb_image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stb_image.h; sourceTree = "<group>"; };
|
||||
F3F07D59269640160074468B /* SDL_hidapi_luna.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_luna.c; sourceTree = "<group>"; };
|
||||
F3F15D7C2D011912007AE210 /* SDL_dialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_dialog.h; sourceTree = "<group>"; };
|
||||
F3F15D7D2D011912007AE210 /* SDL_dialog.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_dialog.c; sourceTree = "<group>"; };
|
||||
@@ -1586,43 +1598,47 @@
|
||||
A7D8A60523E2513D00DCD162 /* dummy */,
|
||||
A7D8A72123E2513E00DCD162 /* khronos */,
|
||||
A7D8A5EC23E2513D00DCD162 /* offscreen */,
|
||||
A7D8A61823E2513D00DCD162 /* uikit */,
|
||||
A7D8A76C23E2513E00DCD162 /* yuv2rgb */,
|
||||
A7D8A76B23E2513E00DCD162 /* SDL_blit.h */,
|
||||
A7D8A64C23E2513D00DCD162 /* SDL_blit.c */,
|
||||
A7D8A66223E2513E00DCD162 /* SDL_blit_0.c */,
|
||||
A7D8A6FA23E2513E00DCD162 /* SDL_blit_1.c */,
|
||||
A7D8A66423E2513E00DCD162 /* SDL_blit_A.c */,
|
||||
A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */,
|
||||
A7D8A73F23E2513E00DCD162 /* SDL_blit_auto.h */,
|
||||
A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */,
|
||||
A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */,
|
||||
A7D8A76623E2513E00DCD162 /* SDL_blit_copy.h */,
|
||||
A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */,
|
||||
A7D8A64223E2513D00DCD162 /* SDL_blit_N.c */,
|
||||
A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */,
|
||||
A7D8A66323E2513E00DCD162 /* SDL_blit_slow.h */,
|
||||
A7D8A64C23E2513D00DCD162 /* SDL_blit.c */,
|
||||
A7D8A76B23E2513E00DCD162 /* SDL_blit.h */,
|
||||
A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */,
|
||||
A7D8A77323E2513E00DCD162 /* SDL_bmp.c */,
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */,
|
||||
A7D8A67B23E2513E00DCD162 /* SDL_clipboard.c */,
|
||||
A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */,
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */,
|
||||
A7D8A6B623E2513E00DCD162 /* SDL_egl.c */,
|
||||
A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */,
|
||||
A7D8A76823E2513E00DCD162 /* SDL_fillrect.c */,
|
||||
A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */,
|
||||
A7D8A64D23E2513D00DCD162 /* SDL_pixels.c */,
|
||||
A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */,
|
||||
A7D8A63423E2513D00DCD162 /* SDL_rect.c */,
|
||||
A7D8A60C23E2513D00DCD162 /* SDL_rect_c.h */,
|
||||
F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */,
|
||||
A7D8A63423E2513D00DCD162 /* SDL_rect.c */,
|
||||
A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */,
|
||||
A7D8A61523E2513D00DCD162 /* SDL_RLEaccel.c */,
|
||||
A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */,
|
||||
F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */,
|
||||
F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */,
|
||||
A7D8A60323E2513D00DCD162 /* SDL_stretch.c */,
|
||||
A7D8A61423E2513D00DCD162 /* SDL_surface.c */,
|
||||
F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */,
|
||||
A7D8A61723E2513D00DCD162 /* SDL_sysvideo.h */,
|
||||
A7D8A60E23E2513D00DCD162 /* SDL_video.c */,
|
||||
F3DDCC522AFD42B600B0842B /* SDL_video_c.h */,
|
||||
E4F7981F2AD8D87F00669F54 /* SDL_video_unsupported.c */,
|
||||
A7D8A60E23E2513D00DCD162 /* SDL_video.c */,
|
||||
A7D8A63E23E2513D00DCD162 /* SDL_vulkan_internal.h */,
|
||||
A7D8A64023E2513D00DCD162 /* SDL_vulkan_utils.c */,
|
||||
A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */,
|
||||
A7D8A67C23E2513E00DCD162 /* SDL_yuv.c */,
|
||||
A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */,
|
||||
F3EFA5EC2D5AB97300BCF22F /* stb_image.h */,
|
||||
A7D8A61823E2513D00DCD162 /* uikit */,
|
||||
A7D8A76C23E2513E00DCD162 /* yuv2rgb */,
|
||||
);
|
||||
path = video;
|
||||
sourceTree = "<group>";
|
||||
@@ -2197,29 +2213,31 @@
|
||||
A7D8A93623E2514000DCD162 /* scancodes_linux.h */,
|
||||
A7D8A92C23E2514000DCD162 /* scancodes_windows.h */,
|
||||
A7D8A94123E2514000DCD162 /* scancodes_xfree86.h */,
|
||||
F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */,
|
||||
F3C2CB212C5DDDB2004D7998 /* SDL_categories.c */,
|
||||
A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */,
|
||||
F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */,
|
||||
A7D8A93A23E2514000DCD162 /* SDL_clipboardevents.c */,
|
||||
A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */,
|
||||
A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */,
|
||||
A7D8A92D23E2514000DCD162 /* SDL_displayevents.c */,
|
||||
A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */,
|
||||
A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */,
|
||||
A7D8A93B23E2514000DCD162 /* SDL_dropevents.c */,
|
||||
A7D8A94223E2514000DCD162 /* SDL_events_c.h */,
|
||||
A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */,
|
||||
A7D8A93523E2514000DCD162 /* SDL_events.c */,
|
||||
A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */,
|
||||
A7D8A94223E2514000DCD162 /* SDL_events_c.h */,
|
||||
F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */,
|
||||
F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */,
|
||||
A7D8A93823E2514000DCD162 /* SDL_keyboard.c */,
|
||||
F31013C62C24E98200FBE946 /* SDL_keymap_c.h */,
|
||||
A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */,
|
||||
F31013C52C24E98200FBE946 /* SDL_keymap.c */,
|
||||
A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */,
|
||||
F31013C62C24E98200FBE946 /* SDL_keymap_c.h */,
|
||||
A7D8A92A23E2514000DCD162 /* SDL_mouse.c */,
|
||||
63134A232A7902FD0021E9A6 /* SDL_pen_c.h */,
|
||||
A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */,
|
||||
63134A242A7902FD0021E9A6 /* SDL_pen.c */,
|
||||
63134A232A7902FD0021E9A6 /* SDL_pen_c.h */,
|
||||
A7D8A93C23E2514000DCD162 /* SDL_quit.c */,
|
||||
A7D8A93723E2514000DCD162 /* SDL_touch_c.h */,
|
||||
A7D8A93E23E2514000DCD162 /* SDL_touch.c */,
|
||||
A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */,
|
||||
A7D8A93723E2514000DCD162 /* SDL_touch_c.h */,
|
||||
A7D8A92F23E2514000DCD162 /* SDL_windowevents.c */,
|
||||
A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */,
|
||||
);
|
||||
path = events;
|
||||
sourceTree = "<group>";
|
||||
@@ -2458,6 +2476,9 @@
|
||||
A7D8BB6F23E2514500DCD162 /* SDL_clipboardevents_c.h in Headers */,
|
||||
A7D8AECA23E2514100DCD162 /* SDL_cocoaclipboard.h in Headers */,
|
||||
A7D8AF1223E2514100DCD162 /* SDL_cocoaevents.h in Headers */,
|
||||
F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */,
|
||||
F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */,
|
||||
F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */,
|
||||
A7D8AE8E23E2514100DCD162 /* SDL_cocoakeyboard.h in Headers */,
|
||||
A7D8AF0623E2514100DCD162 /* SDL_cocoamessagebox.h in Headers */,
|
||||
A7D8AEB223E2514100DCD162 /* SDL_cocoametalview.h in Headers */,
|
||||
@@ -2692,6 +2713,7 @@
|
||||
A7D8B3D423E2514300DCD162 /* yuv_rgb.h in Headers */,
|
||||
F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */,
|
||||
F3FA5A1D2B59ACE000FEAD97 /* yuv_rgb_internal.h in Headers */,
|
||||
F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */,
|
||||
F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */,
|
||||
F3FA5A1E2B59ACE000FEAD97 /* yuv_rgb_lsx_func.h in Headers */,
|
||||
F3FA5A1F2B59ACE000FEAD97 /* yuv_rgb_sse.h in Headers */,
|
||||
@@ -2950,6 +2972,8 @@
|
||||
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */,
|
||||
A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||
A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||
F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */,
|
||||
F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */,
|
||||
A7D8BBB123E2514500DCD162 /* SDL_assert.c in Sources */,
|
||||
A7D8B3DA23E2514300DCD162 /* SDL_bmp.c in Sources */,
|
||||
A7D8B96E23E2514400DCD162 /* SDL_stdlib.c in Sources */,
|
||||
@@ -3062,7 +3086,7 @@
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.4.0;
|
||||
DYLIB_CURRENT_VERSION = 201.6.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||
@@ -3097,7 +3121,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.4;
|
||||
MARKETING_VERSION = 3.2.6;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
PRODUCT_NAME = SDL3;
|
||||
@@ -3126,7 +3150,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.4.0;
|
||||
DYLIB_CURRENT_VERSION = 201.6.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -3158,7 +3182,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.4;
|
||||
MARKETING_VERSION = 3.2.6;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Title SDL 3.2.4
|
||||
Title SDL 3.2.6
|
||||
Version 1
|
||||
Description SDL Library for macOS (http://www.libsdl.org)
|
||||
DefaultLocation /Library/Frameworks
|
||||
|
||||
@@ -167,6 +167,9 @@
|
||||
F399C6512A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; };
|
||||
F399C6522A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; };
|
||||
F399C6552A78933100C86979 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F399C6542A78933000C86979 /* Cocoa.framework */; };
|
||||
F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; };
|
||||
F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */; };
|
||||
F3C17C7728E40BC800E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
F3C17C7928E40C6E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
F3C17C7B28E40D4E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
@@ -717,6 +720,17 @@
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD652D73FC630086D1D0 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3CB568B2A7895F800766177 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1356,6 +1370,8 @@
|
||||
F399C6492A78929400C86979 /* gamepadutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamepadutils.c; sourceTree = "<group>"; };
|
||||
F399C6502A7892D800C86979 /* testautomation_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_intrinsics.c; sourceTree = "<group>"; };
|
||||
F399C6542A78933000C86979 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
F3B7FD6A2D73FC630086D1D0 /* testpen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testpen.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testpen.c; sourceTree = "<group>"; };
|
||||
F3C17C6A28E3FD4400E1A26D /* config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = "<group>"; };
|
||||
F3C17C7328E40ADE00E1A26D /* testutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testutils.c; sourceTree = "<group>"; };
|
||||
F3C17CD628E416AC00E1A26D /* testgeometry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testgeometry.c; sourceTree = "<group>"; };
|
||||
@@ -1732,6 +1748,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD632D73FC630086D1D0 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3C17CD928E416CF00E1A26D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1789,6 +1813,7 @@
|
||||
083E4872006D84C97F000001 /* loopwave.c */,
|
||||
0017958F1074216E00F5D044 /* testatomic.c */,
|
||||
001795B01074222D00F5D044 /* testaudioinfo.c */,
|
||||
F35E56CC2983130F00A43A5F /* testautomation.c */,
|
||||
F35E56C42983130D00A43A5F /* testautomation_audio.c */,
|
||||
F35E56BC2983130B00A43A5F /* testautomation_clipboard.c */,
|
||||
F35E56BB2983130B00A43A5F /* testautomation_events.c */,
|
||||
@@ -1815,7 +1840,6 @@
|
||||
A1A8594B2BC72FC20045DD6C /* testautomation_time.c */,
|
||||
F35E56BD2983130B00A43A5F /* testautomation_timer.c */,
|
||||
F35E56C12983130C00A43A5F /* testautomation_video.c */,
|
||||
F35E56CC2983130F00A43A5F /* testautomation.c */,
|
||||
F36C342C2C0F869B00991150 /* testcamera.c */,
|
||||
BBFC088E164C6820003E6A99 /* testcontroller.c */,
|
||||
001797711074320D00F5D044 /* testdraw.c */,
|
||||
@@ -1837,11 +1861,12 @@
|
||||
092D6D75FFB313BB7F000001 /* testlock.c */,
|
||||
DB166CBD16A1C74100A1396C /* testmessage.c */,
|
||||
001798151074359B00F5D044 /* testmultiaudio.c */,
|
||||
0017985A107436ED00F5D044 /* testnative.c */,
|
||||
0017985B107436ED00F5D044 /* testnative.h */,
|
||||
0017985A107436ED00F5D044 /* testnative.c */,
|
||||
0017985C107436ED00F5D044 /* testnativecocoa.m */,
|
||||
00179872107438D000F5D044 /* testnativex11.c */,
|
||||
002F345209CA201C00EBEB88 /* testoverlay.c */,
|
||||
F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */,
|
||||
002F346F09CA20A600EBEB88 /* testplatform.c */,
|
||||
001798B910743A4900F5D044 /* testpower.c */,
|
||||
DB166CBF16A1C74100A1396C /* testrelative.c */,
|
||||
@@ -1918,6 +1943,7 @@
|
||||
F3C17CDC28E416CF00E1A26D /* testgeometry.app */,
|
||||
F35E56AA298312CB00A43A5F /* testautomation.app */,
|
||||
F36C34272C0F85DB00991150 /* testcamera.app */,
|
||||
F3B7FD6A2D73FC630086D1D0 /* testpen.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -2756,6 +2782,23 @@
|
||||
productReference = F36C34272C0F85DB00991150 /* testcamera.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
F3B7FD602D73FC630086D1D0 /* testpen */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */;
|
||||
buildPhases = (
|
||||
F3B7FD612D73FC630086D1D0 /* Sources */,
|
||||
F3B7FD632D73FC630086D1D0 /* Frameworks */,
|
||||
F3B7FD652D73FC630086D1D0 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = testpen;
|
||||
productName = testalpha;
|
||||
productReference = F3B7FD6A2D73FC630086D1D0 /* testpen.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
F3C17CDB28E416CF00E1A26D /* testgeometry */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */;
|
||||
@@ -2972,6 +3015,7 @@
|
||||
001798781074392D00F5D044 /* testnative */,
|
||||
002F343C09CA1FB300EBEB88 /* testoverlay */,
|
||||
002F345909CA204F00EBEB88 /* testplatform */,
|
||||
F3B7FD602D73FC630086D1D0 /* testpen */,
|
||||
0017989D107439DF00F5D044 /* testpower */,
|
||||
DB166DDC16A1D50C00A1396C /* testrelative */,
|
||||
DB166DF316A1D57C00A1396C /* testrendercopyex */,
|
||||
@@ -3455,6 +3499,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD612D73FC630086D1D0 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3C17CD828E416CF00E1A26D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4704,6 +4756,26 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
F3B7FD682D73FC630086D1D0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F3B7FD692D73FC630086D1D0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
F3C17CE928E416D000E1A26D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -5159,6 +5231,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
F3B7FD682D73FC630086D1D0 /* Debug */,
|
||||
F3B7FD692D73FC630086D1D0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -60,7 +60,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 3;
|
||||
private static final int SDL_MINOR_VERSION = 2;
|
||||
private static final int SDL_MICRO_VERSION = 4;
|
||||
private static final int SDL_MICRO_VERSION = 6;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
|
||||
@@ -276,7 +276,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
int buttonState = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30));
|
||||
|
||||
SDLActivity.onNativePen(pointerId, buttonState, action, x, y, p);
|
||||
} else if (toolType == MotionEvent.TOOL_TYPE_FINGER) {
|
||||
} else { // MotionEvent.TOOL_TYPE_FINGER or MotionEvent.TOOL_TYPE_UNKNOWN
|
||||
pointerId = event.getPointerId(i);
|
||||
x = getNormalizedX(event.getX(i));
|
||||
y = getNormalizedY(event.getY(i));
|
||||
|
||||
@@ -161,6 +161,7 @@ def find_symbols_in_file(file: pathlib.Path) -> int:
|
||||
"src/libm",
|
||||
"src/hidapi",
|
||||
"src/video/khronos",
|
||||
"src/video/stb_image.h",
|
||||
"include/SDL3",
|
||||
"build-scripts/gen_audio_resampler_filter.c",
|
||||
"build-scripts/gen_audio_channel_conversion.c",
|
||||
|
||||
@@ -77,6 +77,9 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT SDL3_COMPONENTS AND NOT TARGET SDL3::Headers AND NOT TARGET SDL3::SDL3-shared AND NOT TARGET SDL3::SDL3-static)
|
||||
set(SDL3_FOUND FALSE)
|
||||
endif()
|
||||
check_required_components(SDL3)
|
||||
|
||||
function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
|
||||
@@ -93,7 +96,7 @@ endfunction()
|
||||
if(NOT TARGET SDL3::SDL3)
|
||||
if(TARGET SDL3::SDL3-shared)
|
||||
_sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-shared)
|
||||
else()
|
||||
elseif(TARGET SDL3::SDL3-static)
|
||||
_sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-static)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -19,7 +19,7 @@ Ubuntu 18.04, all available features enabled:
|
||||
libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
|
||||
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
|
||||
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
|
||||
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
|
||||
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev
|
||||
|
||||
Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev` to that command line.
|
||||
|
||||
@@ -28,7 +28,7 @@ Fedora 35, all available features enabled:
|
||||
sudo yum install gcc git-core make cmake \
|
||||
alsa-lib-devel pulseaudio-libs-devel nas-devel pipewire-devel \
|
||||
libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \
|
||||
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel fcitx-devel \
|
||||
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \
|
||||
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \
|
||||
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
|
||||
libdrm-devel mesa-libgbm-devel libusb-devel libdecor-devel \
|
||||
@@ -45,6 +45,10 @@ openSUSE Tumbleweed:
|
||||
sudo zypper in libunwind-devel libusb-1_0-devel Mesa-libGL-devel libxkbcommon-devel libdrm-devel \
|
||||
libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel
|
||||
|
||||
Arch:
|
||||
sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
|
||||
|
||||
|
||||
Joystick does not work
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ The iscapture field of SDL_AudioDeviceEvent has been renamed recording.
|
||||
|
||||
SDL_QUERY, SDL_IGNORE, SDL_ENABLE, and SDL_DISABLE have been removed. You can use the functions SDL_SetEventEnabled() and SDL_EventEnabled() to set and query event processing state.
|
||||
|
||||
SDL_AddEventWatch() now returns SDL_FALSE_ if it fails because it ran out of memory and couldn't add the event watch callback.
|
||||
SDL_AddEventWatch() now returns false if it fails because it ran out of memory and couldn't add the event watch callback.
|
||||
|
||||
SDL_RegisterEvents() now returns 0 if it couldn't allocate any user events.
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
A sine wave is unchanging audio--easy to stream--but for video games, you'll want
|
||||
to generate significantly _less_ audio ahead of time! */
|
||||
const int minimum_audio = (8000 * sizeof (float)) / 2; /* 8000 float samples per second. Half of that. */
|
||||
if (SDL_GetAudioStreamAvailable(stream) < minimum_audio) {
|
||||
if (SDL_GetAudioStreamQueued(stream) < minimum_audio) {
|
||||
static float samples[512]; /* this will feed 512 samples each frame until we get to our maximum. */
|
||||
int i;
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
We're being lazy here, but if there's less than the entire wav file left to play,
|
||||
just shove a whole copy of it into the queue, so we always have _tons_ of
|
||||
data queued for playback. */
|
||||
if (SDL_GetAudioStreamAvailable(stream) < (int)wav_data_len) {
|
||||
if (SDL_GetAudioStreamQueued(stream) < (int)wav_data_len) {
|
||||
/* feed more data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */
|
||||
SDL_PutAudioStreamData(stream, wav_data, wav_data_len);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* If less than a full copy of the audio is queued for playback, put another copy in there.
|
||||
This is overkill, but easy when lots of RAM is cheap. One could be more careful and
|
||||
queue less at a time, as long as the stream doesn't run dry. */
|
||||
if (SDL_GetAudioStreamAvailable(sounds[i].stream) < ((int) sounds[i].wav_data_len)) {
|
||||
if (SDL_GetAudioStreamQueued(sounds[i].stream) < ((int) sounds[i].wav_data_len)) {
|
||||
SDL_PutAudioStreamData(sounds[i].stream, sounds[i].wav_data, (int) sounds[i].wav_data_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ void snake_step(SnakeContext *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
|
||||
static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
|
||||
{
|
||||
switch (key_code) {
|
||||
/* Quit. */
|
||||
@@ -309,7 +309,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
AppState *as = SDL_calloc(1, sizeof(AppState));
|
||||
AppState *as = (AppState *)SDL_calloc(1, sizeof(AppState));
|
||||
if (!as) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!(vm = SDL_calloc(1, sizeof(*vm)))) {
|
||||
if (!(vm = (BytePusher *)SDL_calloc(1, sizeof(*vm)))) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
*(BytePusher**)appstate = vm;
|
||||
@@ -199,7 +199,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||
for (r = 0; r < 6; ++r) {
|
||||
for (g = 0; g < 6; ++g) {
|
||||
for (b = 0; b < 6; ++b, ++i) {
|
||||
SDL_Color color = { r * 0x33, g * 0x33, b * 0x33, SDL_ALPHA_OPAQUE };
|
||||
SDL_Color color = { (Uint8)(r * 0x33), (Uint8)(g * 0x33), (Uint8)(b * 0x33), SDL_ALPHA_OPAQUE };
|
||||
palette->colors[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw axes as bars going across middle of screen. We don't know if it's an X or Y or whatever axis, so we can't do more than this. */
|
||||
total = SDL_GetNumJoystickAxes(joystick);
|
||||
y = (float) ((winh - (total * size)) / 2);
|
||||
y = (winh - (total * size)) / 2;
|
||||
x = ((float) winw) / 2.0f;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
@@ -119,7 +119,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw buttons as blocks across top of window. We only know the button numbers, but not where they are on the device. */
|
||||
total = SDL_GetNumJoystickButtons(joystick);
|
||||
x = (float) ((winw - (total * size)) / 2);
|
||||
x = (winw - (total * size)) / 2;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
const SDL_FRect dst = { x, 0.0f, size, size };
|
||||
@@ -136,7 +136,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw hats across the bottom of the screen. */
|
||||
total = SDL_GetNumJoystickHats(joystick);
|
||||
x = ((float) ((winw - (total * (size * 2.0f))) / 2.0f)) + (size / 2.0f);
|
||||
x = ((winw - (total * (size * 2.0f))) / 2.0f) + (size / 2.0f);
|
||||
y = ((float) winh) - size;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
|
||||
@@ -92,8 +92,8 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* center this one and make it grow and shrink. */
|
||||
dst_rect.w = (float) texture_width + (texture_width * scale);
|
||||
dst_rect.h = (float) texture_height + (texture_height * scale);
|
||||
dst_rect.x = ((float) (WINDOW_WIDTH - dst_rect.w)) / 2.0f;
|
||||
dst_rect.y = ((float) (WINDOW_HEIGHT - dst_rect.h)) / 2.0f;
|
||||
dst_rect.x = (WINDOW_WIDTH - dst_rect.w) / 2.0f;
|
||||
dst_rect.y = (WINDOW_HEIGHT - dst_rect.h) / 2.0f;
|
||||
SDL_RenderTexture(renderer, texture, NULL, &dst_rect);
|
||||
|
||||
SDL_RenderPresent(renderer); /* put it all on the screen! */
|
||||
|
||||
@@ -141,7 +141,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* we need one more vertex, since the two triangles can share two of them. */
|
||||
vertices[3].position.x = 600.0f;
|
||||
vertices[3].position.y = 150.0f;
|
||||
vertices[3].color.r = vertices[0].color.g = vertices[0].color.b = vertices[0].color.a = 1.0f;
|
||||
vertices[3].color.r = vertices[3].color.g = vertices[3].color.b = vertices[3].color.a = 1.0f;
|
||||
vertices[3].tex_coord.x = 1.0f;
|
||||
vertices[3].tex_coord.y = 1.0f;
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.2.4
|
||||
* Main include header for the SDL library, version 3.2.6
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
||||
@@ -149,6 +149,8 @@ extern "C" {
|
||||
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" )
|
||||
#elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) )
|
||||
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" )
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */
|
||||
#elif defined(__386__) && defined(__WATCOMC__)
|
||||
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
|
||||
|
||||
@@ -84,8 +84,8 @@ typedef struct SDL_DialogFileFilter
|
||||
* - A pointer to NULL, the user either didn't choose any file or canceled the
|
||||
* dialog.
|
||||
* - A pointer to non-`NULL`, the user chose one or more files. The argument
|
||||
* is a null-terminated list of pointers to C strings, each containing a
|
||||
* path.
|
||||
* is a null-terminated array of pointers to UTF-8 encoded strings, each
|
||||
* containing a path.
|
||||
*
|
||||
* The filelist argument should not be freed; it will automatically be freed
|
||||
* when the callback returns.
|
||||
|
||||
@@ -132,7 +132,7 @@ typedef enum SDL_EventType
|
||||
|
||||
/* Window events */
|
||||
/* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
|
||||
/* 0x201 was SDL_EVENT_SYSWM, reserve the number for sdl2-compat */
|
||||
/* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */
|
||||
SDL_EVENT_WINDOW_SHOWN = 0x202, /**< Window has been shown */
|
||||
SDL_EVENT_WINDOW_HIDDEN, /**< Window has been hidden */
|
||||
SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */
|
||||
@@ -1108,7 +1108,7 @@ typedef enum SDL_EventAction
|
||||
* \param numevents if action is SDL_ADDEVENT, the number of events to add
|
||||
* back to the event queue; if action is SDL_PEEKEVENT or
|
||||
* SDL_GETEVENT, the maximum number of events to retrieve.
|
||||
* \param action action to take; see [[#action|Remarks]] for details.
|
||||
* \param action action to take; see [Remarks](#remarks) for details.
|
||||
* \param minType minimum value of the event type to be considered;
|
||||
* SDL_EVENT_FIRST is a safe choice.
|
||||
* \param maxType maximum value of the event type to be considered;
|
||||
|
||||
+29
-12
@@ -35,13 +35,14 @@
|
||||
* can render offscreen entirely, perhaps for image processing, and not use a
|
||||
* window at all.
|
||||
*
|
||||
* Next the app prepares static data (things that are created once and used
|
||||
* Next, the app prepares static data (things that are created once and used
|
||||
* over and over). For example:
|
||||
*
|
||||
* - Shaders (programs that run on the GPU): use SDL_CreateGPUShader().
|
||||
* - Vertex buffers (arrays of geometry data) and other data rendering will
|
||||
* need: use SDL_UploadToGPUBuffer().
|
||||
* - Textures (images): use SDL_UploadToGPUTexture().
|
||||
* - Vertex buffers (arrays of geometry data) and other rendering data: use
|
||||
* SDL_CreateGPUBuffer() and SDL_UploadToGPUBuffer().
|
||||
* - Textures (images): use SDL_CreateGPUTexture() and
|
||||
* SDL_UploadToGPUTexture().
|
||||
* - Samplers (how textures should be read from): use SDL_CreateGPUSampler().
|
||||
* - Render pipelines (precalculated rendering state): use
|
||||
* SDL_CreateGPUGraphicsPipeline()
|
||||
@@ -1495,9 +1496,16 @@ typedef struct SDL_GPUIndirectDispatchCommand
|
||||
/**
|
||||
* A structure specifying the parameters of a sampler.
|
||||
*
|
||||
* Note that mip_lod_bias is a no-op for the Metal driver. For Metal, LOD bias
|
||||
* must be applied via shader instead.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateGPUSampler
|
||||
* \sa SDL_GPUFilter
|
||||
* \sa SDL_GPUSamplerMipmapMode
|
||||
* \sa SDL_GPUSamplerAddressMode
|
||||
* \sa SDL_GPUCompareOp
|
||||
*/
|
||||
typedef struct SDL_GPUSamplerCreateInfo
|
||||
{
|
||||
@@ -1536,14 +1544,14 @@ typedef struct SDL_GPUSamplerCreateInfo
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GPUVertexAttribute
|
||||
* \sa SDL_GPUVertexInputState
|
||||
* \sa SDL_GPUVertexInputRate
|
||||
*/
|
||||
typedef struct SDL_GPUVertexBufferDescription
|
||||
{
|
||||
Uint32 slot; /**< The binding slot of the vertex buffer. */
|
||||
Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */
|
||||
SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */
|
||||
Uint32 instance_step_rate; /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE */
|
||||
Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */
|
||||
} SDL_GPUVertexBufferDescription;
|
||||
|
||||
/**
|
||||
@@ -1713,10 +1721,13 @@ typedef struct SDL_GPUTransferBufferCreateInfo
|
||||
* A structure specifying the parameters of the graphics pipeline rasterizer
|
||||
* state.
|
||||
*
|
||||
* NOTE: Some backend APIs (D3D11/12) will enable depth clamping even if
|
||||
* enable_depth_clip is true. If you rely on this clamp+clip behavior,
|
||||
* consider enabling depth clip and then manually clamping depth in your
|
||||
* fragment shaders on Metal and Vulkan.
|
||||
* Note that SDL_GPU_FILLMODE_LINE is not supported on many Android devices.
|
||||
* For those devices, the fill mode will automatically fall back to FILL.
|
||||
*
|
||||
* Also note that the D3D12 driver will enable depth clamping even if
|
||||
* enable_depth_clip is true. If you need this clamp+clip behavior, consider
|
||||
* enabling depth clip and then manually clamping depth in your fragment
|
||||
* shaders on Metal and Vulkan.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1747,8 +1758,8 @@ typedef struct SDL_GPURasterizerState
|
||||
typedef struct SDL_GPUMultisampleState
|
||||
{
|
||||
SDL_GPUSampleCount sample_count; /**< The number of samples to be used in rasterization. */
|
||||
Uint32 sample_mask; /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. */
|
||||
bool enable_mask; /**< Enables sample masking. */
|
||||
Uint32 sample_mask; /**< Reserved for future use. Must be set to 0. */
|
||||
bool enable_mask; /**< Reserved for future use. Must be set to false. */
|
||||
Uint8 padding1;
|
||||
Uint8 padding2;
|
||||
Uint8 padding3;
|
||||
@@ -1798,6 +1809,8 @@ typedef struct SDL_GPUColorTargetDescription
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GPUGraphicsPipelineCreateInfo
|
||||
* \sa SDL_GPUColorTargetDescription
|
||||
* \sa SDL_GPUTextureFormat
|
||||
*/
|
||||
typedef struct SDL_GPUGraphicsPipelineTargetInfo
|
||||
{
|
||||
@@ -3920,6 +3933,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
|
||||
* freed by the user. You MUST NOT call this function from any thread other
|
||||
* than the one that created the window.
|
||||
*
|
||||
* The swapchain texture is write-only and cannot be used as a sampler or for
|
||||
* another reading operation.
|
||||
*
|
||||
* \param command_buffer a command buffer.
|
||||
* \param window a window that has been claimed.
|
||||
* \param swapchain_texture a pointer filled in with a swapchain texture
|
||||
@@ -3938,6 +3954,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
|
||||
*
|
||||
* \sa SDL_SubmitGPUCommandBuffer
|
||||
* \sa SDL_SubmitGPUCommandBufferAndAcquireFence
|
||||
* \sa SDL_AcquireGPUSwapchainTexture
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WaitAndAcquireGPUSwapchainTexture(
|
||||
SDL_GPUCommandBuffer *command_buffer,
|
||||
|
||||
@@ -2191,6 +2191,28 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
|
||||
|
||||
/**
|
||||
* A variable containing a list of devices and their desired number of haptic
|
||||
* (force feedback) enabled axis.
|
||||
*
|
||||
* The format of the string is a comma separated list of USB VID/PID pairs in
|
||||
* hexadecimal form plus the number of desired axes, e.g.
|
||||
*
|
||||
* `0xAAAA/0xBBBB/1,0xCCCC/0xDDDD/3`
|
||||
*
|
||||
* This hint supports a "wildcard" device that will set the number of haptic
|
||||
* axes on all initialized haptic devices which were not defined explicitly in
|
||||
* this hint.
|
||||
*
|
||||
* `0xFFFF/0xFFFF/1`
|
||||
*
|
||||
* This hint should be set before a controller is opened. The number of haptic
|
||||
* axes won't exceed the number of real axes found on the device.
|
||||
*
|
||||
* \since This hint is available since SDL 3.2.5.
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_HAPTIC_AXES "SDL_JOYSTICK_HAPTIC_AXES"
|
||||
|
||||
/**
|
||||
* A variable that controls keycode representation in keyboard events.
|
||||
*
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
* "system", "audio", "video", "render", "input", "test", or `*` for any
|
||||
* unspecified category.
|
||||
*
|
||||
* The level can be a numeric level, one of "verbose", "debug", "info",
|
||||
* "warn", "error", "critical", or "quiet" to disable that category.
|
||||
* The level can be a numeric level, one of "trace", "verbose", "debug",
|
||||
* "info", "warn", "error", "critical", or "quiet" to disable that category.
|
||||
*
|
||||
* You can omit the category if you want to set the logging level for all
|
||||
* categories.
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
* should look like this:
|
||||
*
|
||||
* ```c
|
||||
* #include <SDL3/SDL.h>
|
||||
* #include <SDL3/SDL_main.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* }
|
||||
@@ -38,9 +41,9 @@
|
||||
* This is also where an app can be configured to use the main callbacks, via
|
||||
* the SDL_MAIN_USE_CALLBACKS macro.
|
||||
*
|
||||
* This is a "single-header library," which is to say that including this
|
||||
* header inserts code into your program, and you should only include it once
|
||||
* in most cases. SDL.h does not include this header automatically.
|
||||
* SDL_main.h is a "single-header library," which is to say that including
|
||||
* this header inserts code into your program, and you should only include it
|
||||
* once in most cases. SDL.h does not include this header automatically.
|
||||
*
|
||||
* For more information, see:
|
||||
*
|
||||
|
||||
@@ -676,6 +676,9 @@ typedef enum SDL_PixelFormat
|
||||
SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */
|
||||
/* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */
|
||||
|
||||
SDL_PIXELFORMAT_MJPG = 0x47504a4du, /**< Motion JPEG */
|
||||
/* SDL_DEFINE_PIXELFOURCC('M', 'J', 'P', 'G') */
|
||||
|
||||
/* Aliases for RGBA byte arrays of color data, for the current platform */
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888,
|
||||
|
||||
+73
-14
@@ -490,6 +490,9 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Rende
|
||||
* This returns the true output size in pixels, ignoring any render targets or
|
||||
* logical size and presentation.
|
||||
*
|
||||
* For the output size of the current rendering target, with logical size
|
||||
* adjustments, use SDL_GetCurrentRenderOutputSize() instead.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w a pointer filled in with the width in pixels.
|
||||
* \param h a pointer filled in with the height in pixels.
|
||||
@@ -508,9 +511,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderOutputSize(SDL_Renderer *renderer,
|
||||
* Get the current output size in pixels of a rendering context.
|
||||
*
|
||||
* If a rendering target is active, this will return the size of the rendering
|
||||
* target in pixels, otherwise if a logical size is set, it will return the
|
||||
* logical size, otherwise it will return the value of
|
||||
* SDL_GetRenderOutputSize().
|
||||
* target in pixels, otherwise return the value of SDL_GetRenderOutputSize().
|
||||
*
|
||||
* Rendering target or not, the output will be adjusted by the current logical
|
||||
* presentation state, dictated by SDL_SetRenderLogicalPresentation().
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w a pointer filled in with the current width.
|
||||
@@ -1318,6 +1322,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture *texture);
|
||||
* To stop rendering to a texture and render to the window again, call this
|
||||
* function with a NULL `texture`.
|
||||
*
|
||||
* Viewport, cliprect, scale, and logical presentation are unique to each
|
||||
* render target. Get and set functions for these states apply to the current
|
||||
* render target set by this function, and those states persist on each target
|
||||
* when the current render target changes.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param texture the targeted texture, which must be created with the
|
||||
* `SDL_TEXTUREACCESS_TARGET` flag, or NULL to render to the
|
||||
@@ -1351,25 +1360,39 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer, SDL
|
||||
extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer);
|
||||
|
||||
/**
|
||||
* Set a device independent resolution and presentation mode for rendering.
|
||||
* Set a device-independent resolution and presentation mode for rendering.
|
||||
*
|
||||
* This function sets the width and height of the logical rendering output.
|
||||
* The renderer will act as if the window is always the requested dimensions,
|
||||
* scaling to the actual window resolution as necessary.
|
||||
* The renderer will act as if the current render target is always the
|
||||
* requested dimensions, scaling to the actual resolution as necessary.
|
||||
*
|
||||
* This can be useful for games that expect a fixed size, but would like to
|
||||
* scale the output to whatever is available, regardless of how a user resizes
|
||||
* a window, or if the display is high DPI.
|
||||
*
|
||||
* Logical presentation can be used with both render target textures and the
|
||||
* renderer's window; the state is unique to each render target, and this
|
||||
* function sets the state for the current render target. It might be useful
|
||||
* to draw to a texture that matches the window dimensions with logical
|
||||
* presentation enabled, and then draw that texture across the entire window
|
||||
* with logical presentation disabled. Be careful not to render both with
|
||||
* logical presentation enabled, however, as this could produce
|
||||
* double-letterboxing, etc.
|
||||
*
|
||||
* You can disable logical coordinates by setting the mode to
|
||||
* SDL_LOGICAL_PRESENTATION_DISABLED, and in that case you get the full pixel
|
||||
* resolution of the output window; it is safe to toggle logical presentation
|
||||
* resolution of the render target; it is safe to toggle logical presentation
|
||||
* during the rendering of a frame: perhaps most of the rendering is done to
|
||||
* specific dimensions but to make fonts look sharp, the app turns off logical
|
||||
* presentation while drawing text.
|
||||
* presentation while drawing text, for example.
|
||||
*
|
||||
* Letterboxing will only happen if logical presentation is enabled during
|
||||
* SDL_RenderPresent; be sure to reenable it first if you were using it.
|
||||
* For the renderer's window, letterboxing is drawn into the framebuffer if
|
||||
* logical presentation is enabled during SDL_RenderPresent; be sure to
|
||||
* reenable it before presenting if you were toggling it, otherwise the
|
||||
* letterbox areas might have artifacts from previous frames (or artifacts
|
||||
* from external overlays, etc). Letterboxing is never drawn into texture
|
||||
* render targets; be sure to call SDL_RenderClear() before drawing into the
|
||||
* texture so the letterboxing areas are cleared, if appropriate.
|
||||
*
|
||||
* You can convert coordinates in an event into rendering coordinates using
|
||||
* SDL_ConvertEventToRenderCoordinates().
|
||||
@@ -1397,6 +1420,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *
|
||||
* This function gets the width and height of the logical rendering output, or
|
||||
* the output size in pixels if a logical resolution is not enabled.
|
||||
*
|
||||
* Each render target has its own logical presentation state. This function
|
||||
* gets the state for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w an int to be filled with the width.
|
||||
* \param h an int to be filled with the height.
|
||||
@@ -1420,6 +1446,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer *
|
||||
* presentation is disabled, it will fill the rectangle with the output size,
|
||||
* in pixels.
|
||||
*
|
||||
* Each render target has its own logical presentation state. This function
|
||||
* gets the rectangle for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect a pointer filled in with the final presentation rectangle, may
|
||||
* be NULL.
|
||||
@@ -1536,6 +1565,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertEventToRenderCoordinates(SDL_Rendere
|
||||
*
|
||||
* The area's width and height must be >= 0.
|
||||
*
|
||||
* Each render target has its own viewport. This function sets the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect the SDL_Rect structure representing the drawing area, or NULL
|
||||
* to set the viewport to the entire target.
|
||||
@@ -1554,6 +1586,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, c
|
||||
/**
|
||||
* Get the drawing area for the current target.
|
||||
*
|
||||
* Each render target has its own viewport. This function gets the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure filled in with the current drawing area.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
@@ -1575,6 +1610,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
|
||||
* whether you should restore a specific rectangle or NULL. Note that the
|
||||
* viewport is always reset when changing rendering targets.
|
||||
*
|
||||
* Each render target has its own viewport. This function checks the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \returns true if the viewport was set to a specific rectangle, or false if
|
||||
* it was set to NULL (the entire target).
|
||||
@@ -1613,6 +1651,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderSafeArea(SDL_Renderer *renderer, S
|
||||
/**
|
||||
* Set the clip rectangle for rendering on the specified target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function sets the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure representing the clip area, relative to
|
||||
* the viewport, or NULL to disable clipping.
|
||||
@@ -1631,6 +1672,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c
|
||||
/**
|
||||
* Get the clip rectangle for the current target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function gets the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure filled in with the current clipping area
|
||||
* or an empty rectangle if clipping is disabled.
|
||||
@@ -1647,7 +1691,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect);
|
||||
|
||||
/**
|
||||
* Get whether clipping is enabled on the given renderer.
|
||||
* Get whether clipping is enabled on the given render target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function checks the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \returns true if clipping is enabled or false if not; call SDL_GetError()
|
||||
@@ -1673,6 +1720,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderClipEnabled(SDL_Renderer *renderer);
|
||||
* will be handled using the appropriate quality hints. For best results use
|
||||
* integer scaling factors.
|
||||
*
|
||||
* Each render target has its own scale. This function sets the scale for the
|
||||
* current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param scaleX the horizontal scaling factor.
|
||||
* \param scaleY the vertical scaling factor.
|
||||
@@ -1690,6 +1740,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderScale(SDL_Renderer *renderer, floa
|
||||
/**
|
||||
* Get the drawing scale for the current target.
|
||||
*
|
||||
* Each render target has its own scale. This function gets the scale for the
|
||||
* current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param scaleX a pointer filled in with the horizontal scaling factor.
|
||||
* \param scaleY a pointer filled in with the vertical scaling factor.
|
||||
@@ -2247,15 +2300,21 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer,
|
||||
/**
|
||||
* Read pixels from the current rendering target.
|
||||
*
|
||||
* The returned surface should be freed with SDL_DestroySurface()
|
||||
* The returned surface contains pixels inside the desired area clipped to the
|
||||
* current viewport, and should be freed with SDL_DestroySurface().
|
||||
*
|
||||
* Note that this returns the actual pixels on the screen, so if you are using
|
||||
* logical presentation you should use SDL_GetRenderLogicalPresentationRect()
|
||||
* to get the area containing your content.
|
||||
*
|
||||
* **WARNING**: This is a very slow operation, and should not be used
|
||||
* frequently. If you're using this on the main rendering target, it should be
|
||||
* called after rendering and before SDL_RenderPresent().
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure representing the area in pixels relative
|
||||
* to the to current viewport, or NULL for the entire viewport.
|
||||
* \param rect an SDL_Rect structure representing the area to read, which will
|
||||
* be clipped to the current viewport, or NULL for the entire
|
||||
* viewport.
|
||||
* \returns a new SDL_Surface on success or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
|
||||
@@ -4243,14 +4243,14 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR
|
||||
/**
|
||||
* Seeds the pseudo-random number generator.
|
||||
*
|
||||
* Reusing the seed number will cause SDL_rand_*() to repeat the same stream
|
||||
* of 'random' numbers.
|
||||
* Reusing the seed number will cause SDL_rand() to repeat the same stream of
|
||||
* 'random' numbers.
|
||||
*
|
||||
* \param seed the value to use as a random number seed, or 0 to use
|
||||
* SDL_GetPerformanceCounter().
|
||||
*
|
||||
* \threadsafety This should be called on the same thread that calls
|
||||
* SDL_rand*()
|
||||
* SDL_rand()
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -5969,7 +5969,6 @@ char *strdup(const char *str);
|
||||
their prototype defined (clang-diagnostic-implicit-function-declaration) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define SDL_malloc malloc
|
||||
#define SDL_calloc calloc
|
||||
|
||||
@@ -450,7 +450,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CloseStorage(SDL_Storage *storage);
|
||||
*
|
||||
* This function should be called in regular intervals until it returns true -
|
||||
* however, it is not recommended to spinwait on this call, as the backend may
|
||||
* depend on a synchronous message loop.
|
||||
* depend on a synchronous message loop. You might instead poll this in your
|
||||
* game's main loop while processing events and drawing a loading screen.
|
||||
*
|
||||
* \param storage a storage container to query.
|
||||
* \returns true if the container is ready, false otherwise.
|
||||
|
||||
@@ -120,6 +120,9 @@ typedef enum SDL_FlipMode
|
||||
* format with a pitch of 32 would consist of 32x32 bytes of Y plane followed
|
||||
* by 32x16 bytes of UV plane.
|
||||
*
|
||||
* When a surface holds MJPG format data, pixels points at the compressed JPEG
|
||||
* image and pitch is the length of that data.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -221,6 +224,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||
* the same tone mapping that Chrome uses for HDR content, the form "*=N",
|
||||
* where N is a floating point scale factor applied in linear space, and
|
||||
* "none", which disables tone mapping. This defaults to "chrome".
|
||||
* - `SDL_PROP_SURFACE_HOTSPOT_X_NUMBER`: the hotspot pixel offset from the
|
||||
* left edge of the image, if this surface is being used as a cursor.
|
||||
* - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the
|
||||
* top edge of the image, if this surface is being used as a cursor.
|
||||
*
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns a valid property ID on success or 0 on failure; call
|
||||
@@ -233,6 +240,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
|
||||
#define SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT "SDL.surface.SDR_white_point"
|
||||
#define SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT "SDL.surface.HDR_headroom"
|
||||
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y"
|
||||
|
||||
/**
|
||||
* Set the colorspace used by a surface.
|
||||
|
||||
@@ -62,7 +62,7 @@ extern "C" {
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MICRO_VERSION 4
|
||||
#define SDL_MICRO_VERSION 6
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
||||
+164
-252
@@ -19,34 +19,6 @@
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_hashtable.h"
|
||||
|
||||
// XXX: We can't use SDL_assert here because it's going to call into hashtable code
|
||||
#ifdef NDEBUG
|
||||
#define HT_ASSERT(x) (void)(0)
|
||||
#else
|
||||
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
/* This is not declared in any header, although it is shared between some
|
||||
parts of SDL, because we don't want anything calling it without an
|
||||
extremely good reason. */
|
||||
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
|
||||
static void HT_ASSERT_FAIL(const char *msg)
|
||||
{
|
||||
const char *caption = "SDL_HashTable Assertion Failure!";
|
||||
(void)caption;
|
||||
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
|
||||
#elif defined(HAVE_STDIO_H)
|
||||
fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
SDL_TriggerBreakpoint();
|
||||
SDL_ExitProcess(-1);
|
||||
}
|
||||
#define HT_ASSERT(x) if (!(x)) HT_ASSERT_FAIL("SDL_HashTable Assertion Failure: " #x)
|
||||
#endif
|
||||
|
||||
typedef struct SDL_HashItem
|
||||
{
|
||||
@@ -67,47 +39,49 @@ SDL_COMPILE_TIME_ASSERT(sizeof_SDL_HashItem, sizeof(SDL_HashItem) <= MAX_HASHITE
|
||||
|
||||
struct SDL_HashTable
|
||||
{
|
||||
SDL_RWLock *lock;
|
||||
SDL_RWLock *lock; // NULL if not created threadsafe
|
||||
SDL_HashItem *table;
|
||||
SDL_HashTable_HashFn hash;
|
||||
SDL_HashTable_KeyMatchFn keymatch;
|
||||
SDL_HashTable_NukeFn nuke;
|
||||
void *data;
|
||||
SDL_HashCallback hash;
|
||||
SDL_HashKeyMatchCallback keymatch;
|
||||
SDL_HashDestroyCallback destroy;
|
||||
void *userdata;
|
||||
Uint32 hash_mask;
|
||||
Uint32 max_probe_len;
|
||||
Uint32 num_occupied_slots;
|
||||
bool stackable;
|
||||
};
|
||||
|
||||
SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
Uint32 num_buckets,
|
||||
SDL_HashTable_HashFn hashfn,
|
||||
SDL_HashTable_KeyMatchFn keymatchfn,
|
||||
SDL_HashTable_NukeFn nukefn,
|
||||
bool threadsafe,
|
||||
bool stackable)
|
||||
|
||||
static Uint32 CalculateHashBucketsFromEstimate(int estimated_capacity)
|
||||
{
|
||||
SDL_HashTable *table;
|
||||
|
||||
// num_buckets must be a power of two so we can derive the bucket index with just a bit-and.
|
||||
if ((num_buckets < 1) || !SDL_HasExactlyOneBitSet32(num_buckets)) {
|
||||
SDL_SetError("num_buckets must be a power of two");
|
||||
return NULL;
|
||||
if (estimated_capacity <= 0) {
|
||||
return 4; // start small, grow as necessary.
|
||||
}
|
||||
|
||||
if (num_buckets > MAX_HASHTABLE_SIZE) {
|
||||
SDL_SetError("num_buckets is too large");
|
||||
return NULL;
|
||||
const Uint32 estimated32 = (Uint32) estimated_capacity;
|
||||
Uint32 buckets = ((Uint32) 1) << SDL_MostSignificantBitIndex32(estimated32);
|
||||
if (!SDL_HasExactlyOneBitSet32(estimated32)) {
|
||||
buckets <<= 1; // need next power of two up to fit overflow capacity bits.
|
||||
}
|
||||
|
||||
table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable));
|
||||
return SDL_min(buckets, MAX_HASHTABLE_SIZE);
|
||||
}
|
||||
|
||||
SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, bool threadsafe, SDL_HashCallback hash,
|
||||
SDL_HashKeyMatchCallback keymatch,
|
||||
SDL_HashDestroyCallback destroy, void *userdata)
|
||||
{
|
||||
const Uint32 num_buckets = CalculateHashBucketsFromEstimate(estimated_capacity);
|
||||
SDL_HashTable *table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable));
|
||||
if (!table) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (threadsafe) {
|
||||
// Don't fail if we can't create a lock (single threaded environment?)
|
||||
table->lock = SDL_CreateRWLock();
|
||||
if (!table->lock) {
|
||||
SDL_DestroyHashTable(table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
table->table = (SDL_HashItem *)SDL_calloc(num_buckets, sizeof(SDL_HashItem));
|
||||
@@ -117,24 +91,22 @@ SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
}
|
||||
|
||||
table->hash_mask = num_buckets - 1;
|
||||
table->stackable = stackable;
|
||||
table->data = data;
|
||||
table->hash = hashfn;
|
||||
table->keymatch = keymatchfn;
|
||||
table->nuke = nukefn;
|
||||
table->userdata = userdata;
|
||||
table->hash = hash;
|
||||
table->keymatch = keymatch;
|
||||
table->destroy = destroy;
|
||||
return table;
|
||||
}
|
||||
|
||||
static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key)
|
||||
{
|
||||
const Uint32 BitMixer = 0x9E3779B1u;
|
||||
return table->hash(key, table->data) * BitMixer;
|
||||
return table->hash(table->userdata, key) * BitMixer;
|
||||
}
|
||||
|
||||
static SDL_INLINE Uint32 get_probe_length(Uint32 zero_idx, Uint32 actual_idx, Uint32 num_buckets)
|
||||
{
|
||||
// returns the probe sequence length from zero_idx to actual_idx
|
||||
|
||||
if (actual_idx < zero_idx) {
|
||||
return num_buckets - zero_idx + actual_idx;
|
||||
}
|
||||
@@ -149,7 +121,7 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32
|
||||
|
||||
SDL_HashItem *table = ht->table;
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
SDL_HashItem *item = table + *i;
|
||||
Uint32 item_hash = item->hash;
|
||||
|
||||
@@ -157,12 +129,12 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (item_hash == hash && ht->keymatch(item->key, key, ht->data)) {
|
||||
if (item_hash == hash && ht->keymatch(ht->userdata, item->key, key)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
Uint32 item_probe_len = item->probe_len;
|
||||
HT_ASSERT(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1));
|
||||
SDL_assert(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1));
|
||||
|
||||
if (*probe_len > item_probe_len) {
|
||||
return NULL;
|
||||
@@ -185,23 +157,23 @@ static SDL_HashItem *find_first_item(const SDL_HashTable *ht, const void *key, U
|
||||
|
||||
static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *table, Uint32 hash_mask, Uint32 *max_probe_len_ptr)
|
||||
{
|
||||
const Uint32 num_buckets = hash_mask + 1;
|
||||
Uint32 idx = item_to_insert->hash & hash_mask;
|
||||
SDL_HashItem temp_item, *target = NULL;
|
||||
Uint32 num_buckets = hash_mask + 1;
|
||||
SDL_HashItem *target = NULL;
|
||||
SDL_HashItem temp_item;
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
SDL_HashItem *candidate = table + idx;
|
||||
|
||||
if (!candidate->live) {
|
||||
// Found an empty slot. Put it here and we're done.
|
||||
|
||||
*candidate = *item_to_insert;
|
||||
|
||||
if (target == NULL) {
|
||||
target = candidate;
|
||||
}
|
||||
|
||||
Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets);
|
||||
const Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets);
|
||||
candidate->probe_len = probe_len;
|
||||
|
||||
if (*max_probe_len_ptr < probe_len) {
|
||||
@@ -211,9 +183,9 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
break;
|
||||
}
|
||||
|
||||
Uint32 candidate_probe_len = candidate->probe_len;
|
||||
HT_ASSERT(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets);
|
||||
const Uint32 candidate_probe_len = candidate->probe_len;
|
||||
SDL_assert(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
const Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets);
|
||||
|
||||
if (candidate_probe_len < new_probe_len) {
|
||||
// Robin Hood hashing: the item at idx has a better probe length than our item would at this position.
|
||||
@@ -229,7 +201,7 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
|
||||
*item_to_insert = temp_item;
|
||||
|
||||
HT_ASSERT(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
SDL_assert(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
candidate->probe_len = new_probe_len;
|
||||
|
||||
if (*max_probe_len_ptr < new_probe_len) {
|
||||
@@ -245,17 +217,19 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
|
||||
static void delete_item(SDL_HashTable *ht, SDL_HashItem *item)
|
||||
{
|
||||
Uint32 hash_mask = ht->hash_mask;
|
||||
const Uint32 hash_mask = ht->hash_mask;
|
||||
SDL_HashItem *table = ht->table;
|
||||
|
||||
if (ht->nuke) {
|
||||
ht->nuke(item->key, item->value, ht->data);
|
||||
if (ht->destroy) {
|
||||
ht->destroy(ht->userdata, item->key, item->value);
|
||||
}
|
||||
|
||||
SDL_assert(ht->num_occupied_slots > 0);
|
||||
ht->num_occupied_slots--;
|
||||
|
||||
Uint32 idx = (Uint32)(item - ht->table);
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
idx = (idx + 1) & hash_mask;
|
||||
SDL_HashItem *next_item = table + idx;
|
||||
|
||||
@@ -266,22 +240,23 @@ static void delete_item(SDL_HashTable *ht, SDL_HashItem *item)
|
||||
|
||||
*item = *next_item;
|
||||
item->probe_len -= 1;
|
||||
HT_ASSERT(item->probe_len < ht->max_probe_len);
|
||||
SDL_assert(item->probe_len < ht->max_probe_len);
|
||||
item = next_item;
|
||||
}
|
||||
}
|
||||
|
||||
static bool resize(SDL_HashTable *ht, Uint32 new_size)
|
||||
{
|
||||
SDL_HashItem *old_table = ht->table;
|
||||
Uint32 old_size = ht->hash_mask + 1;
|
||||
Uint32 new_hash_mask = new_size - 1;
|
||||
const Uint32 new_hash_mask = new_size - 1;
|
||||
SDL_HashItem *new_table = SDL_calloc(new_size, sizeof(*new_table));
|
||||
|
||||
if (!new_table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashItem *old_table = ht->table;
|
||||
const Uint32 old_size = ht->hash_mask + 1;
|
||||
|
||||
ht->max_probe_len = 0;
|
||||
ht->hash_mask = new_hash_mask;
|
||||
ht->table = new_table;
|
||||
@@ -299,14 +274,14 @@ static bool resize(SDL_HashTable *ht, Uint32 new_size)
|
||||
|
||||
static bool maybe_resize(SDL_HashTable *ht)
|
||||
{
|
||||
Uint32 capacity = ht->hash_mask + 1;
|
||||
const Uint32 capacity = ht->hash_mask + 1;
|
||||
|
||||
if (capacity >= MAX_HASHTABLE_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85%
|
||||
Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8);
|
||||
const Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85%
|
||||
const Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8);
|
||||
|
||||
if (ht->num_occupied_slots > resize_threshold) {
|
||||
return resize(ht, capacity * 2);
|
||||
@@ -315,72 +290,66 @@ static bool maybe_resize(SDL_HashTable *ht)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value)
|
||||
bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace)
|
||||
{
|
||||
SDL_HashItem *item;
|
||||
Uint32 hash;
|
||||
if (!table) {
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *item = find_first_item(table, key, hash);
|
||||
bool do_insert = true;
|
||||
|
||||
if (item) {
|
||||
if (replace) {
|
||||
delete_item(table, item);
|
||||
} else {
|
||||
SDL_SetError("key already exists and replace is disabled");
|
||||
do_insert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
if (do_insert) {
|
||||
SDL_HashItem new_item;
|
||||
new_item.key = key;
|
||||
new_item.value = value;
|
||||
new_item.hash = hash;
|
||||
new_item.live = true;
|
||||
new_item.probe_len = 0;
|
||||
|
||||
table->num_occupied_slots++;
|
||||
|
||||
if (!maybe_resize(table)) {
|
||||
table->num_occupied_slots--;
|
||||
} else {
|
||||
// This never returns NULL
|
||||
insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
item = find_first_item(table, key, hash);
|
||||
|
||||
if (item && !table->stackable) {
|
||||
// Allow overwrites, this might have been inserted on another thread
|
||||
delete_item(table, item);
|
||||
}
|
||||
|
||||
SDL_HashItem new_item;
|
||||
new_item.key = key;
|
||||
new_item.value = value;
|
||||
new_item.hash = hash;
|
||||
new_item.live = true;
|
||||
new_item.probe_len = 0;
|
||||
|
||||
table->num_occupied_slots++;
|
||||
|
||||
if (!maybe_resize(table)) {
|
||||
table->num_occupied_slots--;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// This never returns NULL
|
||||
insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len);
|
||||
result = true;
|
||||
|
||||
done:
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value)
|
||||
{
|
||||
Uint32 hash;
|
||||
SDL_HashItem *i;
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
if (value) {
|
||||
*value = NULL;
|
||||
}
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
}
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
i = find_first_item(table, key, hash);
|
||||
bool result = false;
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *i = find_first_item(table, key, hash);
|
||||
if (i) {
|
||||
if (value) {
|
||||
*value = i->value;
|
||||
@@ -388,156 +357,91 @@ bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key)
|
||||
{
|
||||
Uint32 hash;
|
||||
SDL_HashItem *item;
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
|
||||
bool result = false;
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *item = find_first_item(table, key, hash);
|
||||
if (item) {
|
||||
delete_item(table, item);
|
||||
result = true;
|
||||
}
|
||||
|
||||
// FIXME: what to do for stacking hashtables?
|
||||
// The original code removes just one item.
|
||||
// This hashtable happens to preserve the insertion order of multi-value keys,
|
||||
// so deleting the first one will always delete the least-recently inserted one.
|
||||
// But maybe it makes more sense to remove all matching items?
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
item = find_first_item(table, key, hash);
|
||||
if (!item) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
delete_item(table, item);
|
||||
result = true;
|
||||
|
||||
done:
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter)
|
||||
bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata)
|
||||
{
|
||||
SDL_HashItem *item = (SDL_HashItem *)*iter;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
} else if (!callback) {
|
||||
return SDL_InvalidParamError("callback");
|
||||
}
|
||||
|
||||
Uint32 i, probe_len, hash;
|
||||
|
||||
if (item) {
|
||||
HT_ASSERT(item >= table->table);
|
||||
HT_ASSERT(item < table->table + (table->hash_mask + 1));
|
||||
|
||||
hash = item->hash;
|
||||
probe_len = item->probe_len + 1;
|
||||
i = ((Uint32)(item - table->table) + 1) & table->hash_mask;
|
||||
item = table->table + i;
|
||||
} else {
|
||||
hash = calc_hash(table, key);
|
||||
i = hash & table->hash_mask;
|
||||
probe_len = 0;
|
||||
}
|
||||
|
||||
item = find_item(table, key, hash, &i, &probe_len);
|
||||
|
||||
if (!item) {
|
||||
*_value = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
*_value = item->value;
|
||||
*iter = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter)
|
||||
{
|
||||
SDL_HashItem *item = (SDL_HashItem *)*iter;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
item = table->table;
|
||||
} else {
|
||||
item++;
|
||||
}
|
||||
|
||||
HT_ASSERT(item >= table->table);
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
Uint32 num_iterated = 0;
|
||||
|
||||
while (item < end && !item->live) {
|
||||
++item;
|
||||
}
|
||||
|
||||
HT_ASSERT(item <= end);
|
||||
|
||||
if (item == end) {
|
||||
if (_key) {
|
||||
*_key = NULL;
|
||||
for (SDL_HashItem *item = table->table; item < end; item++) {
|
||||
if (item->live) {
|
||||
if (!callback(userdata, table, item->key, item->value)) {
|
||||
break; // callback requested iteration stop.
|
||||
} else if (++num_iterated >= table->num_occupied_slots) {
|
||||
break; // we can drop out early because we've seen all the live items.
|
||||
}
|
||||
}
|
||||
if (_value) {
|
||||
*_value = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_key) {
|
||||
*_key = item->key;
|
||||
}
|
||||
if (_value) {
|
||||
*_value = item->value;
|
||||
}
|
||||
*iter = item;
|
||||
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_HashTableEmpty(SDL_HashTable *table)
|
||||
{
|
||||
return !(table && table->num_occupied_slots);
|
||||
if (!table) {
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
const bool retval = (table->num_occupied_slots == 0);
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void nuke_all(SDL_HashTable *table)
|
||||
{
|
||||
void *data = table->data;
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
SDL_HashItem *i;
|
||||
|
||||
for (i = table->table; i < end; ++i) {
|
||||
if (i->live) {
|
||||
table->nuke(i->key, i->value, data);
|
||||
static void destroy_all(SDL_HashTable *table)
|
||||
{
|
||||
SDL_HashDestroyCallback destroy = table->destroy;
|
||||
if (destroy) {
|
||||
void *userdata = table->userdata;
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
for (SDL_HashItem *i = table->table; i < end; ++i) {
|
||||
if (i->live) {
|
||||
i->live = false;
|
||||
destroy(userdata, i->key, i->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_EmptyHashTable(SDL_HashTable *table)
|
||||
void SDL_ClearHashTable(SDL_HashTable *table)
|
||||
{
|
||||
if (table) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
{
|
||||
if (table->nuke) {
|
||||
nuke_all(table);
|
||||
}
|
||||
|
||||
destroy_all(table);
|
||||
SDL_memset(table->table, 0, sizeof(*table->table) * (table->hash_mask + 1));
|
||||
table->num_occupied_slots = 0;
|
||||
}
|
||||
@@ -548,9 +452,10 @@ void SDL_EmptyHashTable(SDL_HashTable *table)
|
||||
void SDL_DestroyHashTable(SDL_HashTable *table)
|
||||
{
|
||||
if (table) {
|
||||
SDL_EmptyHashTable(table);
|
||||
|
||||
SDL_DestroyRWLock(table->lock);
|
||||
destroy_all(table);
|
||||
if (table->lock) {
|
||||
SDL_DestroyRWLock(table->lock);
|
||||
}
|
||||
SDL_free(table->table);
|
||||
SDL_free(table);
|
||||
}
|
||||
@@ -566,26 +471,26 @@ static SDL_INLINE Uint32 hash_string_djbxor(const char *str, size_t len)
|
||||
return hash;
|
||||
}
|
||||
|
||||
Uint32 SDL_HashPointer(const void *key, void *unused)
|
||||
Uint32 SDL_HashPointer(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
return SDL_murmur3_32(&key, sizeof(key), 0);
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b)
|
||||
{
|
||||
(void)unused;
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
Uint32 SDL_HashString(const void *key, void *unused)
|
||||
Uint32 SDL_HashString(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
const char *str = (const char *)key;
|
||||
return hash_string_djbxor(str, SDL_strlen(str));
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchString(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchString(void *unused, const void *a, const void *b)
|
||||
{
|
||||
const char *a_string = (const char *)a;
|
||||
const char *b_string = (const char *)b;
|
||||
@@ -604,26 +509,33 @@ bool SDL_KeyMatchString(const void *a, const void *b, void *unused)
|
||||
// We assume we can fit the ID in the key directly
|
||||
SDL_COMPILE_TIME_ASSERT(SDL_HashID_KeySize, sizeof(Uint32) <= sizeof(const void *));
|
||||
|
||||
Uint32 SDL_HashID(const void *key, void *unused)
|
||||
Uint32 SDL_HashID(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
return (Uint32)(uintptr_t)key;
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchID(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchID(void *unused, const void *a, const void *b)
|
||||
{
|
||||
(void)unused;
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
void SDL_NukeFreeKey(const void *key, const void *value, void *unused)
|
||||
void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)unused;
|
||||
SDL_free((void *)key);
|
||||
SDL_free((void *)value);
|
||||
}
|
||||
|
||||
void SDL_DestroyHashKey(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)value;
|
||||
(void)unused;
|
||||
SDL_free((void *)key);
|
||||
}
|
||||
|
||||
void SDL_NukeFreeValue(const void *key, const void *value, void *unused)
|
||||
void SDL_DestroyHashValue(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)key;
|
||||
(void)unused;
|
||||
|
||||
+591
-36
@@ -18,61 +18,616 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* this is over-documented because it was almost a public API. Leaving the
|
||||
full docs here in case it _does_ become public some day. */
|
||||
|
||||
/* WIKI CATEGORY: HashTable */
|
||||
|
||||
/**
|
||||
* # CategoryHashTable
|
||||
*
|
||||
* SDL offers a hash table implementation, as a convenience for C code that
|
||||
* needs efficient organization and access of arbitrary data.
|
||||
*
|
||||
* Hash tables are a popular data structure, designed to make it quick to
|
||||
* store and look up arbitrary data. Data is stored with an associated "key."
|
||||
* While one would look up an element of an array with an index, a hash table
|
||||
* uses a unique key to find an element later.
|
||||
*
|
||||
* A key can be anything, as long as its unique and in a format that the table
|
||||
* understands. For example, it's popular to use strings as keys: the key
|
||||
* might be a username, and it is used to lookup account information for that
|
||||
* user, etc.
|
||||
*
|
||||
* Hash tables are named because they "hash" their keys down into simple
|
||||
* integers that can be used to efficiently organize and access the associated
|
||||
* data.
|
||||
*
|
||||
* As this is a C API, there is one generic interface that is intended to work
|
||||
* with different data types. This can be a little awkward to set up, but is
|
||||
* easy to use after that.
|
||||
*
|
||||
* Hashtables are generated by a call to SDL_CreateHashTable(). This function
|
||||
* requires several callbacks to be provided (for hashing keys, comparing
|
||||
* entries, and cleaning up entries when removed). These are necessary to
|
||||
* allow the hash to manage any arbitrary data type.
|
||||
*
|
||||
* Once a hash table is created, the common tasks are inserting data into the
|
||||
* table, (SDL_InsertIntoHashTable), looking up previously inserted data
|
||||
* (SDL_FindInHashTable), and removing data (SDL_RemoveFromHashTable and
|
||||
* SDL_ClearHashTable). Less common but still useful is the ability to
|
||||
* iterate through all the items in the table (SDL_IterateHashTable).
|
||||
*
|
||||
* The underlying hash table implementation is always subject to change, but
|
||||
* at the time of writing, it uses open addressing and Robin Hood hashing.
|
||||
* The technical details are explained [here](https://github.com/libsdl-org/SDL/pull/10897).
|
||||
*
|
||||
* Hashtables keep an SDL_RWLock internally, so multiple threads can perform
|
||||
* hash lookups in parallel, while changes to the table will safely serialize
|
||||
* access between threads.
|
||||
*
|
||||
* SDL provides a layer on top of this hash table implementation that might be
|
||||
* more pleasant to use. SDL_PropertiesID maps a string to arbitrary data of
|
||||
* various types in the same table, which could be both easier to use and more
|
||||
* flexible. Refer to [CategoryProperties](CategoryProperties) for details.
|
||||
*/
|
||||
|
||||
#ifndef SDL_hashtable_h_
|
||||
#define SDL_hashtable_h_
|
||||
|
||||
// this is not (currently) a public API. But maybe it should be!
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
struct SDL_HashTable;
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The opaque type that represents a hash table.
|
||||
*
|
||||
* This is hidden behind an opaque pointer because not only does the table
|
||||
* need to store arbitrary data types, but the hash table implementation may
|
||||
* change in the future.
|
||||
*
|
||||
* \since This struct is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef struct SDL_HashTable SDL_HashTable;
|
||||
typedef Uint32 (*SDL_HashTable_HashFn)(const void *key, void *data);
|
||||
typedef bool (*SDL_HashTable_KeyMatchFn)(const void *a, const void *b, void *data);
|
||||
typedef void (*SDL_HashTable_NukeFn)(const void *key, const void *value, void *data);
|
||||
|
||||
extern SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
Uint32 num_buckets,
|
||||
SDL_HashTable_HashFn hashfn,
|
||||
SDL_HashTable_KeyMatchFn keymatchfn,
|
||||
SDL_HashTable_NukeFn nukefn,
|
||||
bool threadsafe,
|
||||
bool stackable);
|
||||
/**
|
||||
* A function pointer representing a hash table hashing callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when it needs to look up a key in
|
||||
* its dataset. It generates a hash value from that key, and then uses that
|
||||
* value as a basis for an index into an internal array.
|
||||
*
|
||||
* There are no rules on what hashing algorithm is used, so long as it
|
||||
* can produce a reliable 32-bit value from `key`, and ideally distributes
|
||||
* those values well across the 32-bit value space. The quality of a
|
||||
* hashing algorithm is directly related to how well a hash table performs.
|
||||
*
|
||||
* Hashing can be a complicated subject, and often times what works best
|
||||
* for one dataset will be suboptimal for another. There is a good discussion
|
||||
* of the field [on Wikipedia](https://en.wikipedia.org/wiki/Hash_function).
|
||||
*
|
||||
* Also: do you _need_ to write a hashing function? SDL provides generic
|
||||
* functions for strings (SDL_HashString), generic integer IDs (SDL_HashID),
|
||||
* and generic pointers (SDL_HashPointer). Often you should use one of these
|
||||
* before writing your own.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param key the key to be hashed.
|
||||
* \returns a 32-bit value that represents a hash of `key`.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
* \sa SDL_HashString
|
||||
* \sa SDL_HashID
|
||||
* \sa SDL_HashPointer
|
||||
*/
|
||||
typedef Uint32 (SDLCALL *SDL_HashCallback)(void *userdata, const void *key);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern void SDL_EmptyHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is not thread-safe.
|
||||
/**
|
||||
* A function pointer representing a hash table matching callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when it needs to look up a key in its
|
||||
* dataset. After hashing the key, it looks for items stored in relation to
|
||||
* that hash value. Since there can be more than one item found through the
|
||||
* same hash value, this function verifies a specific value is actually
|
||||
* correct before choosing it.
|
||||
*
|
||||
* So this function needs to compare the keys at `a` and `b` and decide if
|
||||
* they are actually the same.
|
||||
*
|
||||
* For example, if the keys are C strings, this function might just be:
|
||||
*
|
||||
* ```c
|
||||
* return (SDL_strcmp((const char *) a, const char *b) == 0);`
|
||||
* ```
|
||||
*
|
||||
* Also: do you _need_ to write a matching function? SDL provides generic
|
||||
* functions for strings (SDL_KeyMatchString), generic integer IDs
|
||||
* (SDL_KeyMatchID), and generic pointers (SDL_KeyMatchPointer). Often you
|
||||
* should use one of these before writing your own.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param a the first key to be compared.
|
||||
* \param b the second key to be compared.
|
||||
* \returns true if two keys are identical, false otherwise.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef bool (SDLCALL *SDL_HashKeyMatchCallback)(void *userdata, const void *a, const void *b);
|
||||
|
||||
|
||||
/**
|
||||
* A function pointer representing a hash table cleanup callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when removing items from the hash, or
|
||||
* destroying the hash table. It is used to optionally deallocate the
|
||||
* key/value pairs.
|
||||
*
|
||||
* This is not required to do anything, if all the data in the table is
|
||||
* static or POD data, but it can also do more than a simple free: for
|
||||
* example, if the hash table is storing open files, it can close them here.
|
||||
* It can also free only the key or only the value; it depends on what the
|
||||
* hash table contains.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param key the key to deallocate.
|
||||
* \param value the value to deallocate.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_HashDestroyCallback)(void *userdata, const void *key, const void *value);
|
||||
|
||||
|
||||
/**
|
||||
* A function pointer representing a hash table iterator callback.
|
||||
*
|
||||
* This function is called once for each key/value pair to be considered
|
||||
* when iterating a hash table.
|
||||
*
|
||||
* Iteration continues as long as there are more items to examine and this
|
||||
* callback continues to return true.
|
||||
*
|
||||
* Do not attempt to modify the hash table during this callback, as it will
|
||||
* cause incorrect behavior and possibly crashes.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to an iterator function.
|
||||
* \param table the hash table being iterated.
|
||||
* \param key the current key being iterated.
|
||||
* \param value the current value being iterated.
|
||||
* \returns true to keep iterating, false to stop iteration.
|
||||
*
|
||||
* \threadsafety A read lock is held during iteration, so other threads can
|
||||
* still access the the hash table, but threads attempting to
|
||||
* make changes will be blocked until iteration completes. If
|
||||
* this is a concern, do as little in the callback as possible
|
||||
* and finish iteration quickly.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_IterateHashTable
|
||||
*/
|
||||
typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_HashTable *table, const void *key, const void *value);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new hash table.
|
||||
*
|
||||
* To deal with different datatypes and needs of the caller, hash tables
|
||||
* require several callbacks that deal with some specifics: how to hash a key,
|
||||
* how to compare a key for equality, and how to clean up keys and values.
|
||||
* SDL provides a few generic functions that can be used for these callbacks:
|
||||
*
|
||||
* - SDL_HashString and SDL_KeyMatchString for C strings.
|
||||
* - SDL_HashPointer and SDL_KeyMatchPointer for generic pointers.
|
||||
* - SDL_HashID and SDL_KeyMatchID for generic (possibly small) integers.
|
||||
*
|
||||
* Oftentimes, these are all you need for any hash table, but depending on
|
||||
* your dataset, custom implementations might make more sense.
|
||||
*
|
||||
* You can specify an estimate of the number of items expected to be stored
|
||||
* in the table, which can help make the table run more efficiently. The table
|
||||
* will preallocate resources to accomodate this number of items, which is
|
||||
* most useful if you intend to fill the table with a lot of data right after
|
||||
* creating it. Otherwise, it might make more sense to specify the _minimum_
|
||||
* you expect the table to hold and let it grow as necessary from there. This
|
||||
* number is only a hint, and the table will be able to handle any amount of
|
||||
* data--as long as the system doesn't run out of resources--so a perfect
|
||||
* answer is not required. A value of 0 signifies no guess at all, and the
|
||||
* table will start small and reallocate as necessary; often this is the
|
||||
* correct thing to do.
|
||||
*
|
||||
* !!! FIXME: add note about `threadsafe` here. And update `threadsafety` tags.
|
||||
* !!! FIXME: note that `threadsafe` tables can't be recursively locked, so
|
||||
* !!! FIXME: you can't use `destroy` callbacks that might end up relocking.
|
||||
*
|
||||
* Note that SDL provides a higher-level option built on its hash tables:
|
||||
* SDL_PropertiesID lets you map strings to various datatypes, and this
|
||||
* might be easier to use. It only allows strings for keys, however. Those are
|
||||
* created with SDL_CreateProperties().
|
||||
*
|
||||
* The returned hash table should be destroyed with SDL_DestroyHashTable()
|
||||
* when no longer needed.
|
||||
*
|
||||
* \param estimated_capacity the approximate maximum number of items to be held
|
||||
* in the hash table, or 0 for no estimate.
|
||||
* \param threadsafe true to create an internal rwlock for this table.
|
||||
* \param hash the function to use to hash keys.
|
||||
* \param keymatch the function to use to compare keys.
|
||||
* \param destroy the function to use to clean up keys and values, may be NULL.
|
||||
* \param userdata a pointer that is passed to the callbacks.
|
||||
* \returns a newly-created hash table, or NULL if there was an error; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_DestroyHashTable
|
||||
*/
|
||||
extern SDL_HashTable * SDL_CreateHashTable(int estimated_capacity,
|
||||
bool threadsafe,
|
||||
SDL_HashCallback hash,
|
||||
SDL_HashKeyMatchCallback keymatch,
|
||||
SDL_HashDestroyCallback destroy,
|
||||
void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a hash table.
|
||||
*
|
||||
* This will call the hash table's SDL_HashDestroyCallback for each item in
|
||||
* the table, removing all inserted items, before deallocating the table
|
||||
* itself.
|
||||
*
|
||||
* The table becomes invalid once this function is called, and no other thread
|
||||
* should be accessing this table once this function has started.
|
||||
*
|
||||
* \param table the hash table to destroy.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern void SDL_DestroyHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value);
|
||||
/**
|
||||
* Add an item to a hash table.
|
||||
*
|
||||
* All keys in the table must be unique. If attempting to insert a key that
|
||||
* already exists in the hash table, what will be done depends on the
|
||||
* `replace` value:
|
||||
*
|
||||
* - If `replace` is false, this function will return false without modifying
|
||||
* the table.
|
||||
* - If `replace` is true, SDL will remove the previous item first, so the new
|
||||
* value is the only one associated with that key. This will call the hash
|
||||
* table's SDL_HashDestroyCallback for the previous item.
|
||||
*
|
||||
* \param table the hash table to insert into.
|
||||
* \param key the key of the new item to insert.
|
||||
* \param value the value of the new item to insert.
|
||||
* \param replace true if a duplicate key should replace the previous value.
|
||||
* \returns true if the new item was inserted, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
/**
|
||||
* Look up an item in a hash table.
|
||||
*
|
||||
* On return, the value associated with `key` is stored to `*value`.
|
||||
* If the key does not exist in the table, `*value` will be set to NULL.
|
||||
*
|
||||
* It is legal for `value` to be NULL, to not retrieve the key's value. In
|
||||
* this case, the return value is still useful for reporting if the key exists
|
||||
* in the table at all.
|
||||
*
|
||||
* \param table the hash table to search.
|
||||
* \param key the key to search for in the table.
|
||||
* \param value the found value will be stored here. Can be NULL.
|
||||
* \returns true if key exists in the table, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_InsertIntoHashTable
|
||||
*/
|
||||
extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value);
|
||||
|
||||
/**
|
||||
* Remove an item from a hash table.
|
||||
*
|
||||
* If there is an item that matches `key`, it is removed from the table. This
|
||||
* will call the hash table's SDL_HashDestroyCallback for the item to be
|
||||
* removed.
|
||||
*
|
||||
* \param table the hash table to remove from.
|
||||
* \param key the key of the item to remove from the table.
|
||||
* \returns true if a key was removed, false if the key was not found.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **_value);
|
||||
/**
|
||||
* Remove all items in a hash table.
|
||||
*
|
||||
* This will call the hash table's SDL_HashDestroyCallback for each item in
|
||||
* the table, removing all inserted items.
|
||||
*
|
||||
* When this function returns, the hash table will be empty.
|
||||
*
|
||||
* \param table the hash table to clear.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern void SDL_ClearHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
/**
|
||||
* Check if any items are currently stored in a hash table.
|
||||
*
|
||||
* If there are no items stored (the table is completely empty), this will
|
||||
* return true.
|
||||
*
|
||||
* \param table the hash table to check.
|
||||
* \returns true if the table is completely empty, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_ClearHashTable
|
||||
*/
|
||||
extern bool SDL_HashTableEmpty(SDL_HashTable *table);
|
||||
|
||||
// iterate all values for a specific key. This only makes sense if the hash is stackable. If not-stackable, just use SDL_FindInHashTable().
|
||||
// This function is not thread-safe, you should use external locking if you use this function
|
||||
extern bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter);
|
||||
/**
|
||||
* Iterate all key/value pairs in a hash table.
|
||||
*
|
||||
* This function will call `callback` once for each key/value pair in the
|
||||
* table, until either all pairs have been presented to the callback, or the
|
||||
* callback has returned false to signal it is done.
|
||||
*
|
||||
* There is no guarantee what order results will be returned in.
|
||||
*
|
||||
* \param table the hash table to iterate.
|
||||
* \param callback the function pointer to call for each value.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns true if iteration happened, false if not (bogus parameter, etc).
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata);
|
||||
|
||||
// iterate all key/value pairs in a hash (stackable hashes can have duplicate keys with multiple values).
|
||||
// This function is not thread-safe, you should use external locking if you use this function
|
||||
extern bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter);
|
||||
|
||||
extern Uint32 SDL_HashPointer(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused);
|
||||
/* Helper functions for SDL_CreateHashTable callbacks... */
|
||||
|
||||
extern Uint32 SDL_HashString(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchString(const void *a, const void *b, void *unused);
|
||||
/**
|
||||
* Generate a hash from a generic pointer.
|
||||
*
|
||||
* The key is intended to be a unique pointer to any datatype.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashPointer(void *unused, const void *key);
|
||||
|
||||
extern Uint32 SDL_HashID(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchID(const void *a, const void *b, void *unused);
|
||||
/**
|
||||
* Compare two generic pointers as hash table keys.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first generic pointer to compare.
|
||||
* \param b the second generic pointer to compare.
|
||||
* \returns true if the pointers are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b);
|
||||
|
||||
extern void SDL_NukeFreeKey(const void *key, const void *value, void *unused);
|
||||
extern void SDL_NukeFreeValue(const void *key, const void *value, void *unused);
|
||||
/**
|
||||
* Generate a hash from a C string.
|
||||
*
|
||||
* The key is intended to be a NULL-terminated string, in UTF-8 format.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashString(void *unused, const void *key);
|
||||
|
||||
#endif // SDL_hashtable_h_
|
||||
/**
|
||||
* Compare two C strings as hash table keys.
|
||||
*
|
||||
* Strings will be compared in a case-sensitive manner. More specifically,
|
||||
* they'll be compared as NULL-terminated arrays of bytes.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first string to compare.
|
||||
* \param b the second string to compare.
|
||||
* \returns true if the strings are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchString(void *unused, const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* Generate a hash from an integer ID.
|
||||
*
|
||||
* The key is intended to a unique integer, possibly within a small range.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashID(void *unused, const void *key);
|
||||
|
||||
/**
|
||||
* Compare two integer IDs as hash table keys.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first ID to compare.
|
||||
* \param b the second ID to compare.
|
||||
* \returns true if the IDs are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchID(void *unused, const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* Free both the key and value pointers of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(key);` and `SDL_free(value);`.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value);
|
||||
|
||||
/**
|
||||
* Free just the value pointer of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(key);` and leaves `value` alone.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashKey(void *unused, const void *key, const void *value);
|
||||
|
||||
/**
|
||||
* Free just the value pointer of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(value);` and leaves `key` alone.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashValue(void *unused, const void *key, const void *value);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_hashtable_h_ */
|
||||
@@ -191,6 +191,11 @@
|
||||
#define SDL_VIDEO_RENDER_SW 1
|
||||
#endif
|
||||
|
||||
/* STB image conversion */
|
||||
#if !defined(SDL_HAVE_STB) && !defined(SDL_LEAN_AND_MEAN)
|
||||
#define SDL_HAVE_STB 1
|
||||
#endif
|
||||
|
||||
/* YUV formats
|
||||
- handling of YUV surfaces
|
||||
- blitting and conversion functions */
|
||||
@@ -198,6 +203,17 @@
|
||||
#define SDL_HAVE_YUV 1
|
||||
#endif
|
||||
|
||||
#ifdef SDL_CAMERA_DISABLED
|
||||
#undef SDL_CAMERA_DRIVER_ANDROID
|
||||
#undef SDL_CAMERA_DRIVER_COREMEDIA
|
||||
#undef SDL_CAMERA_DRIVER_DUMMY
|
||||
#undef SDL_CAMERA_DRIVER_EMSCRIPTEN
|
||||
#undef SDL_CAMERA_DRIVER_MEDIAFOUNDATION
|
||||
#undef SDL_CAMERA_DRIVER_PIPEWIRE
|
||||
#undef SDL_CAMERA_DRIVER_V4L2
|
||||
#undef SDL_CAMERA_DRIVER_VITA
|
||||
#endif
|
||||
|
||||
#ifdef SDL_RENDER_DISABLED
|
||||
#undef SDL_VIDEO_RENDER_SW
|
||||
#undef SDL_VIDEO_RENDER_D3D
|
||||
|
||||
+131
-116
@@ -76,7 +76,7 @@ static void SDL_FreePropertyWithCleanup(const void *key, const void *value, void
|
||||
SDL_free((void *)value);
|
||||
}
|
||||
|
||||
static void SDL_FreeProperty(const void *key, const void *value, void *data)
|
||||
static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *value)
|
||||
{
|
||||
SDL_FreePropertyWithCleanup(key, value, data, true);
|
||||
}
|
||||
@@ -84,14 +84,8 @@ static void SDL_FreeProperty(const void *key, const void *value, void *data)
|
||||
static void SDL_FreeProperties(SDL_Properties *properties)
|
||||
{
|
||||
if (properties) {
|
||||
if (properties->props) {
|
||||
SDL_DestroyHashTable(properties->props);
|
||||
properties->props = NULL;
|
||||
}
|
||||
if (properties->lock) {
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
properties->lock = NULL;
|
||||
}
|
||||
SDL_DestroyHashTable(properties->props);
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
SDL_free(properties);
|
||||
}
|
||||
}
|
||||
@@ -102,18 +96,16 @@ bool SDL_InitProperties(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_properties = SDL_CreateHashTable(NULL, 16, SDL_HashID, SDL_KeyMatchID, NULL, true, false);
|
||||
if (!SDL_properties) {
|
||||
goto error;
|
||||
}
|
||||
SDL_properties = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
|
||||
const bool initialized = (SDL_properties != NULL);
|
||||
SDL_SetInitialized(&SDL_properties_init, initialized);
|
||||
return initialized;
|
||||
}
|
||||
|
||||
SDL_SetInitialized(&SDL_properties_init, true);
|
||||
return true;
|
||||
|
||||
error:
|
||||
SDL_SetInitialized(&SDL_properties_init, true);
|
||||
SDL_QuitProperties();
|
||||
return false;
|
||||
static bool SDLCALL FreeOneProperties(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
SDL_FreeProperties((SDL_Properties *)value);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_QuitProperties(void)
|
||||
@@ -131,17 +123,13 @@ void SDL_QuitProperties(void)
|
||||
SDL_DestroyProperties(props);
|
||||
}
|
||||
|
||||
if (SDL_properties) {
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(SDL_properties, &key, &value, &iter)) {
|
||||
SDL_FreeProperties((SDL_Properties *)value);
|
||||
}
|
||||
SDL_DestroyHashTable(SDL_properties);
|
||||
SDL_properties = NULL;
|
||||
}
|
||||
// this can't just DestroyHashTable with SDL_FreeProperties as the destructor, because
|
||||
// other destructors under this might cause use to attempt a recursive lock on SDL_properties,
|
||||
// which isn't allowed with rwlocks. So manually iterate and free everything.
|
||||
SDL_HashTable *properties = SDL_properties;
|
||||
SDL_properties = NULL;
|
||||
SDL_IterateHashTable(properties, FreeOneProperties, NULL);
|
||||
SDL_DestroyHashTable(properties);
|
||||
|
||||
SDL_SetInitialized(&SDL_properties_init, false);
|
||||
}
|
||||
@@ -167,55 +155,101 @@ SDL_PropertiesID SDL_GetGlobalProperties(void)
|
||||
|
||||
SDL_PropertiesID SDL_CreateProperties(void)
|
||||
{
|
||||
SDL_PropertiesID props = 0;
|
||||
SDL_Properties *properties = NULL;
|
||||
bool inserted = false;
|
||||
|
||||
if (!SDL_CheckInitProperties()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties));
|
||||
SDL_Properties *properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties));
|
||||
if (!properties) {
|
||||
goto error;
|
||||
}
|
||||
properties->props = SDL_CreateHashTable(NULL, 4, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, false, false);
|
||||
if (!properties->props) {
|
||||
goto error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this fails we'll continue without it.
|
||||
properties->lock = SDL_CreateMutex();
|
||||
if (!properties->lock) {
|
||||
SDL_free(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; ; ) {
|
||||
properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL);
|
||||
if (!properties->props) {
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
SDL_free(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_PropertiesID props = 0;
|
||||
while (true) {
|
||||
props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1);
|
||||
if (props == 0) {
|
||||
continue;
|
||||
}
|
||||
if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) {
|
||||
} else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties)) {
|
||||
inserted = true;
|
||||
|
||||
SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already.
|
||||
|
||||
if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) {
|
||||
SDL_FreeProperties(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inserted) {
|
||||
// All done!
|
||||
return props;
|
||||
return props; // All done!
|
||||
}
|
||||
|
||||
typedef struct CopyOnePropertyData
|
||||
{
|
||||
SDL_Properties *dst_properties;
|
||||
bool result;
|
||||
} CopyOnePropertyData;
|
||||
|
||||
static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
const SDL_Property *src_property = (const SDL_Property *)value;
|
||||
if (src_property->cleanup) {
|
||||
// Can't copy properties with cleanup functions, we don't know how to duplicate the data
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
error:
|
||||
SDL_FreeProperties(properties);
|
||||
return 0;
|
||||
CopyOnePropertyData *data = (CopyOnePropertyData *) userdata;
|
||||
SDL_Properties *dst_properties = data->dst_properties;
|
||||
const char *src_name = (const char *)key;
|
||||
SDL_Property *dst_property;
|
||||
|
||||
char *dst_name = SDL_strdup(src_name);
|
||||
if (!dst_name) {
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
|
||||
dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property));
|
||||
if (!dst_property) {
|
||||
SDL_free(dst_name);
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
|
||||
SDL_copyp(dst_property, src_property);
|
||||
if (src_property->type == SDL_PROPERTY_TYPE_STRING) {
|
||||
dst_property->value.string_value = SDL_strdup(src_property->value.string_value);
|
||||
if (!dst_property->value.string_value) {
|
||||
SDL_free(dst_name);
|
||||
SDL_free(dst_property);
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
}
|
||||
|
||||
if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property, true)) {
|
||||
SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false);
|
||||
data->result = false;
|
||||
}
|
||||
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
|
||||
{
|
||||
SDL_Properties *src_properties = NULL;
|
||||
SDL_Properties *dst_properties = NULL;
|
||||
bool result = true;
|
||||
|
||||
if (!src) {
|
||||
return SDL_InvalidParamError("src");
|
||||
}
|
||||
@@ -223,55 +257,25 @@ bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
|
||||
return SDL_InvalidParamError("dst");
|
||||
}
|
||||
|
||||
SDL_Properties *src_properties = NULL;
|
||||
SDL_Properties *dst_properties = NULL;
|
||||
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties);
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
|
||||
if (!src_properties) {
|
||||
return SDL_InvalidParamError("src");
|
||||
}
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
|
||||
if (!dst_properties) {
|
||||
return SDL_InvalidParamError("dst");
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
SDL_LockMutex(src_properties->lock);
|
||||
SDL_LockMutex(dst_properties->lock);
|
||||
{
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(src_properties->props, &key, &value, &iter)) {
|
||||
const char *src_name = (const char *)key;
|
||||
const SDL_Property *src_property = (const SDL_Property *)value;
|
||||
char *dst_name;
|
||||
SDL_Property *dst_property;
|
||||
|
||||
if (src_property->cleanup) {
|
||||
// Can't copy properties with cleanup functions, we don't know how to duplicate the data
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_RemoveFromHashTable(dst_properties->props, src_name);
|
||||
|
||||
dst_name = SDL_strdup(src_name);
|
||||
if (!dst_name) {
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property));
|
||||
if (!dst_property) {
|
||||
SDL_free(dst_name);
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
SDL_copyp(dst_property, src_property);
|
||||
if (src_property->type == SDL_PROPERTY_TYPE_STRING) {
|
||||
dst_property->value.string_value = SDL_strdup(src_property->value.string_value);
|
||||
}
|
||||
if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property)) {
|
||||
SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
CopyOnePropertyData data = { dst_properties, true };
|
||||
SDL_IterateHashTable(src_properties->props, CopyOneProperty, &data);
|
||||
result = data.result;
|
||||
}
|
||||
SDL_UnlockMutex(dst_properties->lock);
|
||||
SDL_UnlockMutex(src_properties->lock);
|
||||
@@ -337,7 +341,7 @@ static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL
|
||||
SDL_RemoveFromHashTable(properties->props, name);
|
||||
if (property) {
|
||||
char *key = SDL_strdup(name);
|
||||
if (!SDL_InsertIntoHashTable(properties->props, key, property)) {
|
||||
if (!key || !SDL_InsertIntoHashTable(properties->props, key, property, false)) {
|
||||
SDL_FreePropertyWithCleanup(key, property, NULL, true);
|
||||
result = false;
|
||||
}
|
||||
@@ -518,10 +522,9 @@ void *SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *def
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Note that taking the lock here only guarantees that we won't read the
|
||||
* hashtable while it's being modified. The value itself can easily be
|
||||
* freed from another thread after it is returned here.
|
||||
*/
|
||||
// Note that taking the lock here only guarantees that we won't read the
|
||||
// hashtable while it's being modified. The value itself can easily be
|
||||
// freed from another thread after it is returned here.
|
||||
SDL_LockMutex(properties->lock);
|
||||
{
|
||||
SDL_Property *property = NULL;
|
||||
@@ -731,6 +734,23 @@ bool SDL_ClearProperty(SDL_PropertiesID props, const char *name)
|
||||
return SDL_PrivateSetProperty(props, name, NULL);
|
||||
}
|
||||
|
||||
typedef struct EnumerateOnePropertyData
|
||||
{
|
||||
SDL_EnumeratePropertiesCallback callback;
|
||||
void *userdata;
|
||||
SDL_PropertiesID props;
|
||||
} EnumerateOnePropertyData;
|
||||
|
||||
|
||||
static bool SDLCALL EnumerateOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
(void) table;
|
||||
(void) value;
|
||||
const EnumerateOnePropertyData *data = (const EnumerateOnePropertyData *) userdata;
|
||||
data->callback(data->userdata, data->props, (const char *)key);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata)
|
||||
{
|
||||
SDL_Properties *properties = NULL;
|
||||
@@ -749,13 +769,8 @@ bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCall
|
||||
|
||||
SDL_LockMutex(properties->lock);
|
||||
{
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(properties->props, &key, &value, &iter)) {
|
||||
callback(userdata, props, (const char *)key);
|
||||
}
|
||||
EnumerateOnePropertyData data = { callback, userdata, props };
|
||||
SDL_IterateHashTable(properties->props, EnumerateOneProperty, &data);
|
||||
}
|
||||
SDL_UnlockMutex(properties->lock);
|
||||
|
||||
@@ -796,14 +811,14 @@ bool SDL_DumpProperties(SDL_PropertiesID props)
|
||||
|
||||
void SDL_DestroyProperties(SDL_PropertiesID props)
|
||||
{
|
||||
SDL_Properties *properties = NULL;
|
||||
|
||||
if (!props) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
||||
SDL_FreeProperties(properties);
|
||||
SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props);
|
||||
if (props) {
|
||||
// this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because
|
||||
// other destructors under this might cause use to attempt a recursive lock on SDL_properties,
|
||||
// which isn't allowed with rwlocks. So manually look it up and remove/free it.
|
||||
SDL_Properties *properties = NULL;
|
||||
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
||||
SDL_FreeProperties(properties);
|
||||
SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props);
|
||||
}
|
||||
}
|
||||
}
|
||||
+210
-67
@@ -24,6 +24,9 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "joystick/SDL_joystick_c.h" // For SDL_GetGamepadTypeFromVIDPID()
|
||||
|
||||
|
||||
// Common utility functions that aren't in the public API
|
||||
|
||||
int SDL_powerof2(int x)
|
||||
@@ -135,12 +138,12 @@ Uint32 SDL_GetNextObjectID(void)
|
||||
static SDL_InitState SDL_objects_init;
|
||||
static SDL_HashTable *SDL_objects;
|
||||
|
||||
static Uint32 SDL_HashObject(const void *key, void *unused)
|
||||
static Uint32 SDLCALL SDL_HashObject(void *unused, const void *key)
|
||||
{
|
||||
return (Uint32)(uintptr_t)key;
|
||||
}
|
||||
|
||||
static bool SDL_KeyMatchObject(const void *a, const void *b, void *unused)
|
||||
static bool SDL_KeyMatchObject(void *unused, const void *a, const void *b)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
@@ -149,16 +152,17 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid)
|
||||
{
|
||||
SDL_assert(object != NULL);
|
||||
|
||||
if (valid && SDL_ShouldInit(&SDL_objects_init)) {
|
||||
SDL_objects = SDL_CreateHashTable(NULL, 32, SDL_HashObject, SDL_KeyMatchObject, NULL, true, false);
|
||||
if (!SDL_objects) {
|
||||
SDL_SetInitialized(&SDL_objects_init, false);
|
||||
if (SDL_ShouldInit(&SDL_objects_init)) {
|
||||
SDL_objects = SDL_CreateHashTable(0, true, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL);
|
||||
const bool initialized = (SDL_objects != NULL);
|
||||
SDL_SetInitialized(&SDL_objects_init, initialized);
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
SDL_SetInitialized(&SDL_objects_init, true);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type);
|
||||
SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type, true);
|
||||
} else {
|
||||
SDL_RemoveFromHashTable(SDL_objects, object);
|
||||
}
|
||||
@@ -178,75 +182,65 @@ bool SDL_ObjectValid(void *object, SDL_ObjectType type)
|
||||
return (((SDL_ObjectType)(uintptr_t)object_type) == type);
|
||||
}
|
||||
|
||||
typedef struct GetOneObjectData
|
||||
{
|
||||
const SDL_ObjectType type;
|
||||
void **objects;
|
||||
const int count;
|
||||
int num_objects;
|
||||
} GetOneObjectData;
|
||||
|
||||
static bool SDLCALL GetOneObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type)
|
||||
{
|
||||
GetOneObjectData *data = (GetOneObjectData *) userdata;
|
||||
if ((SDL_ObjectType)(uintptr_t)object_type == data->type) {
|
||||
if (data->num_objects < data->count) {
|
||||
data->objects[data->num_objects] = (void *)object;
|
||||
}
|
||||
++data->num_objects;
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
|
||||
int SDL_GetObjects(SDL_ObjectType type, void **objects, int count)
|
||||
{
|
||||
const void *object, *object_type;
|
||||
void *iter = NULL;
|
||||
int num_objects = 0;
|
||||
while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) {
|
||||
if ((SDL_ObjectType)(uintptr_t)object_type == type) {
|
||||
if (num_objects < count) {
|
||||
objects[num_objects] = (void *)object;
|
||||
}
|
||||
++num_objects;
|
||||
}
|
||||
GetOneObjectData data = { type, objects, count, 0 };
|
||||
SDL_IterateHashTable(SDL_objects, GetOneObject, &data);
|
||||
return data.num_objects;
|
||||
}
|
||||
|
||||
static bool SDLCALL LogOneLeakedObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type)
|
||||
{
|
||||
const char *type = "unknown object";
|
||||
switch ((SDL_ObjectType)(uintptr_t)object_type) {
|
||||
#define SDLOBJTYPECASE(typ, name) case SDL_OBJECT_TYPE_##typ: type = name; break
|
||||
SDLOBJTYPECASE(WINDOW, "SDL_Window");
|
||||
SDLOBJTYPECASE(RENDERER, "SDL_Renderer");
|
||||
SDLOBJTYPECASE(TEXTURE, "SDL_Texture");
|
||||
SDLOBJTYPECASE(JOYSTICK, "SDL_Joystick");
|
||||
SDLOBJTYPECASE(GAMEPAD, "SDL_Gamepad");
|
||||
SDLOBJTYPECASE(HAPTIC, "SDL_Haptic");
|
||||
SDLOBJTYPECASE(SENSOR, "SDL_Sensor");
|
||||
SDLOBJTYPECASE(HIDAPI_DEVICE, "hidapi device");
|
||||
SDLOBJTYPECASE(HIDAPI_JOYSTICK, "hidapi joystick");
|
||||
SDLOBJTYPECASE(THREAD, "thread");
|
||||
SDLOBJTYPECASE(TRAY, "SDL_Tray");
|
||||
#undef SDLOBJTYPECASE
|
||||
default: break;
|
||||
}
|
||||
return num_objects;
|
||||
SDL_Log("Leaked %s (%p)", type, object);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_SetObjectsInvalid(void)
|
||||
{
|
||||
if (SDL_ShouldQuit(&SDL_objects_init)) {
|
||||
// Log any leaked objects
|
||||
const void *object, *object_type;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) {
|
||||
const char *type;
|
||||
switch ((SDL_ObjectType)(uintptr_t)object_type) {
|
||||
case SDL_OBJECT_TYPE_WINDOW:
|
||||
type = "SDL_Window";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_RENDERER:
|
||||
type = "SDL_Renderer";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_TEXTURE:
|
||||
type = "SDL_Texture";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_JOYSTICK:
|
||||
type = "SDL_Joystick";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_GAMEPAD:
|
||||
type = "SDL_Gamepad";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HAPTIC:
|
||||
type = "SDL_Haptic";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_SENSOR:
|
||||
type = "SDL_Sensor";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HIDAPI_DEVICE:
|
||||
type = "hidapi device";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HIDAPI_JOYSTICK:
|
||||
type = "hidapi joystick";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_THREAD:
|
||||
type = "thread";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_TRAY:
|
||||
type = "SDL_Tray";
|
||||
break;
|
||||
default:
|
||||
type = "unknown object";
|
||||
break;
|
||||
}
|
||||
SDL_Log("Leaked %s (%p)", type, object);
|
||||
}
|
||||
SDL_IterateHashTable(SDL_objects, LogOneLeakedObject, NULL);
|
||||
SDL_assert(SDL_HashTableEmpty(SDL_objects));
|
||||
|
||||
SDL_DestroyHashTable(SDL_objects);
|
||||
SDL_objects = NULL;
|
||||
|
||||
SDL_SetInitialized(&SDL_objects_init, false);
|
||||
}
|
||||
}
|
||||
@@ -384,7 +378,7 @@ const char *SDL_GetPersistentString(const char *string)
|
||||
|
||||
SDL_HashTable *strings = (SDL_HashTable *)SDL_GetTLS(&SDL_string_storage);
|
||||
if (!strings) {
|
||||
strings = SDL_CreateHashTable(NULL, 32, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeValue, false, false);
|
||||
strings = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashValue, NULL);
|
||||
if (!strings) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -400,8 +394,157 @@ const char *SDL_GetPersistentString(const char *string)
|
||||
}
|
||||
|
||||
// If the hash table insert fails, at least we can return the string we allocated
|
||||
SDL_InsertIntoHashTable(strings, new_string, new_string);
|
||||
SDL_InsertIntoHashTable(strings, new_string, new_string, false);
|
||||
result = new_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int PrefixMatch(const char *a, const char *b)
|
||||
{
|
||||
int matchlen = 0;
|
||||
while (*a && *b) {
|
||||
if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) {
|
||||
++matchlen;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *prefix;
|
||||
const char *replacement;
|
||||
} replacements[] = {
|
||||
{ "8BitDo Tech Ltd", "8BitDo" },
|
||||
{ "ASTRO Gaming", "ASTRO" },
|
||||
{ "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" },
|
||||
{ "Guangzhou Chicken Run Network Technology Co., Ltd.", "GameSir" },
|
||||
{ "HORI CO.,LTD", "HORI" },
|
||||
{ "HORI CO.,LTD.", "HORI" },
|
||||
{ "Mad Catz Inc.", "Mad Catz" },
|
||||
{ "Nintendo Co., Ltd.", "Nintendo" },
|
||||
{ "NVIDIA Corporation ", "" },
|
||||
{ "Performance Designed Products", "PDP" },
|
||||
{ "QANBA USA, LLC", "Qanba" },
|
||||
{ "QANBA USA,LLC", "Qanba" },
|
||||
{ "Unknown ", "" },
|
||||
};
|
||||
char *name = NULL;
|
||||
size_t i, len;
|
||||
|
||||
if (!vendor_name) {
|
||||
vendor_name = "";
|
||||
}
|
||||
if (!product_name) {
|
||||
product_name = "";
|
||||
}
|
||||
|
||||
while (*vendor_name == ' ') {
|
||||
++vendor_name;
|
||||
}
|
||||
while (*product_name == ' ') {
|
||||
++product_name;
|
||||
}
|
||||
|
||||
if (*vendor_name && *product_name) {
|
||||
len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
|
||||
name = (char *)SDL_malloc(len);
|
||||
if (name) {
|
||||
(void)SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
|
||||
}
|
||||
} else if (*product_name) {
|
||||
name = SDL_strdup(product_name);
|
||||
} else if (vendor || product) {
|
||||
// Couldn't find a controller name, try to give it one based on device type
|
||||
switch (SDL_GetGamepadTypeFromVIDPID(vendor, product, NULL, true)) {
|
||||
case SDL_GAMEPAD_TYPE_XBOX360:
|
||||
name = SDL_strdup("Xbox 360 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||
name = SDL_strdup("Xbox One Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS3:
|
||||
name = SDL_strdup("PS3 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS4:
|
||||
name = SDL_strdup("PS4 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS5:
|
||||
name = SDL_strdup("DualSense Wireless Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO:
|
||||
name = SDL_strdup("Nintendo Switch Pro Controller");
|
||||
break;
|
||||
default:
|
||||
len = (6 + 1 + 6 + 1);
|
||||
name = (char *)SDL_malloc(len);
|
||||
if (name) {
|
||||
(void)SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (default_name) {
|
||||
name = SDL_strdup(default_name);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Trim trailing whitespace
|
||||
for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
|
||||
// continue
|
||||
}
|
||||
name[len] = '\0';
|
||||
|
||||
// Compress duplicate spaces
|
||||
for (i = 0; i < (len - 1);) {
|
||||
if (name[i] == ' ' && name[i + 1] == ' ') {
|
||||
SDL_memmove(&name[i], &name[i + 1], (len - i));
|
||||
--len;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform any manufacturer replacements
|
||||
for (i = 0; i < SDL_arraysize(replacements); ++i) {
|
||||
size_t prefixlen = SDL_strlen(replacements[i].prefix);
|
||||
if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
|
||||
size_t replacementlen = SDL_strlen(replacements[i].replacement);
|
||||
if (replacementlen <= prefixlen) {
|
||||
SDL_memcpy(name, replacements[i].replacement, replacementlen);
|
||||
SDL_memmove(name + replacementlen, name + prefixlen, (len - prefixlen) + 1);
|
||||
len -= (prefixlen - replacementlen);
|
||||
} else {
|
||||
// FIXME: Need to handle the expand case by reallocating the string
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove duplicate manufacturer or product in the name
|
||||
* e.g. Razer Razer Raiju Tournament Edition Wired
|
||||
*/
|
||||
for (i = 1; i < (len - 1); ++i) {
|
||||
int matchlen = PrefixMatch(name, &name[i]);
|
||||
while (matchlen > 0) {
|
||||
if (name[matchlen] == ' ' || name[matchlen] == '-') {
|
||||
SDL_memmove(name, name + matchlen + 1, len - matchlen);
|
||||
break;
|
||||
}
|
||||
--matchlen;
|
||||
}
|
||||
if (matchlen > 0) {
|
||||
// We matched the manufacturer's name and removed it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -73,4 +73,6 @@ extern void SDL_SetObjectsInvalid(void);
|
||||
|
||||
extern const char *SDL_GetPersistentString(const char *string);
|
||||
|
||||
extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name);
|
||||
|
||||
#endif // SDL_utils_h_
|
||||
+103
-84
@@ -136,6 +136,7 @@ const char *SDL_GetAudioDriver(int index)
|
||||
if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
|
||||
return deduped_bootstrap[index]->name;
|
||||
}
|
||||
SDL_InvalidParamError("index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -650,7 +651,7 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, bool recordi
|
||||
device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/false);
|
||||
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) {
|
||||
SDL_AddAtomicInt(device_count, 1);
|
||||
} else {
|
||||
SDL_DestroyCondition(device->close_cond);
|
||||
@@ -864,50 +865,47 @@ static void CompleteAudioEntryPoints(void)
|
||||
#undef FILL_STUB
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
typedef struct FindLowestDeviceIDData
|
||||
{
|
||||
SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
SDL_AudioDevice *result = NULL;
|
||||
const bool recording;
|
||||
SDL_AudioDeviceID highest;
|
||||
SDL_AudioDevice *result;
|
||||
} FindLowestDeviceIDData;
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == recording) && (devid < highest)) {
|
||||
highest = devid;
|
||||
result = (SDL_AudioDevice *) value;
|
||||
}
|
||||
static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindLowestDeviceIDData *data = (FindLowestDeviceIDData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
|
||||
data->highest = devid;
|
||||
data->result = (SDL_AudioDevice *) value;
|
||||
}
|
||||
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return result;
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static Uint32 HashAudioDeviceID(const void *key, void *data)
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
{
|
||||
const SDL_AudioDeviceID highest = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
FindLowestDeviceIDData data = { recording, highest, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindLowestDeviceID, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return data.result;
|
||||
}
|
||||
|
||||
static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key)
|
||||
{
|
||||
// shift right 2, to dump the first two bits, since these are flags
|
||||
// (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
|
||||
return ((Uint32) ((uintptr_t) key)) >> 2;
|
||||
}
|
||||
|
||||
static bool MatchAudioDeviceID(const void *a, const void *b, void *data)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
static void NukeAudioDeviceHashItem(const void *key, const void *value, void *data)
|
||||
{
|
||||
// no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here.
|
||||
}
|
||||
|
||||
// !!! FIXME: the video subsystem does SDL_VideoInit, not SDL_InitVideo. Make this match.
|
||||
bool SDL_InitAudio(const char *driver_name)
|
||||
{
|
||||
@@ -926,7 +924,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashAudioDeviceID, MatchAudioDeviceID, NukeAudioDeviceHashItem, false, false);
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
|
||||
if (!device_hash) {
|
||||
SDL_DestroyRWLock(device_hash_lock);
|
||||
return false;
|
||||
@@ -964,7 +962,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
}
|
||||
|
||||
for (int i = 0; bootstrap[i]; ++i) {
|
||||
if (SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
if (!bootstrap[i]->is_preferred && SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
tried_to_init = true;
|
||||
SDL_zero(current_audio);
|
||||
current_audio.pending_events_tail = ¤t_audio.pending_events;
|
||||
@@ -1047,6 +1045,17 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_QuitAudio(void)
|
||||
{
|
||||
if (!current_audio.name) { // not initialized?!
|
||||
@@ -1076,17 +1085,7 @@ void SDL_QuitAudio(void)
|
||||
SDL_free(i);
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) {
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(device_hash, DestroyOnePhysicalAudioDevice, NULL);
|
||||
|
||||
// Free the driver data
|
||||
current_audio.impl.Deinitialize();
|
||||
@@ -1383,6 +1382,28 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct CountAudioDevicesData
|
||||
{
|
||||
int devs_seen;
|
||||
const int num_devices;
|
||||
SDL_AudioDeviceID *result;
|
||||
const bool recording;
|
||||
} CountAudioDevicesData;
|
||||
|
||||
static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
CountAudioDevicesData *data = (CountAudioDevicesData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == data->recording)) {
|
||||
SDL_assert(data->devs_seen < data->num_devices);
|
||||
data->result[data->devs_seen++] = devid;
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
{
|
||||
@@ -1395,24 +1416,10 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
num_devices = SDL_GetAtomicInt(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count);
|
||||
result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
|
||||
if (result) {
|
||||
int devs_seen = 0;
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == recording)) {
|
||||
SDL_assert(devs_seen < num_devices);
|
||||
result[devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(devs_seen == num_devices);
|
||||
result[devs_seen] = 0; // null-terminated.
|
||||
CountAudioDevicesData data = { 0, num_devices, result, recording };
|
||||
SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
|
||||
SDL_assert(data.devs_seen == num_devices);
|
||||
result[data.devs_seen] = 0; // null-terminated.
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -1440,7 +1447,30 @@ SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count)
|
||||
return GetAudioDevices(count, true);
|
||||
}
|
||||
|
||||
typedef struct FindAudioDeviceByCallbackData
|
||||
{
|
||||
bool (*callback)(SDL_AudioDevice *device, void *userdata);
|
||||
void *userdata;
|
||||
SDL_AudioDevice *retval;
|
||||
} FindAudioDeviceByCallbackData;
|
||||
|
||||
static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindAudioDeviceByCallbackData *data = (FindAudioDeviceByCallbackData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
// !!! FIXME: SDL convention is for userdata to come first in the callback's params. Fix this at some point.
|
||||
SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata)
|
||||
{
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
@@ -1448,27 +1478,16 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_Audi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
|
||||
FindAudioDeviceByCallbackData data = { callback, userdata, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (callback(device, userdata)) { // found it?
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindAudioDeviceByCallback, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
SDL_SetError("Device not found");
|
||||
return NULL;
|
||||
if (!data.retval) {
|
||||
SDL_SetError("Device not found");
|
||||
}
|
||||
|
||||
return data.retval;
|
||||
}
|
||||
|
||||
static bool TestDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
|
||||
@@ -1794,7 +1813,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
|
||||
if (result) {
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev, false);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
if (!inserted) {
|
||||
SDL_CloseAudioDevice(result);
|
||||
|
||||
@@ -444,7 +444,7 @@ static void SincTable(float *table, int len)
|
||||
}
|
||||
|
||||
// Calculate Sinc(x/y), using a lookup table
|
||||
static float Sinc(float *table, int x, int y)
|
||||
static float Sinc(const float *table, int x, int y)
|
||||
{
|
||||
float s = table[x % y];
|
||||
s = ((x / y) & 1) ? -s : s;
|
||||
@@ -587,7 +587,18 @@ Sint64 SDL_GetResampleRate(int src_rate, int dst_rate)
|
||||
SDL_assert(src_rate > 0);
|
||||
SDL_assert(dst_rate > 0);
|
||||
|
||||
Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
|
||||
Sint64 numerator = (Sint64)src_rate << 32;
|
||||
Sint64 denominator = (Sint64)dst_rate;
|
||||
|
||||
// Generally it's expected that `dst_frames = (src_frames * dst_rate) / src_rate`
|
||||
// To match this as closely as possible without infinite precision, always round up the resample rate.
|
||||
// For example, without rounding up, a sample ratio of 2:3 would have `sample_rate = 0xAAAAAAAA`
|
||||
// After 3 frames, the position would be 0x1.FFFFFFFE, meaning we haven't fully consumed the second input frame.
|
||||
// By rounding up to 0xAAAAAAAB, we would instead reach 0x2.00000001, fulling consuming the second frame.
|
||||
// Technically you could say this is kicking the can 0x100000000 steps down the road, but I'm fine with that :)
|
||||
// sample_rate = div_ceil(numerator, denominator)
|
||||
Sint64 sample_rate = ((numerator - 1) / denominator) + 1;
|
||||
|
||||
SDL_assert(sample_rate > 0);
|
||||
|
||||
return sample_rate;
|
||||
@@ -657,7 +668,7 @@ Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, S
|
||||
}
|
||||
|
||||
// output_frames = div_ceil(input_offset, resample_rate)
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset + resample_rate * 3 / 4) / resample_rate) : 0;
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset - 1) / resample_rate) + 1 : 0;
|
||||
|
||||
*inout_resample_offset = (output_frames * resample_rate) - input_offset;
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ typedef struct AudioBootStrap
|
||||
const char *desc;
|
||||
bool (*init)(SDL_AudioDriverImpl *impl);
|
||||
bool demand_only; // if true: request explicitly, or it won't be available.
|
||||
bool is_preferred;
|
||||
} AudioBootStrap;
|
||||
|
||||
// Not all of these are available in a given build. Use #ifdefs, etc.
|
||||
|
||||
@@ -545,7 +545,7 @@ static bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap AAUDIO_bootstrap = {
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_AAUDIO
|
||||
@@ -566,7 +566,7 @@ static enum snd_pcm_chmap_position sdl_channel_maps[SDL_AUDIO_ALSA__SDL_CHMAPS_N
|
||||
};
|
||||
|
||||
// Helper for the function right below.
|
||||
static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
static bool has_pos(const unsigned int *chmap, unsigned int pos)
|
||||
{
|
||||
for (unsigned int chan_idx = 0; ; chan_idx++) {
|
||||
if (chan_idx == 6) {
|
||||
@@ -586,7 +586,7 @@ static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
#define HAVE_REAR 1
|
||||
#define HAVE_SIDE 2
|
||||
#define HAVE_BOTH 3
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, unsigned int *alsa_6chans)
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, const unsigned int *alsa_6chans)
|
||||
{
|
||||
// For alsa channel maps with 6 channels and with SND_CHMAP_FL,SND_CHMAP_FR,SND_CHMAP_FC,
|
||||
// SND_CHMAP_LFE, reduce our 6 channels maps to a uniq one.
|
||||
@@ -638,7 +638,7 @@ static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *
|
||||
#undef HAVE_SIDE
|
||||
#undef HAVE_BOTH
|
||||
|
||||
static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
static void swizzle_map_compute_alsa_subscan(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
{
|
||||
swizzle_map[sdl_pos_idx] = -1;
|
||||
for (unsigned int alsa_pos_idx = 0; ; alsa_pos_idx++) {
|
||||
@@ -652,7 +652,7 @@ static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *
|
||||
}
|
||||
|
||||
// XXX: this must stay playback/recording symetric.
|
||||
static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
static void swizzle_map_compute(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
{
|
||||
*needs_swizzle = false;
|
||||
for (unsigned int sdl_pos_idx = 0; sdl_pos_idx != ctx->chans_n; sdl_pos_idx++) {
|
||||
@@ -668,7 +668,7 @@ static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map,
|
||||
#define CHMAP_NOT_FOUND 2
|
||||
// Should always be a queried alsa channel map unless the queried alsa channel map was of type VAR,
|
||||
// namely we can program the channel positions directly from the SDL channel map.
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *chmap)
|
||||
{
|
||||
bool isstack;
|
||||
snd_pcm_chmap_t *chmap_to_install = (snd_pcm_chmap_t*)SDL_small_alloc(unsigned int, 1 + ctx->chans_n, &isstack);
|
||||
@@ -698,7 +698,7 @@ static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
|
||||
// We restrict the alsa channel maps because in the unordered matches we do only simple accounting.
|
||||
// In the end, this will handle mostly alsa channel maps with more than one SND_CHMAP_NA position fillers.
|
||||
static bool alsa_chmap_has_duplicate_position(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *pos)
|
||||
static bool alsa_chmap_has_duplicate_position(const struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *pos)
|
||||
{
|
||||
if (ctx->chans_n < 2) {// we need at least 2 positions
|
||||
LOGDEBUG("channel map:no duplicate");
|
||||
@@ -1513,7 +1513,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap ALSA_bootstrap = {
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_ALSA
|
||||
@@ -1034,7 +1034,7 @@ static bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_COREAUDIO
|
||||
@@ -674,7 +674,7 @@ static bool DSOUND_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSOUND_bootstrap = {
|
||||
"directsound", "DirectSound", DSOUND_Init, false
|
||||
"directsound", "DirectSound", DSOUND_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DSOUND
|
||||
@@ -165,7 +165,7 @@ static bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DISKAUDIO_bootstrap = {
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DISK
|
||||
@@ -297,7 +297,7 @@ static bool DSP_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSP_bootstrap = {
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_OSS
|
||||
@@ -131,5 +131,5 @@ static bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DUMMYAUDIO_bootstrap = {
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true, false
|
||||
};
|
||||
@@ -234,7 +234,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
if ((SDL3 === undefined) || (SDL3.audio_recording === undefined)) { return; }
|
||||
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
|
||||
SDL3.audio_recording.currentRecordingBuffer = audioProcessingEvent.inputBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
SDL3.audio_recording.mediaStreamNode.connect(SDL3.audio_recording.scriptProcessorNode);
|
||||
SDL3.audio_recording.scriptProcessorNode.connect(SDL3.audioContext.destination);
|
||||
@@ -250,7 +250,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audio_recording.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
var silence_callback = function() {
|
||||
SDL3.audio_recording.currentRecordingBuffer = SDL3.audio_recording.silenceBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio_recording.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
@@ -275,7 +275,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audio_playback.silenceBuffer = undefined;
|
||||
}
|
||||
SDL3.audio_playback.currentPlaybackBuffer = e['outputBuffer'];
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio_playback.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||
@@ -293,7 +293,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
// the buffer that gets filled here just gets ignored, so the app can make progress
|
||||
// and/or avoid flooding audio queues until we can actually play audio.
|
||||
SDL3.audio_playback.currentPlaybackBuffer = SDL3.audio_playback.silenceBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
SDL3.audio_playback.currentPlaybackBuffer = undefined;
|
||||
};
|
||||
|
||||
@@ -351,7 +351,7 @@ static bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
|
||||
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false
|
||||
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
@@ -216,7 +216,7 @@ static bool HAIKUAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
extern "C" { extern AudioBootStrap HAIKUAUDIO_bootstrap; }
|
||||
|
||||
AudioBootStrap HAIKUAUDIO_bootstrap = {
|
||||
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false
|
||||
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_HAIKU
|
||||
@@ -429,7 +429,7 @@ static bool JACK_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap JACK_bootstrap = {
|
||||
"jack", "JACK Audio Connection Kit", JACK_Init, false
|
||||
"jack", "JACK Audio Connection Kit", JACK_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_JACK
|
||||
@@ -280,7 +280,8 @@ AudioBootStrap N3DSAUDIO_bootstrap = {
|
||||
N3DSAUDIO_DRIVER_NAME,
|
||||
"SDL N3DS audio driver",
|
||||
N3DSAUDIO_Init,
|
||||
0
|
||||
false,
|
||||
false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_N3DS
|
||||
@@ -322,7 +322,7 @@ static bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap NETBSDAUDIO_bootstrap = {
|
||||
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, false
|
||||
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_NETBSD
|
||||
@@ -779,7 +779,7 @@ static bool OPENSLES_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap OPENSLES_bootstrap = {
|
||||
"openslES", "OpenSL ES audio driver", OPENSLES_Init, false
|
||||
"openslES", "OpenSL ES audio driver", OPENSLES_Init, false, false
|
||||
};
|
||||
|
||||
void OPENSLES_ResumeDevices(void)
|
||||
|
||||
@@ -44,7 +44,9 @@ enum PW_READY_FLAGS
|
||||
{
|
||||
PW_READY_FLAG_BUFFER_ADDED = 0x1,
|
||||
PW_READY_FLAG_STREAM_READY = 0x2,
|
||||
PW_READY_FLAG_ALL_BITS = 0x3
|
||||
PW_READY_FLAG_ALL_PREOPEN_BITS = 0x3,
|
||||
PW_READY_FLAG_OPEN_COMPLETE = 0x4,
|
||||
PW_READY_FLAG_ALL_BITS = 0x7
|
||||
};
|
||||
|
||||
#define PW_ID_TO_HANDLE(x) (void *)((uintptr_t)x)
|
||||
@@ -548,7 +550,7 @@ static void node_event_info(void *object, const struct pw_node_info *info)
|
||||
|
||||
// Need to parse the parameters to get the sample rate
|
||||
for (i = 0; i < info->n_params; ++i) {
|
||||
pw_node_enum_params(node->proxy, 0, info->params[i].id, 0, 0, NULL);
|
||||
pw_node_enum_params((struct pw_node*)node->proxy, 0, info->params[i].id, 0, 0, NULL);
|
||||
}
|
||||
|
||||
hotplug_core_sync(node);
|
||||
@@ -1215,12 +1217,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
return SDL_SetError("Pipewire: Failed to start stream loop");
|
||||
}
|
||||
|
||||
// Wait until all init flags are set or the stream has failed.
|
||||
// Wait until all pre-open init flags are set or the stream has failed.
|
||||
PIPEWIRE_pw_thread_loop_lock(priv->loop);
|
||||
while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS &&
|
||||
while (priv->stream_init_status != PW_READY_FLAG_ALL_PREOPEN_BITS &&
|
||||
PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) {
|
||||
PIPEWIRE_pw_thread_loop_wait(priv->loop);
|
||||
}
|
||||
priv->stream_init_status |= PW_READY_FLAG_OPEN_COMPLETE;
|
||||
PIPEWIRE_pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
if (PIPEWIRE_pw_stream_get_state(priv->stream, &error) == PW_STREAM_STATE_ERROR) {
|
||||
@@ -1337,10 +1340,10 @@ static bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = {
|
||||
"pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false
|
||||
"pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false, true
|
||||
};
|
||||
AudioBootStrap PIPEWIRE_bootstrap = {
|
||||
"pipewire", "Pipewire", PIPEWIRE_Init, false
|
||||
"pipewire", "Pipewire", PIPEWIRE_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PIPEWIRE
|
||||
@@ -155,5 +155,5 @@ static bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PS2AUDIO_bootstrap = {
|
||||
"ps2", "PS2 audio driver", PS2AUDIO_Init, false
|
||||
"ps2", "PS2 audio driver", PS2AUDIO_Init, false, false
|
||||
};
|
||||
@@ -177,7 +177,7 @@ static bool PSPAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PSPAUDIO_bootstrap = {
|
||||
"psp", "PSP audio driver", PSPAUDIO_Init, false
|
||||
"psp", "PSP audio driver", PSPAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PSP
|
||||
@@ -543,7 +543,7 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
const void *data = NULL;
|
||||
size_t nbytes = 0;
|
||||
size_t nbytes = 0, buflen = 0;
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
@@ -553,7 +553,8 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
h->recordinglen = 0;
|
||||
}
|
||||
|
||||
while (!SDL_GetAtomicInt(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0)) {
|
||||
buflen = PULSEAUDIO_pa_stream_readable_size(h->stream);
|
||||
while (!SDL_GetAtomicInt(&device->shutdown) && (buflen > 0)) {
|
||||
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
|
||||
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
|
||||
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN FLUSHRECORDING!");
|
||||
@@ -561,11 +562,11 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
break;
|
||||
}
|
||||
|
||||
if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) {
|
||||
// a new fragment is available! Just dump it.
|
||||
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||
PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment.
|
||||
}
|
||||
// a fragment of audio present before FlushCapture was call is
|
||||
// still available! Just drop it.
|
||||
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||
PULSEAUDIO_pa_stream_drop(h->stream);
|
||||
buflen -= nbytes;
|
||||
}
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
@@ -778,8 +779,8 @@ static void AddPulseAudioDevice(const bool recording, const char *description, c
|
||||
SDL_free(handle);
|
||||
} else {
|
||||
handle->device_index = index;
|
||||
SDL_AddAudioDevice(recording, description, &spec, handle);
|
||||
}
|
||||
SDL_AddAudioDevice(recording, description, &spec, handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,7 +1031,7 @@ static bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PULSEAUDIO_bootstrap = {
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, false
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PULSEAUDIO
|
||||
@@ -444,7 +444,7 @@ static bool QSA_Init(SDL_AudioDriverImpl * impl)
|
||||
}
|
||||
|
||||
AudioBootStrap QSAAUDIO_bootstrap = {
|
||||
"qsa", "QNX QSA Audio", QSA_Init, 0
|
||||
"qsa", "QNX QSA Audio", QSA_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_QNX
|
||||
|
||||
@@ -350,7 +350,7 @@ static bool SNDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap SNDIO_bootstrap = {
|
||||
"sndio", "OpenBSD sndio", SNDIO_Init, false
|
||||
"sndio", "OpenBSD sndio", SNDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_SNDIO
|
||||
@@ -232,7 +232,7 @@ static bool VITAAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap VITAAUD_bootstrap = {
|
||||
"vita", "VITA audio driver", VITAAUD_Init, false
|
||||
"vita", "VITA audio driver", VITAAUD_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_VITA
|
||||
@@ -957,7 +957,7 @@ static bool WASAPI_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap WASAPI_bootstrap = {
|
||||
"wasapi", "WASAPI", WASAPI_Init, false
|
||||
"wasapi", "WASAPI", WASAPI_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_WASAPI
|
||||
+175
-144
@@ -32,7 +32,6 @@
|
||||
|
||||
// Available camera drivers
|
||||
static const CameraBootStrap *const bootstrap[] = {
|
||||
#ifndef SDL_CAMERA_DISABLED
|
||||
#ifdef SDL_CAMERA_DRIVER_V4L2
|
||||
&V4L2_bootstrap,
|
||||
#endif
|
||||
@@ -56,7 +55,6 @@ static const CameraBootStrap *const bootstrap[] = {
|
||||
#endif
|
||||
#ifdef SDL_CAMERA_DRIVER_DUMMY
|
||||
&DUMMYCAMERA_bootstrap,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
@@ -74,6 +72,7 @@ const char *SDL_GetCameraDriver(int index)
|
||||
if (index >= 0 && index < SDL_GetNumCameraDrivers()) {
|
||||
return bootstrap[index]->name;
|
||||
}
|
||||
SDL_InvalidParamError("index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -279,23 +278,10 @@ static void ClosePhysicalCamera(SDL_Camera *device)
|
||||
|
||||
device->base_timestamp = 0;
|
||||
device->adjust_timestamp = 0;
|
||||
}
|
||||
|
||||
// this must not be called while `device` is still in a device list, or while a device's camera thread is still running.
|
||||
static void DestroyPhysicalCamera(SDL_Camera *device)
|
||||
{
|
||||
if (device) {
|
||||
// Destroy any logical devices that still exist...
|
||||
ClosePhysicalCamera(device);
|
||||
camera_driver.impl.FreeDeviceHandle(device);
|
||||
SDL_DestroyMutex(device->lock);
|
||||
SDL_free(device->all_specs);
|
||||
SDL_free(device->name);
|
||||
SDL_free(device);
|
||||
}
|
||||
SDL_zero(device->spec);
|
||||
}
|
||||
|
||||
|
||||
// Don't hold the device lock when calling this, as we may destroy the device!
|
||||
void UnrefPhysicalCamera(SDL_Camera *device)
|
||||
{
|
||||
@@ -306,7 +292,6 @@ void UnrefPhysicalCamera(SDL_Camera *device)
|
||||
SDL_AddAtomicInt(&camera_driver.device_count, -1);
|
||||
}
|
||||
SDL_UnlockRWLock(camera_driver.device_hash_lock);
|
||||
DestroyPhysicalCamera(device); // ...and nuke it.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +484,7 @@ SDL_Camera *SDL_AddCamera(const char *name, SDL_CameraPosition position, int num
|
||||
RefPhysicalCamera(device);
|
||||
|
||||
SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
|
||||
if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
|
||||
if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) {
|
||||
SDL_AddAtomicInt(&camera_driver.device_count, 1);
|
||||
} else {
|
||||
SDL_DestroyMutex(device->lock);
|
||||
@@ -623,7 +608,25 @@ void SDL_CameraPermissionOutcome(SDL_Camera *device, bool approved)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct FindOnePhysicalCameraByCallbackData
|
||||
{
|
||||
bool (*callback)(SDL_Camera *device, void *userdata);
|
||||
void *userdata;
|
||||
SDL_Camera *device;
|
||||
} FindOnePhysicalCameraByCallbackData;
|
||||
|
||||
static bool SDLCALL FindOnePhysicalCameraByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindOnePhysicalCameraByCallbackData *data = (FindOnePhysicalCameraByCallbackData *) userdata;
|
||||
SDL_Camera *device = (SDL_Camera *) value;
|
||||
if (data->callback(device, data->userdata)) {
|
||||
data->device = device;
|
||||
return false; // stop iterating.
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
// !!! FIXME: this doesn't follow SDL convention of `userdata` being the first param of the callback.
|
||||
SDL_Camera *SDL_FindPhysicalCameraByCallback(bool (*callback)(SDL_Camera *device, void *userdata), void *userdata)
|
||||
{
|
||||
if (!SDL_GetCurrentCameraDriver()) {
|
||||
@@ -631,28 +634,22 @@ SDL_Camera *SDL_FindPhysicalCameraByCallback(bool (*callback)(SDL_Camera *device
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
|
||||
FindOnePhysicalCameraByCallbackData data = { callback, userdata, NULL };
|
||||
SDL_LockRWLockForReading(camera_driver.device_hash_lock);
|
||||
while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) {
|
||||
SDL_Camera *device = (SDL_Camera *) value;
|
||||
if (callback(device, userdata)) { // found it?
|
||||
SDL_UnlockRWLock(camera_driver.device_hash_lock);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_IterateHashTable(camera_driver.device_hash, FindOnePhysicalCameraByCallback, &data);
|
||||
SDL_UnlockRWLock(camera_driver.device_hash_lock);
|
||||
|
||||
SDL_SetError("Device not found");
|
||||
return NULL;
|
||||
if (!data.device) {
|
||||
SDL_SetError("Device not found");
|
||||
}
|
||||
|
||||
return data.device;
|
||||
}
|
||||
|
||||
void SDL_CloseCamera(SDL_Camera *camera)
|
||||
{
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ClosePhysicalCamera(device);
|
||||
}
|
||||
|
||||
@@ -666,7 +663,7 @@ bool SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec)
|
||||
return SDL_InvalidParamError("spec");
|
||||
}
|
||||
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ObtainPhysicalCameraObj(device);
|
||||
if (device->permission > 0) {
|
||||
SDL_copyp(spec, &device->spec);
|
||||
@@ -703,6 +700,19 @@ SDL_CameraPosition SDL_GetCameraPosition(SDL_CameraID instance_id)
|
||||
}
|
||||
|
||||
|
||||
typedef struct GetOneCameraData
|
||||
{
|
||||
SDL_CameraID *result;
|
||||
int devs_seen;
|
||||
} GetOneCameraData;
|
||||
|
||||
static bool SDLCALL GetOneCamera(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
GetOneCameraData *data = (GetOneCameraData *) userdata;
|
||||
data->result[data->devs_seen++] = (SDL_CameraID) (uintptr_t) key;
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
SDL_CameraID *SDL_GetCameras(int *count)
|
||||
{
|
||||
int dummy_count;
|
||||
@@ -724,16 +734,10 @@ SDL_CameraID *SDL_GetCameras(int *count)
|
||||
if (!result) {
|
||||
num_devices = 0;
|
||||
} else {
|
||||
int devs_seen = 0;
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) {
|
||||
result[devs_seen++] = (SDL_CameraID) (uintptr_t) key;
|
||||
}
|
||||
|
||||
SDL_assert(devs_seen == num_devices);
|
||||
result[devs_seen] = 0; // null-terminated.
|
||||
GetOneCameraData data = { result, 0 };
|
||||
SDL_IterateHashTable(camera_driver.device_hash, GetOneCamera, &data);
|
||||
SDL_assert(data.devs_seen == num_devices);
|
||||
result[num_devices] = 0; // null-terminated.
|
||||
}
|
||||
SDL_UnlockRWLock(camera_driver.device_hash_lock);
|
||||
|
||||
@@ -954,6 +958,110 @@ static int SDLCALL CameraThread(void *devicep)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SDL_PrepareCameraSurfaces(SDL_Camera *device)
|
||||
{
|
||||
SDL_CameraSpec *appspec = &device->spec; // the app wants this format.
|
||||
const SDL_CameraSpec *devspec = &device->actual_spec; // the hardware is set to this format.
|
||||
|
||||
SDL_assert(device->acquire_surface == NULL); // shouldn't call this function twice on an opened camera!
|
||||
SDL_assert(devspec->format != SDL_PIXELFORMAT_UNKNOWN); // fix the backend, it should have an actual format by now.
|
||||
SDL_assert(devspec->width >= 0); // fix the backend, it should have an actual format by now.
|
||||
SDL_assert(devspec->height >= 0); // fix the backend, it should have an actual format by now.
|
||||
|
||||
if (appspec->width <= 0 || appspec->height <= 0) {
|
||||
appspec->width = devspec->width;
|
||||
appspec->height = devspec->height;
|
||||
}
|
||||
|
||||
if (appspec->format == SDL_PIXELFORMAT_UNKNOWN) {
|
||||
appspec->format = devspec->format;
|
||||
}
|
||||
|
||||
if (appspec->framerate_denominator == 0) {
|
||||
appspec->framerate_numerator = devspec->framerate_numerator;
|
||||
appspec->framerate_denominator = devspec->framerate_denominator;
|
||||
}
|
||||
|
||||
if ((devspec->width == appspec->width) && (devspec->height == appspec->height)) {
|
||||
device->needs_scaling = 0;
|
||||
} else {
|
||||
const Uint64 srcarea = ((Uint64) devspec->width) * ((Uint64) devspec->height);
|
||||
const Uint64 dstarea = ((Uint64) appspec->width) * ((Uint64) appspec->height);
|
||||
if (dstarea <= srcarea) {
|
||||
device->needs_scaling = -1; // downscaling (or changing to new aspect ratio with same area)
|
||||
} else {
|
||||
device->needs_scaling = 1; // upscaling
|
||||
}
|
||||
}
|
||||
|
||||
device->needs_conversion = (devspec->format != appspec->format);
|
||||
|
||||
device->acquire_surface = SDL_CreateSurfaceFrom(devspec->width, devspec->height, devspec->format, NULL, 0);
|
||||
if (!device->acquire_surface) {
|
||||
goto failed;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(device->acquire_surface, devspec->colorspace);
|
||||
|
||||
// if we have to scale _and_ convert, we need a middleman surface, since we can't do both changes at once.
|
||||
if (device->needs_scaling && device->needs_conversion) {
|
||||
const bool downscaling_first = (device->needs_scaling < 0);
|
||||
const SDL_CameraSpec *s = downscaling_first ? appspec : devspec;
|
||||
const SDL_PixelFormat fmt = downscaling_first ? devspec->format : appspec->format;
|
||||
device->conversion_surface = SDL_CreateSurface(s->width, s->height, fmt);
|
||||
if (!device->conversion_surface) {
|
||||
goto failed;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(device->conversion_surface, devspec->colorspace);
|
||||
}
|
||||
|
||||
// output surfaces are in the app-requested format. If no conversion is necessary, we'll just use the pointers
|
||||
// the backend fills into acquired_surface, and you can get all the way from DMA access in the camera hardware
|
||||
// to the app without a single copy. Otherwise, these will be full surfaces that hold converted/scaled copies.
|
||||
|
||||
for (int i = 0; i < (SDL_arraysize(device->output_surfaces) - 1); i++) {
|
||||
device->output_surfaces[i].next = &device->output_surfaces[i + 1];
|
||||
}
|
||||
device->empty_output_surfaces.next = device->output_surfaces;
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) {
|
||||
SDL_Surface *surf;
|
||||
if (device->needs_scaling || device->needs_conversion) {
|
||||
surf = SDL_CreateSurface(appspec->width, appspec->height, appspec->format);
|
||||
} else {
|
||||
surf = SDL_CreateSurfaceFrom(appspec->width, appspec->height, appspec->format, NULL, 0);
|
||||
}
|
||||
if (!surf) {
|
||||
goto failed;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(surf, devspec->colorspace);
|
||||
|
||||
device->output_surfaces[i].surface = surf;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
if (device->acquire_surface) {
|
||||
SDL_DestroySurface(device->acquire_surface);
|
||||
device->acquire_surface = NULL;
|
||||
}
|
||||
|
||||
if (device->conversion_surface) {
|
||||
SDL_DestroySurface(device->conversion_surface);
|
||||
device->conversion_surface = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) {
|
||||
SDL_Surface *surf = device->output_surfaces[i].surface;
|
||||
if (surf) {
|
||||
SDL_DestroySurface(surf);
|
||||
}
|
||||
}
|
||||
SDL_zeroa(device->output_surfaces);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ChooseBestCameraSpec(SDL_Camera *device, const SDL_CameraSpec *spec, SDL_CameraSpec *closest)
|
||||
{
|
||||
// Find the closest available native format/size...
|
||||
@@ -1106,85 +1214,19 @@ SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (spec) {
|
||||
SDL_copyp(&device->spec, spec);
|
||||
if (spec->width <= 0 || spec->height <= 0) {
|
||||
device->spec.width = closest.width;
|
||||
device->spec.height = closest.height;
|
||||
}
|
||||
if (spec->format == SDL_PIXELFORMAT_UNKNOWN) {
|
||||
device->spec.format = closest.format;
|
||||
}
|
||||
if (spec->framerate_denominator == 0) {
|
||||
device->spec.framerate_numerator = closest.framerate_numerator;
|
||||
device->spec.framerate_denominator = closest.framerate_denominator;
|
||||
}
|
||||
} else {
|
||||
SDL_copyp(&device->spec, &closest);
|
||||
}
|
||||
|
||||
SDL_copyp(&device->spec, spec ? spec : &closest);
|
||||
SDL_copyp(&device->actual_spec, &closest);
|
||||
|
||||
if ((closest.width == device->spec.width) && (closest.height == device->spec.height)) {
|
||||
device->needs_scaling = 0;
|
||||
} else {
|
||||
const Uint64 srcarea = ((Uint64) closest.width) * ((Uint64) closest.height);
|
||||
const Uint64 dstarea = ((Uint64) device->spec.width) * ((Uint64) device->spec.height);
|
||||
if (dstarea <= srcarea) {
|
||||
device->needs_scaling = -1; // downscaling (or changing to new aspect ratio with same area)
|
||||
} else {
|
||||
device->needs_scaling = 1; // upscaling
|
||||
}
|
||||
}
|
||||
|
||||
device->needs_conversion = (closest.format != device->spec.format);
|
||||
|
||||
device->acquire_surface = SDL_CreateSurfaceFrom(closest.width, closest.height, closest.format, NULL, 0);
|
||||
if (!device->acquire_surface) {
|
||||
ClosePhysicalCamera(device);
|
||||
ReleaseCamera(device);
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(device->acquire_surface, closest.colorspace);
|
||||
|
||||
// if we have to scale _and_ convert, we need a middleman surface, since we can't do both changes at once.
|
||||
if (device->needs_scaling && device->needs_conversion) {
|
||||
const bool downsampling_first = (device->needs_scaling < 0);
|
||||
const SDL_CameraSpec *s = downsampling_first ? &device->spec : &closest;
|
||||
const SDL_PixelFormat fmt = downsampling_first ? closest.format : device->spec.format;
|
||||
device->conversion_surface = SDL_CreateSurface(s->width, s->height, fmt);
|
||||
if (!device->conversion_surface) {
|
||||
// SDL_PIXELFORMAT_UNKNOWN here is taken as a signal that the backend
|
||||
// doesn't know its format yet (Emscripten waiting for user permission,
|
||||
// in this case), and the backend will call SDL_PrepareCameraSurfaces()
|
||||
// itself, later but before the app is allowed to acquire images.
|
||||
if (closest.format != SDL_PIXELFORMAT_UNKNOWN) {
|
||||
if (!SDL_PrepareCameraSurfaces(device)) {
|
||||
ClosePhysicalCamera(device);
|
||||
ReleaseCamera(device);
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(device->conversion_surface, closest.colorspace);
|
||||
}
|
||||
|
||||
// output surfaces are in the app-requested format. If no conversion is necessary, we'll just use the pointers
|
||||
// the backend fills into acquired_surface, and you can get all the way from DMA access in the camera hardware
|
||||
// to the app without a single copy. Otherwise, these will be full surfaces that hold converted/scaled copies.
|
||||
|
||||
for (int i = 0; i < (SDL_arraysize(device->output_surfaces) - 1); i++) {
|
||||
device->output_surfaces[i].next = &device->output_surfaces[i + 1];
|
||||
}
|
||||
device->empty_output_surfaces.next = device->output_surfaces;
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) {
|
||||
SDL_Surface *surf;
|
||||
if (device->needs_scaling || device->needs_conversion) {
|
||||
surf = SDL_CreateSurface(device->spec.width, device->spec.height, device->spec.format);
|
||||
} else {
|
||||
surf = SDL_CreateSurfaceFrom(device->spec.width, device->spec.height, device->spec.format, NULL, 0);
|
||||
}
|
||||
if (!surf) {
|
||||
ClosePhysicalCamera(device);
|
||||
ReleaseCamera(device);
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetSurfaceColorspace(surf, closest.colorspace);
|
||||
|
||||
device->output_surfaces[i].surface = surf;
|
||||
}
|
||||
|
||||
device->drop_frames = 1;
|
||||
@@ -1204,7 +1246,7 @@ SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec)
|
||||
|
||||
ReleaseCamera(device); // unlock, we're good to go!
|
||||
|
||||
return (SDL_Camera *) device; // currently there's no separation between physical and logical device.
|
||||
return device; // currently there's no separation between physical and logical device.
|
||||
}
|
||||
|
||||
SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS)
|
||||
@@ -1218,7 +1260,7 @@ SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
|
||||
ObtainPhysicalCameraObj(device);
|
||||
|
||||
@@ -1260,7 +1302,7 @@ void SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame)
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ObtainPhysicalCameraObj(device);
|
||||
|
||||
SurfaceList *slistprev = &device->app_held_output_surfaces;
|
||||
@@ -1302,7 +1344,7 @@ SDL_CameraID SDL_GetCameraID(SDL_Camera *camera)
|
||||
if (!camera) {
|
||||
SDL_InvalidParamError("camera");
|
||||
} else {
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ObtainPhysicalCameraObj(device);
|
||||
result = device->instance_id;
|
||||
ReleaseCamera(device);
|
||||
@@ -1317,7 +1359,7 @@ SDL_PropertiesID SDL_GetCameraProperties(SDL_Camera *camera)
|
||||
if (!camera) {
|
||||
SDL_InvalidParamError("camera");
|
||||
} else {
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ObtainPhysicalCameraObj(device);
|
||||
if (device->props == 0) {
|
||||
device->props = SDL_CreateProperties();
|
||||
@@ -1336,7 +1378,7 @@ int SDL_GetCameraPermissionState(SDL_Camera *camera)
|
||||
SDL_InvalidParamError("camera");
|
||||
result = -1;
|
||||
} else {
|
||||
SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
|
||||
SDL_Camera *device = camera; // currently there's no separation between physical and logical device.
|
||||
ObtainPhysicalCameraObj(device);
|
||||
result = device->permission;
|
||||
ReleaseCamera(device);
|
||||
@@ -1380,37 +1422,26 @@ void SDL_QuitCamera(void)
|
||||
SDL_free(i);
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) {
|
||||
DestroyPhysicalCamera((SDL_Camera *) value);
|
||||
}
|
||||
SDL_DestroyHashTable(device_hash);
|
||||
|
||||
// Free the driver data
|
||||
camera_driver.impl.Deinitialize();
|
||||
|
||||
SDL_DestroyRWLock(camera_driver.device_hash_lock);
|
||||
SDL_DestroyHashTable(device_hash);
|
||||
|
||||
SDL_zero(camera_driver);
|
||||
}
|
||||
|
||||
|
||||
static Uint32 HashCameraID(const void *key, void *data)
|
||||
// Physical camera objects are only destroyed when removed from the device hash.
|
||||
static void SDLCALL DestroyCameraHashItem(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
// The values are unique incrementing integers, starting at 1, so just return minus 1 to start with bucket zero.
|
||||
return ((Uint32) ((uintptr_t) key)) - 1;
|
||||
}
|
||||
|
||||
static bool MatchCameraID(const void *a, const void *b, void *data)
|
||||
{
|
||||
return (a == b); // simple integers, just compare them as pointer values.
|
||||
}
|
||||
|
||||
static void NukeCameraHashItem(const void *key, const void *value, void *data)
|
||||
{
|
||||
// no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here.
|
||||
SDL_Camera *device = (SDL_Camera *) value;
|
||||
ClosePhysicalCamera(device);
|
||||
camera_driver.impl.FreeDeviceHandle(device);
|
||||
SDL_DestroyMutex(device->lock);
|
||||
SDL_free(device->all_specs);
|
||||
SDL_free(device->name);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
bool SDL_CameraInit(const char *driver_name)
|
||||
@@ -1424,7 +1455,7 @@ bool SDL_CameraInit(const char *driver_name)
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashCameraID, MatchCameraID, NukeCameraHashItem, false, false);
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, DestroyCameraHashItem, NULL);
|
||||
if (!device_hash) {
|
||||
SDL_DestroyRWLock(device_hash_lock);
|
||||
return false;
|
||||
|
||||
@@ -54,6 +54,10 @@ extern void SDL_CameraThreadSetup(SDL_Camera *device);
|
||||
extern bool SDL_CameraThreadIterate(SDL_Camera *device);
|
||||
extern void SDL_CameraThreadShutdown(SDL_Camera *device);
|
||||
|
||||
// Backends can call this if they have to finish initializing later, like Emscripten. Most backends should _not_ call this directly!
|
||||
extern bool SDL_PrepareCameraSurfaces(SDL_Camera *device);
|
||||
|
||||
|
||||
// common utility functionality to gather up camera specs. Not required!
|
||||
typedef struct CameraFormatAddData
|
||||
{
|
||||
@@ -190,7 +194,7 @@ typedef struct SDL_CameraDriver
|
||||
const char *desc; // The description of this camera driver
|
||||
SDL_CameraDriverImpl impl; // the backend's interface
|
||||
|
||||
SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash`
|
||||
SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash` // !!! FIXME: device_hash _also_ has a rwlock, see if we still need this one.
|
||||
SDL_HashTable *device_hash; // the collection of currently-available camera devices
|
||||
SDL_PendingCameraEvent pending_events;
|
||||
SDL_PendingCameraEvent *pending_events_tail;
|
||||
|
||||
@@ -98,17 +98,24 @@ static void EMSCRIPTENCAMERA_CloseDevice(SDL_Camera *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLEmscriptenCameraPermissionOutcome(SDL_Camera *device, int approved, int w, int h, int fps)
|
||||
static int SDLEmscriptenCameraPermissionOutcome(SDL_Camera *device, int approved, int w, int h, int fps)
|
||||
{
|
||||
device->spec.width = device->actual_spec.width = w;
|
||||
device->spec.height = device->actual_spec.height = h;
|
||||
device->spec.framerate_numerator = device->actual_spec.framerate_numerator = fps;
|
||||
device->spec.framerate_denominator = device->actual_spec.framerate_denominator = 1;
|
||||
if (device->acquire_surface) {
|
||||
device->acquire_surface->w = w;
|
||||
device->acquire_surface->h = h;
|
||||
if (approved) {
|
||||
device->actual_spec.format = SDL_PIXELFORMAT_RGBA32;
|
||||
device->actual_spec.width = w;
|
||||
device->actual_spec.height = h;
|
||||
device->actual_spec.framerate_numerator = fps;
|
||||
device->actual_spec.framerate_denominator = 1;
|
||||
|
||||
if (!SDL_PrepareCameraSurfaces(device)) {
|
||||
// uhoh, we're in trouble. Probably ran out of memory.
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Camera could not prepare surfaces: %s ... revoking approval!", SDL_GetError());
|
||||
approved = 0; // disconnecting the SDL camera might not be safe here, just mark it as denied by user.
|
||||
}
|
||||
}
|
||||
|
||||
SDL_CameraPermissionOutcome(device, approved ? true : false);
|
||||
return approved;
|
||||
}
|
||||
|
||||
static bool EMSCRIPTENCAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *spec)
|
||||
@@ -167,40 +174,40 @@ static bool EMSCRIPTENCAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec
|
||||
const actualfps = settings.frameRate;
|
||||
console.log("Camera is opened! Actual spec: (" + actualw + "x" + actualh + "), fps=" + actualfps);
|
||||
|
||||
dynCall('viiiii', outcome, [device, 1, actualw, actualh, actualfps]);
|
||||
if (dynCall('iiiiii', outcome, [device, 1, actualw, actualh, actualfps])) {
|
||||
const video = document.createElement("video");
|
||||
video.width = actualw;
|
||||
video.height = actualh;
|
||||
video.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
|
||||
video.srcObject = stream;
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.width = actualw;
|
||||
video.height = actualh;
|
||||
video.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
|
||||
video.srcObject = stream;
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = actualw;
|
||||
canvas.height = actualh;
|
||||
canvas.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = actualw;
|
||||
canvas.height = actualh;
|
||||
canvas.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
|
||||
const ctx2d = canvas.getContext('2d');
|
||||
|
||||
const ctx2d = canvas.getContext('2d');
|
||||
const SDL3 = Module['SDL3'];
|
||||
SDL3.camera.width = actualw;
|
||||
SDL3.camera.height = actualh;
|
||||
SDL3.camera.fps = actualfps;
|
||||
SDL3.camera.fpsincrms = 1000.0 / actualfps;
|
||||
SDL3.camera.stream = stream;
|
||||
SDL3.camera.video = video;
|
||||
SDL3.camera.canvas = canvas;
|
||||
SDL3.camera.ctx2d = ctx2d;
|
||||
SDL3.camera.next_frame_time = performance.now();
|
||||
|
||||
const SDL3 = Module['SDL3'];
|
||||
SDL3.camera.width = actualw;
|
||||
SDL3.camera.height = actualh;
|
||||
SDL3.camera.fps = actualfps;
|
||||
SDL3.camera.fpsincrms = 1000.0 / actualfps;
|
||||
SDL3.camera.stream = stream;
|
||||
SDL3.camera.video = video;
|
||||
SDL3.camera.canvas = canvas;
|
||||
SDL3.camera.ctx2d = ctx2d;
|
||||
SDL3.camera.next_frame_time = performance.now();
|
||||
|
||||
video.play();
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
grabNextCameraFrame(); // start this loop going.
|
||||
});
|
||||
video.play();
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
grabNextCameraFrame(); // start this loop going.
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Tried to open camera but it threw an error! " + err.name + ": " + err.message);
|
||||
dynCall('viiiii', outcome, [device, 0, 0, 0, 0]); // we call this a permission error, because it probably is.
|
||||
dynCall('iiiiii', outcome, [device, 0, 0, 0, 0]); // we call this a permission error, because it probably is.
|
||||
});
|
||||
}, device, spec->width, spec->height, spec->framerate_numerator, spec->framerate_denominator, SDLEmscriptenCameraPermissionOutcome, SDL_CameraThreadIterate);
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_UYVY, FCC('UYVY'));
|
||||
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_YVYU, FCC('YVYU'));
|
||||
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV12, FCC('NV12'));
|
||||
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV21, FCC('NV21'));
|
||||
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_MJPG, FCC('MJPG'));
|
||||
#undef SDL_DEFINE_MEDIATYPE_GUID
|
||||
|
||||
#ifdef __GNUC__
|
||||
@@ -102,7 +103,8 @@ static const struct
|
||||
{ &SDL_MFVideoFormat_UYVY, SDL_PIXELFORMAT_UYVY, SDL_COLORSPACE_BT709_LIMITED },
|
||||
{ &SDL_MFVideoFormat_YVYU, SDL_PIXELFORMAT_YVYU, SDL_COLORSPACE_BT709_LIMITED },
|
||||
{ &SDL_MFVideoFormat_NV12, SDL_PIXELFORMAT_NV12, SDL_COLORSPACE_BT709_LIMITED },
|
||||
{ &SDL_MFVideoFormat_NV21, SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED }
|
||||
{ &SDL_MFVideoFormat_NV21, SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED },
|
||||
{ &SDL_MFVideoFormat_MJPG, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_SRGB }
|
||||
};
|
||||
|
||||
static SDL_Colorspace GetMediaTypeColorspace(IMFMediaType *mediatype, SDL_Colorspace default_colorspace)
|
||||
@@ -296,6 +298,13 @@ static void MediaTypeToSDLFmt(IMFMediaType *mediatype, SDL_PixelFormat *format,
|
||||
}
|
||||
}
|
||||
}
|
||||
#if DEBUG_CAMERA
|
||||
SDL_Log("Unknown media type: 0x%x (%c%c%c%c)", type.Data1,
|
||||
(char)(Uint8)(type.Data1 >> 0),
|
||||
(char)(Uint8)(type.Data1 >> 8),
|
||||
(char)(Uint8)(type.Data1 >> 16),
|
||||
(char)(Uint8)(type.Data1 >> 24));
|
||||
#endif
|
||||
*format = SDL_PIXELFORMAT_UNKNOWN;
|
||||
*colorspace = SDL_COLORSPACE_UNKNOWN;
|
||||
}
|
||||
@@ -424,7 +433,7 @@ static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value)
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS)
|
||||
{
|
||||
SDL_assert(device->hidden->current_sample != NULL);
|
||||
|
||||
|
||||
SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
|
||||
HRESULT ret;
|
||||
LONGLONG timestamp100NS = 0;
|
||||
@@ -457,46 +466,60 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SD
|
||||
} else {
|
||||
BYTE *pixels = NULL;
|
||||
LONG pitch = 0;
|
||||
DWORD buflen = 0;
|
||||
|
||||
if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer2, (void **)&objs->buffer2d2))) {
|
||||
BYTE *bufstart = NULL;
|
||||
DWORD buflen = 0;
|
||||
ret = IMF2DBuffer2_Lock2DSize(objs->buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen);
|
||||
if (FAILED(ret)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
CleanupIMF2DBuffer2(NULL, objs);
|
||||
} else {
|
||||
if (frame->format == SDL_PIXELFORMAT_MJPG) {
|
||||
pitch = (LONG)buflen;
|
||||
}
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
pixels += -pitch * (frame->h - 1);
|
||||
}
|
||||
frame->pixels = pixels;
|
||||
frame->pitch = (int) pitch;
|
||||
frame->pitch = (int)pitch;
|
||||
if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer2, NULL)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
}
|
||||
}
|
||||
} else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer, (void **)&objs->buffer2d))) {
|
||||
} else if (frame->format != SDL_PIXELFORMAT_MJPG &&
|
||||
SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer, (void **)&objs->buffer2d))) {
|
||||
ret = IMF2DBuffer_Lock2D(objs->buffer2d, &pixels, &pitch);
|
||||
if (FAILED(ret)) {
|
||||
CleanupIMF2DBuffer(NULL, objs);
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
pixels += -pitch * (frame->h - 1);
|
||||
}
|
||||
frame->pixels = pixels;
|
||||
frame->pitch = (int) pitch;
|
||||
frame->pitch = (int)pitch;
|
||||
if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer, NULL)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DWORD maxlen = 0, currentlen = 0;
|
||||
ret = IMFMediaBuffer_Lock(objs->buffer, &pixels, &maxlen, ¤tlen);
|
||||
DWORD maxlen = 0;
|
||||
ret = IMFMediaBuffer_Lock(objs->buffer, &pixels, &maxlen, &buflen);
|
||||
if (FAILED(ret)) {
|
||||
CleanupIMFMediaBuffer(NULL, objs);
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
pitch = (LONG) device->hidden->pitch;
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
if (frame->format == SDL_PIXELFORMAT_MJPG) {
|
||||
pitch = (LONG)buflen;
|
||||
} else {
|
||||
pitch = (LONG)device->hidden->pitch;
|
||||
}
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
pixels += -pitch * (frame->h - 1);
|
||||
}
|
||||
frame->pixels = pixels;
|
||||
frame->pitch = (int) pitch;
|
||||
frame->pitch = (int)pitch;
|
||||
if (!SDL_SetPointerPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMFMediaBuffer, NULL)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
}
|
||||
@@ -522,6 +545,23 @@ static void MEDIAFOUNDATION_ReleaseFrame(SDL_Camera *device, SDL_Surface *frame)
|
||||
|
||||
#else
|
||||
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_CopyFrame(SDL_Surface *frame, const BYTE *pixels, LONG pitch, DWORD buflen)
|
||||
{
|
||||
frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen);
|
||||
if (!frame->pixels) {
|
||||
return SDL_CAMERA_FRAME_ERROR;
|
||||
}
|
||||
|
||||
const BYTE *start = pixels;
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
start += -pitch * (frame->h - 1);
|
||||
}
|
||||
SDL_memcpy(frame->pixels, start, buflen);
|
||||
frame->pitch = (int)pitch;
|
||||
|
||||
return SDL_CAMERA_FRAME_READY;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS)
|
||||
{
|
||||
SDL_assert(device->hidden->current_sample != NULL);
|
||||
@@ -555,63 +595,44 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SD
|
||||
IMF2DBuffer2 *buffer2d2 = NULL;
|
||||
BYTE *pixels = NULL;
|
||||
LONG pitch = 0;
|
||||
DWORD buflen = 0;
|
||||
|
||||
if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer2, (void **)&buffer2d2))) {
|
||||
BYTE *bufstart = NULL;
|
||||
DWORD buflen = 0;
|
||||
ret = IMF2DBuffer2_Lock2DSize(buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen);
|
||||
if (FAILED(ret)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen);
|
||||
if (frame->pixels == NULL) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
SDL_memcpy(frame->pixels, pixels, buflen);
|
||||
frame->pitch = (int)pitch;
|
||||
if (frame->format == SDL_PIXELFORMAT_MJPG) {
|
||||
pitch = (LONG)buflen;
|
||||
}
|
||||
result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen);
|
||||
IMF2DBuffer2_Unlock2D(buffer2d2);
|
||||
}
|
||||
IMF2DBuffer2_Release(buffer2d2);
|
||||
} else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer, (void **)&buffer2d))) {
|
||||
} else if (frame->format != SDL_PIXELFORMAT_MJPG &&
|
||||
SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer, (void **)&buffer2d))) {
|
||||
ret = IMF2DBuffer_Lock2D(buffer2d, &pixels, &pitch);
|
||||
if (FAILED(ret)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
BYTE *bufstart = pixels;
|
||||
const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h;
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
bufstart += -pitch * (frame->h - 1);
|
||||
}
|
||||
frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen);
|
||||
if (frame->pixels == NULL) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
SDL_memcpy(frame->pixels, bufstart, buflen);
|
||||
frame->pitch = (int)pitch;
|
||||
}
|
||||
buflen = SDL_abs((int)pitch) * frame->h;
|
||||
result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen);
|
||||
IMF2DBuffer_Unlock2D(buffer2d);
|
||||
}
|
||||
IMF2DBuffer_Release(buffer2d);
|
||||
} else {
|
||||
DWORD maxlen = 0, currentlen = 0;
|
||||
ret = IMFMediaBuffer_Lock(buffer, &pixels, &maxlen, ¤tlen);
|
||||
DWORD maxlen = 0;
|
||||
ret = IMFMediaBuffer_Lock(buffer, &pixels, &maxlen, &buflen);
|
||||
if (FAILED(ret)) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
} else {
|
||||
BYTE *bufstart = pixels;
|
||||
pitch = (LONG)device->hidden->pitch;
|
||||
const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h;
|
||||
if (pitch < 0) { // image rows are reversed.
|
||||
bufstart += -pitch * (frame->h - 1);
|
||||
}
|
||||
frame->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen);
|
||||
if (frame->pixels == NULL) {
|
||||
result = SDL_CAMERA_FRAME_ERROR;
|
||||
if (frame->format == SDL_PIXELFORMAT_MJPG) {
|
||||
pitch = (LONG)buflen;
|
||||
} else {
|
||||
SDL_memcpy(frame->pixels, bufstart, buflen);
|
||||
frame->pitch = (int)pitch;
|
||||
pitch = (LONG)device->hidden->pitch;
|
||||
}
|
||||
result = MEDIAFOUNDATION_CopyFrame(frame, pixels, pitch, buflen);
|
||||
IMFMediaBuffer_Unlock(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,10 +374,8 @@ static struct sdl_video_format {
|
||||
{ SDL_PIXELFORMAT_YUY2, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_YUY2 },
|
||||
{ SDL_PIXELFORMAT_UYVY, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_UYVY },
|
||||
{ SDL_PIXELFORMAT_YVYU, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_YVYU },
|
||||
#if SDL_VERSION_ATLEAST(2,0,4)
|
||||
{ SDL_PIXELFORMAT_NV12, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV12 },
|
||||
{ SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV21 },
|
||||
#endif
|
||||
{ SDL_PIXELFORMAT_NV21, SDL_COLORSPACE_BT709_LIMITED, SPA_VIDEO_FORMAT_NV21 }
|
||||
};
|
||||
|
||||
static uint32_t sdl_format_to_id(SDL_PixelFormat format)
|
||||
@@ -500,14 +498,24 @@ static bool PIPEWIRECAMERA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *
|
||||
&device->hidden->stream_listener,
|
||||
&stream_events, device);
|
||||
|
||||
params[n_params++] = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_Id(sdl_format_to_id(spec->format)),
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)),
|
||||
SPA_FORMAT_VIDEO_framerate,
|
||||
SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator)));
|
||||
if (spec->format == SDL_PIXELFORMAT_MJPG) {
|
||||
params[n_params++] = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mjpg),
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)),
|
||||
SPA_FORMAT_VIDEO_framerate,
|
||||
SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator)));
|
||||
} else {
|
||||
params[n_params++] = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
SPA_FORMAT_VIDEO_format, SPA_POD_Id(sdl_format_to_id(spec->format)),
|
||||
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(spec->width, spec->height)),
|
||||
SPA_FORMAT_VIDEO_framerate,
|
||||
SPA_POD_Fraction(&SPA_FRACTION(spec->framerate_numerator, spec->framerate_denominator)));
|
||||
}
|
||||
|
||||
if ((res = PIPEWIRE_pw_stream_connect(device->hidden->stream,
|
||||
PW_DIRECTION_INPUT,
|
||||
@@ -573,7 +581,11 @@ static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL
|
||||
*timestampNS = SDL_GetTicksNS();
|
||||
#endif
|
||||
frame->pixels = b->buffer->datas[0].data;
|
||||
frame->pitch = b->buffer->datas[0].chunk->stride;
|
||||
if (frame->format == SDL_PIXELFORMAT_MJPG) {
|
||||
frame->pitch = b->buffer->datas[0].chunk->size;
|
||||
} else {
|
||||
frame->pitch = b->buffer->datas[0].chunk->stride;
|
||||
}
|
||||
|
||||
PIPEWIRE_pw_thread_loop_unlock(hotplug.loop);
|
||||
|
||||
@@ -612,7 +624,7 @@ static void collect_rates(CameraFormatAddData *data, struct param *p, SDL_PixelF
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
n_vals = 1;
|
||||
SPA_FALLTHROUGH;
|
||||
SDL_FALLTHROUGH;
|
||||
case SPA_CHOICE_Enum:
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, size->width, size->height, rates[i].num, rates[i].denom)) {
|
||||
@@ -645,7 +657,7 @@ static void collect_size(CameraFormatAddData *data, struct param *p, SDL_PixelFo
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
n_vals = 1;
|
||||
SPA_FALLTHROUGH;
|
||||
SDL_FALLTHROUGH;
|
||||
case SPA_CHOICE_Enum:
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
collect_rates(data, p, sdlfmt, colorspace, &rectangles[i]);
|
||||
@@ -657,7 +669,7 @@ static void collect_size(CameraFormatAddData *data, struct param *p, SDL_PixelFo
|
||||
}
|
||||
}
|
||||
|
||||
static void collect_format(CameraFormatAddData *data, struct param *p)
|
||||
static void collect_raw(CameraFormatAddData *data, struct param *p)
|
||||
{
|
||||
const struct spa_pod_prop *prop;
|
||||
SDL_PixelFormat sdlfmt;
|
||||
@@ -677,7 +689,7 @@ static void collect_format(CameraFormatAddData *data, struct param *p)
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
n_vals = 1;
|
||||
SPA_FALLTHROUGH;
|
||||
SDL_FALLTHROUGH;
|
||||
case SPA_CHOICE_Enum:
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
id_to_sdl_format(ids[i], &sdlfmt, &colorspace);
|
||||
@@ -688,7 +700,47 @@ static void collect_format(CameraFormatAddData *data, struct param *p)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SDL_Log("CAMERA: unimplemented choice:%d", choice);
|
||||
SDL_Log("CAMERA: unimplemented choice: %d", choice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect_format(CameraFormatAddData *data, struct param *p)
|
||||
{
|
||||
const struct spa_pod_prop *prop;
|
||||
struct spa_pod * values;
|
||||
uint32_t i, n_vals, choice, *ids;
|
||||
|
||||
prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_mediaSubtype);
|
||||
if (prop == NULL)
|
||||
return;
|
||||
|
||||
values = spa_pod_get_values(&prop->value, &n_vals, &choice);
|
||||
if (values->type != SPA_TYPE_Id || n_vals == 0)
|
||||
return;
|
||||
|
||||
ids = SPA_POD_BODY(values);
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
n_vals = 1;
|
||||
SDL_FALLTHROUGH;
|
||||
case SPA_CHOICE_Enum:
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
switch (ids[i]) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
collect_raw(data, p);
|
||||
break;
|
||||
case SPA_MEDIA_SUBTYPE_mjpg:
|
||||
collect_size(data, p, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_JPEG);
|
||||
break;
|
||||
default:
|
||||
// Unsupported format
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SDL_Log("CAMERA: unimplemented choice: %d", choice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +128,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *
|
||||
const io_method io = device->hidden->io;
|
||||
size_t size = device->hidden->buffers[0].length;
|
||||
struct v4l2_buffer buf;
|
||||
ssize_t amount;
|
||||
|
||||
switch (io) {
|
||||
case IO_METHOD_READ:
|
||||
if (read(fd, device->hidden->buffers[0].start, size) == -1) {
|
||||
if ((amount = read(fd, device->hidden->buffers[0].start, size)) == -1) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return SDL_CAMERA_FRAME_SKIP;
|
||||
@@ -148,7 +149,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *
|
||||
|
||||
*timestampNS = SDL_GetTicksNS(); // oh well, close enough.
|
||||
frame->pixels = device->hidden->buffers[0].start;
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
if (device->hidden->driver_pitch) {
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
} else {
|
||||
frame->pitch = (int)amount;
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_METHOD_MMAP:
|
||||
@@ -178,7 +183,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *
|
||||
}
|
||||
|
||||
frame->pixels = device->hidden->buffers[buf.index].start;
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
if (device->hidden->driver_pitch) {
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
} else {
|
||||
frame->pitch = buf.bytesused;
|
||||
}
|
||||
device->hidden->buffers[buf.index].available = 1;
|
||||
|
||||
*timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec);
|
||||
@@ -222,7 +231,11 @@ static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *
|
||||
}
|
||||
|
||||
frame->pixels = (void*)buf.m.userptr;
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
if (device->hidden->driver_pitch) {
|
||||
frame->pitch = device->hidden->driver_pitch;
|
||||
} else {
|
||||
frame->pitch = buf.bytesused;
|
||||
}
|
||||
device->hidden->buffers[i].available = 1;
|
||||
|
||||
*timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec);
|
||||
@@ -404,10 +417,15 @@ static void format_v4l2_to_sdl(Uint32 fmt, SDL_PixelFormat *format, SDL_Colorspa
|
||||
switch (fmt) {
|
||||
#define CASE(x, y, z) case x: *format = y; *colorspace = z; return
|
||||
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2, SDL_COLORSPACE_BT709_LIMITED);
|
||||
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_MJPG, SDL_COLORSPACE_SRGB);
|
||||
#undef CASE
|
||||
default:
|
||||
#if DEBUG_CAMERA
|
||||
SDL_Log("CAMERA: Unknown format V4L2_PIX_FORMAT '%d'", fmt);
|
||||
SDL_Log("CAMERA: Unknown format V4L2_PIX_FORMAT '%c%c%c%c' (0x%x)",
|
||||
(char)(Uint8)(fmt >> 0),
|
||||
(char)(Uint8)(fmt >> 8),
|
||||
(char)(Uint8)(fmt >> 16),
|
||||
(char)(Uint8)(fmt >> 24), fmt);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -420,10 +438,10 @@ static Uint32 format_sdl_to_v4l2(SDL_PixelFormat fmt)
|
||||
switch (fmt) {
|
||||
#define CASE(y, x) case x: return y
|
||||
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2);
|
||||
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN);
|
||||
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_MJPG);
|
||||
#undef CASE
|
||||
default:
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-13
@@ -293,12 +293,9 @@ class SDL_BLooper : public BLooper
|
||||
|
||||
void _HandleKey(BMessage *msg)
|
||||
{
|
||||
SDL_Window *win;
|
||||
int32 winID;
|
||||
int32 scancode;
|
||||
bool down;
|
||||
bool down;
|
||||
if (
|
||||
!_GetWinID(msg, &winID) ||
|
||||
msg->FindInt32("key-scancode", &scancode) != B_OK ||
|
||||
msg->FindBool("key-down", &down) != B_OK) {
|
||||
return;
|
||||
@@ -306,15 +303,17 @@ class SDL_BLooper : public BLooper
|
||||
|
||||
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, scancode, HAIKU_GetScancodeFromBeKey(scancode), down);
|
||||
|
||||
win = GetSDLWindow(winID);
|
||||
if (down && SDL_TextInputActive(win)) {
|
||||
const int8 *keyUtf8;
|
||||
ssize_t count;
|
||||
if (msg->FindData("key-utf8", B_INT8_TYPE, (const void **)&keyUtf8, &count) == B_OK) {
|
||||
char text[64];
|
||||
SDL_zeroa(text);
|
||||
SDL_memcpy(text, keyUtf8, count);
|
||||
SDL_SendKeyboardText(text);
|
||||
if (down) {
|
||||
SDL_Window *win = SDL_GetKeyboardFocus();
|
||||
if (win && SDL_TextInputActive(win)) {
|
||||
const int8 *keyUtf8;
|
||||
ssize_t count;
|
||||
if (msg->FindData("key-utf8", B_INT8_TYPE, (const void **)&keyUtf8, &count) == B_OK) {
|
||||
char text[64];
|
||||
SDL_zeroa(text);
|
||||
SDL_memcpy(text, keyUtf8, count);
|
||||
SDL_SendKeyboardText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS)
|
||||
}
|
||||
// FIXME: Add support for ppoll() for nanosecond precision
|
||||
if (timeoutNS > 0) {
|
||||
timeoutMS = (int)SDL_NS_TO_MS(timeoutNS);
|
||||
timeoutMS = (int)SDL_NS_TO_MS(timeoutNS + (SDL_NS_PER_MS - 1));
|
||||
} else if (timeoutNS == 0) {
|
||||
timeoutMS = 0;
|
||||
} else {
|
||||
@@ -82,7 +82,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS)
|
||||
|
||||
if (timeoutNS >= 0) {
|
||||
tv.tv_sec = (timeoutNS / SDL_NS_PER_SECOND);
|
||||
tv.tv_usec = SDL_NS_TO_US(timeoutNS % SDL_NS_PER_SECOND);
|
||||
tv.tv_usec = SDL_NS_TO_US((timeoutNS % SDL_NS_PER_SECOND) + (SDL_NS_PER_US - 1));
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef HAVE_GAMEINPUT_H
|
||||
|
||||
#include "SDL_windows.h"
|
||||
#include "SDL_gameinput.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
#include <initguid.h>
|
||||
// {11BE2A7E-4254-445A-9C09-FFC40F006918}
|
||||
DEFINE_GUID(SDL_IID_GameInput, 0x11BE2A7E, 0x4254, 0x445A, 0x9C, 0x09, 0xFF, 0xC4, 0x0F, 0x00, 0x69, 0x18);
|
||||
#endif
|
||||
|
||||
static SDL_SharedObject *g_hGameInputDLL;
|
||||
static IGameInput *g_pGameInput;
|
||||
static int g_nGameInputRefCount;
|
||||
|
||||
bool SDL_InitGameInput(IGameInput **ppGameInput)
|
||||
{
|
||||
if (g_nGameInputRefCount == 0) {
|
||||
g_hGameInputDLL = SDL_LoadObject("gameinput.dll");
|
||||
if (!g_hGameInputDLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput * *gameInput);
|
||||
GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate");
|
||||
if (!GameInputCreateFunc) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return false;
|
||||
}
|
||||
|
||||
IGameInput *pGameInput = NULL;
|
||||
HRESULT hr = GameInputCreateFunc(&pGameInput);
|
||||
if (FAILED(hr)) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr);
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
hr = IGameInput_QueryInterface(pGameInput, &SDL_IID_GameInput, (void **)&g_pGameInput);
|
||||
IGameInput_Release(pGameInput);
|
||||
if (FAILED(hr)) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return WIN_SetErrorFromHRESULT("GameInput QueryInterface failed", hr);
|
||||
}
|
||||
#else
|
||||
// Assume that the version we get is compatible with the current SDK
|
||||
// If that isn't the case, define the correct GUID for SDL_IID_GameInput above
|
||||
g_pGameInput = pGameInput;
|
||||
#endif
|
||||
}
|
||||
++g_nGameInputRefCount;
|
||||
|
||||
if (ppGameInput) {
|
||||
*ppGameInput = g_pGameInput;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_QuitGameInput(void)
|
||||
{
|
||||
SDL_assert(g_nGameInputRefCount > 0);
|
||||
|
||||
--g_nGameInputRefCount;
|
||||
if (g_nGameInputRefCount == 0) {
|
||||
if (g_pGameInput) {
|
||||
IGameInput_Release(g_pGameInput);
|
||||
g_pGameInput = NULL;
|
||||
}
|
||||
if (g_hGameInputDLL) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
g_hGameInputDLL = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_GAMEINPUT_H
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_gameinput_h_
|
||||
#define SDL_gameinput_h_
|
||||
|
||||
#ifdef HAVE_GAMEINPUT_H
|
||||
|
||||
#define COBJMACROS
|
||||
#include <gameinput.h>
|
||||
|
||||
extern bool SDL_InitGameInput(IGameInput **ppGameInput);
|
||||
extern void SDL_QuitGameInput(void);
|
||||
|
||||
#endif // HAVE_GAMEINPUT_H
|
||||
|
||||
#endif // SDL_gameinput_h_
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "SDL_hid.h"
|
||||
|
||||
HidD_GetAttributes_t SDL_HidD_GetAttributes;
|
||||
HidD_GetString_t SDL_HidD_GetManufacturerString;
|
||||
HidD_GetString_t SDL_HidD_GetProductString;
|
||||
HidP_GetCaps_t SDL_HidP_GetCaps;
|
||||
@@ -50,6 +51,7 @@ bool WIN_LoadHIDDLL(void)
|
||||
SDL_assert(s_HIDDLLRefCount == 0);
|
||||
s_HIDDLLRefCount = 1;
|
||||
|
||||
SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes");
|
||||
SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
|
||||
SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
|
||||
SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
|
||||
|
||||
@@ -191,6 +191,7 @@ typedef struct
|
||||
extern bool WIN_LoadHIDDLL(void);
|
||||
extern void WIN_UnloadHIDDLL(void);
|
||||
|
||||
typedef BOOLEAN (WINAPI *HidD_GetAttributes_t)(HANDLE HidDeviceObject, PHIDD_ATTRIBUTES Attributes);
|
||||
typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
|
||||
@@ -198,6 +199,7 @@ typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHID
|
||||
typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
|
||||
|
||||
extern HidD_GetAttributes_t SDL_HidD_GetAttributes;
|
||||
extern HidD_GetString_t SDL_HidD_GetManufacturerString;
|
||||
extern HidD_GetString_t SDL_HidD_GetProductString;
|
||||
extern HidP_GetCaps_t SDL_HidP_GetCaps;
|
||||
|
||||
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,4,0
|
||||
PRODUCTVERSION 3,2,4,0
|
||||
FILEVERSION 3,2,6,0
|
||||
PRODUCTVERSION 3,2,6,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
@@ -23,12 +23,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL\0"
|
||||
VALUE "FileVersion", "3, 2, 4, 0\0"
|
||||
VALUE "FileVersion", "3, 2, 6, 0\0"
|
||||
VALUE "InternalName", "SDL\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
|
||||
VALUE "OriginalFilename", "SDL3.dll\0"
|
||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||
VALUE "ProductVersion", "3, 2, 4, 0\0"
|
||||
VALUE "ProductVersion", "3, 2, 6, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -29,8 +29,17 @@
|
||||
void SDL_SendClipboardUpdate(bool owner, char **mime_types, size_t num_mime_types)
|
||||
{
|
||||
if (!owner) {
|
||||
// Clear our internal clipboard contents when external clipboard is set
|
||||
SDL_CancelClipboardData(0);
|
||||
/* Clear our internal clipboard contents when external clipboard is set.
|
||||
*
|
||||
* Wayland recursively sends a data offer to the client from which the clipboard data originated,
|
||||
* and as the client can't determine the origin of the offer, the clipboard must not be cleared,
|
||||
* or the original data may be destroyed. Cleanup will be done in the backend when an offer
|
||||
* cancellation event arrives.
|
||||
*/
|
||||
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") != 0) {
|
||||
SDL_CancelClipboardData(0);
|
||||
}
|
||||
|
||||
SDL_SaveClipboardMimeTypes((const char **)mime_types, num_mime_types);
|
||||
}
|
||||
|
||||
|
||||
+88
-114
@@ -23,6 +23,8 @@
|
||||
// General event handling code for SDL
|
||||
|
||||
#include "SDL_events_c.h"
|
||||
#include "SDL_eventwatch_c.h"
|
||||
#include "SDL_windowevents_c.h"
|
||||
#include "../SDL_hints_c.h"
|
||||
#include "../audio/SDL_audio_c.h"
|
||||
#include "../camera/SDL_camera_c.h"
|
||||
@@ -52,19 +54,53 @@
|
||||
// Make sure the type in the SDL_Event aligns properly across the union
|
||||
SDL_COMPILE_TIME_ASSERT(SDL_Event_type, sizeof(Uint32) == sizeof(SDL_EventType));
|
||||
|
||||
typedef struct SDL_EventWatcher
|
||||
{
|
||||
SDL_EventFilter callback;
|
||||
void *userdata;
|
||||
bool removed;
|
||||
} SDL_EventWatcher;
|
||||
#define SDL2_SYSWMEVENT 0x201
|
||||
|
||||
static SDL_Mutex *SDL_event_watchers_lock;
|
||||
static SDL_EventWatcher SDL_EventOK;
|
||||
static SDL_EventWatcher *SDL_event_watchers = NULL;
|
||||
static int SDL_event_watchers_count = 0;
|
||||
static bool SDL_event_watchers_dispatching = false;
|
||||
static bool SDL_event_watchers_removed = false;
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#include "../core/windows/SDL_windows.h"
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
typedef struct SDL2_version
|
||||
{
|
||||
Uint8 major;
|
||||
Uint8 minor;
|
||||
Uint8 patch;
|
||||
} SDL2_version;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL2_SYSWM_UNKNOWN
|
||||
} SDL2_SYSWM_TYPE;
|
||||
|
||||
typedef struct SDL2_SysWMmsg
|
||||
{
|
||||
SDL2_version version;
|
||||
SDL2_SYSWM_TYPE subsystem;
|
||||
union
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
struct {
|
||||
HWND hwnd; /**< The window for the message */
|
||||
UINT msg; /**< The type of message */
|
||||
WPARAM wParam; /**< WORD message parameter */
|
||||
LPARAM lParam; /**< LONG message parameter */
|
||||
} win;
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
struct {
|
||||
XEvent event;
|
||||
} x11;
|
||||
#endif
|
||||
/* Can't have an empty union */
|
||||
int dummy;
|
||||
} msg;
|
||||
} SDL2_SysWMmsg;
|
||||
|
||||
static SDL_EventWatchList SDL_event_watchers;
|
||||
static SDL_AtomicInt SDL_sentinel_pending;
|
||||
static Uint32 SDL_last_event_id = 0;
|
||||
|
||||
@@ -214,6 +250,17 @@ static void SDL_LinkTemporaryMemoryToEvent(SDL_EventEntry *event, const void *me
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TransferSysWMMemoryToEvent(SDL_EventEntry *event)
|
||||
{
|
||||
SDL2_SysWMmsg **wmmsg = (SDL2_SysWMmsg **)((&event->event.common)+1);
|
||||
SDL2_SysWMmsg *mem = SDL_AllocateTemporaryMemory(sizeof(*mem));
|
||||
if (mem) {
|
||||
SDL_copyp(mem, *wmmsg);
|
||||
*wmmsg = mem;
|
||||
SDL_LinkTemporaryMemoryToEvent(event, mem);
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer the event memory from the thread-local event memory list to the event
|
||||
static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event)
|
||||
{
|
||||
@@ -238,6 +285,10 @@ static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event)
|
||||
case SDL_EVENT_CLIPBOARD_UPDATE:
|
||||
SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types);
|
||||
break;
|
||||
case SDL2_SYSWMEVENT:
|
||||
// We need to copy the stack pointer into temporary memory
|
||||
SDL_TransferSysWMMemoryToEvent(event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -877,16 +928,8 @@ void SDL_StopEventLoop(void)
|
||||
SDL_disabled_events[i] = NULL;
|
||||
}
|
||||
|
||||
if (SDL_event_watchers_lock) {
|
||||
SDL_DestroyMutex(SDL_event_watchers_lock);
|
||||
SDL_event_watchers_lock = NULL;
|
||||
}
|
||||
if (SDL_event_watchers) {
|
||||
SDL_free(SDL_event_watchers);
|
||||
SDL_event_watchers = NULL;
|
||||
SDL_event_watchers_count = 0;
|
||||
}
|
||||
SDL_zero(SDL_EventOK);
|
||||
SDL_QuitEventWatchList(&SDL_event_watchers);
|
||||
SDL_QuitWindowEventWatch();
|
||||
|
||||
SDL_Mutex *lock = NULL;
|
||||
if (SDL_EventQ.lock) {
|
||||
@@ -920,17 +963,19 @@ bool SDL_StartEventLoop(void)
|
||||
}
|
||||
SDL_LockMutex(SDL_EventQ.lock);
|
||||
|
||||
if (SDL_event_watchers_lock == NULL) {
|
||||
SDL_event_watchers_lock = SDL_CreateMutex();
|
||||
if (SDL_event_watchers_lock == NULL) {
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
return false;
|
||||
}
|
||||
if (!SDL_InitEventWatchList(&SDL_event_watchers)) {
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
return false;
|
||||
}
|
||||
#endif // !SDL_THREADS_DISABLED
|
||||
|
||||
SDL_InitWindowEventWatch();
|
||||
|
||||
SDL_EventQ.active = true;
|
||||
|
||||
#ifndef SDL_THREADS_DISABLED
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1326,6 +1371,9 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w
|
||||
}
|
||||
SDL_UnlockMutex(SDL_main_callbacks_lock);
|
||||
|
||||
// If the main thread is waiting for events, wake it up
|
||||
SDL_SendWakeupEvent();
|
||||
|
||||
if (!wait_complete) {
|
||||
// Queued for execution, wait not requested
|
||||
return true;
|
||||
@@ -1674,44 +1722,11 @@ bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
|
||||
|
||||
static bool SDL_CallEventWatchers(SDL_Event *event)
|
||||
{
|
||||
if ((SDL_EventOK.callback || SDL_event_watchers_count > 0) &&
|
||||
(event->common.type != SDL_EVENT_POLL_SENTINEL)) {
|
||||
SDL_LockMutex(SDL_event_watchers_lock);
|
||||
{
|
||||
if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDL_event_watchers_count > 0) {
|
||||
// Make sure we only dispatch the current watcher list
|
||||
int i, event_watchers_count = SDL_event_watchers_count;
|
||||
|
||||
SDL_event_watchers_dispatching = true;
|
||||
for (i = 0; i < event_watchers_count; ++i) {
|
||||
if (!SDL_event_watchers[i].removed) {
|
||||
SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
|
||||
}
|
||||
}
|
||||
SDL_event_watchers_dispatching = false;
|
||||
|
||||
if (SDL_event_watchers_removed) {
|
||||
for (i = SDL_event_watchers_count; i--;) {
|
||||
if (SDL_event_watchers[i].removed) {
|
||||
--SDL_event_watchers_count;
|
||||
if (i < SDL_event_watchers_count) {
|
||||
SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_event_watchers_removed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
if (event->common.type == SDL_EVENT_POLL_SENTINEL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return SDL_DispatchEventWatchList(&SDL_event_watchers, event);
|
||||
}
|
||||
|
||||
bool SDL_PushEvent(SDL_Event *event)
|
||||
@@ -1735,11 +1750,11 @@ bool SDL_PushEvent(SDL_Event *event)
|
||||
void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
SDL_EventEntry *event, *next;
|
||||
SDL_LockMutex(SDL_event_watchers_lock);
|
||||
SDL_LockMutex(SDL_event_watchers.lock);
|
||||
{
|
||||
// Set filter and discard pending events
|
||||
SDL_EventOK.callback = filter;
|
||||
SDL_EventOK.userdata = userdata;
|
||||
SDL_event_watchers.filter.callback = filter;
|
||||
SDL_event_watchers.filter.userdata = userdata;
|
||||
if (filter) {
|
||||
// Cut all events not accepted by the filter
|
||||
SDL_LockMutex(SDL_EventQ.lock);
|
||||
@@ -1754,18 +1769,18 @@ void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
SDL_UnlockMutex(SDL_event_watchers.lock);
|
||||
}
|
||||
|
||||
bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
|
||||
{
|
||||
SDL_EventWatcher event_ok;
|
||||
|
||||
SDL_LockMutex(SDL_event_watchers_lock);
|
||||
SDL_LockMutex(SDL_event_watchers.lock);
|
||||
{
|
||||
event_ok = SDL_EventOK;
|
||||
event_ok = SDL_event_watchers.filter;
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
SDL_UnlockMutex(SDL_event_watchers.lock);
|
||||
|
||||
if (filter) {
|
||||
*filter = event_ok.callback;
|
||||
@@ -1778,53 +1793,12 @@ bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
|
||||
|
||||
bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
SDL_LockMutex(SDL_event_watchers_lock);
|
||||
{
|
||||
SDL_EventWatcher *event_watchers;
|
||||
|
||||
event_watchers = (SDL_EventWatcher *)SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
|
||||
if (event_watchers) {
|
||||
SDL_EventWatcher *watcher;
|
||||
|
||||
SDL_event_watchers = event_watchers;
|
||||
watcher = &SDL_event_watchers[SDL_event_watchers_count];
|
||||
watcher->callback = filter;
|
||||
watcher->userdata = userdata;
|
||||
watcher->removed = false;
|
||||
++SDL_event_watchers_count;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
|
||||
return result;
|
||||
return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata);
|
||||
}
|
||||
|
||||
void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
SDL_LockMutex(SDL_event_watchers_lock);
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_event_watchers_count; ++i) {
|
||||
if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
|
||||
if (SDL_event_watchers_dispatching) {
|
||||
SDL_event_watchers[i].removed = true;
|
||||
SDL_event_watchers_removed = true;
|
||||
} else {
|
||||
--SDL_event_watchers_count;
|
||||
if (i < SDL_event_watchers_count) {
|
||||
SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_watchers_lock);
|
||||
SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata);
|
||||
}
|
||||
|
||||
void SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_eventwatch_c.h"
|
||||
|
||||
|
||||
bool SDL_InitEventWatchList(SDL_EventWatchList *list)
|
||||
{
|
||||
if (list->lock == NULL) {
|
||||
list->lock = SDL_CreateMutex();
|
||||
if (list->lock == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_QuitEventWatchList(SDL_EventWatchList *list)
|
||||
{
|
||||
if (list->lock) {
|
||||
SDL_DestroyMutex(list->lock);
|
||||
list->lock = NULL;
|
||||
}
|
||||
if (list->watchers) {
|
||||
SDL_free(list->watchers);
|
||||
list->watchers = NULL;
|
||||
list->count = 0;
|
||||
}
|
||||
SDL_zero(list->filter);
|
||||
}
|
||||
|
||||
bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event)
|
||||
{
|
||||
SDL_EventWatcher *filter = &list->filter;
|
||||
|
||||
if (!filter->callback && list->count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_LockMutex(list->lock);
|
||||
{
|
||||
// Make sure we only dispatch the current watcher list
|
||||
int i, count = list->count;
|
||||
|
||||
if (filter->callback && !filter->callback(filter->userdata, event)) {
|
||||
SDL_UnlockMutex(list->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
list->dispatching = true;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (!list->watchers[i].removed) {
|
||||
list->watchers[i].callback(list->watchers[i].userdata, event);
|
||||
}
|
||||
}
|
||||
list->dispatching = false;
|
||||
|
||||
if (list->removed) {
|
||||
for (i = list->count; i--;) {
|
||||
if (list->watchers[i].removed) {
|
||||
--list->count;
|
||||
if (i < list->count) {
|
||||
SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
list->removed = false;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(list->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
SDL_LockMutex(list->lock);
|
||||
{
|
||||
SDL_EventWatcher *watchers;
|
||||
|
||||
watchers = (SDL_EventWatcher *)SDL_realloc(list->watchers, (list->count + 1) * sizeof(*watchers));
|
||||
if (watchers) {
|
||||
SDL_EventWatcher *watcher;
|
||||
|
||||
list->watchers = watchers;
|
||||
watcher = &list->watchers[list->count];
|
||||
watcher->callback = filter;
|
||||
watcher->userdata = userdata;
|
||||
watcher->removed = false;
|
||||
++list->count;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(list->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
SDL_LockMutex(list->lock);
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < list->count; ++i) {
|
||||
if (list->watchers[i].callback == filter && list->watchers[i].userdata == userdata) {
|
||||
if (list->dispatching) {
|
||||
list->watchers[i].removed = true;
|
||||
list->removed = true;
|
||||
} else {
|
||||
--list->count;
|
||||
if (i < list->count) {
|
||||
SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(list->lock);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
typedef struct SDL_EventWatcher
|
||||
{
|
||||
SDL_EventFilter callback;
|
||||
void *userdata;
|
||||
bool removed;
|
||||
} SDL_EventWatcher;
|
||||
|
||||
typedef struct SDL_EventWatchList
|
||||
{
|
||||
SDL_Mutex *lock;
|
||||
SDL_EventWatcher filter;
|
||||
SDL_EventWatcher *watchers;
|
||||
int count;
|
||||
bool dispatching;
|
||||
bool removed;
|
||||
} SDL_EventWatchList;
|
||||
|
||||
|
||||
extern bool SDL_InitEventWatchList(SDL_EventWatchList *list);
|
||||
extern void SDL_QuitEventWatchList(SDL_EventWatchList *list);
|
||||
extern bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event);
|
||||
extern bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata);
|
||||
extern void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata);
|
||||
+28
-32
@@ -39,8 +39,8 @@ SDL_Keymap *SDL_CreateKeymap(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
keymap->scancode_to_keycode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, false, false);
|
||||
keymap->keycode_to_scancode = SDL_CreateHashTable(NULL, 64, SDL_HashID, SDL_KeyMatchID, NULL, false, false);
|
||||
keymap->scancode_to_keycode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
|
||||
keymap->keycode_to_scancode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
|
||||
if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) {
|
||||
SDL_DestroyKeymap(keymap);
|
||||
return NULL;
|
||||
@@ -76,31 +76,27 @@ void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod mo
|
||||
Uint32 key = ((Uint32)modstate << 16) | scancode;
|
||||
const void *value;
|
||||
if (SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) {
|
||||
SDL_Keycode existing_keycode = (SDL_Keycode)(uintptr_t)value;
|
||||
const SDL_Keycode existing_keycode = (SDL_Keycode)(uintptr_t)value;
|
||||
if (existing_keycode == keycode) {
|
||||
// We already have this mapping
|
||||
return;
|
||||
}
|
||||
|
||||
// Changing the mapping, need to remove the existing entry from the keymap
|
||||
SDL_RemoveFromHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key);
|
||||
// InsertIntoHashTable will replace the existing entry in the keymap atomically.
|
||||
}
|
||||
SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode);
|
||||
SDL_InsertIntoHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, (void *)(uintptr_t)keycode, true);
|
||||
|
||||
bool update_keycode = true;
|
||||
if (SDL_FindInHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, &value)) {
|
||||
Uint32 existing_value = (Uint32)(uintptr_t)value;
|
||||
SDL_Keymod existing_modstate = (SDL_Keymod)(existing_value >> 16);
|
||||
const Uint32 existing_value = (Uint32)(uintptr_t)value;
|
||||
const SDL_Keymod existing_modstate = (SDL_Keymod)(existing_value >> 16);
|
||||
|
||||
// Keep the simplest combination of scancode and modifiers to generate this keycode
|
||||
if (existing_modstate <= modstate) {
|
||||
update_keycode = false;
|
||||
} else {
|
||||
SDL_RemoveFromHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode);
|
||||
}
|
||||
}
|
||||
if (update_keycode) {
|
||||
SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key);
|
||||
SDL_InsertIntoHashTable(keymap->keycode_to_scancode, (void *)(uintptr_t)keycode, (void *)(uintptr_t)key, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +104,7 @@ SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_
|
||||
{
|
||||
SDL_Keycode keycode;
|
||||
|
||||
Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode;
|
||||
const Uint32 key = ((Uint32)NormalizeModifierStateForKeymap(modstate) << 16) | scancode;
|
||||
const void *value;
|
||||
if (keymap && SDL_FindInHashTable(keymap->scancode_to_keycode, (void *)(uintptr_t)key, &value)) {
|
||||
keycode = (SDL_Keycode)(uintptr_t)value;
|
||||
@@ -777,7 +773,7 @@ static const char *SDL_scancode_names[SDL_SCANCODE_COUNT] =
|
||||
/* 97 */ "Keypad 9",
|
||||
/* 98 */ "Keypad 0",
|
||||
/* 99 */ "Keypad .",
|
||||
/* 100 */ NULL,
|
||||
/* 100 */ "NonUSBackslash",
|
||||
/* 101 */ "Application",
|
||||
/* 102 */ "Power",
|
||||
/* 103 */ "Keypad =",
|
||||
@@ -812,24 +808,24 @@ static const char *SDL_scancode_names[SDL_SCANCODE_COUNT] =
|
||||
/* 132 */ NULL,
|
||||
/* 133 */ "Keypad ,",
|
||||
/* 134 */ "Keypad = (AS400)",
|
||||
/* 135 */ NULL,
|
||||
/* 136 */ NULL,
|
||||
/* 137 */ NULL,
|
||||
/* 138 */ NULL,
|
||||
/* 139 */ NULL,
|
||||
/* 140 */ NULL,
|
||||
/* 141 */ NULL,
|
||||
/* 142 */ NULL,
|
||||
/* 143 */ NULL,
|
||||
/* 144 */ NULL,
|
||||
/* 145 */ NULL,
|
||||
/* 146 */ NULL,
|
||||
/* 147 */ NULL,
|
||||
/* 148 */ NULL,
|
||||
/* 149 */ NULL,
|
||||
/* 150 */ NULL,
|
||||
/* 151 */ NULL,
|
||||
/* 152 */ NULL,
|
||||
/* 135 */ "International 1",
|
||||
/* 136 */ "International 2",
|
||||
/* 137 */ "International 3",
|
||||
/* 138 */ "International 4",
|
||||
/* 139 */ "International 5",
|
||||
/* 140 */ "International 6",
|
||||
/* 141 */ "International 7",
|
||||
/* 142 */ "International 8",
|
||||
/* 143 */ "International 9",
|
||||
/* 144 */ "Language 1",
|
||||
/* 145 */ "Language 2",
|
||||
/* 146 */ "Language 3",
|
||||
/* 147 */ "Language 4",
|
||||
/* 148 */ "Language 5",
|
||||
/* 149 */ "Language 6",
|
||||
/* 150 */ "Language 7",
|
||||
/* 151 */ "Language 8",
|
||||
/* 152 */ "Language 9",
|
||||
/* 153 */ "AltErase",
|
||||
/* 154 */ "SysReq",
|
||||
/* 155 */ "Cancel",
|
||||
|
||||
+13
-10
@@ -484,7 +484,7 @@ SDL_SystemCursor SDL_GetDefaultSystemCursor(void)
|
||||
const char *value = SDL_GetHint(SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR);
|
||||
if (value) {
|
||||
int index = SDL_atoi(value);
|
||||
if (0 <= index && index < (int)SDL_SYSTEM_CURSOR_COUNT) {
|
||||
if (0 <= index && index < SDL_SYSTEM_CURSOR_COUNT) {
|
||||
id = (SDL_SystemCursor)index;
|
||||
}
|
||||
}
|
||||
@@ -631,7 +631,7 @@ void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouse
|
||||
{
|
||||
if (window && !relative) {
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, true), (mouseID != SDL_TOUCH_MOUSEID))) {
|
||||
if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, true), (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -689,7 +689,7 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL
|
||||
|
||||
// SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events
|
||||
if (mouse->mouse_touch_events) {
|
||||
if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
|
||||
if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && !relative && track_mouse_down) {
|
||||
if (window) {
|
||||
float normalized_x = x / (float)window->w;
|
||||
float normalized_y = y / (float)window->h;
|
||||
@@ -748,10 +748,8 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL
|
||||
|
||||
// modify internal state
|
||||
{
|
||||
if (relative) {
|
||||
mouse->x_accu += xrel;
|
||||
mouse->y_accu += yrel;
|
||||
}
|
||||
mouse->x_accu += xrel;
|
||||
mouse->y_accu += yrel;
|
||||
|
||||
if (relative && mouse->has_position) {
|
||||
mouse->x += xrel;
|
||||
@@ -779,7 +777,7 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL
|
||||
|
||||
// Post the event, if desired
|
||||
if (SDL_EventEnabled(SDL_EVENT_MOUSE_MOTION)) {
|
||||
if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID) {
|
||||
if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) {
|
||||
// We're not in relative mode, so all mouse events are global mouse events
|
||||
mouseID = SDL_GLOBAL_MOUSE_ID;
|
||||
}
|
||||
@@ -882,7 +880,7 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL
|
||||
|
||||
// SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events
|
||||
if (mouse->mouse_touch_events) {
|
||||
if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) {
|
||||
if (mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID && button == SDL_BUTTON_LEFT) {
|
||||
if (down) {
|
||||
track_mouse_down = true;
|
||||
} else {
|
||||
@@ -950,7 +948,7 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL
|
||||
|
||||
// Post the event, if desired
|
||||
if (SDL_EventEnabled(type)) {
|
||||
if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID) {
|
||||
if ((!mouse->relative_mode || mouse->warp_emulation_active) && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) {
|
||||
// We're not in relative mode, so all mouse events are global mouse events
|
||||
mouseID = SDL_GLOBAL_MOUSE_ID;
|
||||
} else {
|
||||
@@ -1483,6 +1481,11 @@ SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allow specifying the hot spot via properties on the surface
|
||||
SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
|
||||
hot_x = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_X_NUMBER, hot_x);
|
||||
hot_y = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER, hot_y);
|
||||
|
||||
// Sanity check the hot spot
|
||||
if ((hot_x < 0) || (hot_y < 0) ||
|
||||
(hot_x >= surface->w) || (hot_y >= surface->h)) {
|
||||
|
||||
@@ -346,7 +346,7 @@ void SDL_SendPenTouch(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *windo
|
||||
if (eraser && ((input_state & SDL_PEN_INPUT_ERASER_TIP) == 0)) {
|
||||
input_state |= SDL_PEN_INPUT_ERASER_TIP;
|
||||
send_event = true;
|
||||
} else if (!down && (input_state & SDL_PEN_INPUT_ERASER_TIP)) {
|
||||
} else if (!eraser && (input_state & SDL_PEN_INPUT_ERASER_TIP)) {
|
||||
input_state &= ~SDL_PEN_INPUT_ERASER_TIP;
|
||||
send_event = true;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,39 @@
|
||||
// Window event handling code for SDL
|
||||
|
||||
#include "SDL_events_c.h"
|
||||
#include "SDL_eventwatch_c.h"
|
||||
#include "SDL_mouse_c.h"
|
||||
#include "../render/SDL_sysrender.h"
|
||||
#include "../tray/SDL_tray_utils.h"
|
||||
|
||||
|
||||
#define NUM_WINDOW_EVENT_WATCH_PRIORITIES (SDL_WINDOW_EVENT_WATCH_NORMAL + 1)
|
||||
|
||||
static SDL_EventWatchList SDL_window_event_watchers[NUM_WINDOW_EVENT_WATCH_PRIORITIES];
|
||||
|
||||
void SDL_InitWindowEventWatch(void)
|
||||
{
|
||||
for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) {
|
||||
SDL_InitEventWatchList(&SDL_window_event_watchers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_QuitWindowEventWatch(void)
|
||||
{
|
||||
for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) {
|
||||
SDL_QuitEventWatchList(&SDL_window_event_watchers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
SDL_AddEventWatchList(&SDL_window_event_watchers[priority], filter, userdata);
|
||||
}
|
||||
|
||||
void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
SDL_RemoveEventWatchList(&SDL_window_event_watchers[priority], filter, userdata);
|
||||
}
|
||||
|
||||
static bool SDLCALL RemoveSupercededWindowEvents(void *userdata, SDL_Event *event)
|
||||
{
|
||||
SDL_Event *new_event = (SDL_Event *)userdata;
|
||||
@@ -191,10 +220,8 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data
|
||||
event.window.data2 = data2;
|
||||
event.window.windowID = window->id;
|
||||
|
||||
for (int i = 0; i < window->num_renderers; ++i) {
|
||||
SDL_Renderer *renderer = window->renderers[i];
|
||||
SDL_RendererEventWatch(renderer, &event);
|
||||
}
|
||||
SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_EARLY], &event);
|
||||
SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_NORMAL], &event);
|
||||
|
||||
if (SDL_EventEnabled(windowevent)) {
|
||||
// Fixes queue overflow with move/resize events that aren't processed
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
#ifndef SDL_windowevents_c_h_
|
||||
#define SDL_windowevents_c_h_
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_WINDOW_EVENT_WATCH_EARLY,
|
||||
SDL_WINDOW_EVENT_WATCH_NORMAL
|
||||
} SDL_WindowEventWatchPriority;
|
||||
|
||||
extern void SDL_InitWindowEventWatch(void);
|
||||
extern void SDL_QuitWindowEventWatch(void);
|
||||
extern void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata);
|
||||
extern void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata);
|
||||
|
||||
extern bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2);
|
||||
|
||||
#endif // SDL_windowevents_c_h_
|
||||
@@ -169,7 +169,7 @@ static SDL_Scancode const linux_scancode_table[] = {
|
||||
/* 140, 0x08c */ SDL_SCANCODE_UNKNOWN, // KEY_CALC
|
||||
/* 141, 0x08d */ SDL_SCANCODE_UNKNOWN, // KEY_SETUP
|
||||
/* 142, 0x08e */ SDL_SCANCODE_SLEEP, // KEY_SLEEP
|
||||
/* 143, 0x08f */ SDL_SCANCODE_UNKNOWN, // KEY_WAKEUP
|
||||
/* 143, 0x08f */ SDL_SCANCODE_WAKE, // KEY_WAKEUP
|
||||
/* 144, 0x090 */ SDL_SCANCODE_UNKNOWN, // KEY_FILE
|
||||
/* 145, 0x091 */ SDL_SCANCODE_UNKNOWN, // KEY_SENDFILE
|
||||
/* 146, 0x092 */ SDL_SCANCODE_UNKNOWN, // KEY_DELETEFILE
|
||||
@@ -282,7 +282,6 @@ static SDL_Scancode const linux_scancode_table[] = {
|
||||
/* 253, 0x0fd */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 254, 0x0fe */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 255, 0x0ff */ SDL_SCANCODE_UNKNOWN,
|
||||
#if 0 // We don't have any mapped scancodes after this point (yet)
|
||||
/* 256, 0x100 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 257, 0x101 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 258, 0x102 */ SDL_SCANCODE_UNKNOWN,
|
||||
@@ -380,9 +379,9 @@ static SDL_Scancode const linux_scancode_table[] = {
|
||||
/* 350, 0x15e */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 351, 0x15f */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 352, 0x160 */ SDL_SCANCODE_UNKNOWN, // KEY_OK
|
||||
/* 353, 0x161 */ SDL_SCANCODE_UNKNOWN, // KEY_SELECT
|
||||
/* 353, 0x161 */ SDL_SCANCODE_SELECT, // KEY_SELECT
|
||||
/* 354, 0x162 */ SDL_SCANCODE_UNKNOWN, // KEY_GOTO
|
||||
/* 355, 0x163 */ SDL_SCANCODE_UNKNOWN, // KEY_CLEAR
|
||||
/* 355, 0x163 */ SDL_SCANCODE_CLEAR, // KEY_CLEAR
|
||||
/* 356, 0x164 */ SDL_SCANCODE_UNKNOWN, // KEY_POWER2
|
||||
/* 357, 0x165 */ SDL_SCANCODE_UNKNOWN, // KEY_OPTION
|
||||
/* 358, 0x166 */ SDL_SCANCODE_UNKNOWN, // KEY_INFO
|
||||
@@ -400,7 +399,7 @@ static SDL_Scancode const linux_scancode_table[] = {
|
||||
/* 370, 0x172 */ SDL_SCANCODE_UNKNOWN, // KEY_SUBTITLE
|
||||
/* 371, 0x173 */ SDL_SCANCODE_UNKNOWN, // KEY_ANGLE
|
||||
/* 372, 0x174 */ SDL_SCANCODE_UNKNOWN, // KEY_FULL_SCREEN
|
||||
/* 373, 0x175 */ SDL_SCANCODE_UNKNOWN, // KEY_MODE
|
||||
/* 373, 0x175 */ SDL_SCANCODE_MODE, // KEY_MODE
|
||||
/* 374, 0x176 */ SDL_SCANCODE_UNKNOWN, // KEY_KEYBOARD
|
||||
/* 375, 0x177 */ SDL_SCANCODE_UNKNOWN, // KEY_ASPECT_RATIO
|
||||
/* 376, 0x178 */ SDL_SCANCODE_UNKNOWN, // KEY_PC
|
||||
@@ -429,8 +428,9 @@ static SDL_Scancode const linux_scancode_table[] = {
|
||||
/* 399, 0x18f */ SDL_SCANCODE_UNKNOWN, // KEY_GREEN
|
||||
/* 400, 0x190 */ SDL_SCANCODE_UNKNOWN, // KEY_YELLOW
|
||||
/* 401, 0x191 */ SDL_SCANCODE_UNKNOWN, // KEY_BLUE
|
||||
/* 402, 0x192 */ SDL_SCANCODE_UNKNOWN, // KEY_CHANNELUP
|
||||
/* 403, 0x193 */ SDL_SCANCODE_UNKNOWN, // KEY_CHANNELDOWN
|
||||
/* 402, 0x192 */ SDL_SCANCODE_CHANNEL_INCREMENT, // KEY_CHANNELUP
|
||||
/* 403, 0x193 */ SDL_SCANCODE_CHANNEL_DECREMENT, // KEY_CHANNELDOWN
|
||||
#if 0 // We don't have any mapped scancodes after this point (yet)
|
||||
/* 404, 0x194 */ SDL_SCANCODE_UNKNOWN, // KEY_FIRST
|
||||
/* 405, 0x195 */ SDL_SCANCODE_UNKNOWN, // KEY_LAST
|
||||
/* 406, 0x196 */ SDL_SCANCODE_UNKNOWN, // KEY_AB
|
||||
|
||||
@@ -188,6 +188,12 @@ static bool WildcardMatch(const char *pattern, const char *str, bool *matched_to
|
||||
sch = *str;
|
||||
pch = *pattern;
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
if (sch == '\\') {
|
||||
sch = '/';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// '*' at the end can be ignored, they are allowed to match nothing.
|
||||
|
||||
+31
-1
@@ -158,6 +158,9 @@
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
static const SDL_GPUBootstrap *backends[] = {
|
||||
#ifdef SDL_GPU_PRIVATE
|
||||
&PrivateGPUDriver,
|
||||
#endif
|
||||
#ifdef SDL_GPU_METAL
|
||||
&MetalDriver,
|
||||
#endif
|
||||
@@ -605,6 +608,7 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize(
|
||||
case SDL_GPU_TEXTUREFORMAT_R8_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_A8_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8_INT:
|
||||
return 1;
|
||||
case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM:
|
||||
@@ -613,9 +617,11 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize(
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_D16_UNORM:
|
||||
return 2;
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM:
|
||||
@@ -628,11 +634,15 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize(
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_D24_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_D32_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT:
|
||||
return 4;
|
||||
case SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT:
|
||||
@@ -640,10 +650,15 @@ Uint32 SDL_GPUTextureFormatTexelBlockSize(
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_INT:
|
||||
return 8;
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT:
|
||||
return 16;
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM:
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM:
|
||||
@@ -842,6 +857,12 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
|
||||
SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!");
|
||||
return NULL;
|
||||
}
|
||||
for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers; i += 1) {
|
||||
if (graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate != 0) {
|
||||
SDL_assert_release(!"For all vertex buffer descriptions, instance_step_rate must be 0!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Uint32 locations[MAX_VERTEX_ATTRIBUTES];
|
||||
for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) {
|
||||
CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL);
|
||||
@@ -850,9 +871,18 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
|
||||
for (Uint32 j = 0; j < i; j += 1) {
|
||||
if (locations[j] == locations[i]) {
|
||||
SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (graphicsPipelineCreateInfo->multisample_state.enable_mask) {
|
||||
SDL_assert_release(!"For multisample states, enable_mask must be false!");
|
||||
return NULL;
|
||||
}
|
||||
if (graphicsPipelineCreateInfo->multisample_state.sample_mask != 0) {
|
||||
SDL_assert_release(!"For multisample states, sample_mask must be 0!");
|
||||
return NULL;
|
||||
}
|
||||
if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
|
||||
CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL)
|
||||
}
|
||||
|
||||
+13
-1
@@ -173,12 +173,18 @@ static inline Sint32 Texture_GetBlockWidth(
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_D16_UNORM:
|
||||
@@ -287,12 +293,18 @@ static inline Sint32 Texture_GetBlockHeight(
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT:
|
||||
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_D16_UNORM:
|
||||
@@ -977,7 +989,7 @@ extern "C" {
|
||||
extern SDL_GPUBootstrap VulkanDriver;
|
||||
extern SDL_GPUBootstrap D3D12Driver;
|
||||
extern SDL_GPUBootstrap MetalDriver;
|
||||
extern SDL_GPUBootstrap PS5Driver;
|
||||
extern SDL_GPUBootstrap PrivateGPUDriver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -2028,7 +2028,7 @@ static void D3D12_InsertDebugLabel(
|
||||
d3d12CommandBuffer->graphicsCommandList,
|
||||
0,
|
||||
wchar_text,
|
||||
(UINT)SDL_wcslen(wchar_text));
|
||||
(UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR));
|
||||
|
||||
SDL_free(wchar_text);
|
||||
}
|
||||
@@ -2044,7 +2044,7 @@ static void D3D12_PushDebugGroup(
|
||||
d3d12CommandBuffer->graphicsCommandList,
|
||||
0,
|
||||
wchar_text,
|
||||
(UINT)SDL_wcslen(wchar_text));
|
||||
(UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR));
|
||||
|
||||
SDL_free(wchar_text);
|
||||
}
|
||||
@@ -2928,7 +2928,7 @@ static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState verte
|
||||
desc[i].AlignedByteOffset = attribute.offset;
|
||||
desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate];
|
||||
desc[i].InstanceDataStepRate = (vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
|
||||
? vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].instance_step_rate
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
@@ -3010,15 +3010,13 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Uint32 sampleMask = createinfo->multisample_state.enable_mask ?
|
||||
createinfo->multisample_state.sample_mask :
|
||||
0xFFFFFFFF;
|
||||
|
||||
psoDesc.SampleMask = sampleMask;
|
||||
psoDesc.SampleMask = 0xFFFFFFFF;
|
||||
psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->multisample_state.sample_count];
|
||||
psoDesc.SampleDesc.Quality = (createinfo->multisample_state.sample_count > SDL_GPU_SAMPLECOUNT_1) ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0;
|
||||
|
||||
psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format];
|
||||
if (createinfo->target_info.has_depth_stencil_target) {
|
||||
psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format];
|
||||
}
|
||||
psoDesc.NumRenderTargets = createinfo->target_info.num_color_targets;
|
||||
for (uint32_t i = 0; i < createinfo->target_info.num_color_targets; i += 1) {
|
||||
psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[createinfo->target_info.color_target_descriptions[i].format];
|
||||
@@ -6737,7 +6735,7 @@ static bool D3D12_INTERNAL_CreateSwapchain(
|
||||
swapchainDesc.SampleDesc.Quality = 0;
|
||||
swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapchainDesc.BufferCount = windowData->swapchainTextureCount;
|
||||
swapchainDesc.Scaling = DXGI_SCALING_STRETCH;
|
||||
swapchainDesc.Scaling = DXGI_SCALING_NONE;
|
||||
swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapchainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
swapchainDesc.Flags = 0;
|
||||
|
||||
@@ -478,8 +478,6 @@ typedef struct MetalGraphicsPipeline
|
||||
{
|
||||
id<MTLRenderPipelineState> handle;
|
||||
|
||||
Uint32 sample_mask;
|
||||
|
||||
SDL_GPURasterizerState rasterizerState;
|
||||
SDL_GPUPrimitiveType primitiveType;
|
||||
|
||||
@@ -1181,9 +1179,7 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
|
||||
for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
|
||||
binding = METAL_FIRST_VERTEX_BUFFER_SLOT + createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
|
||||
vertexDescriptor.layouts[binding].stepFunction = SDLToMetal_StepFunction[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate];
|
||||
vertexDescriptor.layouts[binding].stepRate = (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
|
||||
? createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate
|
||||
: 1;
|
||||
vertexDescriptor.layouts[binding].stepRate = 1;
|
||||
vertexDescriptor.layouts[binding].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
|
||||
}
|
||||
|
||||
@@ -1202,13 +1198,8 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
|
||||
SET_ERROR_AND_RETURN("Creating render pipeline failed: %s", [[error description] UTF8String], NULL);
|
||||
}
|
||||
|
||||
Uint32 sampleMask = createinfo->multisample_state.enable_mask ?
|
||||
createinfo->multisample_state.sample_mask :
|
||||
0xFFFFFFFF;
|
||||
|
||||
result = SDL_calloc(1, sizeof(MetalGraphicsPipeline));
|
||||
result->handle = pipelineState;
|
||||
result->sample_mask = sampleMask;
|
||||
result->depth_stencil_state = depthStencilState;
|
||||
result->rasterizerState = createinfo->rasterizer_state;
|
||||
result->primitiveType = createinfo->primitive_type;
|
||||
|
||||
+145
-182
@@ -56,8 +56,6 @@ typedef struct VulkanExtensions
|
||||
|
||||
// Core since 1.2, but requires annoying paperwork to implement
|
||||
Uint8 KHR_driver_properties;
|
||||
// EXT, probably not going to be Core
|
||||
Uint8 EXT_vertex_attribute_divisor;
|
||||
// Only required for special implementations (i.e. MoltenVK)
|
||||
Uint8 KHR_portability_subset;
|
||||
// Only required for decoding HDR ASTC textures
|
||||
@@ -1586,7 +1584,7 @@ static void VULKAN_INTERNAL_RemoveMemoryUsedRegion(
|
||||
|
||||
static bool VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
|
||||
Uint32 memoryTypeIndex,
|
||||
Uint32 *memoryTypeIndexArray,
|
||||
const Uint32 *memoryTypeIndexArray,
|
||||
Uint32 count)
|
||||
{
|
||||
Uint32 i = 0;
|
||||
@@ -2924,57 +2922,74 @@ static void VULKAN_INTERNAL_DestroyFramebuffer(
|
||||
SDL_free(framebuffer);
|
||||
}
|
||||
|
||||
typedef struct CheckOneFramebufferForRemovalData
|
||||
{
|
||||
Uint32 keysToRemoveCapacity;
|
||||
Uint32 keysToRemoveCount;
|
||||
FramebufferHashTableKey **keysToRemove;
|
||||
VkImageView view;
|
||||
} CheckOneFramebufferForRemovalData;
|
||||
|
||||
static bool SDLCALL CheckOneFramebufferForRemoval(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue)
|
||||
{
|
||||
CheckOneFramebufferForRemovalData *data = (CheckOneFramebufferForRemovalData *) userdata;
|
||||
FramebufferHashTableKey *key = (FramebufferHashTableKey *) vkey;
|
||||
VkImageView view = data->view;
|
||||
bool remove = false;
|
||||
|
||||
for (Uint32 i = 0; i < key->numColorTargets; i += 1) {
|
||||
if (key->colorAttachmentViews[i] == view) {
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) {
|
||||
if (key->resolveAttachmentViews[i] == view) {
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
if (key->depthStencilAttachmentView == view) {
|
||||
remove = true;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
if (data->keysToRemoveCount == data->keysToRemoveCapacity) {
|
||||
data->keysToRemoveCapacity *= 2;
|
||||
void *ptr = SDL_realloc(data->keysToRemove, data->keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
|
||||
if (!ptr) {
|
||||
return false; // ugh, stop iterating. We're in trouble.
|
||||
}
|
||||
data->keysToRemove = (FramebufferHashTableKey **) ptr;
|
||||
}
|
||||
data->keysToRemove[data->keysToRemoveCount] = key;
|
||||
data->keysToRemoveCount++;
|
||||
}
|
||||
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_RemoveFramebuffersContainingView(
|
||||
VulkanRenderer *renderer,
|
||||
VkImageView view)
|
||||
{
|
||||
FramebufferHashTableKey *key;
|
||||
VulkanFramebuffer *value;
|
||||
void *iter = NULL;
|
||||
|
||||
// Can't remove while iterating!
|
||||
Uint32 keysToRemoveCapacity = 8;
|
||||
Uint32 keysToRemoveCount = 0;
|
||||
FramebufferHashTableKey **keysToRemove = SDL_malloc(keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
|
||||
|
||||
CheckOneFramebufferForRemovalData data = { 8, 0, NULL, view };
|
||||
data.keysToRemove = (FramebufferHashTableKey **) SDL_malloc(data.keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
|
||||
if (!data.keysToRemove) {
|
||||
return; // uhoh.
|
||||
}
|
||||
|
||||
SDL_LockMutex(renderer->framebufferFetchLock);
|
||||
|
||||
while (SDL_IterateHashTable(renderer->framebufferHashTable, (const void **)&key, (const void **)&value, &iter)) {
|
||||
bool remove = false;
|
||||
for (Uint32 i = 0; i < key->numColorTargets; i += 1) {
|
||||
if (key->colorAttachmentViews[i] == view) {
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) {
|
||||
if (key->resolveAttachmentViews[i] == view) {
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
if (key->depthStencilAttachmentView == view) {
|
||||
remove = true;
|
||||
}
|
||||
SDL_IterateHashTable(renderer->framebufferHashTable, CheckOneFramebufferForRemoval, &data);
|
||||
|
||||
if (remove) {
|
||||
if (keysToRemoveCount == keysToRemoveCapacity) {
|
||||
keysToRemoveCapacity *= 2;
|
||||
keysToRemove = SDL_realloc(
|
||||
keysToRemove,
|
||||
keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
|
||||
}
|
||||
|
||||
keysToRemove[keysToRemoveCount] = key;
|
||||
keysToRemoveCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < keysToRemoveCount; i += 1) {
|
||||
SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)keysToRemove[i]);
|
||||
for (Uint32 i = 0; i < data.keysToRemoveCount; i += 1) {
|
||||
SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)data.keysToRemove[i]);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(renderer->framebufferFetchLock);
|
||||
|
||||
SDL_free(keysToRemove);
|
||||
SDL_free(data.keysToRemove);
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_DestroyTexture(
|
||||
@@ -3280,7 +3295,7 @@ static void VULKAN_INTERNAL_DestroyDescriptorSetCache(
|
||||
|
||||
// Hashtable functions
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const void *key, void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key;
|
||||
/* The algorithm for this hashing function
|
||||
@@ -3299,19 +3314,19 @@ static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const v
|
||||
result = result * hashFactor + hashTableKey->fragmentUniformBufferCount;
|
||||
return result;
|
||||
}
|
||||
static bool VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0;
|
||||
}
|
||||
static void VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value;
|
||||
VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout);
|
||||
SDL_free((void*)key);
|
||||
}
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const void *key, void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key;
|
||||
/* The algorithm for this hashing function
|
||||
@@ -3329,20 +3344,20 @@ static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const vo
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value;
|
||||
VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout);
|
||||
SDL_free((void*)key);
|
||||
}
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key;
|
||||
|
||||
@@ -3362,42 +3377,40 @@ static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, v
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_DescriptorSetLayoutHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
DescriptorSetLayout *layout = (DescriptorSetLayout *)value;
|
||||
VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout);
|
||||
SDL_free((void*)key);
|
||||
}
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_CommandPoolHashFunction(const void *key, void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
return (Uint32)((CommandPoolHashTableKey *)key)->threadID;
|
||||
}
|
||||
|
||||
static bool VULKAN_INTERNAL_CommandPoolHashKeyMatch(const void *aKey, const void *bKey, void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey;
|
||||
CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey;
|
||||
return a->threadID == b->threadID;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_CommandPoolHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
VulkanCommandPool *pool = (VulkanCommandPool *)value;
|
||||
VULKAN_INTERNAL_DestroyCommandPool(renderer, pool);
|
||||
SDL_free((void *)key);
|
||||
}
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_RenderPassHashFunction(
|
||||
const void *key,
|
||||
void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key;
|
||||
|
||||
@@ -3429,10 +3442,7 @@ static Uint32 VULKAN_INTERNAL_RenderPassHashFunction(
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool VULKAN_INTERNAL_RenderPassHashKeyMatch(
|
||||
const void *aKey,
|
||||
const void *bKey,
|
||||
void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey;
|
||||
RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey;
|
||||
@@ -3492,9 +3502,9 @@ static bool VULKAN_INTERNAL_RenderPassHashKeyMatch(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_RenderPassHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value;
|
||||
renderer->vkDestroyRenderPass(
|
||||
renderer->logicalDevice,
|
||||
@@ -3504,9 +3514,7 @@ static void VULKAN_INTERNAL_RenderPassHashNuke(const void *key, const void *valu
|
||||
SDL_free((void *)key);
|
||||
}
|
||||
|
||||
static Uint32 VULKAN_INTERNAL_FramebufferHashFunction(
|
||||
const void *key,
|
||||
void *data)
|
||||
static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key)
|
||||
{
|
||||
FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key;
|
||||
|
||||
@@ -3531,10 +3539,7 @@ static Uint32 VULKAN_INTERNAL_FramebufferHashFunction(
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool VULKAN_INTERNAL_FramebufferHashKeyMatch(
|
||||
const void *aKey,
|
||||
const void *bKey,
|
||||
void *data)
|
||||
static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
|
||||
{
|
||||
FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey;
|
||||
FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey;
|
||||
@@ -3574,9 +3579,9 @@ static bool VULKAN_INTERNAL_FramebufferHashKeyMatch(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_FramebufferHashNuke(const void *key, const void *value, void *data)
|
||||
static void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)data;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)userdata;
|
||||
VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value;
|
||||
VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer);
|
||||
SDL_free((void *)key);
|
||||
@@ -3845,7 +3850,7 @@ static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout(
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->descriptorSetLayoutHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)layout);
|
||||
(const void *)layout, true);
|
||||
|
||||
return layout;
|
||||
}
|
||||
@@ -3962,7 +3967,7 @@ static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipeli
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->graphicsPipelineResourceLayoutHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)pipelineResourceLayout);
|
||||
(const void *)pipelineResourceLayout, true);
|
||||
|
||||
return pipelineResourceLayout;
|
||||
}
|
||||
@@ -4063,7 +4068,7 @@ static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipeline
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->computePipelineResourceLayoutHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)pipelineResourceLayout);
|
||||
(const void *)pipelineResourceLayout, true);
|
||||
|
||||
return pipelineResourceLayout;
|
||||
}
|
||||
@@ -4441,7 +4446,7 @@ static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat(
|
||||
|
||||
static bool VULKAN_INTERNAL_VerifySwapPresentMode(
|
||||
VkPresentModeKHR presentMode,
|
||||
VkPresentModeKHR *availablePresentModes,
|
||||
const VkPresentModeKHR *availablePresentModes,
|
||||
Uint32 availablePresentModesLength)
|
||||
{
|
||||
Uint32 i;
|
||||
@@ -4629,7 +4634,7 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
|
||||
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchainCreateInfo.queueFamilyIndexCount = 0;
|
||||
swapchainCreateInfo.pQueueFamilyIndices = NULL;
|
||||
swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform;
|
||||
swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode];
|
||||
swapchainCreateInfo.clipped = VK_TRUE;
|
||||
@@ -5330,7 +5335,7 @@ static void VULKAN_DrawIndexedPrimitives(
|
||||
Uint32 firstInstance)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
|
||||
|
||||
@@ -5351,7 +5356,7 @@ static void VULKAN_DrawPrimitives(
|
||||
Uint32 firstInstance)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
|
||||
|
||||
@@ -5370,7 +5375,7 @@ static void VULKAN_DrawPrimitivesIndirect(
|
||||
Uint32 drawCount)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
|
||||
Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand);
|
||||
Uint32 i;
|
||||
@@ -5407,7 +5412,7 @@ static void VULKAN_DrawIndexedPrimitivesIndirect(
|
||||
Uint32 drawCount)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
|
||||
Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand);
|
||||
Uint32 i;
|
||||
@@ -5540,12 +5545,12 @@ static void VULKAN_InsertDebugLabel(
|
||||
const char *text)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VkDebugUtilsLabelEXT labelInfo;
|
||||
|
||||
if (renderer->supportsDebugUtils) {
|
||||
SDL_zero(labelInfo);
|
||||
labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
labelInfo.pNext = NULL;
|
||||
labelInfo.pLabelName = text;
|
||||
|
||||
renderer->vkCmdInsertDebugUtilsLabelEXT(
|
||||
@@ -5559,12 +5564,12 @@ static void VULKAN_PushDebugGroup(
|
||||
const char *name)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VkDebugUtilsLabelEXT labelInfo;
|
||||
|
||||
if (renderer->supportsDebugUtils) {
|
||||
SDL_zero(labelInfo);
|
||||
labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
labelInfo.pNext = NULL;
|
||||
labelInfo.pLabelName = name;
|
||||
|
||||
renderer->vkCmdBeginDebugUtilsLabelEXT(
|
||||
@@ -5577,7 +5582,7 @@ static void VULKAN_PopDebugGroup(
|
||||
SDL_GPUCommandBuffer *commandBuffer)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
if (renderer->supportsDebugUtils) {
|
||||
renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer);
|
||||
@@ -6195,11 +6200,8 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2];
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo;
|
||||
VkPipelineVertexInputDivisorStateCreateInfoEXT divisorStateCreateInfo;
|
||||
VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers);
|
||||
VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes);
|
||||
VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions = SDL_stack_alloc(VkVertexInputBindingDivisorDescriptionEXT, createinfo->vertex_input_state.num_vertex_buffers);
|
||||
Uint32 divisorDescriptionCount = 0;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo;
|
||||
|
||||
@@ -6282,10 +6284,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
|
||||
vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate];
|
||||
vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
|
||||
|
||||
if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
|
||||
divisorDescriptionCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) {
|
||||
@@ -6303,26 +6301,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes;
|
||||
vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions;
|
||||
|
||||
if (divisorDescriptionCount > 0) {
|
||||
divisorDescriptionCount = 0;
|
||||
|
||||
for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
|
||||
if (createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) {
|
||||
divisorDescriptions[divisorDescriptionCount].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
|
||||
divisorDescriptions[divisorDescriptionCount].divisor = createinfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate;
|
||||
|
||||
divisorDescriptionCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
divisorStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
|
||||
divisorStateCreateInfo.pNext = NULL;
|
||||
divisorStateCreateInfo.vertexBindingDivisorCount = divisorDescriptionCount;
|
||||
divisorStateCreateInfo.pVertexBindingDivisors = divisorDescriptions;
|
||||
|
||||
vertexInputStateCreateInfo.pNext = &divisorStateCreateInfo;
|
||||
}
|
||||
|
||||
// Topology
|
||||
|
||||
inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
@@ -6369,9 +6347,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
|
||||
// Multisample
|
||||
|
||||
Uint32 sampleMask = createinfo->multisample_state.enable_mask ?
|
||||
createinfo->multisample_state.sample_mask :
|
||||
0xFFFFFFFF;
|
||||
Uint32 sampleMask = 0xFFFFFFFF;
|
||||
|
||||
multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampleStateCreateInfo.pNext = NULL;
|
||||
@@ -6469,7 +6445,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
SDL_stack_free(vertexInputBindingDescriptions);
|
||||
SDL_stack_free(vertexInputAttributeDescriptions);
|
||||
SDL_stack_free(colorBlendAttachmentStates);
|
||||
SDL_stack_free(divisorDescriptions);
|
||||
SDL_free(graphicsPipeline);
|
||||
SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL);
|
||||
}
|
||||
@@ -6508,7 +6483,6 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
SDL_stack_free(vertexInputBindingDescriptions);
|
||||
SDL_stack_free(vertexInputAttributeDescriptions);
|
||||
SDL_stack_free(colorBlendAttachmentStates);
|
||||
SDL_stack_free(divisorDescriptions);
|
||||
|
||||
renderer->vkDestroyRenderPass(
|
||||
renderer->logicalDevice,
|
||||
@@ -6840,15 +6814,12 @@ static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer(
|
||||
Uint32 size,
|
||||
const char *debugName)
|
||||
{
|
||||
// We use dedicated allocations for download buffers to avoid an issue
|
||||
// where a defrag is triggered after submitting a download but before
|
||||
// waiting on the fence.
|
||||
return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer(
|
||||
(VulkanRenderer *)driverData,
|
||||
(VkDeviceSize)size,
|
||||
0,
|
||||
VULKAN_BUFFER_TYPE_TRANSFER,
|
||||
usage == SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD,
|
||||
true, // Dedicated allocations preserve the data even if a defrag is triggered.
|
||||
debugName);
|
||||
}
|
||||
|
||||
@@ -7140,7 +7111,7 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass(
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->renderPassHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)renderPassWrapper);
|
||||
(const void *)renderPassWrapper, true);
|
||||
|
||||
return renderPassHandle;
|
||||
}
|
||||
@@ -7285,7 +7256,7 @@ static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer(
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->framebufferHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)vulkanFramebuffer);
|
||||
(const void *)vulkanFramebuffer, true);
|
||||
|
||||
SDL_UnlockMutex(renderer->framebufferFetchLock);
|
||||
} else {
|
||||
@@ -7300,8 +7271,8 @@ static void VULKAN_INTERNAL_SetCurrentViewport(
|
||||
VulkanCommandBuffer *commandBuffer,
|
||||
const SDL_GPUViewport *viewport)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
vulkanCommandBuffer->currentViewport.x = viewport->x;
|
||||
vulkanCommandBuffer->currentViewport.width = viewport->w;
|
||||
@@ -7334,7 +7305,7 @@ static void VULKAN_INTERNAL_SetCurrentScissor(
|
||||
VulkanCommandBuffer *vulkanCommandBuffer,
|
||||
const SDL_Rect *scissor)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
vulkanCommandBuffer->currentScissor.offset.x = scissor->x;
|
||||
vulkanCommandBuffer->currentScissor.offset.y = scissor->y;
|
||||
@@ -7363,7 +7334,7 @@ static void VULKAN_INTERNAL_SetCurrentBlendConstants(
|
||||
VulkanCommandBuffer *vulkanCommandBuffer,
|
||||
SDL_FColor blendConstants)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
vulkanCommandBuffer->blendConstants[0] = blendConstants.r;
|
||||
vulkanCommandBuffer->blendConstants[1] = blendConstants.g;
|
||||
@@ -7390,7 +7361,7 @@ static void VULKAN_INTERNAL_SetCurrentStencilReference(
|
||||
VulkanCommandBuffer *vulkanCommandBuffer,
|
||||
Uint8 reference)
|
||||
{
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
vulkanCommandBuffer->stencilRef = reference;
|
||||
|
||||
@@ -7699,7 +7670,7 @@ static void VULKAN_BeginRenderPass(
|
||||
const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VkRenderPass renderPass;
|
||||
VulkanFramebuffer *framebuffer;
|
||||
|
||||
@@ -7911,7 +7882,7 @@ static void VULKAN_BindGraphicsPipeline(
|
||||
SDL_GPUGraphicsPipeline *graphicsPipeline)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline;
|
||||
|
||||
renderer->vkCmdBindPipeline(
|
||||
@@ -7976,7 +7947,7 @@ static void VULKAN_BindIndexBuffer(
|
||||
SDL_GPUIndexElementSize indexElementSize)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer;
|
||||
|
||||
VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
|
||||
@@ -8024,7 +7995,7 @@ static void VULKAN_EndRenderPass(
|
||||
SDL_GPUCommandBuffer *commandBuffer)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
Uint32 i;
|
||||
|
||||
renderer->vkCmdEndRenderPass(
|
||||
@@ -8139,7 +8110,7 @@ static void VULKAN_BindComputePipeline(
|
||||
SDL_GPUComputePipeline *computePipeline)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline;
|
||||
|
||||
renderer->vkCmdBindPipeline(
|
||||
@@ -8534,7 +8505,7 @@ static void VULKAN_DispatchCompute(
|
||||
Uint32 groupcountZ)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
|
||||
VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer);
|
||||
|
||||
@@ -8551,7 +8522,7 @@ static void VULKAN_DispatchComputeIndirect(
|
||||
Uint32 offset)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
|
||||
|
||||
VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer);
|
||||
@@ -8673,7 +8644,7 @@ static void VULKAN_UploadToTexture(
|
||||
bool cycle)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer;
|
||||
VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture;
|
||||
VulkanTextureSubresource *vulkanTextureSubresource;
|
||||
@@ -8729,7 +8700,7 @@ static void VULKAN_UploadToBuffer(
|
||||
bool cycle)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer;
|
||||
VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer;
|
||||
VkBufferCopy bufferCopy;
|
||||
@@ -8872,7 +8843,7 @@ static void VULKAN_CopyTextureToTexture(
|
||||
bool cycle)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanTextureSubresource *srcSubresource;
|
||||
VulkanTextureSubresource *dstSubresource;
|
||||
VkImageCopy imageCopy;
|
||||
@@ -8948,7 +8919,7 @@ static void VULKAN_CopyBufferToBuffer(
|
||||
bool cycle)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer;
|
||||
VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer;
|
||||
VkBufferCopy bufferCopy;
|
||||
@@ -8998,7 +8969,7 @@ static void VULKAN_GenerateMipmaps(
|
||||
SDL_GPUTexture *texture)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VulkanTextureContainer *container = (VulkanTextureContainer *)texture;
|
||||
VulkanTextureSubresource *srcTextureSubresource;
|
||||
VulkanTextureSubresource *dstTextureSubresource;
|
||||
@@ -9099,7 +9070,7 @@ static void VULKAN_Blit(
|
||||
const SDL_GPUBlitInfo *info)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture;
|
||||
TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture;
|
||||
VkImageBlit region;
|
||||
@@ -9389,7 +9360,7 @@ static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool(
|
||||
SDL_InsertIntoHashTable(
|
||||
renderer->commandPoolHashTable,
|
||||
(const void *)allocedKey,
|
||||
(const void *)vulkanCommandPool);
|
||||
(const void *)vulkanCommandPool, true);
|
||||
|
||||
return vulkanCommandPool;
|
||||
}
|
||||
@@ -9832,7 +9803,7 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
|
||||
Uint32 *swapchainTextureHeight)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
Uint32 swapchainImageIndex;
|
||||
WindowData *windowData;
|
||||
VkResult acquireResult = VK_SUCCESS;
|
||||
@@ -10450,7 +10421,7 @@ static bool VULKAN_Submit(
|
||||
SDL_GPUCommandBuffer *commandBuffer)
|
||||
{
|
||||
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
|
||||
VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer;
|
||||
VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
|
||||
VkSubmitInfo submitInfo;
|
||||
VkPresentInfoKHR presentInfo;
|
||||
VulkanPresentData *presentData;
|
||||
@@ -10891,7 +10862,7 @@ static inline Uint8 CheckDeviceExtensions(
|
||||
supports->ext = 1; \
|
||||
}
|
||||
CHECK(KHR_swapchain)
|
||||
else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(EXT_vertex_attribute_divisor) else CHECK(KHR_portability_subset) else CHECK(EXT_texture_compression_astc_hdr)
|
||||
else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(KHR_portability_subset) else CHECK(EXT_texture_compression_astc_hdr)
|
||||
#undef CHECK
|
||||
}
|
||||
|
||||
@@ -10905,7 +10876,6 @@ static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports)
|
||||
supports->KHR_swapchain +
|
||||
supports->KHR_maintenance1 +
|
||||
supports->KHR_driver_properties +
|
||||
supports->EXT_vertex_attribute_divisor +
|
||||
supports->KHR_portability_subset +
|
||||
supports->EXT_texture_compression_astc_hdr);
|
||||
}
|
||||
@@ -10922,7 +10892,6 @@ static inline void CreateDeviceExtensionArray(
|
||||
CHECK(KHR_swapchain)
|
||||
CHECK(KHR_maintenance1)
|
||||
CHECK(KHR_driver_properties)
|
||||
CHECK(EXT_vertex_attribute_divisor)
|
||||
CHECK(KHR_portability_subset)
|
||||
CHECK(EXT_texture_compression_astc_hdr)
|
||||
#undef CHECK
|
||||
@@ -11223,7 +11192,7 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
|
||||
&queueFamilyCount,
|
||||
NULL);
|
||||
|
||||
queueProps = (VkQueueFamilyProperties *)SDL_stack_alloc(
|
||||
queueProps = SDL_stack_alloc(
|
||||
VkQueueFamilyProperties,
|
||||
queueFamilyCount);
|
||||
renderer->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
@@ -11739,59 +11708,53 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
|
||||
|
||||
// Initialize caches
|
||||
|
||||
// manually synchronized due to submission timing
|
||||
renderer->commandPoolHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
false, // manually synchronized due to submission timing
|
||||
VULKAN_INTERNAL_CommandPoolHashFunction,
|
||||
VULKAN_INTERNAL_CommandPoolHashKeyMatch,
|
||||
VULKAN_INTERNAL_CommandPoolHashNuke,
|
||||
false, false);
|
||||
VULKAN_INTERNAL_CommandPoolHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// thread-safe
|
||||
renderer->renderPassHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
true, // thread-safe
|
||||
VULKAN_INTERNAL_RenderPassHashFunction,
|
||||
VULKAN_INTERNAL_RenderPassHashKeyMatch,
|
||||
VULKAN_INTERNAL_RenderPassHashNuke,
|
||||
true, false);
|
||||
VULKAN_INTERNAL_RenderPassHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// manually synchronized due to iteration
|
||||
renderer->framebufferHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
false, // manually synchronized due to iteration
|
||||
VULKAN_INTERNAL_FramebufferHashFunction,
|
||||
VULKAN_INTERNAL_FramebufferHashKeyMatch,
|
||||
VULKAN_INTERNAL_FramebufferHashNuke,
|
||||
false, false);
|
||||
VULKAN_INTERNAL_FramebufferHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// thread-safe
|
||||
renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
true, // thread-safe
|
||||
VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction,
|
||||
VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch,
|
||||
VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke,
|
||||
true, false);
|
||||
VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// thread-safe
|
||||
renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
true, // thread-safe
|
||||
VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction,
|
||||
VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch,
|
||||
VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke,
|
||||
true, false);
|
||||
VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// thread-safe
|
||||
renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable(
|
||||
(void *)renderer,
|
||||
64,
|
||||
0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
|
||||
true, // thread-safe
|
||||
VULKAN_INTERNAL_DescriptorSetLayoutHashFunction,
|
||||
VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch,
|
||||
VULKAN_INTERNAL_DescriptorSetLayoutHashNuke,
|
||||
true, false);
|
||||
VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy,
|
||||
(void *)renderer);
|
||||
|
||||
// Initialize fence pool
|
||||
|
||||
|
||||
@@ -23,6 +23,84 @@
|
||||
#include "SDL_syshaptic.h"
|
||||
#include "SDL_haptic_c.h"
|
||||
#include "../joystick/SDL_joystick_c.h" // For SDL_IsJoystickValid
|
||||
#include "../SDL_hints_c.h"
|
||||
|
||||
typedef struct SDL_Haptic_VIDPID_Naxes {
|
||||
Uint16 vid;
|
||||
Uint16 pid;
|
||||
Uint16 naxes;
|
||||
} SDL_Haptic_VIDPID_Naxes;
|
||||
|
||||
static void SDL_Haptic_Load_Axes_List(SDL_Haptic_VIDPID_Naxes **entries, int *num_entries)
|
||||
{
|
||||
SDL_Haptic_VIDPID_Naxes entry;
|
||||
const char *spot;
|
||||
int length = 0;
|
||||
|
||||
spot = SDL_GetHint(SDL_HINT_JOYSTICK_HAPTIC_AXES);
|
||||
if (!spot)
|
||||
return;
|
||||
|
||||
while (SDL_sscanf(spot, "0x%hx/0x%hx/%hu%n", &entry.vid, &entry.pid, &entry.naxes, &length) == 3) {
|
||||
SDL_assert(length > 0);
|
||||
spot += length;
|
||||
length = 0;
|
||||
|
||||
if ((*num_entries % 8) == 0) {
|
||||
int new_max = *num_entries + 8;
|
||||
SDL_Haptic_VIDPID_Naxes *new_entries =
|
||||
(SDL_Haptic_VIDPID_Naxes *)SDL_realloc(*entries, new_max * sizeof(**entries));
|
||||
|
||||
// Out of memory, go with what we have already
|
||||
if (!new_entries)
|
||||
break;
|
||||
|
||||
*entries = new_entries;
|
||||
}
|
||||
(*entries)[(*num_entries)++] = entry;
|
||||
|
||||
if (spot[0] == ',')
|
||||
spot++;
|
||||
}
|
||||
}
|
||||
|
||||
// /* Return -1 if not found */
|
||||
static int SDL_Haptic_Naxes_List_Index(struct SDL_Haptic_VIDPID_Naxes *entries, int num_entries, Uint16 vid, Uint16 pid)
|
||||
{
|
||||
if (!entries)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num_entries; ++i) {
|
||||
if (entries[i].vid == vid && entries[i].pid == pid)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check if device needs a custom number of naxes
|
||||
static int SDL_Haptic_Get_Naxes(Uint16 vid, Uint16 pid)
|
||||
{
|
||||
int num_entries = 0, index = 0, naxes = -1;
|
||||
SDL_Haptic_VIDPID_Naxes *naxes_list = NULL;
|
||||
|
||||
SDL_Haptic_Load_Axes_List(&naxes_list, &num_entries);
|
||||
if (!num_entries || !naxes_list)
|
||||
return -1;
|
||||
|
||||
// Perform "wildcard" pass
|
||||
index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, 0xffff, 0xffff);
|
||||
if (index >= 0)
|
||||
naxes = naxes_list[index].naxes;
|
||||
|
||||
index = SDL_Haptic_Naxes_List_Index(naxes_list, num_entries, vid, pid);
|
||||
if (index >= 0)
|
||||
naxes = naxes_list[index].naxes;
|
||||
|
||||
SDL_free(naxes_list);
|
||||
return naxes;
|
||||
}
|
||||
|
||||
static SDL_Haptic *SDL_haptics = NULL;
|
||||
|
||||
@@ -282,6 +360,19 @@ SDL_Haptic *SDL_OpenHapticFromJoystick(SDL_Joystick *joystick)
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
// Check if custom number of haptic axes was defined
|
||||
Uint16 vid = SDL_GetJoystickVendor(joystick);
|
||||
Uint16 pid = SDL_GetJoystickProduct(joystick);
|
||||
int general_axes = SDL_GetNumJoystickAxes(joystick);
|
||||
|
||||
int naxes = SDL_Haptic_Get_Naxes(vid, pid);
|
||||
if (naxes > 0)
|
||||
haptic->naxes = naxes;
|
||||
|
||||
// Limit to the actual number of axes found on the device
|
||||
if (general_axes >= 0 && naxes > general_axes)
|
||||
haptic->naxes = general_axes;
|
||||
|
||||
// Add haptic to list
|
||||
++haptic->ref_count;
|
||||
// Link the haptic in the list
|
||||
|
||||
@@ -57,12 +57,14 @@ SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode)
|
||||
}
|
||||
|
||||
SDL_AsyncIO *asyncio = (SDL_AsyncIO *)SDL_calloc(1, sizeof(*asyncio));
|
||||
if (asyncio) {
|
||||
asyncio->lock = SDL_CreateMutex();
|
||||
if (!asyncio->lock) {
|
||||
SDL_free(asyncio);
|
||||
return NULL;
|
||||
}
|
||||
if (!asyncio) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asyncio->lock = SDL_CreateMutex();
|
||||
if (!asyncio->lock) {
|
||||
SDL_free(asyncio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!SDL_SYS_AsyncIOFromFile(file, binary_mode, asyncio)) {
|
||||
|
||||
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user