Compare commits
359
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68bfcb6c54 | ||
|
|
0d01efca52 | ||
|
|
0e65e04ce1 | ||
|
|
58d351fe98 | ||
|
|
9b71f18141 | ||
|
|
554f08bac3 | ||
|
|
913813a933 | ||
|
|
4e34c771e4 | ||
|
|
9995174e68 | ||
|
|
5a0197d430 | ||
|
|
4a55143e15 | ||
|
|
87c9bc1b1f | ||
|
|
16a57b70f7 | ||
|
|
69564cd0b1 | ||
|
|
da648b00e7 | ||
|
|
5886d90308 | ||
|
|
e84df0cad1 | ||
|
|
e482904111 | ||
|
|
b8ee44ca6a | ||
|
|
4a4abe4240 | ||
|
|
fe47f5cc30 | ||
|
|
5b64be0810 | ||
|
|
17656d051b | ||
|
|
233fce456a | ||
|
|
5290bb036c | ||
|
|
2bff72b4f6 | ||
|
|
08ebeaee5c | ||
|
|
12b56f5447 | ||
|
|
165b86e7b7 | ||
|
|
608101a185 | ||
|
|
554bee6aae | ||
|
|
3e0ce51067 | ||
|
|
7261c43342 | ||
|
|
ad57c6ea37 | ||
|
|
caecff650d | ||
|
|
f6300be4b2 | ||
|
|
bde5687a3c | ||
|
|
0f3504f78d | ||
|
|
0aaa0321cc | ||
|
|
caaaf52583 | ||
|
|
56449f167d | ||
|
|
c7325228dc | ||
|
|
079967afa5 | ||
|
|
2ed55b614c | ||
|
|
28721e3cd2 | ||
|
|
9d9845d063 | ||
|
|
a96dc76831 | ||
|
|
ad8e517227 | ||
|
|
8d578d590f | ||
|
|
6b4a211374 | ||
|
|
55b023c961 | ||
|
|
e2d0fe3e2f | ||
|
|
6b56ff7a97 | ||
|
|
67f796ebde | ||
|
|
06da7490fc | ||
|
|
af83c442d3 | ||
|
|
d726e98596 | ||
|
|
c9a6709bd2 | ||
|
|
25816bea41 | ||
|
|
e0f6e96da0 | ||
|
|
57de46ae7e | ||
|
|
59693c8996 | ||
|
|
f0efffc093 | ||
|
|
1b41cd759c | ||
|
|
d42a1402e8 | ||
|
|
5c44678d55 | ||
|
|
0638fd58ce | ||
|
|
cb662b6730 | ||
|
|
e874c7515e | ||
|
|
2ba797576b | ||
|
|
180b454d61 | ||
|
|
6ce7ae77b1 | ||
|
|
abbaf95cf0 | ||
|
|
1081b70951 | ||
|
|
4f51f956ad | ||
|
|
b076f4b590 | ||
|
|
91180f8cb4 | ||
|
|
99aa859362 | ||
|
|
31267feb03 | ||
|
|
6a5bac72cb | ||
|
|
2ed5062950 | ||
|
|
0b0b02c5a1 | ||
|
|
28c71368a1 | ||
|
|
25bd4285ab | ||
|
|
180171cad6 | ||
|
|
bc3eeecf7f | ||
|
|
9178d14519 | ||
|
|
6cd35f5b72 | ||
|
|
72d5eb0ecb | ||
|
|
5cf924420d | ||
|
|
290574e6f6 | ||
|
|
d9db975b4b | ||
|
|
e5c0e5efa7 | ||
|
|
26a1aae098 | ||
|
|
ab114490fc | ||
|
|
9546c54286 | ||
|
|
4d3cdb70b5 | ||
|
|
a66816a72f | ||
|
|
c925f72562 | ||
|
|
ef97329f41 | ||
|
|
195f709eda | ||
|
|
eb57d94ec5 | ||
|
|
d6212ae839 | ||
|
|
b494897b3d | ||
|
|
559d4415eb | ||
|
|
49e9134774 | ||
|
|
9571b0ece8 | ||
|
|
b55cfaf90b | ||
|
|
509168856f | ||
|
|
24fa2722c3 | ||
|
|
142700f909 | ||
|
|
f3611681df | ||
|
|
7f0a5d6a10 | ||
|
|
2001cc15d5 | ||
|
|
8d604353a5 | ||
|
|
8410e11ecb | ||
|
|
9f8161bf4a | ||
|
|
c038d6f7f8 | ||
|
|
2fff37fffc | ||
|
|
6feb86be71 | ||
|
|
ed22220bc6 | ||
|
|
219cb1a59d | ||
|
|
71bd25a893 | ||
|
|
01ef4c46a1 | ||
|
|
64f728ec48 | ||
|
|
ba10adf1fb | ||
|
|
c18aa99358 | ||
|
|
3498412611 | ||
|
|
8c1b3ff210 | ||
|
|
1870052af6 | ||
|
|
3b1e3d5176 | ||
|
|
cdf26c6e97 | ||
|
|
9f1a1405a6 | ||
|
|
6e97d8d1b3 | ||
|
|
9d9a24d325 | ||
|
|
0897f4a7d1 | ||
|
|
5aec645191 | ||
|
|
07c33068f3 | ||
|
|
d684e5d57e | ||
|
|
219500d95c | ||
|
|
810addf7ae | ||
|
|
4ef077ca52 | ||
|
|
7d2275c4dc | ||
|
|
cbd8917047 | ||
|
|
c98a19401c | ||
|
|
434836c480 | ||
|
|
50d02ad732 | ||
|
|
5ac37a8ffc | ||
|
|
7dd2915475 | ||
|
|
0ae1ddee17 | ||
|
|
db4c7e47f1 | ||
|
|
362445460e | ||
|
|
de5cb9db23 | ||
|
|
418eab29eb | ||
|
|
2f3d242183 | ||
|
|
4ad6d18203 | ||
|
|
cd4a4f8a9f | ||
|
|
a96e72da02 | ||
|
|
337f012de2 | ||
|
|
3c29b620e4 | ||
|
|
579fc161f0 | ||
|
|
22e968af4e | ||
|
|
e37e96cfff | ||
|
|
56c76c20a0 | ||
|
|
efd812c399 | ||
|
|
b2b92bbe25 | ||
|
|
a29c67ac94 | ||
|
|
f88e0aaac0 | ||
|
|
29a4a4a5d1 | ||
|
|
01000c73b0 | ||
|
|
1a5d1dfef0 | ||
|
|
2c38143834 | ||
|
|
c56a1c664c | ||
|
|
41cae64580 | ||
|
|
c6dd2662c3 | ||
|
|
f48027cf12 | ||
|
|
fabbc8d183 | ||
|
|
a142e5ef7d | ||
|
|
825c0c7691 | ||
|
|
dc30a00a26 | ||
|
|
5a05ef01ad | ||
|
|
0237997e4d | ||
|
|
4f90432a49 | ||
|
|
0cd6942bfc | ||
|
|
1beb6fdedf | ||
|
|
3b4472ecf7 | ||
|
|
faed8b620c | ||
|
|
982b778e45 | ||
|
|
3a8f1cb7c5 | ||
|
|
3c2d7ecdd6 | ||
|
|
0834f1d6ce | ||
|
|
6ce446b768 | ||
|
|
e045edb567 | ||
|
|
6cd14660cf | ||
|
|
f5ac58c9f4 | ||
|
|
c1779ca4a5 | ||
|
|
6d8309f72e | ||
|
|
cf95db46a7 | ||
|
|
b8abfeb7f3 | ||
|
|
014e24e1a8 | ||
|
|
e42071a47c | ||
|
|
1543f523b7 | ||
|
|
f2d0e965fc | ||
|
|
f782278d20 | ||
|
|
3b17d08eb2 | ||
|
|
18d367afd2 | ||
|
|
9a4faf9ab9 | ||
|
|
cb0ba020d4 | ||
|
|
f705e2f9f7 | ||
|
|
e76bffa183 | ||
|
|
a4e19dc567 | ||
|
|
4e1282617a | ||
|
|
f102ff16a2 | ||
|
|
50935a9d41 | ||
|
|
a1dde664d1 | ||
|
|
ba5325fba1 | ||
|
|
e225a10ea8 | ||
|
|
c4fba75a12 | ||
|
|
5b052e6f8c | ||
|
|
d89c3489f8 | ||
|
|
a447863e4f | ||
|
|
34db21cea8 | ||
|
|
943226edc1 | ||
|
|
281494676a | ||
|
|
413b55deb7 | ||
|
|
8222513f63 | ||
|
|
2dd20ce8e7 | ||
|
|
d308df6d62 | ||
|
|
f51b88e6b5 | ||
|
|
7cb0fa5c56 | ||
|
|
976c92a2fb | ||
|
|
15db51d7ff | ||
|
|
4aa4e6a18e | ||
|
|
0759f22a91 | ||
|
|
02036ee643 | ||
|
|
9109e05f3f | ||
|
|
2103451d00 | ||
|
|
b6db091d60 | ||
|
|
9827653c38 | ||
|
|
877399b2b2 | ||
|
|
3f059376ac | ||
|
|
30a6d01cc5 | ||
|
|
b6fb47aa70 | ||
|
|
7ecae856e5 | ||
|
|
5db7694f22 | ||
|
|
366294e1c5 | ||
|
|
4d966ff546 | ||
|
|
6b665066f0 | ||
|
|
519011f271 | ||
|
|
5c224a3221 | ||
|
|
4b8c38e7ba | ||
|
|
16f6c1058c | ||
|
|
7939309520 | ||
|
|
cec6073085 | ||
|
|
a9f121f3f7 | ||
|
|
361218ce15 | ||
|
|
04dcfada00 | ||
|
|
d73ad0ef18 | ||
|
|
a1b888f622 | ||
|
|
d6267afcb9 | ||
|
|
b8325be9cf | ||
|
|
e77ef86f09 | ||
|
|
951ba597ed | ||
|
|
ab5e178dab | ||
|
|
04dace6c75 | ||
|
|
013918cd83 | ||
|
|
996466e855 | ||
|
|
61e7878ac0 | ||
|
|
c067cb4e7d | ||
|
|
38697dd812 | ||
|
|
f03572335a | ||
|
|
d8837edfa2 | ||
|
|
e5f8043037 | ||
|
|
134b57f6f5 | ||
|
|
072e760197 | ||
|
|
d37a3e2a71 | ||
|
|
ed8e7e85f0 | ||
|
|
eb9faad124 | ||
|
|
3ed80843fe | ||
|
|
4029521a63 | ||
|
|
f971a59746 | ||
|
|
5836266bfb | ||
|
|
ed893bde04 | ||
|
|
a934a36a18 | ||
|
|
59857acd08 | ||
|
|
8129b637f3 | ||
|
|
9e1675671d | ||
|
|
d39d951f89 | ||
|
|
10ed6f49a9 | ||
|
|
c2c848a752 | ||
|
|
8b191c3ca6 | ||
|
|
06a412cd68 | ||
|
|
b74609d5f3 | ||
|
|
d8756582f9 | ||
|
|
ff90984dc3 | ||
|
|
81952f9f96 | ||
|
|
d0122ff624 | ||
|
|
7a36aa37aa | ||
|
|
464cb0ab6e | ||
|
|
ac21e3ef3f | ||
|
|
a5b51669fb | ||
|
|
0ac030549b | ||
|
|
6f1afe7084 | ||
|
|
6302589829 | ||
|
|
3225d31679 | ||
|
|
ae05ab280d | ||
|
|
51a6cb2cf5 | ||
|
|
daf468e141 | ||
|
|
cd673c8254 | ||
|
|
3f13c0b36d | ||
|
|
3e34720851 | ||
|
|
0799237d74 | ||
|
|
53f64e40c4 | ||
|
|
a530df20b2 | ||
|
|
b958189c92 | ||
|
|
341f910835 | ||
|
|
84dff407d4 | ||
|
|
21e6c5814c | ||
|
|
776f0a685c | ||
|
|
9f32fafe21 | ||
|
|
74b3b8e9e3 | ||
|
|
fa4a9ba74e | ||
|
|
9a6f8a2512 | ||
|
|
1173bc2dde | ||
|
|
ada55bd887 | ||
|
|
fe97cff7d1 | ||
|
|
8cdeb1a35a | ||
|
|
7c82171a85 | ||
|
|
2d2085c80b | ||
|
|
03a4eea0ef | ||
|
|
fec3e2cd45 | ||
|
|
2aec1c2ef6 | ||
|
|
b32cd4f84b | ||
|
|
550bdc658a | ||
|
|
d75ba9c2d2 | ||
|
|
2477f7f982 | ||
|
|
e454d7d4be | ||
|
|
cd8bffb2dd | ||
|
|
9646e3cc1b | ||
|
|
1a2362ebf1 | ||
|
|
f6864924f7 | ||
|
|
6b3dafa4d3 | ||
|
|
5c0c5d2816 | ||
|
|
de11dd3d60 | ||
|
|
ac09af2600 | ||
|
|
26d1afa29c | ||
|
|
6aab3b9da8 | ||
|
|
d959719a3d | ||
|
|
5a7b17fec5 | ||
|
|
1d6bb62870 | ||
|
|
0c3603d893 | ||
|
|
38a5bca892 | ||
|
|
70a289076a | ||
|
|
1d0ecf982f | ||
|
|
18d93d11e1 | ||
|
|
110a832f5c | ||
|
|
6a9e970880 | ||
|
|
4e3058ce82 | ||
|
|
bc6307a872 |
No files matched your search
@@ -256,7 +256,7 @@ jobs:
|
||||
|
||||
msvc:
|
||||
needs: [src]
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2025
|
||||
outputs:
|
||||
VC-x86: ${{ steps.releaser.outputs.VC-x86 }}
|
||||
VC-x64: ${{ steps.releaser.outputs.VC-x64 }}
|
||||
|
||||
+16
-9
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# See docs/release_checklist.md
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.6")
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.18")
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(SDL3_MAINPROJECT ON)
|
||||
@@ -188,9 +188,12 @@ if(MSVC)
|
||||
# Make sure /RTC1 is disabled, otherwise it will use functions from the CRT
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
set(CMAKE_MSVC_RUNTIME_CHECKS "")
|
||||
endif()
|
||||
|
||||
if(MSVC_CLANG)
|
||||
@@ -634,6 +637,11 @@ if(MSVC)
|
||||
# Mark SDL3.dll as compatible with Control-flow Enforcement Technology (CET)
|
||||
sdl_shared_link_options("-CETCOMPAT")
|
||||
endif()
|
||||
|
||||
# for VS >= 17.14 targeting ARM64: inline the Interlocked funcs
|
||||
if(MSVC_VERSION GREATER 1943 AND SDL_CPU_ARM64 AND NOT SDL_LIBC)
|
||||
sdl_compile_options(PRIVATE "/forceInterlockedFunctions-")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
@@ -1291,8 +1299,8 @@ if(ANDROID)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/android/*.c")
|
||||
sdl_sources("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
|
||||
set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
|
||||
sdl_sources("${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
|
||||
set_property(SOURCE "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/android/*.c")
|
||||
set(HAVE_SDL_MISC TRUE)
|
||||
@@ -1336,9 +1344,7 @@ if(ANDROID)
|
||||
set(HAVE_SDL_HAPTIC TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_HIDAPI)
|
||||
CheckHIDAPI()
|
||||
endif()
|
||||
CheckHIDAPI()
|
||||
|
||||
if(SDL_JOYSTICK)
|
||||
set(SDL_JOYSTICK_ANDROID 1)
|
||||
@@ -2188,6 +2194,7 @@ elseif(APPLE)
|
||||
set(SDL_CAMERA_DRIVER_COREMEDIA 1)
|
||||
set(HAVE_CAMERA TRUE)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/coremedia/*.m")
|
||||
set(SDL_FRAMEWORK_AVFOUNDATION 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -3016,7 +3023,7 @@ if(SDL_GPU)
|
||||
set(SDL_GPU_D3D11 1)
|
||||
set(HAVE_SDL_GPU TRUE)
|
||||
endif()
|
||||
if(SDL_RENDER_D3D12)
|
||||
if(WINDOWS)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c")
|
||||
set(SDL_GPU_D3D12 1)
|
||||
set(HAVE_SDL_GPU TRUE)
|
||||
@@ -3287,7 +3294,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
sdl_include_directories(PRIVATE SYSTEM "${ANDROID_NDK}/sources/android/cpufeatures")
|
||||
sdl_include_directories(PRIVATE SYSTEM "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
SDL supports a number of development environments:
|
||||
- [CMake](docs/INTRO-cmake.md)
|
||||
- [Visual Studio on Windows](docs/INTRO-visualstudio.md)
|
||||
- [gcc on Windows](docs/INTRO-mingw.md)
|
||||
- [Xcode on Apple platforms](docs/INTRO-xcode.md)
|
||||
- [Android Studio](docs/INTRO-androidstudio.md)
|
||||
- [Emscripten for web](docs/INTRO-emscripten.md)
|
||||
|
||||
@@ -168,8 +168,8 @@
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
call $(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat $(ProjectDir)..\
|
||||
call $(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat $(ProjectDir)..\
|
||||
call "$(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
|
||||
call "$(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
|
||||
</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
|
||||
This is a list of major changes in SDL's version history.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.10:
|
||||
---------------------------------------------------------------------------
|
||||
* Added SDL_HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT to control whether XSelectInput() should be called on external windows to enable input events.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.4:
|
||||
---------------------------------------------------------------------------
|
||||
* Added SDL_StretchSurface()
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.0:
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.6</string>
|
||||
<string>3.2.18</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>SDLX</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.2.6</string>
|
||||
<string>3.2.18</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -3086,7 +3086,7 @@
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.6.0;
|
||||
DYLIB_CURRENT_VERSION = 201.18.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||
@@ -3121,7 +3121,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.6;
|
||||
MARKETING_VERSION = 3.2.18;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
PRODUCT_NAME = SDL3;
|
||||
@@ -3150,7 +3150,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.6.0;
|
||||
DYLIB_CURRENT_VERSION = 201.18.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -3182,7 +3182,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.6;
|
||||
MARKETING_VERSION = 3.2.18;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Title SDL 3.2.6
|
||||
Title SDL 3.2.18
|
||||
Version 1
|
||||
Description SDL Library for macOS (http://www.libsdl.org)
|
||||
DefaultLocation /Library/Frameworks
|
||||
|
||||
@@ -92,7 +92,7 @@ if(NOT TARGET SDL3::Headers)
|
||||
add_library(SDL3::Headers INTERFACE IMPORTED)
|
||||
set_target_properties(SDL3::Headers
|
||||
PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
|
||||
INTERFACE_COMPILE_OPTIONS "-F${_sdl3_framework_parent_path}"
|
||||
)
|
||||
endif()
|
||||
set(SDL3_Headers_FOUND TRUE)
|
||||
|
||||
@@ -5,7 +5,7 @@ plugins {
|
||||
def buildWithCMake = project.hasProperty('BUILD_WITH_CMAKE');
|
||||
|
||||
android {
|
||||
namespace "org.libsdl.app"
|
||||
namespace = "org.libsdl.app"
|
||||
compileSdkVersion 35
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
@@ -14,12 +14,12 @@ android {
|
||||
versionName "1.0"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_PLATFORM=android-19"
|
||||
arguments "APP_PLATFORM=android-21"
|
||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
cmake {
|
||||
arguments "-DANDROID_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
||||
arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static"
|
||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
@@ -53,7 +53,7 @@ android {
|
||||
|
||||
}
|
||||
lint {
|
||||
abortOnError false
|
||||
abortOnError = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -51,6 +51,8 @@
|
||||
boolean supportsRelativeMouse();
|
||||
int openFileDescriptor(java.lang.String, java.lang.String);
|
||||
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
|
||||
java.lang.String getPreferredLocales();
|
||||
java.lang.String formatLocale(java.util.Locale);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.LocaleList;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -60,7 +61,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 = 6;
|
||||
private static final int SDL_MICRO_VERSION = 18;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
@@ -2116,6 +2117,44 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
int requestCode;
|
||||
boolean multipleChoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static String getPreferredLocales() {
|
||||
String result = "";
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
|
||||
LocaleList locales = LocaleList.getAdjustedDefault();
|
||||
for (int i = 0; i < locales.size(); i++) {
|
||||
if (i != 0) result += ",";
|
||||
result += formatLocale(locales.get(i));
|
||||
}
|
||||
} else if (mCurrentLocale != null) {
|
||||
result = formatLocale(mCurrentLocale);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String formatLocale(Locale locale) {
|
||||
String result = "";
|
||||
String lang = "";
|
||||
if (locale.getLanguage() == "in") {
|
||||
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
|
||||
lang = "id";
|
||||
} else if (locale.getLanguage() == "") {
|
||||
// Make sure language is never empty
|
||||
lang = "und";
|
||||
} else {
|
||||
lang = locale.getLanguage();
|
||||
}
|
||||
|
||||
if (locale.getCountry() == "") {
|
||||
result = lang;
|
||||
} else {
|
||||
result = lang + "_" + locale.getCountry();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -424,7 +424,11 @@ sub dewikify_chunk {
|
||||
$str .= "\n```$codelang\n$code\n```\n";
|
||||
}
|
||||
} elsif ($dewikify_mode eq 'manpage') {
|
||||
$str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
|
||||
# make sure these can't become part of roff syntax.
|
||||
$str =~ s/\./\\[char46]/gms;
|
||||
$str =~ s/"/\\(dq/gms;
|
||||
$str =~ s/'/\\(aq/gms;
|
||||
|
||||
if ($wikitype eq 'mediawiki') {
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
@@ -449,33 +453,52 @@ sub dewikify_chunk {
|
||||
# bullets
|
||||
$str =~ s/^\* /\n\\\(bu /gm;
|
||||
} elsif ($wikitype eq 'md') {
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\(bu /gm;
|
||||
# merge paragraphs
|
||||
$str =~ s/^[ \t]+//gm;
|
||||
$str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
|
||||
$str =~ s/\n\n/\n.PP\n/g;
|
||||
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
$str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
|
||||
my $apr = $apiprefixregex;
|
||||
if(!($apr =~ /\A\(.*\)\Z/s)) {
|
||||
# we're relying on the apiprefixregex having a capturing group.
|
||||
$apr = "(" . $apr . ")";
|
||||
}
|
||||
$str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
|
||||
# handle cases like "[x](x), [y](y), [z](z)" being separated.
|
||||
while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
|
||||
}
|
||||
|
||||
# links
|
||||
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
|
||||
|
||||
# <code></code> is also popular. :/
|
||||
$str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold+italic (this looks bad, just make it bold).
|
||||
$str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold
|
||||
$str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# italic
|
||||
$str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
|
||||
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\\(bu /gm;
|
||||
$str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
|
||||
}
|
||||
|
||||
# cleanup unnecessary quotes
|
||||
$str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
|
||||
$str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
|
||||
$str =~ s/"(\S+)"/$1/gm;
|
||||
# cleanup unnecessary whitespace
|
||||
$str =~ s/ +\n/\n/gm;
|
||||
|
||||
if (defined $code) {
|
||||
$code =~ s/\A\n+//gms;
|
||||
$code =~ s/\n+\Z//gms;
|
||||
$code =~ s/\\/\\(rs/gms;
|
||||
if ($dewikify_manpage_code_indent) {
|
||||
$str .= "\n.IP\n"
|
||||
} else {
|
||||
@@ -580,7 +603,7 @@ sub dewikify {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
} elsif ($wikitype eq 'md') {
|
||||
while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
|
||||
while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
}
|
||||
@@ -2765,7 +2788,6 @@ __EOF__
|
||||
my $wikitype = $wikitypes{$sym};
|
||||
my $sectionsref = $wikisyms{$sym};
|
||||
my $remarks = $sectionsref->{'Remarks'};
|
||||
my $params = $sectionsref->{'Function Parameters'};
|
||||
my $returns = $sectionsref->{'Return Value'};
|
||||
my $version = $sectionsref->{'Version'};
|
||||
my $threadsafety = $sectionsref->{'Thread Safety'};
|
||||
@@ -2773,6 +2795,23 @@ __EOF__
|
||||
my $examples = $sectionsref->{'Code Examples'};
|
||||
my $deprecated = $sectionsref->{'Deprecated'};
|
||||
my $headerfile = $manpageheaderfiletext;
|
||||
|
||||
my $params = undef;
|
||||
|
||||
if ($symtype == -1) { # category documentation block.
|
||||
# nothing to be done here.
|
||||
} elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
|
||||
$params = $sectionsref->{'Function Parameters'};
|
||||
} elsif ($symtype == 2) {
|
||||
$params = $sectionsref->{'Macro Parameters'};
|
||||
} elsif ($symtype == 3) {
|
||||
$params = $sectionsref->{'Fields'};
|
||||
} elsif ($symtype == 4) {
|
||||
$params = $sectionsref->{'Values'};
|
||||
} else {
|
||||
die("Unexpected symtype $symtype");
|
||||
}
|
||||
|
||||
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
|
||||
$headerfile .= "\n";
|
||||
|
||||
@@ -2839,18 +2878,22 @@ __EOF__
|
||||
$str .= dewikify($wikitype, $deprecated) . "\n";
|
||||
}
|
||||
|
||||
my $incfile = $mainincludefname;
|
||||
if (defined $headerfile) {
|
||||
$str .= ".SH HEADER FILE\n";
|
||||
$str .= dewikify($wikitype, $headerfile) . "\n";
|
||||
if($headerfile =~ /Defined in (.*)/) {
|
||||
$incfile = $1;
|
||||
}
|
||||
}
|
||||
|
||||
$str .= ".SH SYNOPSIS\n";
|
||||
$str .= ".nf\n";
|
||||
$str .= ".B #include \\(dq$mainincludefname\\(dq\n";
|
||||
$str .= ".B #include <$incfile>\n";
|
||||
$str .= ".PP\n";
|
||||
|
||||
my @decllines = split /\n/, $decl;
|
||||
foreach (@decllines) {
|
||||
$_ =~ s/\\/\\(rs/g; # fix multiline macro defs
|
||||
$_ =~ s/"/\\(dq/g;
|
||||
$str .= ".BI \"$_\n";
|
||||
}
|
||||
$str .= ".fi\n";
|
||||
@@ -2938,8 +2981,11 @@ __EOF__
|
||||
}
|
||||
|
||||
if (defined $returns) {
|
||||
# Chop datatype in parentheses off the front.
|
||||
if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
|
||||
$returns =~ s/\A\([^\)]*\) //ms;
|
||||
}
|
||||
$returns = dewikify($wikitype, $returns);
|
||||
$returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
|
||||
$str .= ".SH RETURN VALUE\n";
|
||||
$str .= "$returns\n";
|
||||
}
|
||||
@@ -2975,6 +3021,8 @@ __EOF__
|
||||
s/\A\/*//;
|
||||
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
|
||||
s/\\\(bu//; # dewikify added this, but we want to handle it.
|
||||
s/\A\s*[\:\*\-]\s*//;
|
||||
s/\A\s+//;
|
||||
s/\s+\Z//;
|
||||
|
||||
@@ -823,7 +823,7 @@ macro(CheckPTHREAD)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "SunPro")
|
||||
set(PTHREAD_LDFLAGS "-mt -lpthread")
|
||||
else()
|
||||
set(PTHREAD_LDFLAGS "-pthread -lposix4")
|
||||
set(PTHREAD_LDFLAGS "-pthread")
|
||||
endif()
|
||||
elseif(SYSV5)
|
||||
set(PTHREAD_CFLAGS "-D_REENTRANT -Kthread")
|
||||
@@ -1077,6 +1077,14 @@ endmacro()
|
||||
|
||||
# Check for HIDAPI support
|
||||
macro(CheckHIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
if(SDL_HIDAPI)
|
||||
set(HAVE_HIDAPI ON)
|
||||
if(SDL_HIDAPI_LIBUSB)
|
||||
@@ -1109,14 +1117,6 @@ macro(CheckHIDAPI)
|
||||
endif()
|
||||
|
||||
if(HAVE_HIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
set(HAVE_SDL_HIDAPI TRUE)
|
||||
|
||||
if(SDL_JOYSTICK AND SDL_HIDAPI_JOYSTICK)
|
||||
|
||||
+16
-9
@@ -5,7 +5,12 @@ The easiest way to use SDL is to include it as a subproject in your project.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c)
|
||||
|
||||
Create the file CMakeLists.txt
|
||||
# Get a copy of the SDL source:
|
||||
```sh
|
||||
git clone https://github.com/libsdl-org/SDL.git vendored/SDL
|
||||
```
|
||||
|
||||
# Create the file CMakeLists.txt
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(hello)
|
||||
@@ -25,24 +30,26 @@ add_executable(hello WIN32 hello.c)
|
||||
target_link_libraries(hello PRIVATE SDL3::SDL3)
|
||||
```
|
||||
|
||||
Build:
|
||||
# Configure and Build:
|
||||
```sh
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
Run:
|
||||
- On Windows the executable is in the build Debug directory:
|
||||
```sh
|
||||
cd build/Debug
|
||||
./hello
|
||||
```
|
||||
- On other platforms the executable is in the build directory:
|
||||
# Run:
|
||||
The executable should be in the `build` directory:
|
||||
|
||||
```sh
|
||||
cd build
|
||||
./hello
|
||||
```
|
||||
|
||||
If there wasn't an executable there despite the above Build section running successfully, it's likely because you're following this guide using the Visual Studio toolchain, it should instead be in the `build/Debug` directory:
|
||||
```sh
|
||||
cd build/Debug
|
||||
./hello
|
||||
```
|
||||
|
||||
A more complete example is available at:
|
||||
|
||||
https://github.com/Ravbug/sdl3-sample
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Introduction to SDL with MinGW
|
||||
|
||||
Without getting deep into the history, MinGW is a long running project that aims to bring gcc to Windows. That said, there's many distributions, versions, and forks floating around. We recommend installing [MSYS2](https://www.msys2.org/), as it's the easiest way to get a modern toolchain with a package manager to help with dependency management. This would allow you to follow the MSYS2 section below.
|
||||
|
||||
Otherwise you'll want to follow the "Other Distributions" section below.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c).
|
||||
|
||||
# MSYS2
|
||||
|
||||
Open the `MSYS2 UCRT64` prompt and then ensure you've installed the following packages. This will get you working toolchain, CMake, Ninja, and of course SDL3.
|
||||
|
||||
```sh
|
||||
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-sdl3
|
||||
```
|
||||
|
||||
## Create the file CMakeLists.txt
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
project(hello C CXX)
|
||||
|
||||
find_package(SDL3 REQUIRED)
|
||||
|
||||
add_executable(hello)
|
||||
|
||||
target_sources(hello
|
||||
PRIVATE
|
||||
hello.c
|
||||
)
|
||||
|
||||
target_link_libraries(hello SDL3::SDL3)
|
||||
```
|
||||
|
||||
## Configure and Build:
|
||||
```sh
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
## Run:
|
||||
|
||||
The executable is in the `build` directory:
|
||||
```sh
|
||||
cd build
|
||||
./hello
|
||||
```
|
||||
|
||||
# Other Distributions
|
||||
|
||||
Things can get quite complicated with other distributions of MinGW. If you can't follow [the cmake intro](INTRO-cmake.md), perhaps due to issues getting cmake to understand your toolchain, this section should work.
|
||||
|
||||
## Acquire SDL
|
||||
|
||||
Download the `SDL3-devel-<version>-mingw.zip` asset from [the latest release.](https://github.com/libsdl-org/SDL/releases/latest) Then extract it inside your project folder such that the output of `ls SDL3-<version>` looks like `INSTALL.md LICENSE.txt Makefile README.md cmake i686-w64-mingw32 x86_64-w64-mingw32`.
|
||||
|
||||
## Know your Target Architecture
|
||||
|
||||
It is not uncommon for folks to not realize their distribution is targeting 32bit Windows despite things like the name of the toolchain, or the fact that they're running on a 64bit system. We'll ensure we know up front what we need:
|
||||
|
||||
Create a file named `arch.c` with the following contents:
|
||||
```c
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
#if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
|
||||
size_t ptr_size = sizeof(int*);
|
||||
if (4 == ptr_size) puts("i686-w64-mingw32");
|
||||
else if (8 == ptr_size) puts("x86_64-w64-mingw32");
|
||||
else puts("Unknown Architecture");
|
||||
#else
|
||||
puts("Unknown Architecture");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Then run
|
||||
|
||||
```sh
|
||||
gcc arch.c
|
||||
./a.exe
|
||||
```
|
||||
|
||||
This should print out which library directory we'll need to use when compiling, keep this value in mind, you'll need to use it when compiling in the next section as `<arch>`. If you get "Unknown Architecture" please [report a bug](https://github.com/libsdl-org/SDL/issues).
|
||||
|
||||
|
||||
## Build and Run
|
||||
|
||||
Now we should have everything needed to compile and run our program. You'll need to ensure to replace `<version>` with the version of the release of SDL3 you downloaded, as well as use the `<arch>` we learned in the previous section.
|
||||
|
||||
```sh
|
||||
gcc hello.c -o hello.exe -I SDL3-<version>/<arch>/include -L SDL3-<version>/<arch>/lib -lSDL3 -mwindows
|
||||
cp SDL3-<version>/<arch>/bin/SDL3.dll SDL3.dll
|
||||
./hello.exe
|
||||
```
|
||||
@@ -5,10 +5,12 @@ The easiest way to use SDL is to include it as a subproject in your project.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c)
|
||||
|
||||
- Get a copy of the SDL source, you can clone the repo, or download the "Source Code" asset from [the latest release.](https://github.com/libsdl-org/SDL/releases/latest)
|
||||
- If you've downloaded a release, make sure to extract the contents somewhere you can find it.
|
||||
- Create a new project in Visual Studio, using the C++ Empty Project template
|
||||
- Add hello.c to the Source Files
|
||||
- Right click the solution, select add an existing project, navigate to VisualC/SDL and add SDL.vcxproj
|
||||
- Select your main project and go to Project -> Add Reference and select SDL3
|
||||
- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select VC++ Directories and add the SDL include directory to "Include Directories"
|
||||
- Right click the solution, select add an existing project, navigate to `VisualC/SDL` from within the source you cloned or downloaded above and add SDL.vcxproj
|
||||
- Select your main project and go to Project -> Add -> Reference and select SDL3
|
||||
- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select C/C++ -> General and add the SDL include directory to "Additional Include Directories"
|
||||
- Build and run!
|
||||
|
||||
@@ -242,7 +242,7 @@ not give you any processing time after the events are delivered.
|
||||
|
||||
e.g.
|
||||
|
||||
int HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
bool HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
@@ -250,12 +250,12 @@ e.g.
|
||||
/* Terminate the app.
|
||||
Shut everything down before returning from this function.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_LOW_MEMORY:
|
||||
/* You will get this when your app is paused and iOS wants more memory.
|
||||
Release as much memory as possible.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||
/* Prepare your app to go into the background. Stop loops, etc.
|
||||
This gets called when the user hits the home button, or gets a call.
|
||||
@@ -264,15 +264,15 @@ e.g.
|
||||
in addition, you should set the render target to NULL, if you're using
|
||||
it, e.g. call SDL_SetRenderTarget(renderer, NULL).
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||
/* Your app is NOT active at this point. */
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||
/* This call happens when your app is coming back to the foreground.
|
||||
Restore all your state here.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||
/* Restart your loops here.
|
||||
Your app is interactive and getting CPU again.
|
||||
@@ -283,10 +283,10 @@ e.g.
|
||||
event SDL_EVENT_RENDER_DEVICE_RESET and recreate your OpenGL context and
|
||||
restore your textures when you get it, or quit the app.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
default:
|
||||
/* No special processing, add it to the event queue */
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+30
-26
@@ -1,32 +1,6 @@
|
||||
|
||||
SDL 3.0 has new support for high DPI displays. Interfaces provided by SDL uses the platform's native coordinates unless otherwise specified.
|
||||
|
||||
To reconcile platform differences in their approach to high-density scaling, SDL provides the following interfaces:
|
||||
- `SDL_GetWindowSize()` retrieves the window dimensions in native coordinates.
|
||||
- `SDL_GetWindowSizeInPixels()` retrieves the window dimensions in pixels-addressable.
|
||||
- `SDL_GetDisplayContentScale()` retrieves the suggested amplification factor when drawing in native coordinates.
|
||||
- `SDL_GetWindowDisplayScale()` retrieves the suggested amplification factor when drawing in pixels-addressable.
|
||||
- `SDL_GetWindowPixelDensity()` retrieves how many addressable pixels correspond to one unit of native coordinates.
|
||||
- `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowSizeInPixels()` changes.
|
||||
- `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowDisplayScale()` changes.
|
||||
- Windows created with `SDL_WINDOW_HIGH_PIXEL_DENSITY` will ask the platform to display addressable pixels at their natural scale.
|
||||
|
||||
## Numeric example
|
||||
|
||||
Given a fullscreen window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on MacOS and Win32:
|
||||
|
||||
| Value | MacOS (Default) | MacOS (HD) | Win32 (Default & HD) |
|
||||
|--------------------------------|-----------------|------------|----------------------|
|
||||
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
|
||||
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
|
||||
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
|
||||
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
|
||||
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
|
||||
|
||||
Observe the philosophical difference between the approaches taken by MacOS and Win32:
|
||||
- Win32 coordinate system always deals in physical device pixels, high DPI support is achieved by providing an advisory hint for the developer to enlarge drawn objects. Ignoring the advisory scale factor results in graphics appearing tiny.
|
||||
- MacOS coordinate system always deals in physical content sizes, high DPI support is achieved by providing an optional flag for the developer to request finer granularity. Omitting the granularity request results in graphics appearing coarse.
|
||||
|
||||
## Explanation
|
||||
|
||||
Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
|
||||
@@ -34,3 +8,33 @@ Displays now have a content display scale, which is the expected scale for conte
|
||||
The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
|
||||
|
||||
The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0. You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
|
||||
|
||||
## Numeric example
|
||||
|
||||
Given a window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on macOS and Windows:
|
||||
|
||||
| Value | macOS (Default) | macOS (HD) | Windows (Default & HD) |
|
||||
|--------------------------------|-----------------|------------|------------------------|
|
||||
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
|
||||
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
|
||||
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
|
||||
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
|
||||
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
|
||||
|
||||
Observe the difference between the approaches taken by macOS and Windows:
|
||||
- The Windows and Android coordinate system always deals in physical device pixels, high DPI support is achieved by providing a content scale that tells the developer to draw objects larger. Ignoring this scale factor results in graphics appearing tiny.
|
||||
- The macOS and iOS coordinate system always deals in window coordinates, high DPI support is achieved by providing an optional flag for the developer to request more pixels. Omitting this flag results in graphics having low detail.
|
||||
- On Linux, X11 uses a similar approach to Windows and Wayland uses a similar approach to macOS.
|
||||
|
||||
## Solution
|
||||
|
||||
Proper high DPI support takes into account both the content scale and the pixel density.
|
||||
|
||||
First, you'd create your window with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, assuming you want the highest detail possible. Then you'd get the window display scale to see how much your UI elements should be enlarged to be readable.
|
||||
|
||||
If you're using the SDL 2D renderer, SDL provides the function `SDL_ConvertEventToRenderCoordinates()` to convert mouse coordinates between window coordinates and rendering coordinates, and the more general functions `SDL_RenderCoordinatesFromWindow()` and `SDL_RenderCoordinatesToWindow()` to do other conversion between them.
|
||||
|
||||
If you're not using the 2D renderer, you can implement this yourself using `SDL_GetWindowPixelDensity()` as scale factor to convert from window coordinates to pixels.
|
||||
|
||||
Finally you'll want to test on both Windows and macOS if possible to make sure your high DPI support works in all environments.
|
||||
|
||||
+8
-8
@@ -65,7 +65,7 @@ not give you any processing time after the events are delivered.
|
||||
|
||||
e.g.
|
||||
|
||||
int HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
bool HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
@@ -73,37 +73,37 @@ e.g.
|
||||
/* Terminate the app.
|
||||
Shut everything down before returning from this function.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_LOW_MEMORY:
|
||||
/* You will get this when your app is paused and iOS wants more memory.
|
||||
Release as much memory as possible.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||
/* Prepare your app to go into the background. Stop loops, etc.
|
||||
This gets called when the user hits the home button, or gets a call.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||
/* This will get called if the user accepted whatever sent your app to the background.
|
||||
If the user got a phone call and canceled it, you'll instead get an SDL_EVENT_DID_ENTER_FOREGROUND event and restart your loops.
|
||||
When you get this, you have 5 seconds to save all your state or the app will be terminated.
|
||||
Your app is NOT active at this point.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||
/* This call happens when your app is coming back to the foreground.
|
||||
Restore all your state here.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||
/* Restart your loops here.
|
||||
Your app is interactive and getting CPU again.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
default:
|
||||
/* No special processing, add it to the event queue */
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ NSApplicationDelegate implementation:
|
||||
```objc
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_QUIT) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_QUIT)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_QUIT;
|
||||
@@ -61,7 +61,7 @@ NSApplicationDelegate implementation:
|
||||
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_DROP_FILE) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_DROP_FILE)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_DROP_FILE;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
- [macOS](README-macos.md)
|
||||
- [NetBSD](README-bsd.md)
|
||||
- [Nintendo Switch](README-switch.md)
|
||||
- [Nintendo 3DS](README-3ds.md)
|
||||
- [Nintendo 3DS](README-n3ds.md)
|
||||
- [OpenBSD](README-bsd.md)
|
||||
- [PlayStation 2](README-ps2.md)
|
||||
- [PlayStation 4](README-ps4.md)
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ cmake --install build
|
||||
|
||||
|
||||
## Compiling a HelloWorld
|
||||
[PSP Hello World](https://psp-dev.org/doku.php?id=tutorial:hello_world)
|
||||
[PSP Hello World](https://pspdev.github.io/basic_programs.html#hello-world)
|
||||
|
||||
## To Do
|
||||
- PSP Screen Keyboard
|
||||
|
||||
+28
-40
@@ -1,60 +1,48 @@
|
||||
# Versioning
|
||||
|
||||
## Since 2.23.0
|
||||
## Since 3.2.0
|
||||
|
||||
SDL follows an "odd/even" versioning policy, similar to GLib, GTK, Flatpak
|
||||
and older versions of the Linux kernel:
|
||||
|
||||
* The major version (first part) increases when backwards compatibility
|
||||
is broken, which will happen infrequently.
|
||||
|
||||
* If the minor version (second part) is divisible by 2
|
||||
(for example 2.24.x, 2.26.x), this indicates a version of SDL that
|
||||
is believed to be stable and suitable for production use.
|
||||
* If the minor version (second part) and the patch version (third part) is
|
||||
divisible by 2 (for example 3.2.6, 3.4.0), this indicates a version of
|
||||
SDL that is believed to be stable and suitable for production use.
|
||||
|
||||
* In stable releases, the patchlevel or micro version (third part)
|
||||
indicates bugfix releases. Bugfix releases should not add or
|
||||
remove ABI, so the ".0" release (for example 2.24.0) should be
|
||||
forwards-compatible with all the bugfix releases from the
|
||||
same cycle (for example 2.24.1).
|
||||
indicates bugfix releases. Bugfix releases may add small changes
|
||||
to the ABI, so newer patch versions are backwards-compatible but
|
||||
not fully forwards-compatible. For example, programs built against
|
||||
SDL 3.2.0 should work fine with SDL 3.2.8, but programs built against
|
||||
SDL 3.2.8 may not work with 3.2.0.
|
||||
|
||||
* The minor version increases when new API or ABI is added, or when
|
||||
other significant changes are made. Newer minor versions are
|
||||
backwards-compatible, but not fully forwards-compatible.
|
||||
For example, programs built against SDL 2.24.x should work fine
|
||||
with SDL 2.26.x, but programs built against SDL 2.26.x will not
|
||||
necessarily work with 2.24.x.
|
||||
* The minor version increases when significant changes are made that
|
||||
require longer development or testing time, e.g. major new functionality,
|
||||
or revamping support for a platform. Newer minor versions are
|
||||
backwards-compatible, but not fully forwards-compatible. For example,
|
||||
programs built against SDL 3.2.x should work fine with SDL 3.4.x,
|
||||
but programs built against SDL 3.4.x may not work with 3.2.x.
|
||||
|
||||
* If the minor version (second part) is not divisible by 2
|
||||
(for example 2.23.x, 2.25.x), this indicates a development prerelease
|
||||
of SDL that is not suitable for stable software distributions.
|
||||
* If the minor version (second part) or patch version (third part) is not
|
||||
divisible by 2 (for example 3.2.9, 3.3.x), this indicates a development
|
||||
prerelease of SDL that is not suitable for stable software distributions.
|
||||
Use with caution.
|
||||
|
||||
* The patchlevel or micro version (third part) increases with
|
||||
each prerelease.
|
||||
|
||||
* Each prerelease might add new API and/or ABI.
|
||||
* The patchlevel or micro version (third part) increases with each prerelease.
|
||||
|
||||
* Prereleases are backwards-compatible with older stable branches.
|
||||
For example, 2.25.x will be backwards-compatible with 2.24.x.
|
||||
For example, programs built against SDL 3.2.x should work fine with
|
||||
SDL 3.3.x, but programs built against SDL 3.3.x may not work with 3.2.x.
|
||||
|
||||
* Prereleases are not guaranteed to be backwards-compatible with
|
||||
each other. For example, new API or ABI added in 2.25.1
|
||||
might be removed or changed in 2.25.2.
|
||||
If this would be a problem for you, please do not use prereleases.
|
||||
* Prereleases are not guaranteed to be backwards-compatible with each other.
|
||||
For example, new API or ABI added in 3.3.0 might be removed or changed in
|
||||
3.3.1. If this would be a problem for you, please do not use prereleases.
|
||||
|
||||
* Only upgrade to a prerelease if you can guarantee that you will
|
||||
promptly upgrade to the stable release that follows it.
|
||||
For example, do not upgrade to 2.23.x unless you will be able to
|
||||
upgrade to 2.24.0 when it becomes available.
|
||||
* Only use a prerelease if you can guarantee that you will promptly upgrade
|
||||
to the stable release that follows it. For example, do not use 3.3.x
|
||||
unless you will be able to upgrade to 3.4.0 when it becomes available.
|
||||
|
||||
* Software distributions that have a freeze policy (in particular Linux
|
||||
distributions with a release cycle, such as Debian and Fedora)
|
||||
should usually only package stable releases, and not prereleases.
|
||||
should only package stable releases, and not prereleases.
|
||||
|
||||
## Before 2.23.0
|
||||
|
||||
Older versions of SDL followed a similar policy, but instead of the
|
||||
odd/even rule applying to the minor version, it applied to the patchlevel
|
||||
(micro version, third part). For example, 2.0.22 was a stable release
|
||||
and 2.0.21 was a prerelease.
|
||||
@@ -59,6 +59,10 @@ encounter limitations or behavior that is different from other windowing systems
|
||||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### Keyboard grabs don't work when running under XWayland
|
||||
|
||||
- On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled.
|
||||
|
||||
## Using custom Wayland windowing protocols with SDL windows
|
||||
|
||||
Under normal operation, an `SDL_Window` corresponds to an XDG toplevel window, which provides a standard desktop window.
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.2.6
|
||||
* Main include header for the SDL library, version 3.2.18
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
||||
@@ -1021,7 +1021,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream);
|
||||
/**
|
||||
* Query an audio stream for its currently-bound device.
|
||||
*
|
||||
* This reports the audio device that an audio stream is currently bound to.
|
||||
* This reports the logical audio device that an audio stream is currently bound to.
|
||||
*
|
||||
* If not bound, or invalid, this returns zero, which is not a valid device
|
||||
* ID.
|
||||
@@ -1717,7 +1717,7 @@ typedef void (SDLCALL *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream
|
||||
* audio to the stream during this call; if needed, the request that triggered
|
||||
* this callback will obtain the new data immediately.
|
||||
*
|
||||
* The callback's `approx_request` argument is roughly how many bytes of
|
||||
* The callback's `additional_amount` argument is roughly how many bytes of
|
||||
* _unconverted_ data (in the stream's input format) is needed by the caller,
|
||||
* although this may overestimate a little for safety. This takes into account
|
||||
* how much is already in the stream and only asks for any extra necessary to
|
||||
@@ -1762,13 +1762,13 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamGetCallback(SDL_AudioStream *
|
||||
* The callback can (optionally) call SDL_GetAudioStreamData() to obtain audio
|
||||
* from the stream during this call.
|
||||
*
|
||||
* The callback's `approx_request` argument is how many bytes of _converted_
|
||||
* data (in the stream's output format) was provided by the caller, although
|
||||
* this may underestimate a little for safety. This value might be less than
|
||||
* what is currently available in the stream, if data was already there, and
|
||||
* might be less than the caller provided if the stream needs to keep a buffer
|
||||
* to aid in resampling. Which means the callback may be provided with zero
|
||||
* bytes, and a different amount on each call.
|
||||
* The callback's `additional_amount` argument is how many bytes of
|
||||
* _converted_ data (in the stream's output format) was provided by the
|
||||
* caller, although this may underestimate a little for safety. This value
|
||||
* might be less than what is currently available in the stream, if data was
|
||||
* already there, and might be less than the caller provided if the stream
|
||||
* needs to keep a buffer to aid in resampling. Which means the callback may
|
||||
* be provided with zero bytes, and a different amount on each call.
|
||||
*
|
||||
* The callback may call SDL_GetAudioStreamAvailable to see the total amount
|
||||
* currently available to read from the stream, instead of the total provided
|
||||
|
||||
@@ -486,7 +486,7 @@ SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Swap a 16-bit value from littleendian to native byte order.
|
||||
|
||||
@@ -492,6 +492,8 @@ typedef struct SDL_MouseWheelEvent
|
||||
SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
|
||||
float mouse_x; /**< X coordinate, relative to window */
|
||||
float mouse_y; /**< Y coordinate, relative to window */
|
||||
Sint32 integer_x; /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
Sint32 integer_y; /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
} SDL_MouseWheelEvent;
|
||||
|
||||
/**
|
||||
|
||||
+11
-11
@@ -2467,9 +2467,9 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader(
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only)
|
||||
* if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear
|
||||
* the texture to a depth of this value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12
|
||||
* only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
||||
* clear the texture to a stencil of this value. Defaults to zero.
|
||||
* clear the texture to a stencil of this Uint8 value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed
|
||||
* in debugging tools.
|
||||
*
|
||||
@@ -2495,13 +2495,13 @@ extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture(
|
||||
SDL_GPUDevice *device,
|
||||
const SDL_GPUTextureCreateInfo *createinfo);
|
||||
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
|
||||
/**
|
||||
* Creates a buffer object to be used in graphics or compute workflows.
|
||||
@@ -3775,7 +3775,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice(
|
||||
* supported via SDL_WindowSupportsGPUPresentMode /
|
||||
* SDL_WindowSupportsGPUSwapchainComposition prior to calling this function.
|
||||
*
|
||||
* SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* supported.
|
||||
*
|
||||
* \param device a GPU context.
|
||||
@@ -4145,7 +4145,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUTextureSupportsFormat(
|
||||
* \param device a GPU context.
|
||||
* \param format the texture format to check.
|
||||
* \param sample_count the sample count to check.
|
||||
* \returns a hardware-specific version of min(preferred, possible).
|
||||
* \returns whether the sample count is supported for this texture format.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
|
||||
@@ -1074,8 +1074,8 @@ extern "C" {
|
||||
*
|
||||
* By default, SDL will try all available GPU backends in a reasonable order
|
||||
* until it finds one that can work, but this hint allows the app or user to
|
||||
* force a specific target, such as "direct3d11" if, say, your hardware
|
||||
* supports D3D12 but want to try using D3D11 instead.
|
||||
* force a specific target, such as "direct3d12" if, say, your hardware
|
||||
* supports Vulkan but you want to try using D3D12 instead.
|
||||
*
|
||||
* This hint should be set before any GPU functions are called.
|
||||
*
|
||||
@@ -2026,8 +2026,8 @@ extern "C" {
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": RAWINPUT drivers are not used.
|
||||
* - "1": RAWINPUT drivers are used. (default)
|
||||
* - "0": RAWINPUT drivers are not used. (default)
|
||||
* - "1": RAWINPUT drivers are used.
|
||||
*
|
||||
* This hint should be set before SDL is initialized.
|
||||
*
|
||||
@@ -3607,6 +3607,22 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_VIDEO_WIN_D3DCOMPILER "SDL_VIDEO_WIN_D3DCOMPILER"
|
||||
|
||||
/**
|
||||
* A variable controlling whether SDL should call XSelectInput() to enable
|
||||
* input events on X11 windows wrapped by SDL windows.
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": Don't call XSelectInput(), assuming the native window code has done
|
||||
* it already.
|
||||
* - "1": Call XSelectInput() to enable input events. (default)
|
||||
*
|
||||
* This hint should be set before creating a window.
|
||||
*
|
||||
* \since This hint is available since SDL 3.2.10.
|
||||
*/
|
||||
#define SDL_HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT "SDL_VIDEO_X11_EXTERNAL_WINDOW_INPUT"
|
||||
|
||||
/**
|
||||
* A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint
|
||||
* should be used.
|
||||
|
||||
@@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags;
|
||||
|
||||
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_HAPTIC 0x00001000u
|
||||
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
|
||||
#define SDL_INIT_EVENTS 0x00004000u
|
||||
|
||||
@@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout
|
||||
* ABGR32, define a platform-independent encoding into bytes in the order
|
||||
* specified. For example, in RGB24 data, each pixel is encoded in 3 bytes
|
||||
* (red, green, blue) in that order, and in ABGR32 data, each pixel is
|
||||
* encoded in 4 bytes alpha, blue, green, red) in that order. Use these
|
||||
* encoded in 4 bytes (alpha, blue, green, red) in that order. Use these
|
||||
* names if the property of a format that is important to you is the order
|
||||
* of the bytes in memory or on disk.
|
||||
* - Names with a bit count per component, such as ARGB8888 and XRGB1555, are
|
||||
|
||||
@@ -79,6 +79,10 @@ typedef enum SDL_PowerState
|
||||
* It's possible a platform can only report battery percentage or time left
|
||||
* but not both.
|
||||
*
|
||||
* On some platforms, retrieving power supply details might be expensive. If
|
||||
* you want to display continuous status you could call this function every
|
||||
* minute or so.
|
||||
*
|
||||
* \param seconds a pointer filled in with the seconds of battery life left,
|
||||
* or NULL to ignore. This will be filled in with -1 if we
|
||||
* can't determine a value or there is no battery.
|
||||
|
||||
@@ -1607,8 +1607,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
|
||||
* Return whether an explicit rectangle was set as the viewport.
|
||||
*
|
||||
* This is useful if you're saving and restoring the viewport and want to know
|
||||
* whether you should restore a specific rectangle or NULL. Note that the
|
||||
* viewport is always reset when changing rendering targets.
|
||||
* whether you should restore a specific rectangle or NULL.
|
||||
*
|
||||
* Each render target has its own viewport. This function checks the viewport
|
||||
* for the current render target.
|
||||
|
||||
@@ -1299,8 +1299,11 @@ extern "C" {
|
||||
*
|
||||
* If `size` is 0, it will be set to 1.
|
||||
*
|
||||
* If you want to allocate memory aligned to a specific alignment, consider
|
||||
* using SDL_aligned_alloc().
|
||||
* If the allocation is successful, the returned pointer is guaranteed to be
|
||||
* aligned to either the *fundamental alignment* (`alignof(max_align_t)` in
|
||||
* C11 and later) or `2 * sizeof(void *)`, whichever is smaller. Use
|
||||
* SDL_aligned_alloc() if you need to allocate memory aligned to an alignment
|
||||
* greater than this guarantee.
|
||||
*
|
||||
* \param size the size to allocate.
|
||||
* \returns a pointer to the allocated memory, or NULL if allocation failed.
|
||||
@@ -1323,6 +1326,10 @@ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_malloc(size_t size);
|
||||
*
|
||||
* If either of `nmemb` or `size` is 0, they will both be set to 1.
|
||||
*
|
||||
* If the allocation is successful, the returned pointer is guaranteed to be
|
||||
* aligned to either the *fundamental alignment* (`alignof(max_align_t)` in
|
||||
* C11 and later) or `2 * sizeof(void *)`, whichever is smaller.
|
||||
*
|
||||
* \param nmemb the number of elements in the array.
|
||||
* \param size the size of each element of the array.
|
||||
* \returns a pointer to the allocated array, or NULL if allocation failed.
|
||||
@@ -1357,6 +1364,11 @@ extern SDL_DECLSPEC SDL_MALLOC SDL_ALLOC_SIZE2(1, 2) void * SDLCALL SDL_calloc(s
|
||||
* - If it returns NULL (indicating failure), then `mem` will remain valid and
|
||||
* must still be freed with SDL_free().
|
||||
*
|
||||
* If the allocation is successfully resized, the returned pointer is
|
||||
* guaranteed to be aligned to either the *fundamental alignment*
|
||||
* (`alignof(max_align_t)` in C11 and later) or `2 * sizeof(void *)`,
|
||||
* whichever is smaller.
|
||||
*
|
||||
* \param mem a pointer to allocated memory to reallocate, or NULL.
|
||||
* \param size the new size of the memory.
|
||||
* \returns a pointer to the newly allocated memory, or NULL if allocation
|
||||
@@ -4644,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x);
|
||||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on double-precision floating point values, use
|
||||
* SDL_atan2f for single-precision floats.
|
||||
@@ -4680,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x);
|
||||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on single-precision floating point values, use
|
||||
* SDL_atan2 for double-precision floats.
|
||||
@@ -5962,8 +5974,12 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
|
||||
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* strdup is not ANSI but POSIX, and its prototype might be hidden... */
|
||||
/* not for windows: might conflict with string.h where strdup may have
|
||||
* dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */
|
||||
char *strdup(const char *str);
|
||||
#endif
|
||||
|
||||
/* Starting LLVM 16, the analyser errors out if these functions do not have
|
||||
their prototype defined (clang-diagnostic-implicit-function-declaration) */
|
||||
|
||||
+130
-29
@@ -82,6 +82,7 @@ typedef Uint32 SDL_SurfaceFlags;
|
||||
*/
|
||||
typedef enum SDL_ScaleMode
|
||||
{
|
||||
SDL_SCALEMODE_INVALID = -1,
|
||||
SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
|
||||
SDL_SCALEMODE_LINEAR /**< linear filtering */
|
||||
} SDL_ScaleMode;
|
||||
@@ -156,6 +157,8 @@ typedef struct SDL_Surface SDL_Surface;
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* 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.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurfaceFrom
|
||||
@@ -184,6 +187,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurface(int width, int heigh
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* 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.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -198,6 +203,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurfaceFrom(int width, int h
|
||||
*
|
||||
* \param surface the SDL_Surface to free.
|
||||
*
|
||||
* \threadsafety No other thread should be using the surface when it is freed.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -233,6 +240,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||
* \returns a valid property ID on success or 0 on failure; 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.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
|
||||
@@ -255,6 +264,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorspace
|
||||
@@ -272,6 +283,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface,
|
||||
* \returns the colorspace used by the surface, or SDL_COLORSPACE_UNKNOWN if
|
||||
* the surface is NULL.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorspace
|
||||
@@ -300,6 +313,8 @@ extern SDL_DECLSPEC SDL_Colorspace SDLCALL SDL_GetSurfaceColorspace(SDL_Surface
|
||||
* the surface didn't have an index format); call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetPaletteColors
|
||||
@@ -316,6 +331,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface *
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreatePalette
|
||||
@@ -330,6 +347,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfacePalette(SDL_Surface *surface, SDL
|
||||
* \returns a pointer to the palette used by the surface, or NULL if there is
|
||||
* no palette used.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfacePalette
|
||||
@@ -353,6 +372,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetSurfacePalette(SDL_Surface *sur
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RemoveSurfaceAlternateImages
|
||||
@@ -367,6 +388,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AddSurfaceAlternateImage(SDL_Surface *surfa
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if alternate versions are available or false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -392,6 +415,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasAlternateImages(SDL_Surface *surf
|
||||
* failure; call SDL_GetError() for more information. This should be
|
||||
* freed with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -408,6 +433,8 @@ extern SDL_DECLSPEC SDL_Surface ** SDLCALL SDL_GetSurfaceImages(SDL_Surface *sur
|
||||
*
|
||||
* \param surface the SDL_Surface structure to update.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -432,6 +459,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveSurfaceAlternateImages(SDL_Surface *s
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe. The locking referred to by
|
||||
* this function is making the pixels available for direct
|
||||
* access, not thread-safe locking.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MUSTLOCK
|
||||
@@ -444,6 +475,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_LockSurface(SDL_Surface *surface);
|
||||
*
|
||||
* \param surface the SDL_Surface structure to be unlocked.
|
||||
*
|
||||
* \threadsafety This function is not thread safe. The locking referred to by
|
||||
* this function is making the pixels available for direct
|
||||
* access, not thread-safe locking.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LockSurface
|
||||
@@ -462,6 +497,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface);
|
||||
* \returns a pointer to a new SDL_Surface structure or NULL on failure; 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.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -480,6 +517,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP_IO(SDL_IOStream *src, bool
|
||||
* \returns a pointer to a new SDL_Surface structure or NULL on failure; 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.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -504,6 +543,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP(const char *file);
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LoadBMP_IO
|
||||
@@ -525,6 +566,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStre
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LoadBMP
|
||||
@@ -543,6 +586,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *f
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_BlitSurface
|
||||
@@ -559,6 +604,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceRLE(SDL_Surface *surface, bool en
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if the surface is RLE enabled, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceRLE
|
||||
@@ -581,6 +628,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasRLE(SDL_Surface *surface);
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorKey
|
||||
@@ -597,6 +646,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorKey(SDL_Surface *surface, bo
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if the surface has a color key, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorKey
|
||||
@@ -617,6 +668,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasColorKey(SDL_Surface *surface);
|
||||
* \returns true on success or false on failure; 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.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorKey
|
||||
@@ -640,6 +693,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorMod
|
||||
@@ -658,6 +713,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceAlphaMod
|
||||
@@ -678,6 +735,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceAlphaMod
|
||||
@@ -693,6 +752,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; 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.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorMod
|
||||
@@ -712,6 +773,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceBlendMode
|
||||
@@ -726,6 +789,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface, S
|
||||
* \returns true on success or false on failure; 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.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceBlendMode
|
||||
@@ -747,6 +812,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface, S
|
||||
* \returns true if the rectangle intersects the surface, otherwise false and
|
||||
* blits will be completely clipped.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceClipRect
|
||||
@@ -766,6 +833,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface, co
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceClipRect
|
||||
@@ -780,6 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface, SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip);
|
||||
@@ -796,6 +867,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM
|
||||
* \returns a copy of the surface or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -815,6 +888,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_DuplicateSurface(SDL_Surface *surf
|
||||
* \returns a copy of the surface or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -840,6 +915,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ScaleSurface(SDL_Surface *surface,
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertSurfaceAndColorspace
|
||||
@@ -866,6 +943,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurface(SDL_Surface *surfac
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertSurface
|
||||
@@ -887,6 +966,10 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurfaceAndColorspace(SDL_Su
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertPixelsAndColorspace
|
||||
@@ -916,6 +999,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixels(int width, int height, SDL_Pi
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertPixels
|
||||
@@ -940,6 +1027,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixelsAndColorspace(int width, int h
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL_PixelFormat src_format, const void *src, int src_pitch, SDL_PixelFormat dst_format, void *dst, int dst_pitch, bool linear);
|
||||
@@ -955,6 +1046,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surface, bool linear);
|
||||
@@ -975,6 +1068,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surfac
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r, float g, float b, float a);
|
||||
@@ -998,6 +1093,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_FillSurfaceRects
|
||||
@@ -1023,6 +1120,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRect(SDL_Surface *dst, const SDL
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_FillSurfaceRect
|
||||
@@ -1036,9 +1135,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
|
||||
* If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or
|
||||
* `dst`) is copied while ensuring clipping to `dst->clip_rect`.
|
||||
*
|
||||
* The final blit rectangles are saved in `srcrect` and `dstrect` after all
|
||||
* clipping is performed.
|
||||
*
|
||||
* The blit function should not be called on a locked surface.
|
||||
*
|
||||
* The blit semantics for surfaces with and without blending and colorkey are
|
||||
@@ -1096,9 +1192,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1121,9 +1216,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface(SDL_Surface *src, const SDL_Rec
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1146,9 +1240,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUnchecked(SDL_Surface *src, cons
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1172,9 +1265,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const S
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1187,17 +1279,17 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src
|
||||
*
|
||||
* \param src the SDL_Surface structure to be copied from.
|
||||
* \param srcrect the SDL_Rect structure representing the rectangle to be
|
||||
* copied, may not be NULL.
|
||||
* copied, or NULL to copy the entire surface.
|
||||
* \param dst the SDL_Surface structure that is the blit target.
|
||||
* \param dstrect the SDL_Rect structure representing the target rectangle in
|
||||
* the destination surface, may not be NULL.
|
||||
* the destination surface, or NULL to fill the entire
|
||||
* destination surface.
|
||||
* \param scaleMode the SDL_ScaleMode to be used.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
@@ -1221,9 +1313,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_StretchSurface(SDL_Surface *src, const SDL_
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1251,9 +1342,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiled(SDL_Surface *src, const SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1288,9 +1378,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiledWithScale(SDL_Surface *src,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1322,6 +1411,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface9Grid(SDL_Surface *src, const SD
|
||||
* \param b the blue component of the pixel in the range 0-255.
|
||||
* \returns a pixel value.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MapSurfaceRGBA
|
||||
@@ -1353,6 +1444,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8
|
||||
* \param a the alpha component of the pixel in the range 0-255.
|
||||
* \returns a pixel value.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MapSurfaceRGB
|
||||
@@ -1382,6 +1475,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
|
||||
@@ -1406,6 +1501,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, float *g, float *b, float *a);
|
||||
@@ -1429,6 +1526,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
@@ -1449,6 +1548,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixelFloat(SDL_Surface *surface, int x, int y, float r, float g, float b, float a);
|
||||
|
||||
@@ -62,7 +62,7 @@ extern "C" {
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MICRO_VERSION 6
|
||||
#define SDL_MICRO_VERSION 18
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
||||
@@ -426,10 +426,10 @@ typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDi
|
||||
*/
|
||||
typedef enum SDL_GLAttr
|
||||
{
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */
|
||||
SDL_GL_DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */
|
||||
SDL_GL_DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */
|
||||
@@ -1041,6 +1041,10 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count);
|
||||
/**
|
||||
* Create a window with the specified dimensions and flags.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* `flags` may be any of the following OR'd together:
|
||||
*
|
||||
* - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution
|
||||
@@ -1127,6 +1131,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
||||
/**
|
||||
* Create a child popup window of the specified parent window.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* The flags parameter **must** contain at least one of the following:
|
||||
*
|
||||
* - `SDL_WINDOW_TOOLTIP`: The popup window is a tooltip and will not pass any
|
||||
@@ -1159,6 +1167,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
||||
* Popup windows implicitly do not have a border/decorations and do not appear
|
||||
* on the taskbar/dock or in lists of windows such as alt-tab menus.
|
||||
*
|
||||
* By default, popup window positions will automatically be constrained to keep
|
||||
* the entire window within display bounds. This can be overridden with the
|
||||
* `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN` property.
|
||||
*
|
||||
* By default, popup menus will automatically grab keyboard focus from the parent
|
||||
* when shown. This behavior can be overridden by setting the `SDL_WINDOW_NOT_FOCUSABLE`
|
||||
* flag, setting the `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN` property to false, or
|
||||
* toggling it after creation via the `SDL_SetWindowFocusable()` function.
|
||||
*
|
||||
* If a parent window is hidden or destroyed, any child popup windows will be
|
||||
* recursively hidden or destroyed as well. Child popup windows not explicitly
|
||||
* hidden will be restored when the parent is shown.
|
||||
@@ -1189,12 +1206,19 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
||||
/**
|
||||
* Create a window with the specified properties.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN`: true if the window should
|
||||
* be always on top
|
||||
* - `SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN`: true if the window has no
|
||||
* window decoration
|
||||
* - `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN`: true if the "tooltip" and
|
||||
* "menu" window types should be automatically constrained to be entirely within
|
||||
* display bounds (default), false if no constraints on the position are desired.
|
||||
* - `SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN`: true if the
|
||||
* window will be used with an externally managed graphics context.
|
||||
* - `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN`: true if the window should
|
||||
@@ -1309,6 +1333,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop
|
||||
|
||||
#define SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN "SDL.window.create.always_on_top"
|
||||
#define SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN "SDL.window.create.borderless"
|
||||
#define SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN "SDL.window.create.constrain_popup"
|
||||
#define SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN "SDL.window.create.focusable"
|
||||
#define SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN "SDL.window.create.external_graphics_context"
|
||||
#define SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER "SDL.window.create.flags"
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Avoid including vulkan.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_H_
|
||||
/* Avoid including vulkan_core.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_CORE_H_
|
||||
#define NO_SDL_VULKAN_TYPEDEFS
|
||||
#endif
|
||||
#ifndef NO_SDL_VULKAN_TYPEDEFS
|
||||
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
|
||||
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64)
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
|
||||
#else
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// Initialization/Cleanup routines
|
||||
#include "timer/SDL_timer_c.h"
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
extern bool SDL_HelperWindowCreate(void);
|
||||
extern void SDL_HelperWindowDestroy(void);
|
||||
#endif
|
||||
@@ -317,7 +317,7 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_DBus_Init();
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) {
|
||||
if (!SDL_HelperWindowCreate()) {
|
||||
goto quit_and_error;
|
||||
@@ -356,7 +356,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO);
|
||||
if (!SDL_VideoInit(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -381,7 +383,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_AUDIO);
|
||||
if (!SDL_InitAudio(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -406,7 +410,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_JOYSTICK);
|
||||
if (!SDL_InitJoysticks()) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -430,7 +436,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_GAMEPAD);
|
||||
if (!SDL_InitGamepads()) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -493,7 +501,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA);
|
||||
if (!SDL_CameraInit(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -511,7 +521,11 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
return SDL_ClearError();
|
||||
|
||||
quit_and_error:
|
||||
SDL_QuitSubSystem(flags_initialized);
|
||||
{
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(flags_initialized);
|
||||
SDL_PopError();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -639,7 +653,7 @@ void SDL_Quit(void)
|
||||
SDL_bInMainQuit = true;
|
||||
|
||||
// Quit all subsystems
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
SDL_HelperWindowDestroy();
|
||||
#endif
|
||||
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
|
||||
|
||||
+16
-18
@@ -34,15 +34,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
// older Emscriptens don't have this, but we need to for wasm64 compatibility.
|
||||
#ifndef MAIN_THREAD_EM_ASM_PTR
|
||||
#ifdef __wasm64__
|
||||
#error You need to upgrade your Emscripten compiler to support wasm64
|
||||
#else
|
||||
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
|
||||
#endif
|
||||
#endif
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
// The size of the stack buffer to use for rendering assert messages.
|
||||
@@ -252,7 +244,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
for (;;) {
|
||||
bool okay = true;
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
char *buf = (char *) MAIN_THREAD_EM_ASM_PTR({
|
||||
int reply = MAIN_THREAD_EM_ASM_INT({
|
||||
var str =
|
||||
UTF8ToString($0) + '\n\n' +
|
||||
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
|
||||
@@ -260,26 +252,32 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
if (reply === null) {
|
||||
reply = "i";
|
||||
}
|
||||
return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
|
||||
return reply.length === 1 ? reply.charCodeAt(0) : -1;
|
||||
}, message);
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
if (SDL_strcmp(buf, "a") == 0) {
|
||||
switch (reply) {
|
||||
case 'a':
|
||||
state = SDL_ASSERTION_ABORT;
|
||||
break;
|
||||
#if 0 // (currently) no break functionality on Emscripten
|
||||
} else if (SDL_strcmp(buf, "b") == 0) {
|
||||
case 'b':
|
||||
state = SDL_ASSERTION_BREAK;
|
||||
break;
|
||||
#endif
|
||||
} else if (SDL_strcmp(buf, "r") == 0) {
|
||||
case 'r':
|
||||
state = SDL_ASSERTION_RETRY;
|
||||
} else if (SDL_strcmp(buf, "i") == 0) {
|
||||
break;
|
||||
case 'i':
|
||||
state = SDL_ASSERTION_IGNORE;
|
||||
} else if (SDL_strcmp(buf, "A") == 0) {
|
||||
break;
|
||||
case 'A':
|
||||
state = SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
okay = false;
|
||||
break;
|
||||
}
|
||||
free(buf); // This should NOT be SDL_free()
|
||||
|
||||
if (okay) {
|
||||
break;
|
||||
|
||||
@@ -46,4 +46,16 @@ typedef struct SDL_error
|
||||
// Defined in SDL_thread.c
|
||||
extern SDL_error *SDL_GetErrBuf(bool create);
|
||||
|
||||
// Macros to save and restore error values
|
||||
#define SDL_PushError() \
|
||||
char *saved_error = SDL_strdup(SDL_GetError())
|
||||
|
||||
#define SDL_PopError() \
|
||||
do { \
|
||||
if (saved_error) { \
|
||||
SDL_SetError("%s", saved_error); \
|
||||
SDL_free(saved_error); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // SDL_error_c_h_
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "SDL_hints_c.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "core/android/SDL_android.h"
|
||||
#endif
|
||||
|
||||
typedef struct SDL_HintWatch
|
||||
{
|
||||
SDL_HintCallback callback;
|
||||
@@ -147,6 +151,13 @@ bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriori
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(value, false));
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
@@ -185,6 +196,17 @@ bool SDL_ResetHint(const char *name)
|
||||
result = true;
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
@@ -210,6 +232,17 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
|
||||
SDL_free(hint->value);
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
}
|
||||
|
||||
void SDL_ResetHints(void)
|
||||
|
||||
@@ -265,6 +265,12 @@ extern "C" {
|
||||
#include "SDL_utils_c.h"
|
||||
#include "SDL_hashtable.h"
|
||||
|
||||
#define PUSH_SDL_ERROR() \
|
||||
{ char *_error = SDL_strdup(SDL_GetError());
|
||||
|
||||
#define POP_SDL_ERROR() \
|
||||
SDL_SetError("%s", _error); SDL_free(_error); }
|
||||
|
||||
// Do any initialization that needs to happen before threads are started
|
||||
extern void SDL_InitMainThread(void);
|
||||
|
||||
|
||||
+5
-1
@@ -403,6 +403,10 @@ const char *SDL_GetPersistentString(const char *string)
|
||||
static int PrefixMatch(const char *a, const char *b)
|
||||
{
|
||||
int matchlen = 0;
|
||||
// Fixes the "HORI HORl Taiko No Tatsujin Drum Controller"
|
||||
if (SDL_strncmp(a, "HORI ", 5) == 0 && SDL_strncmp(b, "HORl ", 5) == 0) {
|
||||
return 5;
|
||||
}
|
||||
while (*a && *b) {
|
||||
if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) {
|
||||
++matchlen;
|
||||
@@ -424,8 +428,8 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
|
||||
{ "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" },
|
||||
{ "HORI CO.,LTD", "HORI" },
|
||||
{ "Mad Catz Inc.", "Mad Catz" },
|
||||
{ "Nintendo Co., Ltd.", "Nintendo" },
|
||||
{ "NVIDIA Corporation ", "" },
|
||||
|
||||
+61
-18
@@ -410,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
|
||||
if (logdev) {
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
device = logdev->physical_device;
|
||||
SDL_assert(device != NULL);
|
||||
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
|
||||
@@ -459,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
|
||||
} else {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
|
||||
SDL_assert(device->instance_id == devid);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
if (!device) {
|
||||
@@ -883,6 +885,7 @@ static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *tabl
|
||||
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
|
||||
data->highest = devid;
|
||||
data->result = (SDL_AudioDevice *) value;
|
||||
SDL_assert(data->result->instance_id == devid);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
@@ -1051,7 +1054,10 @@ static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_Hash
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
|
||||
|
||||
SDL_assert(dev->instance_id == devid);
|
||||
DestroyPhysicalAudioDevice(dev);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
@@ -1256,11 +1262,11 @@ static int SDLCALL PlaybackAudioThread(void *devicep) // thread entry point
|
||||
SDL_assert(!device->recording);
|
||||
SDL_PlaybackAudioThreadSetup(device);
|
||||
|
||||
do {
|
||||
while (SDL_PlaybackAudioThreadIterate(device)) {
|
||||
if (!device->WaitDevice(device)) {
|
||||
SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
|
||||
}
|
||||
} while (SDL_PlaybackAudioThreadIterate(device));
|
||||
}
|
||||
|
||||
SDL_PlaybackAudioThreadShutdown(device);
|
||||
return 0;
|
||||
@@ -1385,6 +1391,7 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
typedef struct CountAudioDevicesData
|
||||
{
|
||||
int devs_seen;
|
||||
int devs_skipped;
|
||||
const int num_devices;
|
||||
SDL_AudioDeviceID *result;
|
||||
const bool recording;
|
||||
@@ -1400,7 +1407,13 @@ static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table
|
||||
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;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value; // this is normally risky, but we hold the device_hash_lock here.
|
||||
const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
|
||||
if (zombie) {
|
||||
data->devs_skipped++;
|
||||
} else {
|
||||
data->result[data->devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
@@ -1416,10 +1429,11 @@ 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) {
|
||||
CountAudioDevicesData data = { 0, num_devices, result, recording };
|
||||
CountAudioDevicesData data = { 0, 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_assert((data.devs_seen + data.devs_skipped) == num_devices);
|
||||
num_devices = data.devs_seen; // might be less if we skipped any.
|
||||
result[num_devices] = 0; // null-terminated.
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -1464,6 +1478,7 @@ static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTabl
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
SDL_assert(data->retval->instance_id == devid);
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
@@ -1502,12 +1517,33 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
|
||||
|
||||
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool islogical = !(devid & (1<<1));
|
||||
const char *result = NULL;
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
|
||||
if (device) {
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
const void *vdev = NULL;
|
||||
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
SDL_SetError("Audio subsystem is not initialized");
|
||||
} else {
|
||||
// This does not call ObtainPhysicalAudioDevice() because the device's name never changes, so
|
||||
// it doesn't have to lock the whole device. However, just to make sure the device pointer itself
|
||||
// remains valid (in case the device is unplugged at the wrong moment), we hold the
|
||||
// device_hash_lock while we copy the string.
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
|
||||
if (!vdev) {
|
||||
SDL_SetError("Invalid audio device instance ID");
|
||||
} else if (islogical) {
|
||||
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
result = SDL_GetPersistentString(logdev->physical_device->name);
|
||||
} else {
|
||||
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
|
||||
SDL_assert(device->instance_id == devid);
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1539,7 +1575,9 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
|
||||
if (device) {
|
||||
channels = device->spec.channels;
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
if (channels > 0 && device->chmap) {
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
}
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
@@ -1715,13 +1753,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->recording, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
|
||||
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
|
||||
/* We impose a simple minimum on device formats. This prevents something low quality, like an old game using S8/8000Hz audio,
|
||||
from ruining a music thing playing at CD quality that tries to open later, or some VoIP library that opens for mono output
|
||||
ruining your surround-sound game because it got there first.
|
||||
These are just requests! The backend may change any of these values during OpenDevice method! */
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
|
||||
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
|
||||
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
|
||||
|
||||
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
|
||||
device->spec.channels = SDL_max(minimum_channels, spec.channels);
|
||||
device->spec.freq = SDL_max(minimum_freq, spec.freq);
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "SDL_sysaudio.h"
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
#include <fenv.h>
|
||||
#endif
|
||||
|
||||
#define DIVBY2147483648 0.0000000004656612873077392578125f // 0x1p-31f
|
||||
|
||||
// start fallback scalar converters
|
||||
@@ -527,9 +531,27 @@ static void SDL_TARGETING("ssse3") SDL_Convert_Swap32_SSSE3(Uint32* dst, const U
|
||||
#endif
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
|
||||
// C99 requires that all code modifying floating point environment should
|
||||
// be guarded by the STDC FENV_ACCESS pragma; otherwise, it's undefined
|
||||
// behavior. However, the compiler support for this pragma is bad.
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (on)
|
||||
#elif defined(__GNUC__)
|
||||
// GCC does not support the pragma at all
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
|
||||
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 7), 0);
|
||||
@@ -549,11 +571,14 @@ static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("U8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -575,11 +600,14 @@ static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S16", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 15), 0);
|
||||
@@ -597,11 +625,14 @@ static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vld1_dup_s32(&src[i]), 31), 0);
|
||||
@@ -621,11 +652,14 @@ static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s8(&dst[i], vreinterpret_s8_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 3);
|
||||
@@ -647,11 +681,14 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_s8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "U8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -679,11 +716,14 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_u8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S16 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s16(&dst[i], vreinterpret_s16_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 1);
|
||||
@@ -704,11 +744,14 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
|
||||
vst1q_s16(&dst[i], shorts0);
|
||||
vst1q_s16(&dst[i + 8], shorts1);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s32(&dst[i], vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31), 0);
|
||||
@@ -728,6 +771,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
|
||||
vst1q_s32(&dst[i + 8], ints2);
|
||||
vst1q_s32(&dst[i + 12], ints3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_Swap16_NEON(Uint16* dst, const Uint16* src, int num_samples)
|
||||
@@ -767,6 +811,19 @@ static void SDL_Convert_Swap32_NEON(Uint32* dst, const Uint32* src, int num_samp
|
||||
vst1q_u8((Uint8*)&dst[i + 12], ints3);
|
||||
})
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (off)
|
||||
#elif defined(__GNUC__)
|
||||
//
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#undef CONVERT_16_FWD
|
||||
|
||||
@@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
ctx.AAudioStreamBuilder_setFormat(builder, format);
|
||||
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
|
||||
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
|
||||
|
||||
// If no specific buffer size has been requested, the device will pick the optimal
|
||||
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
|
||||
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
|
||||
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
|
||||
}
|
||||
|
||||
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
@@ -366,7 +372,7 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
hidden->processed_bytes = 0;
|
||||
hidden->callback_bytes = 0;
|
||||
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers - 1);
|
||||
if (!hidden->semaphore) {
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
|
||||
return false;
|
||||
|
||||
@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
|
||||
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
|
||||
|
||||
@@ -1156,7 +1156,7 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
#if SDL_ALSA_DEBUG
|
||||
snd_pcm_uframes_t bufsize;
|
||||
ALSA_snd_pcm_hw_params_get_buffer_size(cfg_ctx.hwparams, &bufsize);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO,
|
||||
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
|
||||
cfg_ctx.persize, cfg_ctx.periods, bufsize);
|
||||
#endif
|
||||
@@ -1187,7 +1187,6 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
ALSA_snd_pcm_nonblock(cfg_ctx.device->hidden->pcm, 0);
|
||||
}
|
||||
#endif
|
||||
ALSA_snd_pcm_start(cfg_ctx.device->hidden->pcm);
|
||||
return true; // We're ready to rock and roll. :-)
|
||||
|
||||
err_cleanup_ctx:
|
||||
@@ -1200,6 +1199,13 @@ err_free_device_hidden:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ALSA_ThreadInit(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
// do snd_pcm_start as close to the first time we PlayDevice as possible to prevent an underrun at startup.
|
||||
ALSA_snd_pcm_start(device->hidden->pcm);
|
||||
}
|
||||
|
||||
static ALSA_Device *hotplug_devices = NULL;
|
||||
|
||||
static int hotplug_device_process(snd_ctl_t *ctl, snd_ctl_card_info_t *ctl_card_info, int dev_idx,
|
||||
@@ -1497,6 +1503,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
|
||||
impl->DetectDevices = ALSA_DetectDevices;
|
||||
impl->OpenDevice = ALSA_OpenDevice;
|
||||
impl->ThreadInit = ALSA_ThreadInit;
|
||||
impl->WaitDevice = ALSA_WaitDevice;
|
||||
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
|
||||
impl->PlayDevice = ALSA_PlayDevice;
|
||||
|
||||
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
|
||||
{
|
||||
#ifdef HAVE_MMDEVICEAPI_H
|
||||
if (SupportsIMMDevice) {
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
@@ -189,7 +189,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// limit to native freq
|
||||
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->spec.freq = MAIN_THREAD_EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq) * 2; // double the buffer size, some browsers need more, and we'll just have to live with the latency.
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
@@ -1118,7 +1118,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
||||
if (!stream_name || *stream_name == '\0') {
|
||||
stream_name = "Audio Stream";
|
||||
if (app_name) {
|
||||
stream_name = app_name;
|
||||
} else if (app_id) {
|
||||
stream_name = app_id;
|
||||
} else {
|
||||
stream_name = "SDL Audio Stream";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1187,7 +1193,11 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", device->sample_frames, device->spec.freq);
|
||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", device->spec.freq);
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); // Requesting a specific device, don't migrate to new default hardware.
|
||||
|
||||
// UPDATE: This prevents users from moving the audio to a new sink (device) using standard tools. This is slightly in conflict
|
||||
// with how SDL wants to manage audio devices, but if people want to do it, we should let them, so this is commented out
|
||||
// for now. We might revisit later.
|
||||
//PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); // Requesting a specific device, don't migrate to new default hardware.
|
||||
|
||||
if (node_id != PW_ID_ANY) {
|
||||
PIPEWIRE_pw_thread_loop_lock(hotplug_loop);
|
||||
|
||||
@@ -409,7 +409,7 @@ static bool PULSEAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
bool result = true;
|
||||
|
||||
//SDL_Log("PULSEAUDIO PLAYDEVICE START! mixlen=%d", available);
|
||||
//SDL_Log("PULSEAUDIO WAITDEVICE START! mixlen=%d", available);
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
@@ -672,7 +672,8 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
paspec.rate = device->spec.freq;
|
||||
|
||||
// Reduced prebuffering compared to the defaults.
|
||||
paattr.fragsize = device->buffer_size; // despite the name, this is only used for recording devices, according to PulseAudio docs!
|
||||
|
||||
paattr.fragsize = device->buffer_size * 2; // despite the name, this is only used for recording devices, according to PulseAudio docs! (times 2 because we want _more_ than our buffer size sent from the server at a time, which helps some drivers).
|
||||
paattr.tlength = device->buffer_size;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
@@ -701,7 +702,10 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
PULSEAUDIO_pa_stream_set_state_callback(h->stream, PulseStreamStateChangeCallback, NULL);
|
||||
|
||||
// SDL manages device moves if the default changes, so don't ever let Pulse automatically migrate this stream.
|
||||
flags |= PA_STREAM_DONT_MOVE;
|
||||
// UPDATE: This prevents users from moving the audio to a new sink (device) using standard tools. This is slightly in conflict
|
||||
// with how SDL wants to manage audio devices, but if people want to do it, we should let them, so this is commented out
|
||||
// for now. We might revisit later.
|
||||
//flags |= PA_STREAM_DONT_MOVE;
|
||||
|
||||
const char *device_path = ((PulseDeviceHandle *) device->handle)->device_path;
|
||||
if (recording) {
|
||||
|
||||
@@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
|
||||
// sceAudioOutOutput returns amount of samples queued or < 0 on error
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
|
||||
@@ -337,7 +337,7 @@ typedef struct
|
||||
static bool mgmtthrtask_DetectDevices(void *userdata)
|
||||
{
|
||||
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, S
|
||||
|
||||
SDL3.camera.ctx2d.drawImage(SDL3.camera.video, 0, 0, w, h);
|
||||
const imgrgba = SDL3.camera.ctx2d.getImageData(0, 0, w, h).data;
|
||||
Module.HEAPU8.set(imgrgba, rgba);
|
||||
HEAPU8.set(imgrgba, rgba);
|
||||
|
||||
return 1;
|
||||
}, device->actual_spec.width, device->actual_spec.height, rgba);
|
||||
|
||||
@@ -58,7 +58,9 @@ static bool pipewire_initialized = false;
|
||||
|
||||
// Pipewire entry points
|
||||
static const char *(*PIPEWIRE_pw_get_library_version)(void);
|
||||
#if PW_CHECK_VERSION(0, 3, 75)
|
||||
static bool (*PIPEWIRE_pw_check_library_version)(int major, int minor, int micro);
|
||||
#endif
|
||||
static void (*PIPEWIRE_pw_init)(int *, char ***);
|
||||
static void (*PIPEWIRE_pw_deinit)(void);
|
||||
static struct pw_main_loop *(*PIPEWIRE_pw_main_loop_new)(const struct spa_dict *loop);
|
||||
@@ -151,7 +153,9 @@ static void unload_pipewire_library(void)
|
||||
static bool load_pipewire_syms(void)
|
||||
{
|
||||
SDL_PIPEWIRE_SYM(pw_get_library_version);
|
||||
#if PW_CHECK_VERSION(0, 3, 75)
|
||||
SDL_PIPEWIRE_SYM(pw_check_library_version);
|
||||
#endif
|
||||
SDL_PIPEWIRE_SYM(pw_init);
|
||||
SDL_PIPEWIRE_SYM(pw_deinit);
|
||||
SDL_PIPEWIRE_SYM(pw_main_loop_new);
|
||||
@@ -1024,7 +1028,11 @@ static bool hotplug_loop_init(void)
|
||||
|
||||
spa_list_init(&hotplug.global_list);
|
||||
|
||||
#if PW_CHECK_VERSION(0, 3, 75)
|
||||
hotplug.have_1_0_5 = PIPEWIRE_pw_check_library_version(1,0,5);
|
||||
#else
|
||||
hotplug.have_1_0_5 = false;
|
||||
#endif
|
||||
|
||||
hotplug.loop = PIPEWIRE_pw_thread_loop_new("SDLPwCameraPlug", NULL);
|
||||
if (!hotplug.loop) {
|
||||
|
||||
@@ -371,6 +371,7 @@ static jmethodID midShowTextInput;
|
||||
static jmethodID midSupportsRelativeMouse;
|
||||
static jmethodID midOpenFileDescriptor;
|
||||
static jmethodID midShowFileDialog;
|
||||
static jmethodID midGetPreferredLocales;
|
||||
|
||||
// audio manager
|
||||
static jclass mAudioManagerClass;
|
||||
@@ -660,6 +661,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
||||
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
|
||||
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
|
||||
midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
|
||||
|
||||
if (!midClipboardGetText ||
|
||||
!midClipboardHasText ||
|
||||
@@ -691,7 +693,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
||||
!midShowTextInput ||
|
||||
!midSupportsRelativeMouse ||
|
||||
!midOpenFileDescriptor ||
|
||||
!midShowFileDialog) {
|
||||
!midShowFileDialog ||
|
||||
!midGetPreferredLocales) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
|
||||
}
|
||||
|
||||
@@ -751,6 +754,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
|
||||
typedef int (*SDL_main_func)(int argc, char *argv[]);
|
||||
|
||||
static int run_count = 0;
|
||||
static bool allow_recreate_activity;
|
||||
static bool allow_recreate_activity_set;
|
||||
|
||||
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
|
||||
JNIEnv *env, jclass jcls)
|
||||
@@ -760,10 +765,16 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void Android_SetAllowRecreateActivity(bool enabled)
|
||||
{
|
||||
allow_recreate_activity = enabled;
|
||||
allow_recreate_activity_set = true;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
|
||||
JNIEnv *env, jclass jcls)
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY, false);
|
||||
return allow_recreate_activity;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitMainThread)(
|
||||
@@ -1526,6 +1537,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
|
||||
// Note that we call setenv() directly to avoid affecting SDL environments
|
||||
setenv(utfname, utfvalue, 1); // This should NOT be SDL_setenv()
|
||||
|
||||
if (SDL_strcmp(utfname, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
// Only set this the first time we run, in case it's been set by the application via SDL_SetHint()
|
||||
if (!allow_recreate_activity_set) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(utfvalue, false));
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, name, utfname);
|
||||
(*env)->ReleaseStringUTFChars(env, value, utfvalue);
|
||||
}
|
||||
@@ -2569,65 +2588,22 @@ bool Android_JNI_ShowToast(const char *message, int duration, int gravity, int x
|
||||
|
||||
bool Android_JNI_GetLocale(char *buf, size_t buflen)
|
||||
{
|
||||
AConfiguration *cfg;
|
||||
|
||||
SDL_assert(buflen > 6);
|
||||
|
||||
// Need to re-create the asset manager if locale has changed (SDL_EVENT_LOCALE_CHANGED)
|
||||
Internal_Android_Destroy_AssetManager();
|
||||
|
||||
if (!asset_manager) {
|
||||
Internal_Android_Create_AssetManager();
|
||||
}
|
||||
|
||||
if (!asset_manager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cfg = AConfiguration_new();
|
||||
if (!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
char language[2] = {};
|
||||
char country[2] = {};
|
||||
size_t id = 0;
|
||||
|
||||
AConfiguration_fromAssetManager(cfg, asset_manager);
|
||||
AConfiguration_getLanguage(cfg, language);
|
||||
AConfiguration_getCountry(cfg, country);
|
||||
|
||||
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
|
||||
if (language[0] == 'i' && language[1] == 'n') {
|
||||
language[1] = 'd';
|
||||
}
|
||||
|
||||
// copy language (not null terminated)
|
||||
if (language[0]) {
|
||||
buf[id++] = language[0];
|
||||
if (language[1]) {
|
||||
buf[id++] = language[1];
|
||||
bool result = false;
|
||||
if (buf && buflen > 0) {
|
||||
*buf = '\0';
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
jstring string = (jstring)(*env)->CallStaticObjectMethod(env, mActivityClass, midGetPreferredLocales);
|
||||
if (string) {
|
||||
const char *utf8string = (*env)->GetStringUTFChars(env, string, NULL);
|
||||
if (utf8string) {
|
||||
result = true;
|
||||
SDL_strlcpy(buf, utf8string, buflen);
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf8string);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
}
|
||||
|
||||
buf[id++] = '_';
|
||||
|
||||
// copy country (not null terminated)
|
||||
if (country[0]) {
|
||||
buf[id++] = country[0];
|
||||
if (country[1]) {
|
||||
buf[id++] = country[1];
|
||||
}
|
||||
}
|
||||
|
||||
buf[id++] = '\0';
|
||||
SDL_assert(id <= buflen);
|
||||
}
|
||||
|
||||
AConfiguration_delete(cfg);
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Android_JNI_OpenURL(const char *url)
|
||||
|
||||
@@ -55,6 +55,8 @@ bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeout
|
||||
void Android_LockActivityMutex(void);
|
||||
void Android_UnlockActivityMutex(void);
|
||||
|
||||
void Android_SetAllowRecreateActivity(bool enabled);
|
||||
|
||||
// Interface from the SDL library into the Android Java activity
|
||||
extern void Android_JNI_SetActivityTitle(const char *title);
|
||||
extern void Android_JNI_SetWindowStyle(bool fullscreen);
|
||||
|
||||
@@ -105,7 +105,7 @@ bool GDK_RegisterChangeNotifications(void)
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppConstrainedChangeNotification handler");
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this) {
|
||||
if (constrained) {
|
||||
if (constrained && !((_this->windows) && _this->windows->text_input_active)) {
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
} else {
|
||||
SDL_SetKeyboardFocus(_this->windows);
|
||||
|
||||
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format)
|
||||
{
|
||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||
@@ -162,7 +162,7 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devn
|
||||
SDL_zero(spec);
|
||||
spec.channels = (Uint8)fmt->Format.nChannels;
|
||||
spec.freq = fmt->Format.nSamplesPerSec;
|
||||
spec.format = SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
spec.format = (force_format != SDL_AUDIO_UNKNOWN) ? force_format : SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
|
||||
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
|
||||
if (!device) {
|
||||
@@ -183,6 +183,7 @@ typedef struct SDLMMNotificationClient
|
||||
{
|
||||
const IMMNotificationClientVtbl *lpVtbl;
|
||||
SDL_AtomicInt refcount;
|
||||
SDL_AudioFormat force_format;
|
||||
} SDLMMNotificationClient;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
|
||||
@@ -241,6 +242,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceRemoved(IMMNoti
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId, DWORD dwNewState)
|
||||
{
|
||||
SDLMMNotificationClient *client = (SDLMMNotificationClient *)iclient;
|
||||
IMMDevice *device = NULL;
|
||||
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
|
||||
@@ -255,7 +257,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
|
||||
GUID dsoundguid;
|
||||
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
|
||||
if (utf8dev) {
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
@@ -286,7 +288,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
|
||||
SDLMMNotificationClient_OnPropertyValueChanged
|
||||
};
|
||||
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN };
|
||||
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
|
||||
{
|
||||
@@ -363,7 +365,7 @@ bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool reco
|
||||
return true;
|
||||
}
|
||||
|
||||
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device)
|
||||
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format)
|
||||
{
|
||||
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
|
||||
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
|
||||
@@ -405,7 +407,7 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
|
||||
SDL_zero(dsoundguid);
|
||||
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
|
||||
if (devname) {
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid);
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format);
|
||||
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
|
||||
*default_device = sdldevice;
|
||||
}
|
||||
@@ -422,10 +424,12 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format)
|
||||
{
|
||||
EnumerateEndpointsForFlow(false, default_playback);
|
||||
EnumerateEndpointsForFlow(true, default_recording);
|
||||
EnumerateEndpointsForFlow(false, default_playback, force_format);
|
||||
EnumerateEndpointsForFlow(true, default_recording, force_format);
|
||||
|
||||
notification_client.force_format = force_format;
|
||||
|
||||
// if this fails, we just won't get hotplug events. Carry on anyhow.
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)¬ification_client);
|
||||
|
||||
@@ -37,7 +37,7 @@ typedef struct SDL_IMMDevice_callbacks
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
|
||||
void SDL_IMMDevice_Quit(void);
|
||||
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format);
|
||||
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
|
||||
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
|
||||
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);
|
||||
|
||||
@@ -53,6 +53,78 @@ typedef enum RO_INIT_TYPE
|
||||
#define WC_ERR_INVALID_CHARS 0x00000080
|
||||
#endif
|
||||
|
||||
// Fake window to help with DirectInput events.
|
||||
HWND SDL_HelperWindow = NULL;
|
||||
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
|
||||
static const TCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
|
||||
static ATOM SDL_HelperWindowClass = 0;
|
||||
|
||||
/*
|
||||
* Creates a HelperWindow used for DirectInput.
|
||||
*/
|
||||
bool SDL_HelperWindowCreate(void)
|
||||
{
|
||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
WNDCLASS wce;
|
||||
|
||||
// Make sure window isn't created twice.
|
||||
if (SDL_HelperWindow != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create the class.
|
||||
SDL_zero(wce);
|
||||
wce.lpfnWndProc = DefWindowProc;
|
||||
wce.lpszClassName = SDL_HelperWindowClassName;
|
||||
wce.hInstance = hInstance;
|
||||
|
||||
// Register the class.
|
||||
SDL_HelperWindowClass = RegisterClass(&wce);
|
||||
if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
|
||||
return WIN_SetError("Unable to create Helper Window Class");
|
||||
}
|
||||
|
||||
// Create the window.
|
||||
SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
|
||||
SDL_HelperWindowName,
|
||||
WS_OVERLAPPED, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, HWND_MESSAGE, NULL,
|
||||
hInstance, NULL);
|
||||
if (!SDL_HelperWindow) {
|
||||
UnregisterClass(SDL_HelperWindowClassName, hInstance);
|
||||
return WIN_SetError("Unable to create Helper Window");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
|
||||
*/
|
||||
void SDL_HelperWindowDestroy(void)
|
||||
{
|
||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
|
||||
// Destroy the window.
|
||||
if (SDL_HelperWindow != NULL) {
|
||||
if (DestroyWindow(SDL_HelperWindow) == 0) {
|
||||
WIN_SetError("Unable to destroy Helper Window");
|
||||
return;
|
||||
}
|
||||
SDL_HelperWindow = NULL;
|
||||
}
|
||||
|
||||
// Unregister the class.
|
||||
if (SDL_HelperWindowClass != 0) {
|
||||
if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
|
||||
WIN_SetError("Unable to destroy Helper Window Class");
|
||||
return;
|
||||
}
|
||||
SDL_HelperWindowClass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets an error message based on an HRESULT
|
||||
bool WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
|
||||
{
|
||||
@@ -330,10 +402,10 @@ void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect)
|
||||
winrect->bottom = sdlrect->y + sdlrect->h - 1;
|
||||
}
|
||||
|
||||
BOOL WIN_IsRectEmpty(const RECT *rect)
|
||||
bool WIN_WindowRectValid(const RECT *rect)
|
||||
{
|
||||
// Calculating this manually because Xbox does not support Win32 IsRectEmpty.
|
||||
return (rect->right <= rect->left) || (rect->bottom <= rect->top);
|
||||
// A window can be resized to zero height, but not zero width
|
||||
return (rect->right > 0);
|
||||
}
|
||||
|
||||
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
|
||||
|
||||
@@ -156,8 +156,8 @@ extern BOOL WIN_IsEqualIID(REFIID a, REFIID b);
|
||||
extern void WIN_RECTToRect(const RECT *winrect, SDL_Rect *sdlrect);
|
||||
extern void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect);
|
||||
|
||||
// Returns true if the rect is empty
|
||||
extern BOOL WIN_IsRectEmpty(const RECT *rect);
|
||||
// Returns false if a window client rect is not valid
|
||||
bool WIN_WindowRectValid(const RECT *rect);
|
||||
|
||||
extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,6,0
|
||||
PRODUCTVERSION 3,2,6,0
|
||||
FILEVERSION 3,2,18,0
|
||||
PRODUCTVERSION 3,2,18,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
@@ -23,12 +23,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL\0"
|
||||
VALUE "FileVersion", "3, 2, 6, 0\0"
|
||||
VALUE "FileVersion", "3, 2, 18, 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, 6, 0\0"
|
||||
VALUE "ProductVersion", "3, 2, 18, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -85,7 +85,9 @@
|
||||
#include <kernel.h>
|
||||
#include <swis.h>
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_3DS
|
||||
#include <3ds.h>
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_PS2
|
||||
#include <kernel.h>
|
||||
#endif
|
||||
@@ -113,7 +115,11 @@
|
||||
#define CPU_CFG2_LSX (1 << 6)
|
||||
#define CPU_CFG2_LASX (1 << 7)
|
||||
|
||||
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
|
||||
#if !defined(SDL_CPUINFO_DISABLED) && \
|
||||
!((defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))) && \
|
||||
!(defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)) && \
|
||||
!(defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)) && \
|
||||
defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
|
||||
/* This is the brute force way of detecting instruction sets...
|
||||
the idea is borrowed from the libmpeg2 library - thanks!
|
||||
*/
|
||||
@@ -342,6 +348,8 @@ static int CPU_haveAltiVec(void)
|
||||
elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
|
||||
altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
|
||||
return altivec;
|
||||
#elif defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)
|
||||
altivec = getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC;
|
||||
#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
|
||||
void (*handler)(int sig);
|
||||
handler = signal(SIGILL, illegal_instruction);
|
||||
@@ -642,6 +650,15 @@ int SDL_GetNumLogicalCPUCores(void)
|
||||
GetSystemInfo(&info);
|
||||
SDL_NumLogicalCPUCores = info.dwNumberOfProcessors;
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_3DS
|
||||
if (SDL_NumLogicalCPUCores <= 0) {
|
||||
bool isNew3DS = false;
|
||||
APT_CheckNew3DS(&isNew3DS);
|
||||
// 1 core is always dedicated to the OS
|
||||
// Meaning that the New3DS has 3 available core, and the Old3DS only one.
|
||||
SDL_NumLogicalCPUCores = isNew3DS ? 4 : 2;
|
||||
}
|
||||
#endif
|
||||
// There has to be at least 1, right? :)
|
||||
if (SDL_NumLogicalCPUCores <= 0) {
|
||||
@@ -1156,6 +1173,12 @@ int SDL_GetSystemRAM(void)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_3DS
|
||||
if (SDL_SystemRAM <= 0) {
|
||||
// The New3DS has 255MiB, the Old3DS 127MiB
|
||||
SDL_SystemRAM = (int)(osGetMemRegionSize(MEMREGION_ALL) / (1024 * 1024));
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_VITA
|
||||
if (SDL_SystemRAM <= 0) {
|
||||
/* Vita has 512MiB on SoC, that's split into 256MiB(+109MiB in extended memory mode) for app
|
||||
|
||||
@@ -27,6 +27,37 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <UniformTypeIdentifiers/UTType.h>
|
||||
|
||||
extern void Cocoa_SetWindowHasModalDialog(SDL_Window *window, bool has_modal);
|
||||
|
||||
static void AddFileExtensionType(NSMutableArray *types, const char *pattern_ptr)
|
||||
{
|
||||
if (!*pattern_ptr) {
|
||||
return; // in case the string had an extra ';' at the end.
|
||||
}
|
||||
|
||||
// -[UTType typeWithFilenameExtension] will return nil if there's a period in the string. It's better to
|
||||
// allow too many files than not allow the one the user actually needs, so just take the part after the '.'
|
||||
const char *dot = SDL_strrchr(pattern_ptr, '.');
|
||||
NSString *extstr = [NSString stringWithFormat: @"%s", dot ? (dot + 1) : pattern_ptr];
|
||||
if (@available(macOS 11.0, *)) {
|
||||
UTType *uttype = [UTType typeWithFilenameExtension:extstr];
|
||||
if (uttype) { // still failed? Don't add the pattern. This is what the pre-macOS11 path does internally anyhow.
|
||||
[types addObject:uttype];
|
||||
}
|
||||
} else {
|
||||
[types addObject:extstr];
|
||||
}
|
||||
}
|
||||
|
||||
static void ReactivateAfterDialog(void)
|
||||
{
|
||||
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
|
||||
[i activateWithOptions:0];
|
||||
break;
|
||||
}
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
|
||||
{
|
||||
SDL_Window* window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL);
|
||||
@@ -87,7 +118,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
|
||||
if (filters) {
|
||||
// On macOS 11.0 and up, this is an array of UTType. Prior to that, it's an array of NSString
|
||||
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ];
|
||||
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters];
|
||||
|
||||
int has_all_files = 0;
|
||||
for (int i = 0; i < nfilters; i++) {
|
||||
@@ -102,21 +133,14 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
for (char *c = pattern; *c; c++) {
|
||||
if (*c == ';') {
|
||||
*c = '\0';
|
||||
if(@available(macOS 11.0, *)) {
|
||||
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
|
||||
} else {
|
||||
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
|
||||
}
|
||||
AddFileExtensionType(types, pattern_ptr);
|
||||
pattern_ptr = c + 1;
|
||||
} else if (*c == '*') {
|
||||
has_all_files = 1;
|
||||
}
|
||||
}
|
||||
if(@available(macOS 11.0, *)) {
|
||||
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
|
||||
} else {
|
||||
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
|
||||
}
|
||||
|
||||
AddFileExtensionType(types, pattern_ptr); // get the last piece of the string.
|
||||
|
||||
SDL_free(pattern);
|
||||
}
|
||||
@@ -141,6 +165,9 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
|
||||
if (window) {
|
||||
w = (__bridge NSWindow *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
||||
if (w) {
|
||||
Cocoa_SetWindowHasModalDialog(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (w) {
|
||||
@@ -163,6 +190,9 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
const char *files[1] = { NULL };
|
||||
callback(userdata, files, -1);
|
||||
}
|
||||
|
||||
Cocoa_SetWindowHasModalDialog(window, false);
|
||||
ReactivateAfterDialog();
|
||||
}];
|
||||
} else {
|
||||
if ([dialog runModal] == NSModalResponseOK) {
|
||||
@@ -182,6 +212,8 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
const char *files[1] = { NULL };
|
||||
callback(userdata, files, -1);
|
||||
}
|
||||
|
||||
ReactivateAfterDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ void windows_ShowFileDialog(void *ptr)
|
||||
|
||||
chosen_files_list[nfiles] = NULL;
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) >= MAX_PATH) {
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) == 0) {
|
||||
SDL_SetError("Path too long or invalid character in path");
|
||||
SDL_free(chosen_files_list);
|
||||
callback(userdata, NULL, -1);
|
||||
@@ -273,7 +273,7 @@ void windows_ShowFileDialog(void *ptr)
|
||||
SDL_strlcpy(chosen_file, chosen_folder, MAX_PATH);
|
||||
chosen_file[chosen_folder_size] = '\\';
|
||||
|
||||
file_ptr += SDL_strlen(chosen_folder) + 1;
|
||||
file_ptr += SDL_wcslen(file_ptr) + 1;
|
||||
|
||||
while (*file_ptr) {
|
||||
nfiles++;
|
||||
@@ -295,7 +295,7 @@ void windows_ShowFileDialog(void *ptr)
|
||||
|
||||
int diff = ((int) chosen_folder_size) + 1;
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) >= MAX_PATH - diff) {
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) == 0) {
|
||||
SDL_SetError("Path too long or invalid character in path");
|
||||
|
||||
for (size_t i = 0; i < nfiles - 1; i++) {
|
||||
@@ -308,7 +308,7 @@ void windows_ShowFileDialog(void *ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
file_ptr += SDL_strlen(chosen_file) + 1 - diff;
|
||||
file_ptr += SDL_wcslen(file_ptr) + 1;
|
||||
|
||||
chosen_files_list[nfiles - 1] = SDL_strdup(chosen_file);
|
||||
|
||||
@@ -516,6 +516,14 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
|
||||
|
||||
filters_str = win_get_filters(filters, nfilters);
|
||||
|
||||
DWORD flags = 0;
|
||||
if (allow_many) {
|
||||
flags |= OFN_ALLOWMULTISELECT;
|
||||
}
|
||||
if (is_save) {
|
||||
flags |= OFN_OVERWRITEPROMPT;
|
||||
}
|
||||
|
||||
if (!filters_str && filters) {
|
||||
callback(userdata, NULL, -1);
|
||||
SDL_free(args);
|
||||
@@ -526,7 +534,7 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
|
||||
args->filters_str = filters_str;
|
||||
args->default_file = default_location ? SDL_strdup(default_location) : NULL;
|
||||
args->parent = window;
|
||||
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
|
||||
args->flags = flags;
|
||||
args->callback = callback;
|
||||
args->userdata = userdata;
|
||||
args->title = title ? SDL_strdup(title) : NULL;
|
||||
|
||||
+20
-37
@@ -110,7 +110,7 @@ typedef struct
|
||||
} SDL_DisabledEventBlock;
|
||||
|
||||
static SDL_DisabledEventBlock *SDL_disabled_events[256];
|
||||
static Uint32 SDL_userevents = SDL_EVENT_USER;
|
||||
static SDL_AtomicInt SDL_userevents;
|
||||
|
||||
typedef struct SDL_TemporaryMemory
|
||||
{
|
||||
@@ -633,9 +633,10 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||
#undef PRINT_MBUTTON_EVENT
|
||||
|
||||
SDL_EVENT_CASE(SDL_EVENT_MOUSE_WHEEL)
|
||||
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)",
|
||||
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g integer_x=%d integer_y=%d direction=%s)",
|
||||
(uint)event->wheel.timestamp, (uint)event->wheel.windowID,
|
||||
(uint)event->wheel.which, event->wheel.x, event->wheel.y,
|
||||
(int)event->wheel.integer_x, (int)event->wheel.integer_y,
|
||||
event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
|
||||
break;
|
||||
|
||||
@@ -1076,16 +1077,11 @@ static void SDL_SendWakeupEvent(void)
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockMutex(_this->wakeup_lock);
|
||||
{
|
||||
if (_this->wakeup_window) {
|
||||
_this->SendWakeupEvent(_this, _this->wakeup_window);
|
||||
|
||||
// No more wakeup events needed until we enter a new wait
|
||||
_this->wakeup_window = NULL;
|
||||
}
|
||||
// We only want to do this once while waiting for an event, so set it to NULL atomically here
|
||||
SDL_Window *wakeup_window = (SDL_Window *)SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
|
||||
if (wakeup_window) {
|
||||
_this->SendWakeupEvent(_this, wakeup_window);
|
||||
}
|
||||
SDL_UnlockMutex(_this->wakeup_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1379,9 +1375,7 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w
|
||||
return true;
|
||||
}
|
||||
|
||||
// Maximum wait of 30 seconds to prevent deadlocking forever
|
||||
const Sint32 MAX_CALLBACK_WAIT = 30 * 1000;
|
||||
SDL_WaitSemaphoreTimeout(entry->semaphore, MAX_CALLBACK_WAIT);
|
||||
SDL_WaitSemaphore(entry->semaphore);
|
||||
|
||||
switch (SDL_GetAtomicInt(&entry->state)) {
|
||||
case SDL_MAIN_CALLBACK_COMPLETE:
|
||||
@@ -1525,18 +1519,7 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
||||
*/
|
||||
SDL_PumpEventsInternal(true);
|
||||
|
||||
SDL_LockMutex(_this->wakeup_lock);
|
||||
{
|
||||
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
// If status == 0 we are going to block so wakeup will be needed.
|
||||
if (status == 0) {
|
||||
_this->wakeup_window = wakeup_window;
|
||||
} else {
|
||||
_this->wakeup_window = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(_this->wakeup_lock);
|
||||
|
||||
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
if (status < 0) {
|
||||
// Got an error: return
|
||||
break;
|
||||
@@ -1549,8 +1532,6 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
||||
if (timeoutNS > 0) {
|
||||
Sint64 elapsed = SDL_GetTicksNS() - start;
|
||||
if (elapsed >= timeoutNS) {
|
||||
// Set wakeup_window to NULL without holding the lock.
|
||||
_this->wakeup_window = NULL;
|
||||
return 0;
|
||||
}
|
||||
loop_timeoutNS = (timeoutNS - elapsed);
|
||||
@@ -1563,9 +1544,9 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
||||
loop_timeoutNS = poll_intervalNS;
|
||||
}
|
||||
}
|
||||
SDL_SetAtomicPointer(&_this->wakeup_window, wakeup_window);
|
||||
status = _this->WaitEventTimeout(_this, loop_timeoutNS);
|
||||
// Set wakeup_window to NULL without holding the lock.
|
||||
_this->wakeup_window = NULL;
|
||||
SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
|
||||
if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
|
||||
// We may have woken up to poll. Try again
|
||||
continue;
|
||||
@@ -1823,7 +1804,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
||||
Uint8 lo = (type & 0xff);
|
||||
|
||||
if (SDL_disabled_events[hi] &&
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
|
||||
current_state = false;
|
||||
} else {
|
||||
current_state = true;
|
||||
@@ -1832,7 +1813,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
||||
if ((enabled != false) != current_state) {
|
||||
if (enabled) {
|
||||
SDL_assert(SDL_disabled_events[hi] != NULL);
|
||||
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31));
|
||||
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1U << (lo & 31));
|
||||
|
||||
// Gamepad events depend on joystick events
|
||||
switch (type) {
|
||||
@@ -1863,7 +1844,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
||||
}
|
||||
// Out of memory, nothing we can do...
|
||||
if (SDL_disabled_events[hi]) {
|
||||
SDL_disabled_events[hi]->bits[lo / 32] |= (1 << (lo & 31));
|
||||
SDL_disabled_events[hi]->bits[lo / 32] |= (1U << (lo & 31));
|
||||
SDL_FlushEvent(type);
|
||||
}
|
||||
}
|
||||
@@ -1882,7 +1863,7 @@ bool SDL_EventEnabled(Uint32 type)
|
||||
Uint8 lo = (type & 0xff);
|
||||
|
||||
if (SDL_disabled_events[hi] &&
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -1893,9 +1874,11 @@ Uint32 SDL_RegisterEvents(int numevents)
|
||||
{
|
||||
Uint32 event_base = 0;
|
||||
|
||||
if ((numevents > 0) && (SDL_userevents + numevents <= SDL_EVENT_LAST)) {
|
||||
event_base = SDL_userevents;
|
||||
SDL_userevents += numevents;
|
||||
if (numevents > 0) {
|
||||
int value = SDL_AddAtomicInt(&SDL_userevents, numevents);
|
||||
if (value >= 0 && value <= (SDL_EVENT_LAST - SDL_EVENT_USER)) {
|
||||
event_base = (Uint32)(SDL_EVENT_USER + value);
|
||||
}
|
||||
}
|
||||
return event_base;
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ void SDL_SendKeyboardText(const char *text)
|
||||
{
|
||||
SDL_Keyboard *keyboard = &SDL_keyboard;
|
||||
|
||||
if (!SDL_TextInputActive(keyboard->focus)) {
|
||||
if (!keyboard->focus || !SDL_TextInputActive(keyboard->focus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ void SDL_SendEditingText(const char *text, int start, int length)
|
||||
{
|
||||
SDL_Keyboard *keyboard = &SDL_keyboard;
|
||||
|
||||
if (!SDL_TextInputActive(keyboard->focus)) {
|
||||
if (!keyboard->focus || !SDL_TextInputActive(keyboard->focus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -838,7 +838,7 @@ void SDL_SendEditingTextCandidates(char **candidates, int num_candidates, int se
|
||||
{
|
||||
SDL_Keyboard *keyboard = &SDL_keyboard;
|
||||
|
||||
if (!SDL_TextInputActive(keyboard->focus)) {
|
||||
if (!keyboard->focus || !SDL_TextInputActive(keyboard->focus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+54
-6
@@ -138,21 +138,25 @@ static void SDLCALL SDL_TouchMouseEventsChanged(void *userdata, const char *name
|
||||
#ifdef SDL_PLATFORM_VITA
|
||||
static void SDLCALL SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
Uint8 vita_touch_mouse_device = 1;
|
||||
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
if (hint) {
|
||||
switch (*hint) {
|
||||
default:
|
||||
case '0':
|
||||
mouse->vita_touch_mouse_device = 1;
|
||||
vita_touch_mouse_device = 1;
|
||||
break;
|
||||
case '1':
|
||||
mouse->vita_touch_mouse_device = 2;
|
||||
vita_touch_mouse_device = 2;
|
||||
break;
|
||||
case '2':
|
||||
mouse->vita_touch_mouse_device = 3;
|
||||
vita_touch_mouse_device = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
mouse->vita_touch_mouse_device = vita_touch_mouse_device;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -234,6 +238,17 @@ static void SDLCALL SDL_MouseRelativeCursorVisibleChanged(void *userdata, const
|
||||
SDL_SetCursor(NULL); // Update cursor visibility
|
||||
}
|
||||
|
||||
static void SDLCALL SDL_MouseIntegerModeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
|
||||
if (hint && *hint) {
|
||||
mouse->integer_mode_flags = (Uint8)SDL_atoi(hint);
|
||||
} else {
|
||||
mouse->integer_mode_flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Public functions
|
||||
bool SDL_PreInitMouse(void)
|
||||
{
|
||||
@@ -288,6 +303,9 @@ bool SDL_PreInitMouse(void)
|
||||
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
|
||||
SDL_MouseRelativeCursorVisibleChanged, mouse);
|
||||
|
||||
SDL_AddHintCallback("SDL_MOUSE_INTEGER_MODE",
|
||||
SDL_MouseIntegerModeChanged, mouse);
|
||||
|
||||
mouse->was_touch_mouse_events = false; // no touch to mouse movement event pending
|
||||
|
||||
mouse->cursor_shown = true;
|
||||
@@ -720,12 +738,22 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL
|
||||
y *= mouse->normal_speed_scale;
|
||||
}
|
||||
}
|
||||
if (mouse->integer_mode_flags & 1) {
|
||||
// Accumulate the fractional relative motion and only process the integer portion
|
||||
mouse->integer_mode_residual_motion_x = SDL_modff(mouse->integer_mode_residual_motion_x + x, &x);
|
||||
mouse->integer_mode_residual_motion_y = SDL_modff(mouse->integer_mode_residual_motion_y + y, &y);
|
||||
}
|
||||
xrel = x;
|
||||
yrel = y;
|
||||
x = (mouse->last_x + xrel);
|
||||
y = (mouse->last_y + yrel);
|
||||
ConstrainMousePosition(mouse, window, &x, &y);
|
||||
} else {
|
||||
if (mouse->integer_mode_flags & 1) {
|
||||
// Discard the fractional component from absolute coordinates
|
||||
x = SDL_truncf(x);
|
||||
y = SDL_truncf(y);
|
||||
}
|
||||
ConstrainMousePosition(mouse, window, &x, &y);
|
||||
if (mouse->has_position) {
|
||||
xrel = x - mouse->last_x;
|
||||
@@ -1004,6 +1032,8 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
|
||||
|
||||
// Post the event, if desired
|
||||
if (SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL)) {
|
||||
float integer_x, integer_y;
|
||||
|
||||
if (!mouse->relative_mode || mouse->warp_emulation_active) {
|
||||
// We're not in relative mode, so all mouse events are global mouse events
|
||||
mouseID = SDL_GLOBAL_MOUSE_ID;
|
||||
@@ -1014,11 +1044,26 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
|
||||
event.common.timestamp = timestamp;
|
||||
event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
|
||||
event.wheel.which = mouseID;
|
||||
event.wheel.x = x;
|
||||
event.wheel.y = y;
|
||||
event.wheel.direction = direction;
|
||||
event.wheel.mouse_x = mouse->x;
|
||||
event.wheel.mouse_y = mouse->y;
|
||||
|
||||
mouse->residual_scroll_x = SDL_modff(mouse->residual_scroll_x + x, &integer_x);
|
||||
event.wheel.integer_x = (Sint32)integer_x;
|
||||
|
||||
mouse->residual_scroll_y = SDL_modff(mouse->residual_scroll_y + y, &integer_y);
|
||||
event.wheel.integer_y = (Sint32)integer_y;
|
||||
|
||||
// Return the accumulated values in x/y when integer wheel mode is enabled.
|
||||
// This is necessary for compatibility with sdl2-compat 2.32.54.
|
||||
if (mouse->integer_mode_flags & 2) {
|
||||
event.wheel.x = integer_x;
|
||||
event.wheel.y = integer_y;
|
||||
} else {
|
||||
event.wheel.x = x;
|
||||
event.wheel.y = y;
|
||||
}
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
@@ -1108,6 +1153,9 @@ void SDL_QuitMouse(void)
|
||||
SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
|
||||
SDL_MouseRelativeCursorVisibleChanged, mouse);
|
||||
|
||||
SDL_RemoveHintCallback("SDL_MOUSE_INTEGER_MODE",
|
||||
SDL_MouseIntegerModeChanged, mouse);
|
||||
|
||||
for (int i = SDL_mouse_count; i--; ) {
|
||||
SDL_RemoveMouse(SDL_mice[i].instance_id, false);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ typedef struct
|
||||
void (*ApplySystemScale)(void *internal, Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, float *x, float *y);
|
||||
void *system_scale_data;
|
||||
|
||||
// integer mode data
|
||||
Uint8 integer_mode_flags; // 1 to enable mouse quantization, 2 to enable wheel quantization
|
||||
float integer_mode_residual_motion_x;
|
||||
float integer_mode_residual_motion_y;
|
||||
|
||||
// Data common to all mice
|
||||
SDL_Window *focus;
|
||||
float x;
|
||||
@@ -98,6 +103,8 @@ typedef struct
|
||||
float x_accu;
|
||||
float y_accu;
|
||||
float last_x, last_y; // the last reported x and y coordinates
|
||||
float residual_scroll_x;
|
||||
float residual_scroll_y;
|
||||
double click_motion_x;
|
||||
double click_motion_y;
|
||||
bool has_position;
|
||||
|
||||
+11
-2
@@ -565,10 +565,19 @@ void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *wind
|
||||
event.pbutton.down = down;
|
||||
SDL_PushEvent(&event);
|
||||
|
||||
if (window && (pen_touching == instance_id)) {
|
||||
if (window && (!pen_touching || (pen_touching == instance_id))) {
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (mouse && mouse->pen_mouse_events) {
|
||||
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, button + 1, down);
|
||||
static const Uint8 mouse_buttons[] = {
|
||||
SDL_BUTTON_LEFT,
|
||||
SDL_BUTTON_RIGHT,
|
||||
SDL_BUTTON_MIDDLE,
|
||||
SDL_BUTTON_X1,
|
||||
SDL_BUTTON_X2
|
||||
};
|
||||
if (button < SDL_arraysize(mouse_buttons)) {
|
||||
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, mouse_buttons[button], down);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,10 +371,10 @@ static const SDL_Scancode xfree86_scancode_table2[] = {
|
||||
/* 188, 0x0bc */ SDL_SCANCODE_F18, // XF86Launch9
|
||||
/* 189, 0x0bd */ SDL_SCANCODE_F19, // NoSymbol
|
||||
/* 190, 0x0be */ SDL_SCANCODE_F20, // XF86AudioMicMute
|
||||
/* 191, 0x0bf */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadToggle
|
||||
/* 192, 0x0c0 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOn
|
||||
/* 193, 0x0c1 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOff
|
||||
/* 194, 0x0c2 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
/* 191, 0x0bf */ SDL_SCANCODE_F21, // XF86TouchpadToggle
|
||||
/* 192, 0x0c0 */ SDL_SCANCODE_F22, // XF86TouchpadOn
|
||||
/* 193, 0x0c1 */ SDL_SCANCODE_F23, // XF86TouchpadOff
|
||||
/* 194, 0x0c2 */ SDL_SCANCODE_F24, // NoSymbol
|
||||
/* 195, 0x0c3 */ SDL_SCANCODE_MODE, // Mode_switch
|
||||
/* 196, 0x0c4 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
/* 197, 0x0c5 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
|
||||
+413
-35
@@ -56,15 +56,47 @@
|
||||
}
|
||||
|
||||
#define CHECK_RENDERPASS \
|
||||
if (!((Pass *)render_pass)->in_progress) { \
|
||||
if (!((RenderPass *)render_pass)->in_progress) { \
|
||||
SDL_assert_release(!"Render pass not in progress!"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
#define CHECK_SAMPLER_TEXTURES \
|
||||
RenderPass *rp = (RenderPass *)render_pass; \
|
||||
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->color_targets[color_target_index] == texture_sampler_bindings[texture_sampler_index].texture) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a sampler!"); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == texture_sampler_bindings[texture_sampler_index].texture) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a sampler!"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_STORAGE_TEXTURES \
|
||||
RenderPass *rp = (RenderPass *)render_pass; \
|
||||
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->color_targets[color_target_index] == storage_textures[texture_sampler_index]) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a storage texture!"); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == storage_textures[texture_sampler_index]) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a storage texture!"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((RenderPass *)render_pass)->graphics_pipeline) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_COMPUTEPASS \
|
||||
@@ -74,7 +106,7 @@
|
||||
}
|
||||
|
||||
#define CHECK_COMPUTE_PIPELINE_BOUND \
|
||||
if (!((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->compute_pipeline_bound) { \
|
||||
if (!((ComputePass *)compute_pass)->compute_pipeline) { \
|
||||
SDL_assert_release(!"Compute pipeline not bound!"); \
|
||||
return; \
|
||||
}
|
||||
@@ -137,23 +169,137 @@
|
||||
((CommandBufferCommonHeader *)command_buffer)->device
|
||||
|
||||
#define RENDERPASS_COMMAND_BUFFER \
|
||||
((Pass *)render_pass)->command_buffer
|
||||
((RenderPass *)render_pass)->command_buffer
|
||||
|
||||
#define RENDERPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device
|
||||
|
||||
#define RENDERPASS_BOUND_PIPELINE \
|
||||
((RenderPass *)render_pass)->graphics_pipeline
|
||||
|
||||
#define COMPUTEPASS_COMMAND_BUFFER \
|
||||
((Pass *)compute_pass)->command_buffer
|
||||
|
||||
#define COMPUTEPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device
|
||||
|
||||
#define COMPUTEPASS_BOUND_PIPELINE \
|
||||
((ComputePass *)compute_pass)->compute_pipeline
|
||||
|
||||
#define COPYPASS_COMMAND_BUFFER \
|
||||
((Pass *)copy_pass)->command_buffer
|
||||
|
||||
#define COPYPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
|
||||
|
||||
static bool TextureFormatIsComputeWritable[] = {
|
||||
false, // INVALID
|
||||
false, // A8_UNORM
|
||||
true, // R8_UNORM
|
||||
true, // R8G8_UNORM
|
||||
true, // R8G8B8A8_UNORM
|
||||
true, // R16_UNORM
|
||||
true, // R16G16_UNORM
|
||||
true, // R16G16B16A16_UNORM
|
||||
true, // R10G10B10A2_UNORM
|
||||
false, // B5G6R5_UNORM
|
||||
false, // B5G5R5A1_UNORM
|
||||
false, // B4G4R4A4_UNORM
|
||||
false, // B8G8R8A8_UNORM
|
||||
false, // BC1_UNORM
|
||||
false, // BC2_UNORM
|
||||
false, // BC3_UNORM
|
||||
false, // BC4_UNORM
|
||||
false, // BC5_UNORM
|
||||
false, // BC7_UNORM
|
||||
false, // BC6H_FLOAT
|
||||
false, // BC6H_UFLOAT
|
||||
true, // R8_SNORM
|
||||
true, // R8G8_SNORM
|
||||
true, // R8G8B8A8_SNORM
|
||||
true, // R16_SNORM
|
||||
true, // R16G16_SNORM
|
||||
true, // R16G16B16A16_SNORM
|
||||
true, // R16_FLOAT
|
||||
true, // R16G16_FLOAT
|
||||
true, // R16G16B16A16_FLOAT
|
||||
true, // R32_FLOAT
|
||||
true, // R32G32_FLOAT
|
||||
true, // R32G32B32A32_FLOAT
|
||||
true, // R11G11B10_UFLOAT
|
||||
true, // R8_UINT
|
||||
true, // R8G8_UINT
|
||||
true, // R8G8B8A8_UINT
|
||||
true, // R16_UINT
|
||||
true, // R16G16_UINT
|
||||
true, // R16G16B16A16_UINT
|
||||
true, // R32_UINT
|
||||
true, // R32G32_UINT
|
||||
true, // R32G32B32A32_UINT
|
||||
true, // R8_INT
|
||||
true, // R8G8_INT
|
||||
true, // R8G8B8A8_INT
|
||||
true, // R16_INT
|
||||
true, // R16G16_INT
|
||||
true, // R16G16B16A16_INT
|
||||
true, // R32_INT
|
||||
true, // R32G32_INT
|
||||
true, // R32G32B32A32_INT
|
||||
false, // R8G8B8A8_UNORM_SRGB
|
||||
false, // B8G8R8A8_UNORM_SRGB
|
||||
false, // BC1_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC7_UNORM_SRGB
|
||||
false, // D16_UNORM
|
||||
false, // D24_UNORM
|
||||
false, // D32_FLOAT
|
||||
false, // D24_UNORM_S8_UINT
|
||||
false, // D32_FLOAT_S8_UINT
|
||||
false, // ASTC_4x4_UNORM
|
||||
false, // ASTC_5x4_UNORM
|
||||
false, // ASTC_5x5_UNORM
|
||||
false, // ASTC_6x5_UNORM
|
||||
false, // ASTC_6x6_UNORM
|
||||
false, // ASTC_8x5_UNORM
|
||||
false, // ASTC_8x6_UNORM
|
||||
false, // ASTC_8x8_UNORM
|
||||
false, // ASTC_10x5_UNORM
|
||||
false, // ASTC_10x6_UNORM
|
||||
false, // ASTC_10x8_UNORM
|
||||
false, // ASTC_10x10_UNORM
|
||||
false, // ASTC_12x10_UNORM
|
||||
false, // ASTC_12x12_UNORM
|
||||
false, // ASTC_4x4_UNORM_SRGB
|
||||
false, // ASTC_5x4_UNORM_SRGB
|
||||
false, // ASTC_5x5_UNORM_SRGB
|
||||
false, // ASTC_6x5_UNORM_SRGB
|
||||
false, // ASTC_6x6_UNORM_SRGB
|
||||
false, // ASTC_8x5_UNORM_SRGB
|
||||
false, // ASTC_8x6_UNORM_SRGB
|
||||
false, // ASTC_8x8_UNORM_SRGB
|
||||
false, // ASTC_10x5_UNORM_SRGB
|
||||
false, // ASTC_10x6_UNORM_SRGB
|
||||
false, // ASTC_10x8_UNORM_SRGB
|
||||
false, // ASTC_10x10_UNORM_SRGB
|
||||
false, // ASTC_12x10_UNORM_SRGB
|
||||
false, // ASTC_12x12_UNORM_SRGB
|
||||
false, // ASTC_4x4_FLOAT
|
||||
false, // ASTC_5x4_FLOAT
|
||||
false, // ASTC_5x5_FLOAT
|
||||
false, // ASTC_6x5_FLOAT
|
||||
false, // ASTC_6x6_FLOAT
|
||||
false, // ASTC_8x5_FLOAT
|
||||
false, // ASTC_8x6_FLOAT
|
||||
false, // ASTC_8x8_FLOAT
|
||||
false, // ASTC_10x5_FLOAT
|
||||
false, // ASTC_10x6_FLOAT
|
||||
false, // ASTC_10x8_FLOAT
|
||||
false, // ASTC_10x10_FLOAT
|
||||
false, // ASTC_12x10_FLOAT
|
||||
false // ASTC_12x12_FLOAT
|
||||
};
|
||||
|
||||
// Drivers
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
@@ -371,6 +517,73 @@ void SDL_GPU_BlitCommon(
|
||||
SDL_EndGPURenderPass(render_pass);
|
||||
}
|
||||
|
||||
static void SDL_GPU_CheckGraphicsBindings(SDL_GPURenderPass *render_pass)
|
||||
{
|
||||
RenderPass *rp = (RenderPass *)render_pass;
|
||||
GraphicsPipelineCommonHeader *pipeline = (GraphicsPipelineCommonHeader *)RENDERPASS_BOUND_PIPELINE;
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_samplers; i += 1) {
|
||||
if (!rp->vertex_sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_storage_textures; i += 1) {
|
||||
if (!rp->vertex_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_storage_buffers; i += 1) {
|
||||
if (!rp->vertex_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex storage buffer binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_samplers; i += 1) {
|
||||
if (!rp->fragment_sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_storage_textures; i += 1) {
|
||||
if (!rp->fragment_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_storage_buffers; i += 1) {
|
||||
if (!rp->fragment_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment storage buffer binding!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_GPU_CheckComputeBindings(SDL_GPUComputePass *compute_pass)
|
||||
{
|
||||
ComputePass *cp = (ComputePass *)compute_pass;
|
||||
ComputePipelineCommonHeader *pipeline = (ComputePipelineCommonHeader *)COMPUTEPASS_BOUND_PIPELINE;
|
||||
for (Uint32 i = 0; i < pipeline->numSamplers; i += 1) {
|
||||
if (!cp->sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadonlyStorageTextures; i += 1) {
|
||||
if (!cp->read_only_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute readonly storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadonlyStorageBuffers; i += 1) {
|
||||
if (!cp->read_only_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute readonly storage buffer binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageTextures; i += 1) {
|
||||
if (!cp->read_write_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute read-write storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageBuffers; i += 1) {
|
||||
if (!cp->read_write_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute read-write storage buffer bbinding!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Functions
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
@@ -532,7 +745,6 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
|
||||
result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props);
|
||||
if (result != NULL) {
|
||||
result->backend = selectedBackend->name;
|
||||
result->shader_formats = selectedBackend->shader_formats;
|
||||
result->debug_mode = debug_mode;
|
||||
}
|
||||
}
|
||||
@@ -721,6 +933,13 @@ bool SDL_GPUTextureSupportsFormat(
|
||||
CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false)
|
||||
}
|
||||
|
||||
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
|
||||
(usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
|
||||
if (!TextureFormatIsComputeWritable[format]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return device->SupportsTextureFormat(
|
||||
device->driverData,
|
||||
format,
|
||||
@@ -1343,15 +1562,30 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->device = device;
|
||||
commandBufferHeader->render_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->graphics_pipeline_bound = false;
|
||||
commandBufferHeader->compute_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pipeline_bound = false;
|
||||
commandBufferHeader->copy_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
|
||||
if (device->debug_mode) {
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->render_pass.graphics_pipeline = NULL;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pass.compute_pipeline = NULL;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = false;
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
|
||||
return command_buffer;
|
||||
}
|
||||
@@ -1469,30 +1703,47 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
|
||||
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
|
||||
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
if (color_target_infos[i].resolve_texture == NULL) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
|
||||
return NULL;
|
||||
} else {
|
||||
TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
|
||||
if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Resolve texture must have a sample count of 1!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.format != textureHeader->info.format) {
|
||||
SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
|
||||
return NULL;
|
||||
}
|
||||
if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
|
||||
SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
|
||||
SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
@@ -1500,10 +1751,12 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
|
||||
if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
|
||||
SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
|
||||
SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
|
||||
@@ -1511,6 +1764,7 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
|
||||
depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1522,7 +1776,18 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
depth_stencil_target_info);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->render_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->render_pass.in_progress = true;
|
||||
for (Uint32 i = 0; i < num_color_targets; i += 1) {
|
||||
commandBufferHeader->render_pass.color_targets[i] = color_target_infos[i].texture;
|
||||
}
|
||||
commandBufferHeader->render_pass.num_color_targets = num_color_targets;
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
commandBufferHeader->render_pass.depth_stencil_target = depth_stencil_target_info->texture;
|
||||
}
|
||||
}
|
||||
|
||||
return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass);
|
||||
}
|
||||
|
||||
@@ -1530,8 +1795,6 @@ void SDL_BindGPUGraphicsPipeline(
|
||||
SDL_GPURenderPass *render_pass,
|
||||
SDL_GPUGraphicsPipeline *graphics_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
return;
|
||||
@@ -1545,8 +1808,10 @@ void SDL_BindGPUGraphicsPipeline(
|
||||
RENDERPASS_COMMAND_BUFFER,
|
||||
graphics_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->graphics_pipeline_bound = true;
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
RENDERPASS_BOUND_PIPELINE = graphics_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_SetGPUViewport(
|
||||
@@ -1696,6 +1961,15 @@ void SDL_BindGPUVertexSamplers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
|
||||
{
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexSamplers(
|
||||
@@ -1722,6 +1996,11 @@ void SDL_BindGPUVertexStorageTextures(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_STORAGE_TEXTURES
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexStorageTextures(
|
||||
@@ -1748,6 +2027,10 @@ void SDL_BindGPUVertexStorageBuffers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexStorageBuffers(
|
||||
@@ -1774,6 +2057,14 @@ void SDL_BindGPUFragmentSamplers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation) {
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentSamplers(
|
||||
@@ -1800,6 +2091,11 @@ void SDL_BindGPUFragmentStorageTextures(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_STORAGE_TEXTURES
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentStorageTextures(
|
||||
@@ -1826,6 +2122,10 @@ void SDL_BindGPUFragmentStorageBuffers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentStorageBuffers(
|
||||
@@ -1851,6 +2151,7 @@ void SDL_DrawGPUIndexedPrimitives(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitives(
|
||||
@@ -1877,6 +2178,7 @@ void SDL_DrawGPUPrimitives(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitives(
|
||||
@@ -1905,6 +2207,7 @@ void SDL_DrawGPUPrimitivesIndirect(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitivesIndirect(
|
||||
@@ -1932,6 +2235,7 @@ void SDL_DrawGPUIndexedPrimitivesIndirect(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
|
||||
@@ -1945,6 +2249,7 @@ void SDL_EndGPURenderPass(
|
||||
SDL_GPURenderPass *render_pass)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferCommonHeader;
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
@@ -1958,9 +2263,22 @@ void SDL_EndGPURenderPass(
|
||||
RENDERPASS_DEVICE->EndRenderPass(
|
||||
RENDERPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->render_pass.in_progress = false;
|
||||
commandBufferCommonHeader->graphics_pipeline_bound = false;
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
commandBufferCommonHeader->render_pass.in_progress = false;
|
||||
for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
|
||||
{
|
||||
commandBufferCommonHeader->render_pass.color_targets[i] = NULL;
|
||||
}
|
||||
commandBufferCommonHeader->render_pass.num_color_targets = 0;
|
||||
commandBufferCommonHeader->render_pass.depth_stencil_target = NULL;
|
||||
commandBufferCommonHeader->render_pass.graphics_pipeline = NULL;
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_buffer_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute Pass
|
||||
@@ -2004,6 +2322,16 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
||||
SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
|
||||
SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate buffer usage?
|
||||
@@ -2017,7 +2345,19 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
||||
num_storage_buffer_bindings);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_texture_bound[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_buffer_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_buffer_bound[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
|
||||
}
|
||||
|
||||
@@ -2025,8 +2365,6 @@ void SDL_BindGPUComputePipeline(
|
||||
SDL_GPUComputePass *compute_pass,
|
||||
SDL_GPUComputePipeline *compute_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (compute_pass == NULL) {
|
||||
SDL_InvalidParamError("compute_pass");
|
||||
return;
|
||||
@@ -2044,8 +2382,10 @@ void SDL_BindGPUComputePipeline(
|
||||
COMPUTEPASS_COMMAND_BUFFER,
|
||||
compute_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->compute_pipeline_bound = true;
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
COMPUTEPASS_BOUND_PIPELINE = compute_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BindGPUComputeSamplers(
|
||||
@@ -2065,6 +2405,10 @@ void SDL_BindGPUComputeSamplers(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeSamplers(
|
||||
@@ -2091,6 +2435,10 @@ void SDL_BindGPUComputeStorageTextures(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageTextures(
|
||||
@@ -2117,6 +2465,10 @@ void SDL_BindGPUComputeStorageBuffers(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
|
||||
@@ -2140,6 +2492,7 @@ void SDL_DispatchGPUCompute(
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchCompute(
|
||||
@@ -2162,6 +2515,7 @@ void SDL_DispatchGPUComputeIndirect(
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchComputeIndirect(
|
||||
@@ -2187,9 +2541,16 @@ void SDL_EndGPUComputePass(
|
||||
COMPUTEPASS_DEVICE->EndComputePass(
|
||||
COMPUTEPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pipeline_bound = false;
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pass.compute_pipeline = NULL;
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// TransferBuffer Data
|
||||
@@ -2247,7 +2608,11 @@ SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
|
||||
command_buffer);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
}
|
||||
|
||||
return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
|
||||
}
|
||||
|
||||
@@ -2498,7 +2863,9 @@ void SDL_EndGPUCopyPass(
|
||||
COPYPASS_DEVICE->EndCopyPass(
|
||||
COPYPASS_COMMAND_BUFFER);
|
||||
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
if (COPYPASS_DEVICE->debug_mode) {
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_GenerateMipmapsForGPUTexture(
|
||||
@@ -2528,11 +2895,19 @@ void SDL_GenerateMipmapsForGPUTexture(
|
||||
SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = true;
|
||||
}
|
||||
|
||||
COMMAND_BUFFER_DEVICE->GenerateMipmaps(
|
||||
command_buffer,
|
||||
texture);
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BlitGPUTexture(
|
||||
@@ -2646,8 +3021,11 @@ bool SDL_ClaimWindowForGPUDevice(
|
||||
{
|
||||
CHECK_DEVICE_MAGIC(device, false);
|
||||
if (window == NULL) {
|
||||
SDL_InvalidParamError("window");
|
||||
return false;
|
||||
return SDL_InvalidParamError("window");
|
||||
}
|
||||
|
||||
if ((window->flags & SDL_WINDOW_TRANSPARENT) != 0) {
|
||||
return SDL_SetError("The GPU API doesn't support transparent windows");
|
||||
}
|
||||
|
||||
return device->ClaimWindow(
|
||||
|
||||
+79
-19
@@ -24,6 +24,21 @@
|
||||
#ifndef SDL_GPU_DRIVER_H
|
||||
#define SDL_GPU_DRIVER_H
|
||||
|
||||
// GraphicsDevice Limits
|
||||
|
||||
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
|
||||
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
|
||||
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
|
||||
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
|
||||
#define MAX_COMPUTE_WRITE_TEXTURES 8
|
||||
#define MAX_COMPUTE_WRITE_BUFFERS 8
|
||||
#define UNIFORM_BUFFER_SIZE 32768
|
||||
#define MAX_VERTEX_BUFFERS 16
|
||||
#define MAX_VERTEX_ATTRIBUTES 16
|
||||
#define MAX_COLOR_TARGET_BINDINGS 4
|
||||
#define MAX_PRESENT_COUNT 16
|
||||
#define MAX_FRAMES_IN_FLIGHT 3
|
||||
|
||||
// Common Structs
|
||||
|
||||
typedef struct Pass
|
||||
@@ -32,16 +47,51 @@ typedef struct Pass
|
||||
bool in_progress;
|
||||
} Pass;
|
||||
|
||||
typedef struct ComputePass
|
||||
{
|
||||
SDL_GPUCommandBuffer *command_buffer;
|
||||
bool in_progress;
|
||||
|
||||
SDL_GPUComputePipeline *compute_pipeline;
|
||||
|
||||
bool sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool read_only_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool read_only_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
bool read_write_storage_texture_bound[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
bool read_write_storage_buffer_bound[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
} ComputePass;
|
||||
|
||||
typedef struct RenderPass
|
||||
{
|
||||
SDL_GPUCommandBuffer *command_buffer;
|
||||
bool in_progress;
|
||||
SDL_GPUTexture *color_targets[MAX_COLOR_TARGET_BINDINGS];
|
||||
Uint32 num_color_targets;
|
||||
SDL_GPUTexture *depth_stencil_target;
|
||||
|
||||
SDL_GPUGraphicsPipeline *graphics_pipeline;
|
||||
|
||||
bool vertex_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool vertex_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool vertex_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
bool fragment_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool fragment_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool fragment_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
} RenderPass;
|
||||
|
||||
typedef struct CommandBufferCommonHeader
|
||||
{
|
||||
SDL_GPUDevice *device;
|
||||
Pass render_pass;
|
||||
bool graphics_pipeline_bound;
|
||||
Pass compute_pass;
|
||||
bool compute_pipeline_bound;
|
||||
|
||||
RenderPass render_pass;
|
||||
ComputePass compute_pass;
|
||||
|
||||
Pass copy_pass;
|
||||
bool swapchain_texture_acquired;
|
||||
bool submitted;
|
||||
// used to avoid tripping assert on GenerateMipmaps
|
||||
bool ignore_render_pass_texture_validation;
|
||||
} CommandBufferCommonHeader;
|
||||
|
||||
typedef struct TextureCommonHeader
|
||||
@@ -49,6 +99,29 @@ typedef struct TextureCommonHeader
|
||||
SDL_GPUTextureCreateInfo info;
|
||||
} TextureCommonHeader;
|
||||
|
||||
typedef struct GraphicsPipelineCommonHeader
|
||||
{
|
||||
Uint32 num_vertex_samplers;
|
||||
Uint32 num_vertex_storage_textures;
|
||||
Uint32 num_vertex_storage_buffers;
|
||||
Uint32 num_vertex_uniform_buffers;
|
||||
|
||||
Uint32 num_fragment_samplers;
|
||||
Uint32 num_fragment_storage_textures;
|
||||
Uint32 num_fragment_storage_buffers;
|
||||
Uint32 num_fragment_uniform_buffers;
|
||||
} GraphicsPipelineCommonHeader;
|
||||
|
||||
typedef struct ComputePipelineCommonHeader
|
||||
{
|
||||
Uint32 numSamplers;
|
||||
Uint32 numReadonlyStorageTextures;
|
||||
Uint32 numReadonlyStorageBuffers;
|
||||
Uint32 numReadWriteStorageTextures;
|
||||
Uint32 numReadWriteStorageBuffers;
|
||||
Uint32 numUniformBuffers;
|
||||
} ComputePipelineCommonHeader;
|
||||
|
||||
typedef struct BlitFragmentUniforms
|
||||
{
|
||||
// texcoord space
|
||||
@@ -136,6 +209,7 @@ static inline Sint32 Texture_GetBlockWidth(
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM:
|
||||
@@ -253,6 +327,7 @@ static inline Sint32 Texture_GetBlockHeight(
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM:
|
||||
@@ -385,21 +460,6 @@ static inline Uint32 BytesPerRow(
|
||||
return blocksPerRow * SDL_GPUTextureFormatTexelBlockSize(format);
|
||||
}
|
||||
|
||||
// GraphicsDevice Limits
|
||||
|
||||
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
|
||||
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
|
||||
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
|
||||
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
|
||||
#define MAX_COMPUTE_WRITE_TEXTURES 8
|
||||
#define MAX_COMPUTE_WRITE_BUFFERS 8
|
||||
#define UNIFORM_BUFFER_SIZE 32768
|
||||
#define MAX_VERTEX_BUFFERS 16
|
||||
#define MAX_VERTEX_ATTRIBUTES 16
|
||||
#define MAX_COLOR_TARGET_BINDINGS 4
|
||||
#define MAX_PRESENT_COUNT 16
|
||||
#define MAX_FRAMES_IN_FLIGHT 3
|
||||
|
||||
// Internal Macros
|
||||
|
||||
#define EXPAND_ARRAY_IF_NEEDED(arr, elementType, newCount, capacity, newCapacity) \
|
||||
|
||||
+337
-177
File diff suppressed because it is too large.
Load diff
@@ -476,33 +476,21 @@ typedef struct MetalShader
|
||||
|
||||
typedef struct MetalGraphicsPipeline
|
||||
{
|
||||
GraphicsPipelineCommonHeader header;
|
||||
|
||||
id<MTLRenderPipelineState> handle;
|
||||
|
||||
SDL_GPURasterizerState rasterizerState;
|
||||
SDL_GPUPrimitiveType primitiveType;
|
||||
|
||||
id<MTLDepthStencilState> depth_stencil_state;
|
||||
|
||||
Uint32 vertexSamplerCount;
|
||||
Uint32 vertexUniformBufferCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexStorageTextureCount;
|
||||
|
||||
Uint32 fragmentSamplerCount;
|
||||
Uint32 fragmentUniformBufferCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentStorageTextureCount;
|
||||
} MetalGraphicsPipeline;
|
||||
|
||||
typedef struct MetalComputePipeline
|
||||
{
|
||||
ComputePipelineCommonHeader header;
|
||||
|
||||
id<MTLComputePipelineState> handle;
|
||||
Uint32 numSamplers;
|
||||
Uint32 numReadonlyStorageTextures;
|
||||
Uint32 numReadWriteStorageTextures;
|
||||
Uint32 numReadonlyStorageBuffers;
|
||||
Uint32 numReadWriteStorageBuffers;
|
||||
Uint32 numUniformBuffers;
|
||||
Uint32 threadcountX;
|
||||
Uint32 threadcountY;
|
||||
Uint32 threadcountZ;
|
||||
@@ -840,6 +828,10 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader(
|
||||
dispatch_data_t data;
|
||||
id<MTLFunction> function;
|
||||
|
||||
if (!entrypoint) {
|
||||
entrypoint = "main0";
|
||||
}
|
||||
|
||||
if (format == SDL_GPU_SHADERFORMAT_MSL) {
|
||||
NSString *codeString = [[NSString alloc]
|
||||
initWithBytes:code
|
||||
@@ -854,7 +846,7 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader(
|
||||
code,
|
||||
codeSize,
|
||||
dispatch_get_global_queue(0, 0),
|
||||
^{ /* do nothing */ });
|
||||
DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
||||
library = [renderer->device newLibraryWithData:data error:&error];
|
||||
} else {
|
||||
SDL_assert(!"SDL_gpu.c should have already validated this!");
|
||||
@@ -1055,12 +1047,12 @@ static SDL_GPUComputePipeline *METAL_CreateComputePipeline(
|
||||
|
||||
pipeline = SDL_calloc(1, sizeof(MetalComputePipeline));
|
||||
pipeline->handle = handle;
|
||||
pipeline->numSamplers = createinfo->num_samplers;
|
||||
pipeline->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
pipeline->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
pipeline->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
pipeline->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
pipeline->numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
pipeline->header.numSamplers = createinfo->num_samplers;
|
||||
pipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
pipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
pipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
pipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
pipeline->header.numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
pipeline->threadcountX = createinfo->threadcount_x;
|
||||
pipeline->threadcountY = createinfo->threadcount_y;
|
||||
pipeline->threadcountZ = createinfo->threadcount_z;
|
||||
@@ -1203,14 +1195,14 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
|
||||
result->depth_stencil_state = depthStencilState;
|
||||
result->rasterizerState = createinfo->rasterizer_state;
|
||||
result->primitiveType = createinfo->primitive_type;
|
||||
result->vertexSamplerCount = vertexShader->numSamplers;
|
||||
result->vertexUniformBufferCount = vertexShader->numUniformBuffers;
|
||||
result->vertexStorageBufferCount = vertexShader->numStorageBuffers;
|
||||
result->vertexStorageTextureCount = vertexShader->numStorageTextures;
|
||||
result->fragmentSamplerCount = fragmentShader->numSamplers;
|
||||
result->fragmentUniformBufferCount = fragmentShader->numUniformBuffers;
|
||||
result->fragmentStorageBufferCount = fragmentShader->numStorageBuffers;
|
||||
result->fragmentStorageTextureCount = fragmentShader->numStorageTextures;
|
||||
result->header.num_vertex_samplers = vertexShader->numSamplers;
|
||||
result->header.num_vertex_uniform_buffers = vertexShader->numUniformBuffers;
|
||||
result->header.num_vertex_storage_buffers = vertexShader->numStorageBuffers;
|
||||
result->header.num_vertex_storage_textures = vertexShader->numStorageTextures;
|
||||
result->header.num_fragment_samplers = fragmentShader->numSamplers;
|
||||
result->header.num_fragment_uniform_buffers = fragmentShader->numUniformBuffers;
|
||||
result->header.num_fragment_storage_buffers = fragmentShader->numStorageBuffers;
|
||||
result->header.num_fragment_storage_textures = fragmentShader->numStorageTextures;
|
||||
return (SDL_GPUGraphicsPipeline *)result;
|
||||
}
|
||||
}
|
||||
@@ -1494,7 +1486,9 @@ static SDL_GPUTexture *METAL_CreateTexture(
|
||||
// Copy properties so we don't lose information when the client destroys them
|
||||
container->header.info = *createinfo;
|
||||
container->header.info.props = SDL_CreateProperties();
|
||||
SDL_CopyProperties(createinfo->props, container->header.info.props);
|
||||
if (createinfo->props) {
|
||||
SDL_CopyProperties(createinfo->props, container->header.info.props);
|
||||
}
|
||||
|
||||
container->activeTexture = texture;
|
||||
container->textureCapacity = 1;
|
||||
@@ -2406,14 +2400,14 @@ static void METAL_BindGraphicsPipeline(
|
||||
metalCommandBuffer->needFragmentUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->vertexUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) {
|
||||
if (metalCommandBuffer->vertexUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->vertexUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->fragmentUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) {
|
||||
if (metalCommandBuffer->fragmentUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->fragmentUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
@@ -2644,11 +2638,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Vertex Samplers+Textures
|
||||
|
||||
if (commandBuffer->needVertexSamplerBind) {
|
||||
if (graphicsPipeline->vertexSamplerCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_samplers > 0) {
|
||||
[commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers
|
||||
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
|
||||
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures
|
||||
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
|
||||
}
|
||||
commandBuffer->needVertexSamplerBind = false;
|
||||
}
|
||||
@@ -2656,10 +2650,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Vertex Storage Textures
|
||||
|
||||
if (commandBuffer->needVertexStorageTextureBind) {
|
||||
if (graphicsPipeline->vertexStorageTextureCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_storage_textures > 0) {
|
||||
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures
|
||||
withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount,
|
||||
graphicsPipeline->vertexStorageTextureCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_samplers,
|
||||
graphicsPipeline->header.num_vertex_storage_textures)];
|
||||
}
|
||||
commandBuffer->needVertexStorageTextureBind = false;
|
||||
}
|
||||
@@ -2667,20 +2661,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Vertex Storage Buffers
|
||||
|
||||
if (commandBuffer->needVertexStorageBufferBind) {
|
||||
if (graphicsPipeline->vertexStorageBufferCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_storage_buffers > 0) {
|
||||
[commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount,
|
||||
graphicsPipeline->vertexStorageBufferCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_uniform_buffers,
|
||||
graphicsPipeline->header.num_vertex_storage_buffers)];
|
||||
}
|
||||
commandBuffer->needVertexStorageBufferBind = false;
|
||||
}
|
||||
|
||||
// Vertex Uniform Buffers
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_uniform_buffers; i += 1) {
|
||||
if (commandBuffer->needVertexUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->vertexUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_vertex_uniform_buffers > i) {
|
||||
[commandBuffer->renderEncoder
|
||||
setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle
|
||||
offset:commandBuffer->vertexUniformBuffers[i]->drawOffset
|
||||
@@ -2693,11 +2687,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Fragment Samplers+Textures
|
||||
|
||||
if (commandBuffer->needFragmentSamplerBind) {
|
||||
if (graphicsPipeline->fragmentSamplerCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_samplers > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers
|
||||
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
|
||||
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures
|
||||
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
|
||||
}
|
||||
commandBuffer->needFragmentSamplerBind = false;
|
||||
}
|
||||
@@ -2705,10 +2699,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Fragment Storage Textures
|
||||
|
||||
if (commandBuffer->needFragmentStorageTextureBind) {
|
||||
if (graphicsPipeline->fragmentStorageTextureCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_storage_textures > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures
|
||||
withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount,
|
||||
graphicsPipeline->fragmentStorageTextureCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_samplers,
|
||||
graphicsPipeline->header.num_fragment_storage_textures)];
|
||||
}
|
||||
commandBuffer->needFragmentStorageTextureBind = false;
|
||||
}
|
||||
@@ -2716,20 +2710,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
||||
// Fragment Storage Buffers
|
||||
|
||||
if (commandBuffer->needFragmentStorageBufferBind) {
|
||||
if (graphicsPipeline->fragmentStorageBufferCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_storage_buffers > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount,
|
||||
graphicsPipeline->fragmentStorageBufferCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_uniform_buffers,
|
||||
graphicsPipeline->header.num_fragment_storage_buffers)];
|
||||
}
|
||||
commandBuffer->needFragmentStorageBufferBind = false;
|
||||
}
|
||||
|
||||
// Fragment Uniform Buffers
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_uniform_buffers; i += 1) {
|
||||
if (commandBuffer->needFragmentUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->fragmentUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_fragment_uniform_buffers > i) {
|
||||
[commandBuffer->renderEncoder
|
||||
setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle
|
||||
offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset
|
||||
@@ -2748,38 +2742,38 @@ static void METAL_INTERNAL_BindComputeResources(
|
||||
NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 };
|
||||
|
||||
if (commandBuffer->needComputeSamplerBind) {
|
||||
if (computePipeline->numSamplers > 0) {
|
||||
if (computePipeline->header.numSamplers > 0) {
|
||||
[commandBuffer->computeEncoder setTextures:commandBuffer->computeSamplerTextures
|
||||
withRange:NSMakeRange(0, computePipeline->numSamplers)];
|
||||
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
|
||||
[commandBuffer->computeEncoder setSamplerStates:commandBuffer->computeSamplers
|
||||
withRange:NSMakeRange(0, computePipeline->numSamplers)];
|
||||
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
|
||||
}
|
||||
commandBuffer->needComputeSamplerBind = false;
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageTextureBind) {
|
||||
if (computePipeline->numReadonlyStorageTextures > 0) {
|
||||
if (computePipeline->header.numReadonlyStorageTextures > 0) {
|
||||
[commandBuffer->computeEncoder setTextures:commandBuffer->computeReadOnlyTextures
|
||||
withRange:NSMakeRange(
|
||||
computePipeline->numSamplers,
|
||||
computePipeline->numReadonlyStorageTextures)];
|
||||
computePipeline->header.numSamplers,
|
||||
computePipeline->header.numReadonlyStorageTextures)];
|
||||
}
|
||||
commandBuffer->needComputeReadOnlyStorageTextureBind = false;
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageBufferBind) {
|
||||
if (computePipeline->numReadonlyStorageBuffers > 0) {
|
||||
if (computePipeline->header.numReadonlyStorageBuffers > 0) {
|
||||
[commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadOnlyBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(computePipeline->numUniformBuffers,
|
||||
computePipeline->numReadonlyStorageBuffers)];
|
||||
withRange:NSMakeRange(computePipeline->header.numUniformBuffers,
|
||||
computePipeline->header.numReadonlyStorageBuffers)];
|
||||
}
|
||||
commandBuffer->needComputeReadOnlyStorageBufferBind = false;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
|
||||
if (commandBuffer->needComputeUniformBufferBind[i]) {
|
||||
if (computePipeline->numUniformBuffers > i) {
|
||||
if (computePipeline->header.numUniformBuffers > i) {
|
||||
[commandBuffer->computeEncoder
|
||||
setBuffer:commandBuffer->computeUniformBuffers[i]->handle
|
||||
offset:commandBuffer->computeUniformBuffers[i]->drawOffset
|
||||
@@ -3127,7 +3121,7 @@ static void METAL_BindComputePipeline(
|
||||
metalCommandBuffer->needComputeUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < pipeline->numUniformBuffers; i += 1) {
|
||||
for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) {
|
||||
if (metalCommandBuffer->computeUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->computeUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
@@ -3135,22 +3129,22 @@ static void METAL_BindComputePipeline(
|
||||
}
|
||||
|
||||
// Bind write-only resources
|
||||
if (pipeline->numReadWriteStorageTextures > 0) {
|
||||
if (pipeline->header.numReadWriteStorageTextures > 0) {
|
||||
[metalCommandBuffer->computeEncoder setTextures:metalCommandBuffer->computeReadWriteTextures
|
||||
withRange:NSMakeRange(
|
||||
pipeline->numSamplers +
|
||||
pipeline->numReadonlyStorageTextures,
|
||||
pipeline->numReadWriteStorageTextures)];
|
||||
pipeline->header.numSamplers +
|
||||
pipeline->header.numReadonlyStorageTextures,
|
||||
pipeline->header.numReadWriteStorageTextures)];
|
||||
}
|
||||
|
||||
NSUInteger offsets[MAX_COMPUTE_WRITE_BUFFERS] = { 0 };
|
||||
if (pipeline->numReadWriteStorageBuffers > 0) {
|
||||
if (pipeline->header.numReadWriteStorageBuffers > 0) {
|
||||
[metalCommandBuffer->computeEncoder setBuffers:metalCommandBuffer->computeReadWriteBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(
|
||||
pipeline->numUniformBuffers +
|
||||
pipeline->numReadonlyStorageBuffers,
|
||||
pipeline->numReadWriteStorageBuffers)];
|
||||
pipeline->header.numUniformBuffers +
|
||||
pipeline->header.numReadonlyStorageBuffers,
|
||||
pipeline->header.numReadWriteStorageBuffers)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4564,6 +4558,7 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD
|
||||
SDL_GPUDevice *result = SDL_calloc(1, sizeof(SDL_GPUDevice));
|
||||
ASSIGN_DRIVER(METAL)
|
||||
result->driverData = (SDL_GPURenderer *)renderer;
|
||||
result->shader_formats = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
|
||||
renderer->sdlGPUDevice = result;
|
||||
|
||||
return result;
|
||||
|
||||
+296
-199
File diff suppressed because it is too large.
Load diff
@@ -31,11 +31,7 @@
|
||||
/*
|
||||
* External stuff.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
extern HWND SDL_HelperWindow;
|
||||
#else
|
||||
static const HWND SDL_HelperWindow = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal stuff.
|
||||
|
||||
@@ -807,6 +807,8 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
|
||||
#define hid_send_feature_report LIBUSB_hid_send_feature_report
|
||||
#define hid_set_nonblocking LIBUSB_hid_set_nonblocking
|
||||
#define hid_write LIBUSB_hid_write
|
||||
#define hid_version LIBUSB_hid_version
|
||||
#define hid_version_str LIBUSB_hid_version_str
|
||||
#define input_report LIBUSB_input_report
|
||||
#define make_path LIBUSB_make_path
|
||||
#define new_hid_device LIBUSB_new_hid_device
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
#define wcsstr SDL_wcsstr
|
||||
#define wcstol SDL_wcstol
|
||||
|
||||
// These functions conflict when linking both SDL and hidapi statically
|
||||
#define hid_winapi_descriptor_reconstruct_pp_data SDL_hid_winapi_descriptor_reconstruct_pp_data
|
||||
#define hid_winapi_get_container_id SDL_hid_winapi_get_container_id
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "windows/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
|
||||
+28
-1
@@ -71,6 +71,11 @@ extern "C" {
|
||||
#define DETACH_KERNEL_DRIVER
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:5287) /* operands are different enum types */
|
||||
#endif
|
||||
|
||||
/* Uncomment to enable the retrieval of Usage and Usage Page in
|
||||
hid_enumerate(). Warning, on platforms different from FreeBSD
|
||||
this is very invasive as it requires the detach
|
||||
@@ -918,6 +923,22 @@ static int should_enumerate_interface(unsigned short vendor_id, const struct lib
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libusb_blacklist(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
size_t i;
|
||||
static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
|
||||
{ 0x1532, 0x0227 } /* Razer Huntsman Gaming keyboard - long delay asking for device details */
|
||||
};
|
||||
|
||||
for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
|
||||
if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
libusb_device **devs;
|
||||
@@ -948,7 +969,8 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
unsigned short dev_pid = desc.idProduct;
|
||||
|
||||
if ((vendor_id != 0x0 && vendor_id != dev_vid) ||
|
||||
(product_id != 0x0 && product_id != dev_pid)) {
|
||||
(product_id != 0x0 && product_id != dev_pid) ||
|
||||
libusb_blacklist(dev_vid, dev_pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1238,6 +1260,7 @@ static void init_xbox360(libusb_device_handle *device_handle, unsigned short idV
|
||||
(void)conf_desc;
|
||||
|
||||
if ((idVendor == 0x05ac && idProduct == 0x055b) /* Gamesir-G3w */ ||
|
||||
(idVendor == 0x20d6 && idProduct == 0x4010) /* PowerA Battle Dragon Advanced Wireless Controller */ ||
|
||||
idVendor == 0x0f0d /* Hori Xbox controllers */) {
|
||||
unsigned char data[20];
|
||||
|
||||
@@ -2139,6 +2162,10 @@ uint16_t get_usb_code_for_current_locale(void)
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -949,6 +949,7 @@ static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
|
||||
{ 0x0D8C, 0x0014 }, /* Sharkoon Skiller SGH2 headset - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x0109 }, /* Razer Lycosa Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x010B }, /* Razer Arctosa Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x0227 }, /* Razer Huntsman Gaming keyboard - long delay asking for device details */
|
||||
{ 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1CCF, 0x0000 } /* All Konami Amusement Devices - causes deadlock asking for device details */
|
||||
};
|
||||
|
||||
@@ -309,12 +309,13 @@ bool SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata
|
||||
if (asyncio) {
|
||||
asyncio->oneshot = true;
|
||||
|
||||
void *ptr = NULL;
|
||||
Uint8 *ptr = NULL;
|
||||
const Sint64 flen = SDL_GetAsyncIOSize(asyncio);
|
||||
if (flen >= 0) {
|
||||
// !!! FIXME: check if flen > address space, since it'll truncate and we'll just end up with an incomplete buffer or a crash.
|
||||
ptr = SDL_malloc((size_t) (flen + 1)); // over-allocate by one so we can add a null-terminator.
|
||||
ptr = (Uint8 *) SDL_malloc((size_t) (flen + 1)); // over-allocate by one so we can add a null-terminator.
|
||||
if (ptr) {
|
||||
ptr[flen] = '\0';
|
||||
retval = SDL_ReadAsyncIO(asyncio, ptr, 0, (Uint64) flen, queue, userdata);
|
||||
if (!retval) {
|
||||
SDL_free(ptr);
|
||||
|
||||
+30
-17
@@ -405,15 +405,17 @@ static bool SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
|
||||
{
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
|
||||
if (gamepad->joystick->instance_id == event->jdevice.which) {
|
||||
SDL_Event deviceevent;
|
||||
if (SDL_EventEnabled(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE)) {
|
||||
for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
|
||||
if (gamepad->joystick->instance_id == event->jdevice.which) {
|
||||
SDL_Event deviceevent;
|
||||
|
||||
deviceevent.type = SDL_EVENT_GAMEPAD_UPDATE_COMPLETE;
|
||||
deviceevent.common.timestamp = event->jdevice.timestamp;
|
||||
deviceevent.gdevice.which = event->jdevice.which;
|
||||
SDL_PushEvent(&deviceevent);
|
||||
break;
|
||||
deviceevent.type = SDL_EVENT_GAMEPAD_UPDATE_COMPLETE;
|
||||
deviceevent.common.timestamp = event->jdevice.timestamp;
|
||||
deviceevent.gdevice.which = event->jdevice.which;
|
||||
SDL_PushEvent(&deviceevent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -729,7 +731,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,", sizeof(mapping_string));
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_SNES:
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_N64:
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,misc1:b11,", sizeof(mapping_string));
|
||||
@@ -773,13 +775,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
||||
// All other gamepads have the standard set of 19 buttons and 6 axes
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||
|
||||
if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
|
||||
// XBox Series X Controllers have a share button under the guide button
|
||||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickXboxOneElite(vendor, product)) {
|
||||
// XBox One Elite Controllers have 4 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickSteamController(vendor, product)) {
|
||||
if (SDL_IsJoystickSteamController(vendor, product)) {
|
||||
// Steam controllers have 2 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickNintendoSwitchPro(vendor, product) ||
|
||||
@@ -820,6 +816,15 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
||||
SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,paddle3:b14,paddle4:b13,", sizeof(mapping_string));
|
||||
}
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||
if (SDL_IsJoystickXboxOneElite(vendor, product)) {
|
||||
// XBox One Elite Controllers have 4 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
|
||||
// XBox Series X Controllers have a share button under the guide button
|
||||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (vendor == 0 && product == 0) {
|
||||
// This is a Bluetooth Nintendo Switch Pro controller
|
||||
@@ -908,7 +913,7 @@ static GamepadMapping_t *SDL_PrivateMatchGamepadMappingForGUID(SDL_GUID guid, bo
|
||||
// An exact match, including CRC
|
||||
return mapping;
|
||||
} else if (crc && exact_match_crc) {
|
||||
return NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!best_match) {
|
||||
@@ -1781,6 +1786,11 @@ static GamepadMapping_t *SDL_PrivateGenerateAutomaticGamepadMapping(const char *
|
||||
char name_string[128];
|
||||
char mapping[1024];
|
||||
|
||||
// Remove the CRC from the GUID
|
||||
// We already know that this GUID doesn't have a mapping without the CRC, and we want newly
|
||||
// added mappings without a CRC to override this mapping.
|
||||
SDL_SetJoystickGUIDCRC(&guid, 0);
|
||||
|
||||
// Remove any commas in the name
|
||||
SDL_strlcpy(name_string, name, sizeof(name_string));
|
||||
{
|
||||
@@ -2749,6 +2759,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
|
||||
gamepad->joystick = SDL_OpenJoystick(instance_id);
|
||||
if (!gamepad->joystick) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
@@ -2757,6 +2768,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
if (gamepad->joystick->naxes) {
|
||||
gamepad->last_match_axis = (SDL_GamepadBinding **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis));
|
||||
if (!gamepad->last_match_axis) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
@@ -2766,6 +2778,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
if (gamepad->joystick->nhats) {
|
||||
gamepad->last_hat_mask = (Uint8 *)SDL_calloc(gamepad->joystick->nhats, sizeof(*gamepad->last_hat_mask));
|
||||
if (!gamepad->last_hat_mask) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad->last_match_axis);
|
||||
SDL_free(gamepad);
|
||||
|
||||
@@ -215,7 +215,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
|
||||
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
|
||||
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
@@ -416,12 +416,13 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
|
||||
"03000000853200008906000000010000,NACON Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
|
||||
"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
|
||||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
@@ -553,6 +554,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000049190000020400001b010000,GameSir T4 Pro,crc:8283,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b23,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000373500009710000001020000,GameSir-K1 FLUX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"03000000c01100000140000011010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
@@ -641,6 +643,12 @@ static const char *s_GamepadMappings[] = {
|
||||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000007e0500001920000011810000,Nintendo N64 Controller,crc:d670,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b3,start:b11,x:b4,y:b10,",
|
||||
"050000007e0500001920000001800000,Nintendo N64 Controller,crc:5e1c,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b3,start:b11,x:b4,y:b10,",
|
||||
"030000007e0500001e20000011810000,Nintendo SEGA Genesis Controller,crc:bb22,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,",
|
||||
"050000007e0500001720000001800000,Nintendo SEGA Genesis Controller,crc:c1bf,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,",
|
||||
"030000007e0500001720000011810000,Nintendo SNES Controller,crc:f648,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500001720000001800000,Nintendo SNES Controller,crc:dbc0,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000620000001800000,Nintendo Switch Joy-Con (L),a:b16,b:b15,guide:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000620000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -789,6 +797,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
|
||||
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000182e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -861,7 +870,9 @@ static const char *s_GamepadMappings[] = {
|
||||
"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
|
||||
"05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000fd216d04,8BitDo Pro 2,crc:ac95,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,crc:3e00,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,crc:40d6,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -898,7 +909,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"0000000050535669746120436f6e7400,PSVita Controller,crc:d598,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_N3DS
|
||||
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b0,b:b1,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b10,y:b11,",
|
||||
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b1,b:b0,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b11,y:b10,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
+129
-3
@@ -277,6 +277,7 @@ static Uint32 initial_blacklist_devices[] = {
|
||||
MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device
|
||||
MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller
|
||||
MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only)
|
||||
MAKE_VIDPID(0x3434, 0x0211), // Keychron K1 Pro System Control
|
||||
};
|
||||
static SDL_vidpid_list blacklist_devices = {
|
||||
SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL,
|
||||
@@ -289,7 +290,17 @@ static Uint32 initial_flightstick_devices[] = {
|
||||
MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick
|
||||
MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick
|
||||
MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D
|
||||
MAKE_VIDPID(0x0583, 0x6258), // Padix USB joystick with viewfinder
|
||||
MAKE_VIDPID(0x0583, 0x688f), // Padix QF-688uv Windstorm Pro
|
||||
MAKE_VIDPID(0x0583, 0x7070), // Padix QF-707u Bazooka
|
||||
MAKE_VIDPID(0x0583, 0xa019), // Padix USB vibration joystick with viewfinder
|
||||
MAKE_VIDPID(0x0583, 0xa131), // Padix USB Wireless 2.4GHz
|
||||
MAKE_VIDPID(0x0583, 0xa209), // Padix MetalStrike ForceFeedback
|
||||
MAKE_VIDPID(0x0583, 0xb010), // Padix MetalStrike Pro
|
||||
MAKE_VIDPID(0x0583, 0xb012), // Padix Wireless MetalStrike
|
||||
MAKE_VIDPID(0x0583, 0xb013), // Padix USB Wireless 2.4GHZ
|
||||
MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick
|
||||
MAKE_VIDPID(0x10f5, 0x7084), // Turtle Beach VelocityOne
|
||||
MAKE_VIDPID(0x231d, 0x0126), // Gunfighter Mk.III 'Space Combat Edition' (right)
|
||||
MAKE_VIDPID(0x231d, 0x0127), // Gunfighter Mk.III 'Space Combat Edition' (left)
|
||||
MAKE_VIDPID(0x362c, 0x0001), // Yawman Arrow
|
||||
@@ -331,6 +342,7 @@ static SDL_vidpid_list rog_gamepad_mice = {
|
||||
static Uint32 initial_throttle_devices[] = {
|
||||
MAKE_VIDPID(0x044f, 0x0404), // HOTAS Warthog Throttle
|
||||
MAKE_VIDPID(0x0738, 0xa221), // Saitek Pro Flight X-56 Rhino Throttle
|
||||
MAKE_VIDPID(0x10f5, 0x7085), // Turtle Beach VelocityOne Throttle
|
||||
};
|
||||
static SDL_vidpid_list throttle_devices = {
|
||||
SDL_HINT_JOYSTICK_THROTTLE_DEVICES, 0, 0, NULL,
|
||||
@@ -374,6 +386,14 @@ static Uint32 initial_wheel_devices[] = {
|
||||
MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing
|
||||
MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U)
|
||||
MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base
|
||||
MAKE_VIDPID(0x0583, 0xa132), // Padix USB Wireless 2.4GHz Wheelpad
|
||||
MAKE_VIDPID(0x0583, 0xa133), // Padix USB Wireless 2.4GHz Wheel
|
||||
MAKE_VIDPID(0x0583, 0xa202), // Padix Force Feedback Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb002), // Padix Vibration USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb005), // Padix USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb008), // Padix USB Wireless 2.4GHz Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb009), // Padix USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb018), // Padix TW6 Wheel
|
||||
MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2
|
||||
MAKE_VIDPID(0x0eb7, 0x0004), // Fanatec ClubSport Wheel Base V2.5
|
||||
MAKE_VIDPID(0x0eb7, 0x0005), // Fanatec CSL Elite Wheel Base+ (PS4)
|
||||
@@ -427,6 +447,13 @@ static SDL_vidpid_list zero_centered_devices = {
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \
|
||||
if (!joystick->is_virtual) { \
|
||||
SDL_SetError("joystick isn't virtual"); \
|
||||
SDL_UnlockJoysticks(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
bool SDL_JoysticksInitialized(void)
|
||||
{
|
||||
return SDL_joysticks_initialized;
|
||||
@@ -1043,6 +1070,27 @@ static void CleanupSensorFusion(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldSwapFaceButtons(const SDL_SteamVirtualGamepadInfo *info)
|
||||
{
|
||||
// When "Use Nintendo Button Layout" is enabled under Steam (the default)
|
||||
// it will send button 0 for the A (east) button and button 1 for the
|
||||
// B (south) button. This is done so that games that interpret the
|
||||
// buttons as Xbox input will get button 0 for "A" as they expect.
|
||||
//
|
||||
// However, SDL reports positional buttons, so we need to swap
|
||||
// the buttons so they show up in the correct position. This provides
|
||||
// consistent behavior regardless of whether we're running under Steam,
|
||||
// under the default settings.
|
||||
if (info &&
|
||||
(info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO ||
|
||||
info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
|
||||
info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||
info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a joystick for use - the index passed as an argument refers to
|
||||
* the N'th joystick on the system. This index is the value which will
|
||||
@@ -1094,6 +1142,11 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
||||
joystick->attached = true;
|
||||
joystick->led_expiration = SDL_GetTicks();
|
||||
joystick->battery_percent = -1;
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver);
|
||||
#else
|
||||
joystick->is_virtual = false;
|
||||
#endif
|
||||
|
||||
if (!driver->Open(joystick, device_index)) {
|
||||
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);
|
||||
@@ -1137,9 +1190,35 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
||||
|
||||
// If this joystick is known to have all zero centered axes, skip the auto-centering code
|
||||
if (SDL_JoystickAxesCenteredAtZero(joystick)) {
|
||||
int i;
|
||||
for (int i = 0; i < joystick->naxes; ++i) {
|
||||
joystick->axes[i].has_initial_value = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < joystick->naxes; ++i) {
|
||||
// We know the initial values for HIDAPI and XInput joysticks
|
||||
if ((SDL_IsJoystickHIDAPI(joystick->guid) ||
|
||||
SDL_IsJoystickXInput(joystick->guid) ||
|
||||
SDL_IsJoystickRAWINPUT(joystick->guid) ||
|
||||
SDL_IsJoystickWGI(joystick->guid)) &&
|
||||
joystick->naxes >= SDL_GAMEPAD_AXIS_COUNT) {
|
||||
int left_trigger, right_trigger;
|
||||
if (SDL_IsJoystickXInput(joystick->guid)) {
|
||||
left_trigger = 2;
|
||||
right_trigger = 5;
|
||||
} else {
|
||||
left_trigger = SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
|
||||
right_trigger = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER;
|
||||
}
|
||||
for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) {
|
||||
int initial_value;
|
||||
if (i == left_trigger || i == right_trigger) {
|
||||
initial_value = SDL_MIN_SINT16;
|
||||
} else {
|
||||
initial_value = 0;
|
||||
}
|
||||
joystick->axes[i].value = initial_value;
|
||||
joystick->axes[i].zero = initial_value;
|
||||
joystick->axes[i].initial_value = initial_value;
|
||||
joystick->axes[i].has_initial_value = true;
|
||||
}
|
||||
}
|
||||
@@ -1148,6 +1227,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
||||
info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id);
|
||||
if (info) {
|
||||
joystick->steam_handle = info->handle;
|
||||
joystick->swap_face_buttons = ShouldSwapFaceButtons(info);
|
||||
}
|
||||
|
||||
// Use system gyro and accelerometer if the gamepad doesn't have built-in sensors
|
||||
@@ -1225,6 +1305,7 @@ bool SDL_SetJoystickVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value)
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SetJoystickVirtualAxisInner(joystick, axis, value);
|
||||
@@ -1244,6 +1325,7 @@ bool SDL_SetJoystickVirtualBall(SDL_Joystick *joystick, int ball, Sint16 xrel, S
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SetJoystickVirtualBallInner(joystick, ball, xrel, yrel);
|
||||
@@ -1263,6 +1345,7 @@ bool SDL_SetJoystickVirtualButton(SDL_Joystick *joystick, int button, bool down)
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SetJoystickVirtualButtonInner(joystick, button, down);
|
||||
@@ -1282,6 +1365,7 @@ bool SDL_SetJoystickVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value)
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SetJoystickVirtualHatInner(joystick, hat, value);
|
||||
@@ -1301,6 +1385,7 @@ bool SDL_SetJoystickVirtualTouchpad(SDL_Joystick *joystick, int touchpad, int fi
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SetJoystickVirtualTouchpadInner(joystick, touchpad, finger, down, x, y, pressure);
|
||||
@@ -1320,6 +1405,7 @@ bool SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType ty
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, false);
|
||||
CHECK_JOYSTICK_VIRTUAL(joystick, false);
|
||||
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
result = SDL_SendJoystickVirtualSensorDataInner(joystick, type, sensor_timestamp, data, num_values);
|
||||
@@ -1778,6 +1864,14 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
|
||||
result = true;
|
||||
} else {
|
||||
result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
|
||||
if (result) {
|
||||
joystick->trigger_rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS;
|
||||
if (joystick->trigger_rumble_resend == 0) {
|
||||
joystick->trigger_rumble_resend = 1;
|
||||
}
|
||||
} else {
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
@@ -1788,6 +1882,7 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
|
||||
joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
|
||||
} else {
|
||||
joystick->trigger_rumble_expiration = 0;
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2305,6 +2400,25 @@ void SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butt
|
||||
event.type = SDL_EVENT_JOYSTICK_BUTTON_UP;
|
||||
}
|
||||
|
||||
if (joystick->swap_face_buttons) {
|
||||
switch (button) {
|
||||
case 0:
|
||||
button = 1;
|
||||
break;
|
||||
case 1:
|
||||
button = 0;
|
||||
break;
|
||||
case 2:
|
||||
button = 3;
|
||||
break;
|
||||
case 3:
|
||||
button = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we're not getting garbage or duplicate events
|
||||
if (button >= joystick->nbuttons) {
|
||||
return;
|
||||
@@ -2353,11 +2467,13 @@ static void SendSteamHandleUpdateEvents(void)
|
||||
if (info) {
|
||||
if (joystick->steam_handle != info->handle) {
|
||||
joystick->steam_handle = info->handle;
|
||||
joystick->swap_face_buttons = ShouldSwapFaceButtons(info);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (joystick->steam_handle != 0) {
|
||||
joystick->steam_handle = 0;
|
||||
joystick->swap_face_buttons = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -2421,6 +2537,15 @@ void SDL_UpdateJoysticks(void)
|
||||
|
||||
if (joystick->trigger_rumble_expiration && now >= joystick->trigger_rumble_expiration) {
|
||||
SDL_RumbleJoystickTriggers(joystick, 0, 0, 0);
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
|
||||
if (joystick->trigger_rumble_resend && now >= joystick->trigger_rumble_resend) {
|
||||
joystick->driver->RumbleTriggers(joystick, joystick->left_trigger_rumble, joystick->right_trigger_rumble);
|
||||
joystick->trigger_rumble_resend = now + SDL_RUMBLE_RESEND_MS;
|
||||
if (joystick->trigger_rumble_resend == 0) {
|
||||
joystick->trigger_rumble_resend = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2801,7 +2926,8 @@ bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_HORI) {
|
||||
if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X) {
|
||||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ struct SDL_Joystick
|
||||
SDL_GUID guid _guarded; // Joystick guid
|
||||
Uint16 firmware_version _guarded; // Firmware version, if available
|
||||
Uint64 steam_handle _guarded; // Steam controller API handle
|
||||
bool swap_face_buttons _guarded; // Whether we should swap face buttons
|
||||
bool is_virtual _guarded; // Whether this is a virtual joystick
|
||||
|
||||
int naxes _guarded; // Number of axis controls on the joystick
|
||||
SDL_JoystickAxisInfo *axes _guarded;
|
||||
@@ -111,6 +113,7 @@ struct SDL_Joystick
|
||||
Uint16 left_trigger_rumble _guarded;
|
||||
Uint16 right_trigger_rumble _guarded;
|
||||
Uint64 trigger_rumble_expiration _guarded;
|
||||
Uint64 trigger_rumble_resend _guarded;
|
||||
|
||||
Uint8 led_red _guarded;
|
||||
Uint8 led_green _guarded;
|
||||
|
||||
@@ -96,6 +96,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x2e18 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x020a ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS PS4/PS5 (PS4 mode)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "SDL_iokitjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
#include "../../haptic/darwin/SDL_syshaptic_c.h" // For haptic hot plugging
|
||||
#include "../usb_ids.h"
|
||||
|
||||
#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
|
||||
|
||||
@@ -213,6 +214,29 @@ static bool GetHIDScaledCalibratedState(recDevice *pDevice, recElement *pElement
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(recDevice *pDevice, recElement *pElement, SInt32 min, SInt32 max, SInt32 *pValue)
|
||||
{
|
||||
if (pElement->minReport == 0 && pElement->maxReport == 255) {
|
||||
return GetHIDScaledCalibratedState(pDevice, pElement, min, max, pValue);
|
||||
}
|
||||
|
||||
// This device thumbstick axes have an unusual axis range that
|
||||
// doesn't work with GetHIDScaledCalibratedState() above.
|
||||
//
|
||||
// See https://github.com/libsdl-org/SDL/issues/13143 for details
|
||||
if (GetHIDElementState(pDevice, pElement, pValue)) {
|
||||
if (*pValue >= 0) {
|
||||
// Negative axis values range from 32767 (at rest) to 0 (minimum)
|
||||
*pValue = -32767 + *pValue;
|
||||
} else if (*pValue < 0) {
|
||||
// Positive axis values range from -32768 (at rest) to 0 (maximum)
|
||||
*pValue = 32768 + *pValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
|
||||
{
|
||||
recDevice *device = (recDevice *)ctx;
|
||||
@@ -506,6 +530,11 @@ static bool GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
|
||||
pDevice->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, (Uint16)vendor, (Uint16)product, (Uint16)version, manufacturer_string, product_string, 0, 0);
|
||||
pDevice->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot((Uint16)vendor, (Uint16)product, product_string);
|
||||
|
||||
if (vendor == USB_VENDOR_NACON_ALT &&
|
||||
product == USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT) {
|
||||
pDevice->nacon_revolution_x_unlimited = true;
|
||||
}
|
||||
|
||||
array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
|
||||
if (array) {
|
||||
AddHIDElements(array, pDevice);
|
||||
@@ -957,7 +986,11 @@ static void DARWIN_JoystickUpdate(SDL_Joystick *joystick)
|
||||
i = 0;
|
||||
|
||||
while (element) {
|
||||
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
|
||||
if (device->nacon_revolution_x_unlimited) {
|
||||
goodRead = GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(device, element, -32768, 32767, &value);
|
||||
} else {
|
||||
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
|
||||
}
|
||||
if (goodRead) {
|
||||
SDL_SendJoystickAxis(timestamp, joystick, i, value);
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ struct joystick_hwdata
|
||||
int instance_id;
|
||||
SDL_GUID guid;
|
||||
int steam_virtual_gamepad_slot;
|
||||
bool nacon_revolution_x_unlimited;
|
||||
|
||||
struct joystick_hwdata *pNext; // next device
|
||||
};
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_GAMECUBE_PROTOCOL
|
||||
#if 0
|
||||
#define DEBUG_GAMECUBE_PROTOCOL
|
||||
#endif
|
||||
|
||||
#define MAX_CONTROLLERS 4
|
||||
|
||||
@@ -119,22 +121,15 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
ctx->joysticks[0] = 0;
|
||||
ctx->joysticks[1] = 0;
|
||||
ctx->joysticks[2] = 0;
|
||||
ctx->joysticks[3] = 0;
|
||||
ctx->rumble[0] = rumbleMagic;
|
||||
ctx->useRumbleBrake = false;
|
||||
|
||||
if (device->vendor_id != USB_VENDOR_NINTENDO) {
|
||||
ctx->pc_mode = true;
|
||||
}
|
||||
|
||||
if (ctx->pc_mode) {
|
||||
for (i = 0; i < MAX_CONTROLLERS; ++i) {
|
||||
ResetAxisRange(ctx, i);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
|
||||
}
|
||||
ResetAxisRange(ctx, 0);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
|
||||
} else {
|
||||
// This is all that's needed to initialize the device. Really!
|
||||
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
|
||||
@@ -204,69 +199,61 @@ static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device
|
||||
{
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, int size)
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, bool invert_c_stick)
|
||||
{
|
||||
SDL_Joystick *joystick;
|
||||
Uint8 i, v;
|
||||
const Uint8 i = 0; // We have a separate context for each connected controller in PC mode, just use the first index
|
||||
Uint8 v;
|
||||
Sint16 axis_value;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (size != 10) {
|
||||
return; // How do we handle this packet?
|
||||
}
|
||||
|
||||
i = packet[0] - 1;
|
||||
if (i >= MAX_CONTROLLERS) {
|
||||
return; // How do we handle this packet?
|
||||
}
|
||||
|
||||
joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
|
||||
if (!joystick) {
|
||||
// Hasn't been opened yet, skip
|
||||
return;
|
||||
}
|
||||
|
||||
#define READ_BUTTON(off, flag, button) \
|
||||
SDL_SendJoystickButton( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
button, \
|
||||
#define READ_BUTTON(off, flag, button) \
|
||||
SDL_SendJoystickButton( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
button, \
|
||||
((packet[off] & flag) != 0));
|
||||
READ_BUTTON(1, 0x02, 0) // A
|
||||
READ_BUTTON(1, 0x04, 1) // B
|
||||
READ_BUTTON(1, 0x08, 3) // Y
|
||||
READ_BUTTON(1, 0x01, 2) // X
|
||||
READ_BUTTON(2, 0x80, 4) // DPAD_LEFT
|
||||
READ_BUTTON(2, 0x20, 5) // DPAD_RIGHT
|
||||
READ_BUTTON(2, 0x40, 6) // DPAD_DOWN
|
||||
READ_BUTTON(2, 0x10, 7) // DPAD_UP
|
||||
READ_BUTTON(2, 0x02, 8) // START
|
||||
READ_BUTTON(1, 0x80, 9) // RIGHTSHOULDER
|
||||
READ_BUTTON(0, 0x02, 0) // A
|
||||
READ_BUTTON(0, 0x04, 1) // B
|
||||
READ_BUTTON(0, 0x08, 3) // Y
|
||||
READ_BUTTON(0, 0x01, 2) // X
|
||||
READ_BUTTON(1, 0x80, 4) // DPAD_LEFT
|
||||
READ_BUTTON(1, 0x20, 5) // DPAD_RIGHT
|
||||
READ_BUTTON(1, 0x40, 6) // DPAD_DOWN
|
||||
READ_BUTTON(1, 0x10, 7) // DPAD_UP
|
||||
READ_BUTTON(1, 0x02, 8) // START
|
||||
READ_BUTTON(0, 0x80, 9) // RIGHTSHOULDER
|
||||
/* These two buttons are for the bottoms of the analog triggers.
|
||||
* More than likely, you're going to want to read the axes instead!
|
||||
* -flibit
|
||||
*/
|
||||
READ_BUTTON(1, 0x20, 10) // TRIGGERRIGHT
|
||||
READ_BUTTON(1, 0x10, 11) // TRIGGERLEFT
|
||||
READ_BUTTON(0, 0x20, 10) // TRIGGERRIGHT
|
||||
READ_BUTTON(0, 0x10, 11) // TRIGGERLEFT
|
||||
#undef READ_BUTTON
|
||||
|
||||
#define READ_AXIS(off, axis, invert) \
|
||||
v = invert ? (0xff - packet[off]) : packet[off]; \
|
||||
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
#define READ_AXIS(off, axis, invert) \
|
||||
v = (invert) ? (0xff - packet[off]) : packet[off]; \
|
||||
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
axis_value = (Sint16)HIDAPI_RemapVal(v, ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \
|
||||
SDL_SendJoystickAxis( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
SDL_SendJoystickAxis( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
axis, axis_value);
|
||||
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX, 0)
|
||||
READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY, 1)
|
||||
READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTX, 0)
|
||||
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTY, 1)
|
||||
READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
|
||||
READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
|
||||
READ_AXIS(2, SDL_GAMEPAD_AXIS_LEFTX, 0)
|
||||
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTY, 1)
|
||||
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX, invert_c_stick ? 1 : 0)
|
||||
READ_AXIS(4, SDL_GAMEPAD_AXIS_RIGHTY, invert_c_stick ? 0 : 1)
|
||||
READ_AXIS(6, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
|
||||
READ_AXIS(7, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
|
||||
#undef READ_AXIS
|
||||
}
|
||||
|
||||
@@ -365,7 +352,18 @@ static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
|
||||
#endif
|
||||
if (ctx->pc_mode) {
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, size);
|
||||
if (size == 10) {
|
||||
// This is the older firmware
|
||||
// The first byte is the index of the connected controller
|
||||
// The C stick has an inverted value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, &packet[1], true);
|
||||
} else if (size == 9) {
|
||||
// This is the newer firmware (version 0x7)
|
||||
// The C stick has the same value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, false);
|
||||
} else {
|
||||
// How do we handle this packet?
|
||||
}
|
||||
} else {
|
||||
HIDAPI_DriverGameCube_HandleNintendoPacket(device, ctx, packet, size);
|
||||
}
|
||||
|
||||
@@ -1003,8 +1003,8 @@ static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
|
||||
|
||||
static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet, int size)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 920; // This is noted as being 944 resolution, but 920 feels better
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 1.08695652e-3f; // 1.0f / 920 // This is noted as being 944 resolution, but 920 feels better
|
||||
Sint16 axis;
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
@@ -812,14 +812,19 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
|
||||
}
|
||||
|
||||
if (ctx->sensors_supported) {
|
||||
// Standard DualSense sensor update rate is 250 Hz over USB
|
||||
float update_rate = 250.0f;
|
||||
|
||||
if (ctx->device->is_bluetooth) {
|
||||
// Bluetooth sensor update rate appears to be 1000 Hz
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 1000.0f);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 1000.0f);
|
||||
} else {
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 250.0f);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 250.0f);
|
||||
update_rate = 1000.0f;
|
||||
} else if (SDL_IsJoystickDualSenseEdge(ctx->device->vendor_id, ctx->device->product_id)) {
|
||||
// DualSense Edge sensor update rate is 1000 Hz over USB
|
||||
update_rate = 1000.0f;
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, update_rate);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
|
||||
}
|
||||
|
||||
ctx->report_battery = true;
|
||||
@@ -1355,8 +1360,8 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
@@ -1406,8 +1411,8 @@ static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
|
||||
@@ -58,9 +58,7 @@
|
||||
#define SWITCH_GYRO_SCALE 14.2842f
|
||||
#define SWITCH_ACCEL_SCALE 4096.f
|
||||
|
||||
#define SWITCH_GYRO_SCALE_OFFSET 13371.0f
|
||||
#define SWITCH_GYRO_SCALE_MULT 936.0f
|
||||
#define SWITCH_ACCEL_SCALE_OFFSET 16384.0f
|
||||
#define SWITCH_ACCEL_SCALE_MULT 4.0f
|
||||
|
||||
enum
|
||||
@@ -930,13 +928,14 @@ static bool SetIMUEnabled(SDL_DriverSwitch_Context *ctx, bool enabled)
|
||||
|
||||
static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
Uint8 *pLeftStickCal;
|
||||
Uint8 *pRightStickCal;
|
||||
Uint8 *pLeftStickCal = NULL;
|
||||
Uint8 *pRightStickCal = NULL;
|
||||
size_t stick, axis;
|
||||
SwitchSubcommandInputPacket_t *user_reply = NULL;
|
||||
SwitchSubcommandInputPacket_t *factory_reply = NULL;
|
||||
SwitchSPIOpData_t readUserParams;
|
||||
SwitchSPIOpData_t readFactoryParams;
|
||||
Uint8 userParamsReadSuccessCount = 0;
|
||||
|
||||
// Read User Calibration Info
|
||||
readUserParams.unAddress = k_unSPIStickUserCalibrationStartOffset;
|
||||
@@ -949,33 +948,46 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
|
||||
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
|
||||
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
for (int attempt = 0; ; ++attempt) {
|
||||
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
|
||||
// We successfully read the calibration data
|
||||
break;
|
||||
}
|
||||
|
||||
if (attempt == MAX_ATTEMPTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically select the user calibration if magic bytes are set
|
||||
if (user_reply && user_reply->stickUserCalibration.rgucLeftMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucLeftMagic[1] == 0xA1) {
|
||||
userParamsReadSuccessCount += 1;
|
||||
pLeftStickCal = user_reply->stickUserCalibration.rgucLeftCalibration;
|
||||
} else {
|
||||
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
|
||||
}
|
||||
|
||||
if (user_reply && user_reply->stickUserCalibration.rgucRightMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucRightMagic[1] == 0xA1) {
|
||||
userParamsReadSuccessCount += 1;
|
||||
pRightStickCal = user_reply->stickUserCalibration.rgucRightCalibration;
|
||||
} else {
|
||||
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
|
||||
}
|
||||
|
||||
// Only read the factory calibration info if we failed to receive the correct magic bytes
|
||||
if (userParamsReadSuccessCount < 2) {
|
||||
// Read Factory Calibration Info
|
||||
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
|
||||
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
|
||||
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
for (int attempt = 0;; ++attempt) {
|
||||
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
|
||||
// We successfully read the calibration data
|
||||
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
|
||||
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
|
||||
break;
|
||||
}
|
||||
|
||||
if (attempt == MAX_ATTEMPTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have calibration data, return false
|
||||
if (pLeftStickCal == NULL || pRightStickCal == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stick calibration values are 12-bits each and are packed by bit
|
||||
@@ -1044,6 +1056,8 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
|
||||
Uint8 *pIMUScale;
|
||||
Sint16 sAccelRawX, sAccelRawY, sAccelRawZ, sGyroRawX, sGyroRawY, sGyroRawZ;
|
||||
Sint16 sAccelSensCoeffX, sAccelSensCoeffY, sAccelSensCoeffZ;
|
||||
Sint16 sGyroSensCoeffX, sGyroSensCoeffY, sGyroSensCoeffZ;
|
||||
|
||||
// IMU scale gives us multipliers for converting raw values to real world values
|
||||
pIMUScale = reply->spiReadData.rgucReadData;
|
||||
@@ -1052,10 +1066,18 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
sAccelRawY = (pIMUScale[3] << 8) | pIMUScale[2];
|
||||
sAccelRawZ = (pIMUScale[5] << 8) | pIMUScale[4];
|
||||
|
||||
sAccelSensCoeffX = (pIMUScale[7] << 8) | pIMUScale[6];
|
||||
sAccelSensCoeffY = (pIMUScale[9] << 8) | pIMUScale[8];
|
||||
sAccelSensCoeffZ = (pIMUScale[11] << 8) | pIMUScale[10];
|
||||
|
||||
sGyroRawX = (pIMUScale[13] << 8) | pIMUScale[12];
|
||||
sGyroRawY = (pIMUScale[15] << 8) | pIMUScale[14];
|
||||
sGyroRawZ = (pIMUScale[17] << 8) | pIMUScale[16];
|
||||
|
||||
sGyroSensCoeffX = (pIMUScale[19] << 8) | pIMUScale[18];
|
||||
sGyroSensCoeffY = (pIMUScale[21] << 8) | pIMUScale[20];
|
||||
sGyroSensCoeffZ = (pIMUScale[23] << 8) | pIMUScale[22];
|
||||
|
||||
// Check for user calibration data. If it's present and set, it'll override the factory settings
|
||||
readParams.unAddress = k_unSPIIMUUserScaleStartOffset;
|
||||
readParams.ucLength = k_unSPIIMUUserScaleLength;
|
||||
@@ -1072,14 +1094,14 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
}
|
||||
|
||||
// Accelerometer scale
|
||||
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffX - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffY - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffZ - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
|
||||
|
||||
// Gyro scale
|
||||
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawX) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawY) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffX - (float)sGyroRawX) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffY - (float)sGyroRawY) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffZ - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
|
||||
|
||||
} else {
|
||||
// Use default values
|
||||
@@ -1101,14 +1123,17 @@ static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, i
|
||||
{
|
||||
sRawValue -= ctx->m_StickCalData[nStick].axis[nAxis].sCenter;
|
||||
|
||||
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
if (sRawValue >= 0) {
|
||||
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
|
||||
} else {
|
||||
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
|
||||
}
|
||||
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, ctx->m_StickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
}
|
||||
|
||||
static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
|
||||
@@ -1118,14 +1143,17 @@ static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nSt
|
||||
|
||||
sRawValue -= usJoystickCenter;
|
||||
|
||||
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
if (sRawValue >= 0) {
|
||||
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
|
||||
} else {
|
||||
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
|
||||
}
|
||||
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
}
|
||||
|
||||
static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
|
||||
|
||||
@@ -751,11 +751,12 @@ bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoysti
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
if (pJoystickID) {
|
||||
*pJoystickID = joystickID;
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -868,10 +869,8 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK, true);
|
||||
device->path = SDL_strdup(info->path);
|
||||
if (!device->path) {
|
||||
SDL_free(device);
|
||||
return NULL;
|
||||
if (info->path) {
|
||||
device->path = SDL_strdup(info->path);
|
||||
}
|
||||
device->seen = true;
|
||||
device->vendor_id = info->vendor_id;
|
||||
@@ -1053,6 +1052,11 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
|
||||
info.usage = USB_USAGE_GENERIC_GAMEPAD;
|
||||
info.manufacturer_string = L"Nintendo";
|
||||
info.product_string = L"Switch Joy-Con (L/R)";
|
||||
if (children[0]->is_bluetooth || children[1]->is_bluetooth) {
|
||||
info.bus_type = SDL_HID_API_BUS_BLUETOOTH;
|
||||
} else {
|
||||
info.bus_type = SDL_HID_API_BUS_USB;
|
||||
}
|
||||
|
||||
combined = HIDAPI_AddDevice(&info, 2, children);
|
||||
if (combined && combined->driver) {
|
||||
@@ -1135,12 +1139,13 @@ check_removed:
|
||||
goto check_removed;
|
||||
} else {
|
||||
HIDAPI_DelDevice(device);
|
||||
device = NULL;
|
||||
|
||||
// Update the device list again in case this device comes back
|
||||
SDL_HIDAPI_change_count = 0;
|
||||
}
|
||||
}
|
||||
if (device->broken && device->parent) {
|
||||
if (device && device->broken && device->parent) {
|
||||
HIDAPI_DelDevice(device->parent);
|
||||
|
||||
// We deleted a different device here, restart the loop
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER 0x01AB
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER_BT 0x0196
|
||||
#define USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER 0x01b2
|
||||
#define USB_PRODUCT_LOGITECH_F310 0xc216
|
||||
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
|
||||
#define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218
|
||||
@@ -83,6 +84,7 @@
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRED 0x0d17
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS 0x0d18
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED 0x0d19
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT 0x0689
|
||||
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
|
||||
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
|
||||
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e
|
||||
|
||||
Loaded 100 of 195 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user