diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 544e9372c5..d45bf1fe4f 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -20,7 +20,6 @@ class AppleArch(Enum): class MsvcArch(Enum): X86 = "x86" X64 = "x64" - Arm32 = "arm" Arm64 = "arm64" @@ -31,7 +30,8 @@ class JobOs(Enum): Ubuntu22_04 = "ubuntu-22.04" Ubuntu24_04 = "ubuntu-24.04" Ubuntu24_04_arm = "ubuntu-24.04-arm" - Macos13 = "macos-13" + Macos13 = "macos-13" # macOS Ventura (2022) + Macos26 = "macos-26" # macOS Tahoe (2025) class SdlPlatform(Enum): @@ -112,7 +112,6 @@ JOB_SPECS = { "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), - "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), @@ -123,6 +122,7 @@ JOB_SPECS = { "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), + "macos-26-framework-arm64": JobSpec(name="MacOS 26 (Framework) (arm64)",os=JobOs.Macos26, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), @@ -421,10 +421,6 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta job.msvc_vcvars_arch = "x64_x86" case MsvcArch.X64: job.msvc_vcvars_arch = "x64" - case MsvcArch.Arm32: - job.msvc_vcvars_arch = "x64_arm" - job.msvc_vcvars_sdk = "10.0.22621.0" # 10.0.26100.0 dropped ARM32 um and ucrt libraries - job.run_tests = False case MsvcArch.Arm64: job.msvc_vcvars_arch = "x64_arm64" job.run_tests = False @@ -530,11 +526,14 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta job.shared_lib = SharedLibType.DYLIB job.static_lib = StaticLibType.A job.ccache = True + if spec.os == JobOs.Macos13: + job.ccache = False job.apt_packages = [] job.brew_packages.extend(( - "ccache", "ninja", )) + if job.ccache: + job.brew_packages.append("ccache") if job.clang_tidy: job.brew_packages.append("llvm") if spec.xcode: diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 4ca6719139..5dc8ee0fa4 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -30,6 +30,7 @@ jobs: install: >- ${{ matrix.platform.msys2-env }}-cc ${{ matrix.platform.msys2-env }}-cmake + ${{ matrix.platform.msys2-env }}-ffmpeg ${{ matrix.platform.msys2-env }}-ninja ${{ (!matrix.platform.msys2-no-perl && format('{0}-perl', matrix.platform.msys2-env)) || '' }} ${{ matrix.platform.msys2-env }}-pkg-config diff --git a/.gitignore b/.gitignore index 394f4b8439..3f82abce64 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ compile_commands.json *.pc test/*.test wayland-generated-protocols +CMakeSettings.json # for CLion .idea @@ -98,6 +99,7 @@ src/render/direct3d12/D3D12_*_One.h src/render/direct3d12/D3D12_*_Series.h src/gpu/d3d12/D3D12_*_One.h src/gpu/d3d12/D3D12_*_Series.h +out/ # for Android android-project/local.properties diff --git a/Android.mk b/Android.mk index 3ecc631d10..87dd21a867 100644 --- a/Android.mk +++ b/Android.mk @@ -123,6 +123,12 @@ include $(BUILD_SHARED_LIBRARY) # ########################### +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/src + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include + LOCAL_MODULE := SDL3_test LOCAL_MODULE_FILENAME := libSDL3_test @@ -139,24 +145,4 @@ LOCAL_EXPORT_LDLIBS := include $(BUILD_STATIC_LIBRARY) - -########################### -# -# SDL static library -# -########################### - -LOCAL_MODULE := SDL3_static - -LOCAL_MODULE_FILENAME := libSDL3 - -LOCAL_LDLIBS := - -LOCAL_LDFLAGS := - -LOCAL_EXPORT_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid - -include $(BUILD_STATIC_LIBRARY) - $(call import-module,android/cpufeatures) - diff --git a/CMakeLists.txt b/CMakeLists.txt index 0100ae8999..3056de99b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,7 +382,6 @@ set_option(SDL_LIBUDEV "Enable libudev support" ON) set_option(SDL_ASAN "Use AddressSanitizer to detect memory errors" OFF) set_option(SDL_CCACHE "Use Ccache to speed up build" OFF) set_option(SDL_CLANG_TIDY "Run clang-tidy static analysis" OFF) -set_option(SDL_GPU_DXVK "Build SDL_GPU with DXVK support" OFF) set(SDL_VENDOR_INFO "" CACHE STRING "Vendor name and/or version to add to SDL_REVISION") @@ -457,6 +456,7 @@ if(SDL_SHARED) add_library(SDL3-shared SHARED) add_library(SDL3::SDL3-shared ALIAS SDL3-shared) SDL_AddCommonCompilerFlags(SDL3-shared) + target_compile_definitions(SDL3-shared PRIVATE "$<$:DEBUG>") set_property(TARGET SDL3-shared PROPERTY UNITY_BUILD OFF) if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES) target_compile_features(SDL3-shared PRIVATE c_std_99) @@ -469,6 +469,7 @@ if(SDL_STATIC) add_library(SDL3-static STATIC) add_library(SDL3::SDL3-static ALIAS SDL3-static) SDL_AddCommonCompilerFlags(SDL3-static) + target_compile_definitions(SDL3-static PRIVATE "$<$:DEBUG>") set_property(TARGET SDL3-static PROPERTY UNITY_BUILD OFF) if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES) target_compile_features(SDL3-static PRIVATE c_std_99) @@ -481,6 +482,7 @@ if(SDL_TEST_LIBRARY) add_library(SDL3_test STATIC) add_library(SDL3::SDL3_test ALIAS SDL3_test) SDL_AddCommonCompilerFlags(SDL3_test) + target_compile_definitions(SDL3_test PRIVATE "$<$:DEBUG>") endif() # Make sure SDL3::SDL3 always exists @@ -638,6 +640,10 @@ if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC) if(COMPILER_SUPPORTS_WNO_ERROR_DEPRECATED_DECLARATIONS) sdl_compile_options(PRIVATE "-Wno-error=deprecated-declarations") endif() + check_c_compiler_flag(-Wno-deprecated-declarations COMPILER_SUPPORTS_WNO_DEPRECATED_DECLARATIONS) + if(COMPILER_SUPPORTS_WNO_DEPRECATED_DECLARATIONS) + sdl_compile_options(PRIVATE "-Wno-deprecated-declarations") + endif() endif() if(APPLE) @@ -1264,6 +1270,7 @@ target_include_directories(SDL_uclibc PRIVATE "${SDL3_BINARY_DIR}/include-config target_include_directories(SDL_uclibc PRIVATE "${SDL3_SOURCE_DIR}/src") target_include_directories(SDL_uclibc PRIVATE "${SDL3_SOURCE_DIR}/include") SDL_AddCommonCompilerFlags(SDL_uclibc) +target_compile_definitions(SDL_uclibc PRIVATE "$<$:DEBUG>") sdl_sources(STATIC "$") set_property(TARGET SDL_uclibc PROPERTY UNITY_BUILD OFF) if(TARGET SDL3-shared) @@ -1607,6 +1614,9 @@ if(ANDROID) endif() endif() endif() + if(TARGET SDL3-static) + target_link_options(SDL3-static INTERFACE "-Wl,-u,JNI_OnLoad") + endif() if(TARGET SDL3-shared) target_link_options(SDL3-shared PRIVATE "-Wl,-z,max-page-size=16384") @@ -2038,16 +2048,6 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) ) endif() - if(SDL_GPU AND SDL_GPU_DXVK) - if(PKG_CONFIG_FOUND) - pkg_search_module(DXVK_NATIVE dxvk-dxgi) - if(DXVK_NATIVE_FOUND) - set(HAVE_D3D11_H TRUE) - sdl_include_directories(PRIVATE SYSTEM ${DXVK_NATIVE_INCLUDE_DIRS}) - endif() - endif() - endif() - if(HAVE_LIBURING_H) sdl_sources("${SDL3_SOURCE_DIR}/src/io/io_uring/SDL_asyncio_liburing.c") endif() @@ -2221,7 +2221,7 @@ elseif(WINDOWS) else() set(PROCESSOR_ARCH "x86") endif() - sdl_link_directories("$") + sdl_link_directories("$") sdl_include_directories(PRIVATE SYSTEM "$") endif() endif() @@ -2232,7 +2232,8 @@ elseif(WINDOWS) check_c_source_compiles(" #include #include - int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_H) + int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_H + ) endif() # headers needed elsewhere @@ -2261,6 +2262,7 @@ elseif(WINDOWS) #include #include #include + static MFVideoPrimaries primaries = MFVideoPrimaries_DCI_P3; int main(int argc, char **argv) { return 0; } " HAVE_MFAPI_H ) @@ -2304,7 +2306,7 @@ elseif(WINDOWS) set(SDL_VIDEO_RENDER_D3D11 1) set(HAVE_RENDER_D3D11 TRUE) endif() - if(SDL_RENDER_D3D12) + if(SDL_RENDER_D3D12 AND HAVE_DXGI1_6_H) set(SDL_VIDEO_RENDER_D3D12 1) set(HAVE_RENDER_D3D12 TRUE) endif() @@ -2655,6 +2657,7 @@ elseif(APPLE) set(SDL_FRAMEWORK_UIKIT 1) set(SDL_IPHONE_KEYBOARD 1) set(SDL_IPHONE_LAUNCHSCREEN 1) + set(SDL_FRAMEWORK_GAMECONTROLLER 1) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/video/uikit/*.m" "${SDL3_SOURCE_DIR}/src/video/uikit/*.h" @@ -3438,6 +3441,10 @@ if (SDL_DIALOG) set(HAVE_SDL_DIALOG TRUE) endif() endif() +if(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) + sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_zenitymessagebox.h) + sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_zenitymessagebox.c) +endif() sdl_sources("${SDL3_SOURCE_DIR}/src/process/SDL_process.c") if(WINDOWS) @@ -3511,15 +3518,7 @@ endif() sdl_glob_sources(${SDL3_SOURCE_DIR}/src/tray/*.c) if(SDL_GPU) - if(HAVE_D3D11_H) - sdl_glob_sources( - "${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.c" - "${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.h" - ) - set(SDL_GPU_D3D11 1) - set(HAVE_SDL_GPU TRUE) - endif() - if(WINDOWS) + if(HAVE_DXGI1_6_H) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c" "${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.h" @@ -3535,7 +3534,7 @@ if(SDL_GPU) set(SDL_GPU_VULKAN 1) set(HAVE_SDL_GPU TRUE) endif() - if(SDL_RENDER_GPU) + if(SDL_RENDER_GPU AND HAVE_SDL_GPU) set(SDL_VIDEO_RENDER_GPU 1) set(HAVE_RENDER_GPU TRUE) endif() @@ -3691,14 +3690,15 @@ endforeach() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/REVISION.txt") file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/REVISION.txt" revisions) list(GET revisions 0 revisions_0) - string(STRIP "${revisions_0}" SDL_REVISION) + string(STRIP "${revisions_0}" revisions_0_stripped) + set(SDL_REVISION "SDL-${revisions_0_stripped}") else() set(SDL_REVISION "" CACHE STRING "Custom SDL revision (only used when REVISION.txt does not exist)") endif() if(NOT SDL_REVISION) # If SDL_REVISION is not overrided, use git to describe git_describe(SDL_REVISION_GIT) - set(SDL_REVISION "SDL3-${SDL3_VERSION}-${SDL_REVISION_GIT}") + set(SDL_REVISION "SDL-${SDL3_VERSION}-${SDL_REVISION_GIT}") endif() execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${SDL3_BINARY_DIR}/include-revision/SDL3") diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj index 7bba0226db..fc014c84a3 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj +++ b/VisualC-GDK/SDL/SDL.vcxproj @@ -423,6 +423,7 @@ + @@ -600,6 +601,7 @@ + @@ -734,6 +736,7 @@ + diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters index 31eb986125..aee0794aaa 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj.filters +++ b/VisualC-GDK/SDL/SDL.vcxproj.filters @@ -86,6 +86,7 @@ + @@ -330,6 +331,7 @@ + @@ -452,6 +454,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 9514dd5a8d..78539fc5a7 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -334,6 +334,7 @@ + @@ -508,6 +509,7 @@ + @@ -624,6 +626,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index 2c927ac42c..661206d034 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -489,6 +489,9 @@ audio + + core + core\windows @@ -684,12 +687,15 @@ video - + video video + + video + video\dummy @@ -1254,6 +1260,9 @@ joystick\hidapi + + joystick\hidapi + joystick\hidapi diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 074c5b69fc..a0c52a3dff 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -66,6 +66,7 @@ 566E26D8246274CC00718109 /* SDL_locale.c in Sources */ = {isa = PBXBuildFile; fileRef = 566E26CD246274CB00718109 /* SDL_locale.c */; }; 566E26E1246274CC00718109 /* SDL_syslocale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26CE246274CC00718109 /* SDL_syslocale.h */; }; 56A2373329F9C113003CCA5F /* SDL_sysrwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */; }; + 63124A422E5C357500A53610 /* SDL_hidapi_zuiki.c in Sources */ = {isa = PBXBuildFile; fileRef = 63124A412E5C357500A53610 /* SDL_hidapi_zuiki.c */; }; 6312C66D2B42341400A7BB00 /* SDL_murmur3.c in Sources */ = {isa = PBXBuildFile; fileRef = 6312C66C2B42341400A7BB00 /* SDL_murmur3.c */; }; 63134A252A7902FD0021E9A6 /* SDL_pen_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */; }; 63134A262A7902FD0021E9A6 /* SDL_pen.c in Sources */ = {isa = PBXBuildFile; fileRef = 63134A242A7902FD0021E9A6 /* SDL_pen.c */; }; @@ -614,6 +615,7 @@ 566E26CD246274CB00718109 /* SDL_locale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_locale.c; path = locale/SDL_locale.c; sourceTree = ""; }; 566E26CE246274CC00718109 /* SDL_syslocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_syslocale.h; path = locale/SDL_syslocale.h; sourceTree = ""; }; 56A2373229F9C113003CCA5F /* SDL_sysrwlock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_sysrwlock.c; sourceTree = ""; }; + 63124A412E5C357500A53610 /* SDL_hidapi_zuiki.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_zuiki.c; sourceTree = ""; }; 6312C66C2B42341400A7BB00 /* SDL_murmur3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_murmur3.c; sourceTree = ""; }; 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_pen_c.h; sourceTree = ""; }; 63134A242A7902FD0021E9A6 /* SDL_pen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_pen.c; sourceTree = ""; }; @@ -1964,6 +1966,7 @@ A7D8A7C223E2513E00DCD162 /* SDL_hidapi_xbox360.c */, A7D8A7C823E2513E00DCD162 /* SDL_hidapi_xbox360w.c */, A7D8A7C523E2513E00DCD162 /* SDL_hidapi_xboxone.c */, + 63124A412E5C357500A53610 /* SDL_hidapi_zuiki.c */, A7D8A7C423E2513E00DCD162 /* SDL_hidapijoystick.c */, A7D8A7C723E2513E00DCD162 /* SDL_hidapijoystick_c.h */, ); @@ -3116,6 +3119,7 @@ 00004D0B73767647AD550000 /* SDL_asyncio_generic.c in Sources */, 0000A03C0F32C43816F40000 /* SDL_asyncio_windows_ioring.c in Sources */, 0000A877C7DB9FA935FC0000 /* SDL_uikitpen.m in Sources */, + 63124A422E5C357500A53610 /* SDL_hidapi_zuiki.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3181,7 +3185,7 @@ SUPPORTED_PLATFORMS = "xrsimulator xros macosx iphonesimulator iphoneos appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; TVOS_DEPLOYMENT_TARGET = 11.0; - XROS_DEPLOYMENT_TARGET = 1.0; + XROS_DEPLOYMENT_TARGET = 1.3; }; name = Release; }; @@ -3245,7 +3249,7 @@ SUPPORTED_PLATFORMS = "xrsimulator xros macosx iphonesimulator iphoneos appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; TVOS_DEPLOYMENT_TARGET = 11.0; - XROS_DEPLOYMENT_TARGET = 1.0; + XROS_DEPLOYMENT_TARGET = 1.3; }; name = Debug; }; diff --git a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj index 3a2e59d0d1..5742f3338e 100644 --- a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj +++ b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj @@ -162,6 +162,7 @@ F36C34232C0F85DB00991150 /* SDL3.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; F36C342D2C0F869B00991150 /* testcamera.c in Sources */ = {isa = PBXBuildFile; fileRef = F36C342C2C0F869B00991150 /* testcamera.c */; }; F36C342E2C0F869B00991150 /* testcamera.c in Sources */ = {isa = PBXBuildFile; fileRef = F36C342C2C0F869B00991150 /* testcamera.c */; }; + F38908B72E81276900CE01D5 /* testautomation_blit.c in Sources */ = {isa = PBXBuildFile; fileRef = F38908B42E81276900CE01D5 /* testautomation_blit.c */; }; F399C64E2A78929400C86979 /* gamepadutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6492A78929400C86979 /* gamepadutils.c */; }; F399C64F2A78929400C86979 /* gamepadutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6492A78929400C86979 /* gamepadutils.c */; }; F399C6512A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; }; @@ -1367,6 +1368,9 @@ F35E56CD2983130F00A43A5F /* testautomation_mouse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_mouse.c; sourceTree = ""; }; F36C34272C0F85DB00991150 /* testcamera.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testcamera.app; sourceTree = BUILT_PRODUCTS_DIR; }; F36C342C2C0F869B00991150 /* testcamera.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testcamera.c; sourceTree = ""; }; + F38908B42E81276900CE01D5 /* testautomation_blit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testautomation_blit.c; sourceTree = ""; }; + F38908B52E81276900CE01D5 /* testautomation_images.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = testautomation_images.h; sourceTree = ""; }; + F38908B62E81276900CE01D5 /* testautomation_suites.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = testautomation_suites.h; sourceTree = ""; }; F399C6492A78929400C86979 /* gamepadutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamepadutils.c; sourceTree = ""; }; F399C6502A7892D800C86979 /* testautomation_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_intrinsics.c; sourceTree = ""; }; F399C6542A78933000C86979 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; @@ -1815,10 +1819,12 @@ 001795B01074222D00F5D044 /* testaudioinfo.c */, F35E56CC2983130F00A43A5F /* testautomation.c */, F35E56C42983130D00A43A5F /* testautomation_audio.c */, + F38908B42E81276900CE01D5 /* testautomation_blit.c */, F35E56BC2983130B00A43A5F /* testautomation_clipboard.c */, F35E56BB2983130B00A43A5F /* testautomation_events.c */, F35E56C92983130E00A43A5F /* testautomation_guid.c */, F35E56B72983130A00A43A5F /* testautomation_hints.c */, + F38908B52E81276900CE01D5 /* testautomation_images.h */, F35E56BF2983130C00A43A5F /* testautomation_images.c */, F399C6502A7892D800C86979 /* testautomation_intrinsics.c */, F35E56B92983130B00A43A5F /* testautomation_iostream.c */, @@ -1836,6 +1842,7 @@ F35E56C82983130E00A43A5F /* testautomation_sdltest.c */, F35E56BE2983130C00A43A5F /* testautomation_stdlib.c */, A1A859492BC72FC20045DD6C /* testautomation_subsystems.c */, + F38908B62E81276900CE01D5 /* testautomation_suites.h */, F35E56CB2983130F00A43A5F /* testautomation_surface.c */, A1A8594B2BC72FC20045DD6C /* testautomation_time.c */, F35E56BD2983130B00A43A5F /* testautomation_timer.c */, @@ -3478,6 +3485,7 @@ F35E56DE2983130F00A43A5F /* testautomation_joystick.c in Sources */, F35E56D82983130F00A43A5F /* testautomation_images.c in Sources */, F35E56DC2983130F00A43A5F /* testautomation_audio.c in Sources */, + F38908B72E81276900CE01D5 /* testautomation_blit.c in Sources */, F35E56D32983130F00A43A5F /* testautomation_math.c in Sources */, F35E56E02983130F00A43A5F /* testautomation_sdltest.c in Sources */, F35E56D42983130F00A43A5F /* testautomation_events.c in Sources */, @@ -4061,8 +4069,8 @@ ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = "org.libsdl.$(PRODUCT_NAME)"; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - SUPPORTS_MACCATALYST = NO; + SUPPORTED_PLATFORMS = "xrsimulator xros macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = YES; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -4234,8 +4242,8 @@ MARKETING_VERSION = 1.0; OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)"; PRODUCT_BUNDLE_IDENTIFIER = "org.libsdl.$(PRODUCT_NAME)"; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - SUPPORTS_MACCATALYST = NO; + SUPPORTED_PLATFORMS = "xrsimulator xros macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = YES; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -4476,7 +4484,6 @@ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; }; name = Debug; @@ -4487,7 +4494,6 @@ ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; }; name = Release; diff --git a/android-project/app/proguard-rules.pro b/android-project/app/proguard-rules.pro index 147cbd378e..41c2a0380d 100644 --- a/android-project/app/proguard-rules.pro +++ b/android-project/app/proguard-rules.pro @@ -23,7 +23,7 @@ void clipboardSetText(java.lang.String); int createCustomCursor(int[], int, int, int, int); void destroyCustomCursor(int); - android.content.Context getContext(); + android.app.Activity getContext(); boolean getManifestEnvironmentVariables(); android.view.Surface getNativeSurface(); void initTouch(); diff --git a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java index 2fd7c15ba1..b91a8211b1 100644 --- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java @@ -113,7 +113,7 @@ public class HIDDeviceManager { // if (shouldClear) { // SharedPreferences.Editor spedit = mSharedPreferences.edit(); // spedit.clear(); -// spedit.commit(); +// spedit.apply(); // } // else { @@ -135,7 +135,7 @@ public class HIDDeviceManager { } spedit.putInt(identifier, result); - spedit.commit(); + spedit.apply(); return result; } diff --git a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java index e33f3aea1d..f9e9389802 100644 --- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java +++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java @@ -4,6 +4,7 @@ import android.hardware.usb.*; import android.os.Build; import android.util.Log; import java.util.Arrays; +import java.util.Locale; class HIDDeviceUSB implements HIDDevice { @@ -31,7 +32,7 @@ class HIDDeviceUSB implements HIDDevice { } String getIdentifier() { - return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex); + return String.format(Locale.ENGLISH, "%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex); } @Override diff --git a/android-project/app/src/main/java/org/libsdl/app/SDL.java b/android-project/app/src/main/java/org/libsdl/app/SDL.java index d5d3d69ae7..d9650a72e4 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDL.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDL.java @@ -1,8 +1,8 @@ package org.libsdl.app; +import android.app.Activity; import android.content.Context; -import java.lang.Class; import java.lang.reflect.Method; /** @@ -28,12 +28,12 @@ public class SDL { } // This function stores the current activity (SDL or not) - static public void setContext(Context context) { + static public void setContext(Activity context) { SDLAudioManager.setContext(context); mContext = context; } - static public Context getContext() { + static public Activity getContext() { return mContext; } @@ -86,5 +86,5 @@ public class SDL { } } - protected static Context mContext; + protected static Activity mContext; } diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 384e378484..422fe76424 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -894,7 +894,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh protected static class SDLCommandHandler extends Handler { @Override public void handleMessage(Message msg) { - Context context = SDL.getContext(); + Context context = getContext(); if (context == null) { Log.e(TAG, "error handling message, getContext() returned null"); return; @@ -929,7 +929,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); SDLActivity.mFullscreenModeActive = false; } - if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) { + if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */) { window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; } if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */ && @@ -1018,7 +1018,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh } } - if (bShouldWait && (SDLActivity.getContext() != null)) { + if (bShouldWait && (getContext() != null)) { // We'll wait for the surfaceChanged() method, which will notify us // when called. That way, we know our current size is really the // size we need, instead of grabbing a size that's still got @@ -1028,9 +1028,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh // take a surprisingly long time for the surface resize, but // then we'll just give up and return. // - synchronized (SDLActivity.getContext()) { + synchronized (getContext()) { try { - SDLActivity.getContext().wait(500); + getContext().wait(500); } catch (InterruptedException ie) { ie.printStackTrace(); } @@ -1043,7 +1043,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh // C functions we call public static native String nativeGetVersion(); - public static native int nativeSetupJNI(); + public static native void nativeSetupJNI(); public static native void nativeInitMainThread(); public static native void nativeCleanupMainThread(); public static native int nativeRunMain(String library, String function, Object arguments); @@ -1213,7 +1213,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh return false; } - InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE); return imm.isAcceptingText(); } @@ -1262,7 +1262,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh /** * This method is called by SDL using JNI. */ - public static Context getContext() { + public static Activity getContext() { return SDL.getContext(); } @@ -1423,7 +1423,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh params.topMargin = y; if (mTextEdit == null) { - mTextEdit = new SDLDummyEdit(SDL.getContext()); + mTextEdit = new SDLDummyEdit(getContext()); mLayout.addView(mTextEdit, params); } else { @@ -1434,7 +1434,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh mTextEdit.setVisibility(View.VISIBLE); mTextEdit.requestFocus(); - InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(mTextEdit, 0); mScreenKeyboardShown = true; @@ -1928,7 +1928,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh } if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) { try { - mSurface.setPointerIcon(PointerIcon.getSystemIcon(SDL.getContext(), cursor_type)); + mSurface.setPointerIcon(PointerIcon.getSystemIcon(getContext(), cursor_type)); } catch (Exception e) { return false; } @@ -2190,7 +2190,11 @@ class SDLClipboardHandler implements } public boolean clipboardHasText() { - return mClipMgr.hasPrimaryClip(); + if (Build.VERSION.SDK_INT >= 28 /* Android 9 (P) */) { + return mClipMgr.hasPrimaryClip(); + } else { + return mClipMgr.hasText(); + } } public String clipboardGetText() { @@ -2208,10 +2212,19 @@ class SDLClipboardHandler implements } public void clipboardSetText(String string) { - mClipMgr.removePrimaryClipChangedListener(this); - ClipData clip = ClipData.newPlainText(null, string); - mClipMgr.setPrimaryClip(clip); - mClipMgr.addPrimaryClipChangedListener(this); + mClipMgr.removePrimaryClipChangedListener(this); + if (string.isEmpty()) { + if (Build.VERSION.SDK_INT >= 28 /* Android 9 (P) */) { + mClipMgr.clearPrimaryClip(); + } else { + ClipData clip = ClipData.newPlainText(null, ""); + mClipMgr.setPrimaryClip(clip); + } + } else { + ClipData clip = ClipData.newPlainText(null, string); + mClipMgr.setPrimaryClip(clip); + } + mClipMgr.addPrimaryClipChangedListener(this); } @Override diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java index 36d8a3cd81..43706fa409 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java @@ -117,7 +117,7 @@ class SDLAudioManager { } } - static native int nativeSetupJNI(); + static native void nativeSetupJNI(); static native void nativeRemoveAudioDevice(boolean recording, int deviceId); diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index 07ec25111d..7807a1e93d 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -20,7 +20,7 @@ import android.view.View; public class SDLControllerManager { - static native int nativeSetupJNI(); + static native void nativeSetupJNI(); static native void nativeAddJoystick(int device_id, String name, String desc, int vendor_id, int product_id, @@ -471,6 +471,11 @@ class SDLHapticHandler_API31 extends SDLHapticHandler { return; } + if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) { + /* Silence 'lint' warning */ + return; + } + VibratorManager manager = device.getVibratorManager(); int[] vibrators = manager.getVibratorIds(); if (vibrators.length >= 2) { @@ -483,6 +488,12 @@ class SDLHapticHandler_API31 extends SDLHapticHandler { } private void vibrate(Vibrator vibrator, float intensity, int length) { + + if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) { + /* Silence 'lint' warning */ + return; + } + if (intensity == 0.0f) { vibrator.cancel(); return; @@ -510,6 +521,12 @@ class SDLHapticHandler_API31 extends SDLHapticHandler { class SDLHapticHandler_API26 extends SDLHapticHandler { @Override void run(int device_id, float intensity, int length) { + + if (Build.VERSION.SDK_INT < 26 /* Android 8.0 (O) */) { + /* Silence 'lint' warning */ + return; + } + SDLHaptic haptic = getHaptic(device_id); if (haptic != null) { if (intensity == 0.0f) { @@ -743,6 +760,11 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 { @Override float getEventX(MotionEvent event, int pointerIndex) { + if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) { + /* Silence 'lint' warning */ + return 0; + } + if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) { return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X, pointerIndex); } else { @@ -752,6 +774,11 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 { @Override float getEventY(MotionEvent event, int pointerIndex) { + if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) { + /* Silence 'lint' warning */ + return 0; + } + if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) { return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y, pointerIndex); } else { @@ -776,6 +803,12 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 { @Override boolean setRelativeMouseEnabled(boolean enabled) { + + if (Build.VERSION.SDK_INT < 26 /* Android 8.0 (O) */) { + /* Silence 'lint' warning */ + return false; + } + if (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */) { if (enabled) { SDLActivity.getContentView().requestPointerCapture(); @@ -791,6 +824,12 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 { @Override void reclaimRelativeMouseModeIfNeeded() { + + if (Build.VERSION.SDK_INT < 26 /* Android 8.0 (O) */) { + /* Silence 'lint' warning */ + return; + } + if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) { SDLActivity.getContentView().requestPointerCapture(); } @@ -798,6 +837,10 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 { @Override boolean checkRelativeEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT < 26 /* Android 8.0 (O) */) { + /* Silence 'lint' warning */ + return false; + } return event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE; } diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py index e25bda8c11..747797091a 100755 --- a/build-scripts/build-release.py +++ b/build-scripts/build-release.py @@ -1517,7 +1517,7 @@ def main(argv=None) -> int: if args.android_home is None or not Path(args.android_home).is_dir(): parser.error("Invalid $ANDROID_HOME or --android-home: must be a directory containing the Android SDK") if args.android_ndk_home is None or not Path(args.android_ndk_home).is_dir(): - parser.error("Invalid $ANDROID_NDK_HOME or --android_ndk_home: must be a directory containing the Android NDK") + parser.error("Invalid $ANDROID_NDK_HOME or --android-ndk-home: must be a directory containing the Android NDK") if args.android_api is None: with section_printer.group("Detect Android APIS"): args.android_api = releaser._detect_android_api(android_home=args.android_home) diff --git a/build-scripts/build-web-examples.pl b/build-scripts/build-web-examples.pl index c255ea3a91..3916a5f67f 100755 --- a/build-scripts/build-web-examples.pl +++ b/build-scripts/build-web-examples.pl @@ -187,6 +187,11 @@ sub handle_example_dir { $description =~ s/\s+\Z//; } + my $short_description = "$description"; + $short_description =~ s/\\n.*//gms; + $short_description =~ s/\A\s+//; + $short_description =~ s/\s+\Z//; + do_mkdir($dst); do_copy($jssrc, $jsdst); do_copy($wasmsrc, $wasmdst); @@ -222,7 +227,7 @@ sub handle_example_dir { my $other_examples_html = "
    "; foreach my $example (get_examples_for_category($category)) { - $other_examples_html .= "
  • $category/$example
  • "; + $other_examples_html .= "
  • $category/$example
  • "; } $other_examples_html .= "
"; @@ -238,6 +243,7 @@ sub handle_example_dir { s/\@example_name\@/$example/g; s/\@javascript_file\@/$jsfname/g; s/\@htmlified_source_code\@/$htmlified_source_code/g; + s/\@short_description\@/$short_description/g; s/\@description\@/$description/g; s/\@preview_image\@/$preview_image/g; s/\@other_examples_html\@/$other_examples_html/g; @@ -268,6 +274,7 @@ sub generate_example_thumbnail { my $project = shift; my $category = shift; my $example = shift; + my $preloadhtmlref = shift; my $example_no_num = "$example"; $example_no_num =~ s/\A\d+\-//; @@ -277,12 +284,14 @@ sub generate_example_thumbnail { my $example_mouseover_html = ''; if ( -f "$examples_dir/$category/$example/onmouseover.webp" ) { $example_mouseover_html = "onmouseover=\"this.src='/$project/$category/$example/onmouseover.webp'\" onmouseout=\"this.src='$example_image_url';\""; + $$preloadhtmlref .= " \n"; } elsif ( -f "$examples_dir/$category/onmouseover.webp" ) { $example_mouseover_html = "onmouseover=\"this.src='/$project/$category/onmouseover.webp'\" onmouseout=\"this.src='$example_image_url';\""; + $$preloadhtmlref .= " \n"; } return " - +
$example_no_num
@@ -294,10 +303,11 @@ sub generate_example_thumbnail { sub generate_example_thumbnails_for_category { my $project = shift; my $category = shift; + my $preloadhtmlref = shift; my @examples = get_examples_for_category($category); my $retval = ''; foreach my $example (@examples) { - $retval .= generate_example_thumbnail($project, $category, $example); + $retval .= generate_example_thumbnail($project, $category, $example, $preloadhtmlref); } return $retval; } @@ -319,7 +329,8 @@ sub handle_category_dir { closedir($dh); - my $examples_list_html = generate_example_thumbnails_for_category($project, $category); + my $preloadhtml = ''; + my $examples_list_html = generate_example_thumbnails_for_category($project, $category, \$preloadhtml); my $dst = "$output_dir/$category"; @@ -339,6 +350,7 @@ sub handle_category_dir { s/\@project_name\@/$project/g; s/\@category_name\@/$category/g; s/\@category_description\@/$category_description/g; + s/\@preload_images_html\@/$preloadhtml/g; s/\@examples_list_html\@/$examples_list_html/g; s/\@preview_image\@/$preview_image/g; $html .= $_; @@ -390,12 +402,13 @@ while (readdir($dh)) { closedir($dh); # write homepage -my $homepage_list_html = ""; +my $homepage_list_html = ''; +my $homepage_preloadhtml = ''; foreach my $category (get_categories()) { my $category_description = get_category_description($category); $homepage_list_html .= "

$category_description

"; $homepage_list_html .= "
"; - $homepage_list_html .= generate_example_thumbnails_for_category($project, $category); + $homepage_list_html .= generate_example_thumbnails_for_category($project, $category, \$homepage_preloadhtml); $homepage_list_html .= "
"; } @@ -408,6 +421,7 @@ while (<$htmltemplate>) { s/\@project_name\@/$project/g; s/\@homepage_list_html\@/$homepage_list_html/g; s/\@preview_image\@/$preview_image/g; + s/\@preload_images_html\@/$homepage_preloadhtml/g; $html .= $_; } close($htmltemplate); diff --git a/build-scripts/pkg-support/android/aar/__main__.py.in b/build-scripts/pkg-support/android/aar/__main__.py.in index 344cf71937..917049f443 100755 --- a/build-scripts/pkg-support/android/aar/__main__.py.in +++ b/build-scripts/pkg-support/android/aar/__main__.py.in @@ -26,7 +26,6 @@ import zipfile AAR_PATH = pathlib.Path(__file__).resolve().parent -ANDROID_ARCHS = { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" } def main(): diff --git a/cmake/PkgConfigHelper.cmake b/cmake/PkgConfigHelper.cmake index 7070fac795..408e76177e 100644 --- a/cmake/PkgConfigHelper.cmake +++ b/cmake/PkgConfigHelper.cmake @@ -1,16 +1,16 @@ # Helper for Find modules function(get_flags_from_pkg_config _library _pc_prefix _out_prefix) - if("${_library}" MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$") - set(_cflags ${_pc_prefix}_STATIC_CFLAGS_OTHER) - set(_link_libraries ${_pc_prefix}_STATIC_LIBRARIES) - set(_link_options ${_pc_prefix}_STATIC_LDFLAGS_OTHER) - set(_library_dirs ${_pc_prefix}_STATIC_LIBRARY_DIRS) - else() + if(NOT "${_library}" MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$") set(_cflags ${_pc_prefix}_CFLAGS_OTHER) set(_link_libraries ${_pc_prefix}_LIBRARIES) set(_link_options ${_pc_prefix}_LDFLAGS_OTHER) set(_library_dirs ${_pc_prefix}_LIBRARY_DIRS) + else() + set(_cflags ${_pc_prefix}_STATIC_CFLAGS_OTHER) + set(_link_libraries ${_pc_prefix}_STATIC_LIBRARIES) + set(_link_options ${_pc_prefix}_STATIC_LDFLAGS_OTHER) + set(_library_dirs ${_pc_prefix}_STATIC_LIBRARY_DIRS) endif() # The *_LIBRARIES lists always start with the library itself diff --git a/cmake/PreseedMSVCCache.cmake b/cmake/PreseedMSVCCache.cmake index 17495aa480..e6fe70a335 100644 --- a/cmake/PreseedMSVCCache.cmake +++ b/cmake/PreseedMSVCCache.cmake @@ -1,183 +1,193 @@ if(MSVC) function(SDL_Preseed_CMakeCache) - set(COMPILER_SUPPORTS_W3 "1" CACHE INTERNAL "Test /W3") - set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS "" CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS") - set(HAVE_ALLOCA_H "" CACHE INTERNAL "Have include alloca.h") - set(HAVE_AUDIOCLIENT_H "1" CACHE INTERNAL "Have include audioclient.h") - set(HAVE_D3D11_H "1" CACHE INTERNAL "Have include d3d11_1.h") - set(HAVE_D3D9_H "1" CACHE INTERNAL "Have include d3d9.h") - set(HAVE_DDRAW_H "1" CACHE INTERNAL "Have include ddraw.h") - set(HAVE_DINPUT_H "1" CACHE INTERNAL "Have include dinput.h") - set(HAVE_DSOUND_H "1" CACHE INTERNAL "Have include dsound.h") - set(HAVE_DXGI_H "1" CACHE INTERNAL "Have include dxgi.h") - set(HAVE_LIBM "" CACHE INTERNAL "Have library m") - set(HAVE_MALLOC "1" CACHE INTERNAL "Have include malloc.h") - set(HAVE_MMDEVICEAPI_H "1" CACHE INTERNAL "Have include mmdeviceapi.h") - set(HAVE_SENSORSAPI_H "1" CACHE INTERNAL "Have include sensorsapi.h") - set(HAVE_SHELLSCALINGAPI_H "1" CACHE INTERNAL "Have include shellscalingapi.h") - set(HAVE_TPCSHRD_H "1" CACHE INTERNAL "Have include tpcshrd.h") - set(HAVE_WIN32_CC "1" CACHE INTERNAL "Test HAVE_WIN32_CC") - set(HAVE_XINPUT_H "1" CACHE INTERNAL "Test HAVE_XINPUT_H") - set(LIBC_HAS_ABS "1" CACHE INTERNAL "Have symbol abs") - set(LIBC_HAS_ACOS "1" CACHE INTERNAL "Have symbol acos") - set(LIBC_HAS_ACOSF "1" CACHE INTERNAL "Have symbol acosf") - set(LIBC_HAS_ASIN "1" CACHE INTERNAL "Have symbol asin") - set(LIBC_HAS_ASINF "1" CACHE INTERNAL "Have symbol asinf") - set(LIBC_HAS_ATAN "1" CACHE INTERNAL "Have symbol atan") - set(LIBC_HAS_ATAN2 "1" CACHE INTERNAL "Have symbol atan2") - set(LIBC_HAS_ATAN2F "1" CACHE INTERNAL "Have symbol atan2f") - set(LIBC_HAS_ATANF "1" CACHE INTERNAL "Have symbol atanf") - set(LIBC_HAS_ATOF "1" CACHE INTERNAL "Have symbol atof") - set(LIBC_HAS_ATOI "1" CACHE INTERNAL "Have symbol atoi") - set(LIBC_HAS_BCOPY "" CACHE INTERNAL "Have symbol bcopy") - set(LIBC_HAS_CALLOC "1" CACHE INTERNAL "Have symbol calloc") - set(LIBC_HAS_CEIL "1" CACHE INTERNAL "Have symbol ceil") - set(LIBC_HAS_CEILF "1" CACHE INTERNAL "Have symbol ceilf") - set(LIBC_HAS_COPYSIGN "1" CACHE INTERNAL "Have symbol copysign") - set(LIBC_HAS_COPYSIGNF "1" CACHE INTERNAL "Have symbol copysignf") - set(LIBC_HAS_COS "1" CACHE INTERNAL "Have symbol cos") - set(LIBC_HAS_COSF "1" CACHE INTERNAL "Have symbol cosf") - set(LIBC_HAS_EXP "1" CACHE INTERNAL "Have symbol exp") - set(LIBC_HAS_EXPF "1" CACHE INTERNAL "Have symbol expf") - set(LIBC_HAS_FABS "1" CACHE INTERNAL "Have symbol fabs") - set(LIBC_HAS_FABSF "1" CACHE INTERNAL "Have symbol fabsf") - set(LIBC_HAS_FLOAT_H "1" CACHE INTERNAL "Have include float.h") - set(LIBC_HAS_FLOOR "1" CACHE INTERNAL "Have symbol floor") - set(LIBC_HAS_FLOORF "1" CACHE INTERNAL "Have symbol floorf") - set(LIBC_HAS_FMOD "1" CACHE INTERNAL "Have symbol fmod") - set(LIBC_HAS_FMODF "1" CACHE INTERNAL "Have symbol fmodf") - set(LIBC_HAS_FOPEN64 "" CACHE INTERNAL "Have symbol fopen64") - set(LIBC_HAS_FREE "1" CACHE INTERNAL "Have symbol free") - set(LIBC_HAS_FSEEKO "" CACHE INTERNAL "Have symbol fseeko") - set(LIBC_HAS_FSEEKO64 "" CACHE INTERNAL "Have symbol fseeko64") - set(LIBC_HAS_GETENV "1" CACHE INTERNAL "Have symbol getenv") - set(LIBC_HAS_ICONV_H "" CACHE INTERNAL "Have include iconv.h") - set(LIBC_HAS_INDEX "" CACHE INTERNAL "Have symbol index") - set(LIBC_HAS_INTTYPES_H "1" CACHE INTERNAL "Have include inttypes.h") - set(LIBC_HAS_ISINF "1" CACHE INTERNAL "Have include isinf(double)") - set(LIBC_ISINF_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isinf(float)") - set(LIBC_HAS_ISINFF "" CACHE INTERNAL "Have include isinff(float)") - set(LIBC_HAS_ISNAN "1" CACHE INTERNAL "Have include isnan(double)") - set(LIBC_ISNAN_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isnan(float)") - set(LIBC_HAS_ISNANF "" CACHE INTERNAL "Have include isnanf(float)") - set(LIBC_HAS_ITOA "1" CACHE INTERNAL "Have symbol itoa") - set(LIBC_HAS_LIMITS_H "1" CACHE INTERNAL "Have include limits.h") - set(LIBC_HAS_LOG "1" CACHE INTERNAL "Have symbol log") - set(LIBC_HAS_LOG10 "1" CACHE INTERNAL "Have symbol log10") - set(LIBC_HAS_LOG10F "1" CACHE INTERNAL "Have symbol log10f") - set(LIBC_HAS_LOGF "1" CACHE INTERNAL "Have symbol logf") - set(LIBC_HAS_LROUND "1" CACHE INTERNAL "Have symbol lround") - set(LIBC_HAS_LROUNDF "1" CACHE INTERNAL "Have symbol lroundf") - set(LIBC_HAS_MALLOC "1" CACHE INTERNAL "Have symbol malloc") - set(LIBC_HAS_MALLOC_H "1" CACHE INTERNAL "Have include malloc.h") - set(LIBC_HAS_MATH_H "1" CACHE INTERNAL "Have include math.h") - set(LIBC_HAS_MEMCMP "1" CACHE INTERNAL "Have symbol memcmp") - set(LIBC_HAS_MEMCPY "1" CACHE INTERNAL "Have symbol memcpy") - set(LIBC_HAS_MEMMOVE "1" CACHE INTERNAL "Have symbol memmove") - set(LIBC_HAS_MEMORY_H "1" CACHE INTERNAL "Have include memory.h") - set(LIBC_HAS_MEMSET "1" CACHE INTERNAL "Have symbol memset") - set(LIBC_HAS_MODF "1" CACHE INTERNAL "Have symbol modf") - set(LIBC_HAS_MODFF "1" CACHE INTERNAL "Have symbol modff") - set(LIBC_HAS_POW "1" CACHE INTERNAL "Have symbol pow") - set(LIBC_HAS_POWF "1" CACHE INTERNAL "Have symbol powf") - set(LIBC_HAS_PUTENV "1" CACHE INTERNAL "Have symbol putenv") - set(LIBC_HAS_REALLOC "1" CACHE INTERNAL "Have symbol realloc") - set(LIBC_HAS_RINDEX "" CACHE INTERNAL "Have symbol rindex") - set(LIBC_HAS_ROUND "1" CACHE INTERNAL "Have symbol round") - set(LIBC_HAS_ROUNDF "1" CACHE INTERNAL "Have symbol roundf") - set(LIBC_HAS_SCALBN "1" CACHE INTERNAL "Have symbol scalbn") - set(LIBC_HAS_SCALBNF "1" CACHE INTERNAL "Have symbol scalbnf") - set(LIBC_HAS_SETENV "" CACHE INTERNAL "Have symbol setenv") - set(LIBC_HAS_SIGNAL_H "1" CACHE INTERNAL "Have include signal.h") - set(LIBC_HAS_SIN "1" CACHE INTERNAL "Have symbol sin") - set(LIBC_HAS_SINF "1" CACHE INTERNAL "Have symbol sinf") - set(LIBC_HAS_SQR "" CACHE INTERNAL "Have symbol sqr") - set(LIBC_HAS_SQRT "1" CACHE INTERNAL "Have symbol sqrt") - set(LIBC_HAS_SQRTF "1" CACHE INTERNAL "Have symbol sqrtf") - set(LIBC_HAS_SSCANF "1" CACHE INTERNAL "Have symbol sscanf") - set(LIBC_HAS_STDARG_H "1" CACHE INTERNAL "Have include stdarg.h") - set(LIBC_HAS_STDBOOL_H "1" CACHE INTERNAL "Have include stdbool.h") - set(LIBC_HAS_STDDEF_H "1" CACHE INTERNAL "Have include stddef.h") - set(LIBC_HAS_STDINT_H "1" CACHE INTERNAL "Have include stdint.h") - set(LIBC_HAS_STDIO_H "1" CACHE INTERNAL "Have include stdio.h") - set(LIBC_HAS_STDLIB_H "1" CACHE INTERNAL "Have include stdlib.h") - set(LIBC_HAS_STRCHR "1" CACHE INTERNAL "Have symbol strchr") - set(LIBC_HAS_STRCMP "1" CACHE INTERNAL "Have symbol strcmp") - set(LIBC_HAS_STRINGS_H "" CACHE INTERNAL "Have include strings.h") - set(LIBC_HAS_STRING_H "1" CACHE INTERNAL "Have include string.h") - set(LIBC_HAS_STRLCAT "" CACHE INTERNAL "Have symbol strlcat") - set(LIBC_HAS_STRLCPY "" CACHE INTERNAL "Have symbol strlcpy") - set(LIBC_HAS_STRLEN "1" CACHE INTERNAL "Have symbol strlen") - set(LIBC_HAS_STRNCMP "1" CACHE INTERNAL "Have symbol strncmp") - set(LIBC_HAS_STRNLEN "1" CACHE INTERNAL "Have symbol strnlen") - set(LIBC_HAS_STRNSTR "" CACHE INTERNAL "Have symbol strnstr") - set(LIBC_HAS_STRPBRK "1" CACHE INTERNAL "Have symbol strpbrk") - set(LIBC_HAS_STRRCHR "1" CACHE INTERNAL "Have symbol strrchr") - set(LIBC_HAS_STRSTR "1" CACHE INTERNAL "Have symbol strstr") - set(LIBC_HAS_STRTOD "1" CACHE INTERNAL "Have symbol strtod") - set(LIBC_HAS_STRTOK_R "" CACHE INTERNAL "Have symbol strtok_r") - set(LIBC_HAS_STRTOL "1" CACHE INTERNAL "Have symbol strtol") - set(LIBC_HAS_STRTOLL "1" CACHE INTERNAL "Have symbol strtoll") - set(LIBC_HAS_STRTOUL "1" CACHE INTERNAL "Have symbol strtoul") - set(LIBC_HAS_STRTOULL "1" CACHE INTERNAL "Have symbol strtoull") - set(LIBC_HAS_SYS_TYPES_H "1" CACHE INTERNAL "Have include sys/types.h") - set(LIBC_HAS_TAN "1" CACHE INTERNAL "Have symbol tan") - set(LIBC_HAS_TANF "1" CACHE INTERNAL "Have symbol tanf") - set(LIBC_HAS_TIME_H "1" CACHE INTERNAL "Have include time.h") - set(LIBC_HAS_TRUNC "1" CACHE INTERNAL "Have symbol trunc") - set(LIBC_HAS_TRUNCF "1" CACHE INTERNAL "Have symbol truncf") - set(LIBC_HAS_UNSETENV "" CACHE INTERNAL "Have symbol unsetenv") - set(LIBC_HAS_VSNPRINTF "1" CACHE INTERNAL "Have symbol vsnprintf") - set(LIBC_HAS_VSSCANF "1" CACHE INTERNAL "Have symbol vsscanf") - set(LIBC_HAS_WCHAR_H "1" CACHE INTERNAL "Have include wchar.h") - set(LIBC_HAS_WCSCMP "1" CACHE INTERNAL "Have symbol wcscmp") - set(LIBC_HAS_WCSDUP "1" CACHE INTERNAL "Have symbol wcsdup") - set(LIBC_HAS_WCSLCAT "" CACHE INTERNAL "Have symbol wcslcat") - set(LIBC_HAS_WCSLCPY "" CACHE INTERNAL "Have symbol wcslcpy") - set(LIBC_HAS_WCSLEN "1" CACHE INTERNAL "Have symbol wcslen") - set(LIBC_HAS_WCSNCMP "1" CACHE INTERNAL "Have symbol wcsncmp") - set(LIBC_HAS_WCSNLEN "1" CACHE INTERNAL "Have symbol wcsnlen") - set(LIBC_HAS_WCSSTR "1" CACHE INTERNAL "Have symbol wcsstr") - set(LIBC_HAS_WCSTOL "1" CACHE INTERNAL "Have symbol wcstol") - set(LIBC_HAS__EXIT "1" CACHE INTERNAL "Have symbol _Exit") - set(LIBC_HAS__I64TOA "1" CACHE INTERNAL "Have symbol _i64toa") - set(LIBC_HAS__LTOA "1" CACHE INTERNAL "Have symbol _ltoa") - set(LIBC_HAS__STRREV "1" CACHE INTERNAL "Have symbol _strrev") - set(LIBC_HAS__UI64TOA "1" CACHE INTERNAL "Have symbol _ui64toa") - set(LIBC_HAS__UITOA "" CACHE INTERNAL "Have symbol _uitoa") - set(LIBC_HAS__ULTOA "1" CACHE INTERNAL "Have symbol _ultoa") - set(LIBC_HAS__WCSDUP "1" CACHE INTERNAL "Have symbol _wcsdup") - set(LIBC_IS_GLIBC "" CACHE INTERNAL "Have symbol __GLIBC__") - set(_ALLOCA_IN_MALLOC_H "" CACHE INTERNAL "Have symbol _alloca") + check_c_source_compiles(" + #include + #if _WIN32_WINNT < 0x0A00 + #error Preseeding is only supported for MSVC supporting Windows 10 or higher + #endif + int main(int argc, char **argv) { return 0; } + " CAN_PRESEED + ) + if(CAN_PRESEED) + set(COMPILER_SUPPORTS_W3 "1" CACHE INTERNAL "Test /W3") + set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS "" CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS") + set(HAVE_ALLOCA_H "" CACHE INTERNAL "Have include alloca.h") + set(HAVE_AUDIOCLIENT_H "1" CACHE INTERNAL "Have include audioclient.h") + set(HAVE_D3D11_H "1" CACHE INTERNAL "Have include d3d11_1.h") + set(HAVE_D3D9_H "1" CACHE INTERNAL "Have include d3d9.h") + set(HAVE_DDRAW_H "1" CACHE INTERNAL "Have include ddraw.h") + set(HAVE_DINPUT_H "1" CACHE INTERNAL "Have include dinput.h") + set(HAVE_DSOUND_H "1" CACHE INTERNAL "Have include dsound.h") + set(HAVE_DXGI_H "1" CACHE INTERNAL "Have include dxgi.h") + set(HAVE_LIBM "" CACHE INTERNAL "Have library m") + set(HAVE_MALLOC "1" CACHE INTERNAL "Have include malloc.h") + set(HAVE_MMDEVICEAPI_H "1" CACHE INTERNAL "Have include mmdeviceapi.h") + set(HAVE_SENSORSAPI_H "1" CACHE INTERNAL "Have include sensorsapi.h") + set(HAVE_SHELLSCALINGAPI_H "1" CACHE INTERNAL "Have include shellscalingapi.h") + set(HAVE_TPCSHRD_H "1" CACHE INTERNAL "Have include tpcshrd.h") + set(HAVE_WIN32_CC "1" CACHE INTERNAL "Test HAVE_WIN32_CC") + set(HAVE_XINPUT_H "1" CACHE INTERNAL "Test HAVE_XINPUT_H") + set(LIBC_HAS_ABS "1" CACHE INTERNAL "Have symbol abs") + set(LIBC_HAS_ACOS "1" CACHE INTERNAL "Have symbol acos") + set(LIBC_HAS_ACOSF "1" CACHE INTERNAL "Have symbol acosf") + set(LIBC_HAS_ASIN "1" CACHE INTERNAL "Have symbol asin") + set(LIBC_HAS_ASINF "1" CACHE INTERNAL "Have symbol asinf") + set(LIBC_HAS_ATAN "1" CACHE INTERNAL "Have symbol atan") + set(LIBC_HAS_ATAN2 "1" CACHE INTERNAL "Have symbol atan2") + set(LIBC_HAS_ATAN2F "1" CACHE INTERNAL "Have symbol atan2f") + set(LIBC_HAS_ATANF "1" CACHE INTERNAL "Have symbol atanf") + set(LIBC_HAS_ATOF "1" CACHE INTERNAL "Have symbol atof") + set(LIBC_HAS_ATOI "1" CACHE INTERNAL "Have symbol atoi") + set(LIBC_HAS_BCOPY "" CACHE INTERNAL "Have symbol bcopy") + set(LIBC_HAS_CALLOC "1" CACHE INTERNAL "Have symbol calloc") + set(LIBC_HAS_CEIL "1" CACHE INTERNAL "Have symbol ceil") + set(LIBC_HAS_CEILF "1" CACHE INTERNAL "Have symbol ceilf") + set(LIBC_HAS_COPYSIGN "1" CACHE INTERNAL "Have symbol copysign") + set(LIBC_HAS_COPYSIGNF "1" CACHE INTERNAL "Have symbol copysignf") + set(LIBC_HAS_COS "1" CACHE INTERNAL "Have symbol cos") + set(LIBC_HAS_COSF "1" CACHE INTERNAL "Have symbol cosf") + set(LIBC_HAS_EXP "1" CACHE INTERNAL "Have symbol exp") + set(LIBC_HAS_EXPF "1" CACHE INTERNAL "Have symbol expf") + set(LIBC_HAS_FABS "1" CACHE INTERNAL "Have symbol fabs") + set(LIBC_HAS_FABSF "1" CACHE INTERNAL "Have symbol fabsf") + set(LIBC_HAS_FLOAT_H "1" CACHE INTERNAL "Have include float.h") + set(LIBC_HAS_FLOOR "1" CACHE INTERNAL "Have symbol floor") + set(LIBC_HAS_FLOORF "1" CACHE INTERNAL "Have symbol floorf") + set(LIBC_HAS_FMOD "1" CACHE INTERNAL "Have symbol fmod") + set(LIBC_HAS_FMODF "1" CACHE INTERNAL "Have symbol fmodf") + set(LIBC_HAS_FOPEN64 "" CACHE INTERNAL "Have symbol fopen64") + set(LIBC_HAS_FREE "1" CACHE INTERNAL "Have symbol free") + set(LIBC_HAS_FSEEKO "" CACHE INTERNAL "Have symbol fseeko") + set(LIBC_HAS_FSEEKO64 "" CACHE INTERNAL "Have symbol fseeko64") + set(LIBC_HAS_GETENV "1" CACHE INTERNAL "Have symbol getenv") + set(LIBC_HAS_ICONV_H "" CACHE INTERNAL "Have include iconv.h") + set(LIBC_HAS_INDEX "" CACHE INTERNAL "Have symbol index") + set(LIBC_HAS_INTTYPES_H "1" CACHE INTERNAL "Have include inttypes.h") + set(LIBC_HAS_ISINF "1" CACHE INTERNAL "Have include isinf(double)") + set(LIBC_ISINF_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isinf(float)") + set(LIBC_HAS_ISINFF "" CACHE INTERNAL "Have include isinff(float)") + set(LIBC_HAS_ISNAN "1" CACHE INTERNAL "Have include isnan(double)") + set(LIBC_ISNAN_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isnan(float)") + set(LIBC_HAS_ISNANF "" CACHE INTERNAL "Have include isnanf(float)") + set(LIBC_HAS_ITOA "1" CACHE INTERNAL "Have symbol itoa") + set(LIBC_HAS_LIMITS_H "1" CACHE INTERNAL "Have include limits.h") + set(LIBC_HAS_LOG "1" CACHE INTERNAL "Have symbol log") + set(LIBC_HAS_LOG10 "1" CACHE INTERNAL "Have symbol log10") + set(LIBC_HAS_LOG10F "1" CACHE INTERNAL "Have symbol log10f") + set(LIBC_HAS_LOGF "1" CACHE INTERNAL "Have symbol logf") + set(LIBC_HAS_LROUND "1" CACHE INTERNAL "Have symbol lround") + set(LIBC_HAS_LROUNDF "1" CACHE INTERNAL "Have symbol lroundf") + set(LIBC_HAS_MALLOC "1" CACHE INTERNAL "Have symbol malloc") + set(LIBC_HAS_MALLOC_H "1" CACHE INTERNAL "Have include malloc.h") + set(LIBC_HAS_MATH_H "1" CACHE INTERNAL "Have include math.h") + set(LIBC_HAS_MEMCMP "1" CACHE INTERNAL "Have symbol memcmp") + set(LIBC_HAS_MEMCPY "1" CACHE INTERNAL "Have symbol memcpy") + set(LIBC_HAS_MEMMOVE "1" CACHE INTERNAL "Have symbol memmove") + set(LIBC_HAS_MEMORY_H "1" CACHE INTERNAL "Have include memory.h") + set(LIBC_HAS_MEMSET "1" CACHE INTERNAL "Have symbol memset") + set(LIBC_HAS_MODF "1" CACHE INTERNAL "Have symbol modf") + set(LIBC_HAS_MODFF "1" CACHE INTERNAL "Have symbol modff") + set(LIBC_HAS_POW "1" CACHE INTERNAL "Have symbol pow") + set(LIBC_HAS_POWF "1" CACHE INTERNAL "Have symbol powf") + set(LIBC_HAS_PUTENV "1" CACHE INTERNAL "Have symbol putenv") + set(LIBC_HAS_REALLOC "1" CACHE INTERNAL "Have symbol realloc") + set(LIBC_HAS_RINDEX "" CACHE INTERNAL "Have symbol rindex") + set(LIBC_HAS_ROUND "1" CACHE INTERNAL "Have symbol round") + set(LIBC_HAS_ROUNDF "1" CACHE INTERNAL "Have symbol roundf") + set(LIBC_HAS_SCALBN "1" CACHE INTERNAL "Have symbol scalbn") + set(LIBC_HAS_SCALBNF "1" CACHE INTERNAL "Have symbol scalbnf") + set(LIBC_HAS_SETENV "" CACHE INTERNAL "Have symbol setenv") + set(LIBC_HAS_SIGNAL_H "1" CACHE INTERNAL "Have include signal.h") + set(LIBC_HAS_SIN "1" CACHE INTERNAL "Have symbol sin") + set(LIBC_HAS_SINF "1" CACHE INTERNAL "Have symbol sinf") + set(LIBC_HAS_SQR "" CACHE INTERNAL "Have symbol sqr") + set(LIBC_HAS_SQRT "1" CACHE INTERNAL "Have symbol sqrt") + set(LIBC_HAS_SQRTF "1" CACHE INTERNAL "Have symbol sqrtf") + set(LIBC_HAS_SSCANF "1" CACHE INTERNAL "Have symbol sscanf") + set(LIBC_HAS_STDARG_H "1" CACHE INTERNAL "Have include stdarg.h") + set(LIBC_HAS_STDBOOL_H "1" CACHE INTERNAL "Have include stdbool.h") + set(LIBC_HAS_STDDEF_H "1" CACHE INTERNAL "Have include stddef.h") + set(LIBC_HAS_STDINT_H "1" CACHE INTERNAL "Have include stdint.h") + set(LIBC_HAS_STDIO_H "1" CACHE INTERNAL "Have include stdio.h") + set(LIBC_HAS_STDLIB_H "1" CACHE INTERNAL "Have include stdlib.h") + set(LIBC_HAS_STRCHR "1" CACHE INTERNAL "Have symbol strchr") + set(LIBC_HAS_STRCMP "1" CACHE INTERNAL "Have symbol strcmp") + set(LIBC_HAS_STRINGS_H "" CACHE INTERNAL "Have include strings.h") + set(LIBC_HAS_STRING_H "1" CACHE INTERNAL "Have include string.h") + set(LIBC_HAS_STRLCAT "" CACHE INTERNAL "Have symbol strlcat") + set(LIBC_HAS_STRLCPY "" CACHE INTERNAL "Have symbol strlcpy") + set(LIBC_HAS_STRLEN "1" CACHE INTERNAL "Have symbol strlen") + set(LIBC_HAS_STRNCMP "1" CACHE INTERNAL "Have symbol strncmp") + set(LIBC_HAS_STRNLEN "1" CACHE INTERNAL "Have symbol strnlen") + set(LIBC_HAS_STRNSTR "" CACHE INTERNAL "Have symbol strnstr") + set(LIBC_HAS_STRPBRK "1" CACHE INTERNAL "Have symbol strpbrk") + set(LIBC_HAS_STRRCHR "1" CACHE INTERNAL "Have symbol strrchr") + set(LIBC_HAS_STRSTR "1" CACHE INTERNAL "Have symbol strstr") + set(LIBC_HAS_STRTOD "1" CACHE INTERNAL "Have symbol strtod") + set(LIBC_HAS_STRTOK_R "" CACHE INTERNAL "Have symbol strtok_r") + set(LIBC_HAS_STRTOL "1" CACHE INTERNAL "Have symbol strtol") + set(LIBC_HAS_STRTOLL "1" CACHE INTERNAL "Have symbol strtoll") + set(LIBC_HAS_STRTOUL "1" CACHE INTERNAL "Have symbol strtoul") + set(LIBC_HAS_STRTOULL "1" CACHE INTERNAL "Have symbol strtoull") + set(LIBC_HAS_SYS_TYPES_H "1" CACHE INTERNAL "Have include sys/types.h") + set(LIBC_HAS_TAN "1" CACHE INTERNAL "Have symbol tan") + set(LIBC_HAS_TANF "1" CACHE INTERNAL "Have symbol tanf") + set(LIBC_HAS_TIME_H "1" CACHE INTERNAL "Have include time.h") + set(LIBC_HAS_TRUNC "1" CACHE INTERNAL "Have symbol trunc") + set(LIBC_HAS_TRUNCF "1" CACHE INTERNAL "Have symbol truncf") + set(LIBC_HAS_UNSETENV "" CACHE INTERNAL "Have symbol unsetenv") + set(LIBC_HAS_VSNPRINTF "1" CACHE INTERNAL "Have symbol vsnprintf") + set(LIBC_HAS_VSSCANF "1" CACHE INTERNAL "Have symbol vsscanf") + set(LIBC_HAS_WCHAR_H "1" CACHE INTERNAL "Have include wchar.h") + set(LIBC_HAS_WCSCMP "1" CACHE INTERNAL "Have symbol wcscmp") + set(LIBC_HAS_WCSDUP "1" CACHE INTERNAL "Have symbol wcsdup") + set(LIBC_HAS_WCSLCAT "" CACHE INTERNAL "Have symbol wcslcat") + set(LIBC_HAS_WCSLCPY "" CACHE INTERNAL "Have symbol wcslcpy") + set(LIBC_HAS_WCSLEN "1" CACHE INTERNAL "Have symbol wcslen") + set(LIBC_HAS_WCSNCMP "1" CACHE INTERNAL "Have symbol wcsncmp") + set(LIBC_HAS_WCSNLEN "1" CACHE INTERNAL "Have symbol wcsnlen") + set(LIBC_HAS_WCSSTR "1" CACHE INTERNAL "Have symbol wcsstr") + set(LIBC_HAS_WCSTOL "1" CACHE INTERNAL "Have symbol wcstol") + set(LIBC_HAS__EXIT "1" CACHE INTERNAL "Have symbol _Exit") + set(LIBC_HAS__I64TOA "1" CACHE INTERNAL "Have symbol _i64toa") + set(LIBC_HAS__LTOA "1" CACHE INTERNAL "Have symbol _ltoa") + set(LIBC_HAS__STRREV "1" CACHE INTERNAL "Have symbol _strrev") + set(LIBC_HAS__UI64TOA "1" CACHE INTERNAL "Have symbol _ui64toa") + set(LIBC_HAS__UITOA "" CACHE INTERNAL "Have symbol _uitoa") + set(LIBC_HAS__ULTOA "1" CACHE INTERNAL "Have symbol _ultoa") + set(LIBC_HAS__WCSDUP "1" CACHE INTERNAL "Have symbol _wcsdup") + set(LIBC_IS_GLIBC "" CACHE INTERNAL "Have symbol __GLIBC__") + set(_ALLOCA_IN_MALLOC_H "" CACHE INTERNAL "Have symbol _alloca") - if(CHECK_CPU_ARCHITECTURE_X86) - set(COMPILER_SUPPORTS_AVX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX") - set(COMPILER_SUPPORTS_AVX2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX2") - set(COMPILER_SUPPORTS_MMX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_MMX") - set(COMPILER_SUPPORTS_SSE "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE") - set(COMPILER_SUPPORTS_SSE2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE2") - set(COMPILER_SUPPORTS_SSE3 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE3") - set(COMPILER_SUPPORTS_SSE4_1 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_1") - set(COMPILER_SUPPORTS_SSE4_2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_2") - endif() + if(CHECK_CPU_ARCHITECTURE_X86) + set(COMPILER_SUPPORTS_AVX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX") + set(COMPILER_SUPPORTS_AVX2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX2") + set(COMPILER_SUPPORTS_MMX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_MMX") + set(COMPILER_SUPPORTS_SSE "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE") + set(COMPILER_SUPPORTS_SSE2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE2") + set(COMPILER_SUPPORTS_SSE3 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE3") + set(COMPILER_SUPPORTS_SSE4_1 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_1") + set(COMPILER_SUPPORTS_SSE4_2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_2") + endif() - if(CHECK_CPU_ARCHITECTURE_X64) - set(COMPILER_SUPPORTS_AVX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX") - set(COMPILER_SUPPORTS_AVX2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX2") - set(COMPILER_SUPPORTS_MMX "" CACHE INTERNAL "Test COMPILER_SUPPORTS_MMX") - set(COMPILER_SUPPORTS_SSE "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE") - set(COMPILER_SUPPORTS_SSE2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE2") - set(COMPILER_SUPPORTS_SSE3 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE3") - set(COMPILER_SUPPORTS_SSE4_1 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_1") - set(COMPILER_SUPPORTS_SSE4_2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_2") - endif() + if(CHECK_CPU_ARCHITECTURE_X64) + set(COMPILER_SUPPORTS_AVX "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX") + set(COMPILER_SUPPORTS_AVX2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_AVX2") + set(COMPILER_SUPPORTS_MMX "" CACHE INTERNAL "Test COMPILER_SUPPORTS_MMX") + set(COMPILER_SUPPORTS_SSE "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE") + set(COMPILER_SUPPORTS_SSE2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE2") + set(COMPILER_SUPPORTS_SSE3 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE3") + set(COMPILER_SUPPORTS_SSE4_1 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_1") + set(COMPILER_SUPPORTS_SSE4_2 "1" CACHE INTERNAL "Test COMPILER_SUPPORTS_SSE4_2") + endif() - if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "19.1") - set(HAVE_ROAPI_H "1" CACHE INTERNAL "Have include roapi.h") - set(HAVE_WINDOWS_GAMING_INPUT_H "1" CACHE INTERNAL "Test HAVE_WINDOWS_GAMING_INPUT_H") - else() - set(HAVE_ROAPI_H "" CACHE INTERNAL "Have include roapi.h") - set(HAVE_WINDOWS_GAMING_INPUT_H "" CACHE INTERNAL "Test HAVE_WINDOWS_GAMING_INPUT_H") + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "19.1") + set(HAVE_ROAPI_H "1" CACHE INTERNAL "Have include roapi.h") + set(HAVE_WINDOWS_GAMING_INPUT_H "1" CACHE INTERNAL "Test HAVE_WINDOWS_GAMING_INPUT_H") + else() + set(HAVE_ROAPI_H "" CACHE INTERNAL "Have include roapi.h") + set(HAVE_WINDOWS_GAMING_INPUT_H "" CACHE INTERNAL "Test HAVE_WINDOWS_GAMING_INPUT_H") + endif() endif() endfunction() endif() diff --git a/cmake/macros.cmake b/cmake/macros.cmake index f5adebc3e8..cd52548727 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -334,6 +334,29 @@ if(APPLE) endif() endif() +function(PrintEnabledBackends _SUBSYS _REGEXP) + get_cmake_property(_ALLVARS VARIABLES) + foreach(_VAR IN LISTS _ALLVARS) + if(_VAR AND _VAR MATCHES "${_REGEXP}") + string(TOLOWER "${CMAKE_MATCH_1}" _LOWERED) + if(NOT _LOWERED MATCHES "available|default|dynamic") # a little hack + if(${_VAR}_DYNAMIC) + list(APPEND _ENABLED_BACKENDS "${_LOWERED}(dynamic)") + else() + list(APPEND _ENABLED_BACKENDS "${_LOWERED}") + endif() + endif() + endif() + endforeach() + + if(_ENABLED_BACKENDS STREQUAL "") + set(_SPACEDOUT "(none)") + else() + string(REPLACE ";" " " _SPACEDOUT "${_ENABLED_BACKENDS}") + endif() + message(STATUS " ${_SUBSYS}: ${_SPACEDOUT}") +endfunction() + function(SDL_PrintSummary) ##### Info output ##### message(STATUS "") @@ -366,6 +389,18 @@ function(SDL_PrintSummary) message(STATUS " Build libraries as Apple Framework: ${SDL_FRAMEWORK}") endif() message(STATUS "") + + message(STATUS "Enabled backends:") + PrintEnabledBackends("Video drivers" "^SDL_VIDEO_DRIVER_([A-Z0-9]*)$") + if(SDL_VIDEO_DRIVER_X11) + PrintEnabledBackends("X11 libraries" "^SDL_VIDEO_DRIVER_X11_([A-Z0-9]*)$") + endif() + PrintEnabledBackends("Render drivers" "^SDL_VIDEO_RENDER_([A-Z0-9_]*)$") + PrintEnabledBackends("GPU drivers" "^SDL_GPU_([A-Z0-9]*)$") + PrintEnabledBackends("Audio drivers" "^SDL_AUDIO_DRIVER_([A-Z0-9]*)$") + PrintEnabledBackends("Joystick drivers" "^SDL_JOYSTICK_([A-Z0-9]*)$") + message(STATUS "") + if(UNIX) message(STATUS "If something was not detected, although the libraries") message(STATUS "were installed, then make sure you have set the") diff --git a/cmake/sdlcpu.cmake b/cmake/sdlcpu.cmake index 5c4b575ec0..a27e7329c4 100644 --- a/cmake/sdlcpu.cmake +++ b/cmake/sdlcpu.cmake @@ -1,6 +1,6 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS) - set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 X86 X64) + set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 RISCV32 RISCV64 X86 X64) if(APPLE AND CMAKE_OSX_ARCHITECTURES) foreach(known_arch IN LISTS known_archs) @@ -39,6 +39,8 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS) set(arch_check_LOONGARCH64 "defined(__loongarch64)") set(arch_check_POWERPC32 "(defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)") set(arch_check_POWERPC64 "defined(__PPC64__) || defined(__powerpc64__)") + set(arch_check_RISCV32 "defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32") + set(arch_check_RISCV64 "defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64") set(arch_check_X86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)") set(arch_check_X64 "(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)) && !defined(_M_ARM64EC)") diff --git a/docs/README-android.md b/docs/README-android.md index b2568e94ef..66e5ea6eda 100644 --- a/docs/README-android.md +++ b/docs/README-android.md @@ -598,7 +598,7 @@ The only caveat is that the APK's support a single architecture. When configuring the CMake project, you need to use the Android NDK CMake toolchain, and pass the Android home path through `SDL_ANDROID_HOME`. ``` -cmake .. -DCMAKE_TOOLCHAIN_FILE= -DANDROID_ABI= -DSDL_ANDROID_HOME= -DANDROID_PLATFORM=23 -DSDL_TESTS=ON +cmake .. -DCMAKE_TOOLCHAIN_FILE= -DANDROID_ABI= -DSDL_ANDROID_HOME= -DANDROID_PLATFORM=21 -DSDL_TESTS=ON ``` Remarks: diff --git a/docs/README-documentation-rules.md b/docs/README-documentation-rules.md index 02809e2bba..2a4d96f1ad 100644 --- a/docs/README-documentation-rules.md +++ b/docs/README-documentation-rules.md @@ -274,6 +274,23 @@ comment. So don't mention the type a second time in the documentation if possible. It looks cluttered and repetitive to do so. +## Keep `\param` and `\returns` sections short. + +These strings end up in a table that we don't want to be bulky. +Try to keep these to one sentence/phrase where possible. If you need more +detail--even extremely common details, like "you need to free the returned +pointer"--put that information in the general Remarks section, where you +can be as verbose as you like. + +(One exception for SDL: the return value almost always notes that on error, +you should call SDL_GetError() to get more information. The documentation +is so saturated with this that it's just the standard now.) + +Convention at the moment is that pointer params that are permitted to +be NULL, which is somewhat uncommon, end with terse "May be NULL." sentence +at the end, and pointers that must be non-NULL (most of them) say nothing. +This is fine. + ## Code examples go in the wiki. We don't want the headers cluttered up with code examples. These live on the diff --git a/docs/README-emscripten.md b/docs/README-emscripten.md index aa6a1e3f30..facda486f2 100644 --- a/docs/README-emscripten.md +++ b/docs/README-emscripten.md @@ -101,7 +101,7 @@ don't want any shutdown code that might be sitting below this code to actually run if main() were to continue on, since we're just getting started. -Another option is to use SDL' main callbacks, which handle this for you +Another option is to use SDL's main callbacks, which handle this for you without platform-specific code in your app. Please refer to [the wiki](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3) or `docs/README-main-functions.md` in the SDL source code. diff --git a/docs/README-linux.md b/docs/README-linux.md index 2e08548df1..bec0e6a4b8 100644 --- a/docs/README-linux.md +++ b/docs/README-linux.md @@ -25,14 +25,14 @@ Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev li Fedora 35, all available features enabled: - sudo yum install gcc git-core make cmake \ + sudo dnf install gcc git-core make cmake \ alsa-lib-devel pulseaudio-libs-devel pipewire-devel \ libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \ libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \ systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \ mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \ - libdrm-devel mesa-libgbm-devel libusb-devel libdecor-devel \ - pipewire-jack-audio-connection-kit-devel \ + libdrm-devel mesa-libgbm-devel libusb1-devel libdecor-devel \ + pipewire-jack-audio-connection-kit-devel Fedora 39+ can also add `liburing-devel` to that command line. diff --git a/docs/README-ps2.md b/docs/README-ps2.md index d35856531f..dbda4459db 100644 --- a/docs/README-ps2.md +++ b/docs/README-ps2.md @@ -11,11 +11,17 @@ Credit to ## Building To build SDL library for the PS2, make sure you have the latest PS2Dev status and run: ```bash -cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$PS2DEV/ps2sdk/ps2dev.cmake +cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$PS2DEV/share/ps2dev.cmake cmake --build build cmake --install build ``` +## Hints +- `SDL_HINT_PS2_GS_WIDTH`: Width of the framebuffer. Defaults to 640. +- `SDL_HINT_PS2_GS_HEIGHT`: Height of the framebuffer. Defaults to 448. +- `SDL_HINT_PS2_GS_PROGRESSIVE`: Whether to use progressive, instead of interlaced. Defaults to 0. +- `SDL_HINT_PS2_GS_MODE`: Regional standard of the signal. "NTSC" (60hz), "PAL" (50hz) or "" (the console's region, default). + ## Notes If you trying to debug a SDL app through [ps2client](https://github.com/ps2dev/ps2client) you need to avoid the IOP reset, otherwise you will lose the connection with your computer. So to avoid the reset of the IOP CPU, you need to call to the macro `SDL_PS2_SKIP_IOP_RESET();`. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fa4ad4dc29..6e1f1c5d0e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -149,9 +149,13 @@ add_sdl_example_executable(audio-multiple-streams SOURCES audio/04-multiple-stre add_sdl_example_executable(audio-planar-data SOURCES audio/05-planar-data/planar-data.c) add_sdl_example_executable(input-joystick-polling SOURCES input/01-joystick-polling/joystick-polling.c) add_sdl_example_executable(input-joystick-events SOURCES input/02-joystick-events/joystick-events.c) +add_sdl_example_executable(input-gamepad-polling SOURCES input/03-gamepad-polling/gamepad-polling.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/gamepad_front.bmp) +add_sdl_example_executable(input-gamepad-events SOURCES input/04-gamepad-events/gamepad-events.c) add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c) add_sdl_example_executable(pen-drawing-lines SOURCES pen/01-drawing-lines/drawing-lines.c) add_sdl_example_executable(asyncio-load-bitmaps SOURCES asyncio/01-load-bitmaps/load-bitmaps.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp ${CMAKE_CURRENT_SOURCE_DIR}/../test/gamepad_front.bmp ${CMAKE_CURRENT_SOURCE_DIR}/../test/speaker.bmp ${CMAKE_CURRENT_SOURCE_DIR}/../test/icon2x.bmp) +add_sdl_example_executable(misc-power SOURCES misc/01-power/power.c) +add_sdl_example_executable(misc-clipboard SOURCES misc/02-clipboard/clipboard.c) add_sdl_example_executable(demo-snake SOURCES demo/01-snake/snake.c) add_sdl_example_executable(demo-woodeneye-008 SOURCES demo/02-woodeneye-008/woodeneye-008.c) add_sdl_example_executable(demo-infinite-monkeys SOURCES demo/03-infinite-monkeys/infinite-monkeys.c) diff --git a/examples/README.md b/examples/README.md index 872e0870ad..ba3ad2b978 100644 --- a/examples/README.md +++ b/examples/README.md @@ -65,3 +65,30 @@ If writing new examples, this is the skeleton code we start from, to keep everything consistent. You can ignore it. +## How are the thumbnails/onmouseover media created? + +(Since I have to figure this out every time.) + +This is how Ryan is doing it currently. + +- `rm -f frame*.bmp` +- Temporarily add `#include "../../save-rendering-to-bitmaps.h"` after any SDL + includes in the example program. +- Launch the example app, interact with it, let it run for a few seconds, quit. +- This will dump a "frameX.bmp" file for each frame rendered. +- Make a video in webp format from the bitmaps (this assumes the bitmaps were + stored at 60fps, you might have to tweak). + + ```bash + ffmpeg -framerate 60 -pattern_type glob -i 'frame*.bmp' -loop 0 -quality 40 -r 10 -frames:v 40 onmouseover.webp + ``` + + You might need to start in the middle of the video, or mess with quality or + number of frames to generate, ymmv. +- Pick a frame for the thumbnail, make it a .png, and run that png through + pngquant for massive file size reduction without any obvious loss in quality: + + ```bash + convert frame00000.bmp cvt.png ; pngquant cvt.png --output thumbnail.png ; rm -f cvt.png + ``` + diff --git a/examples/categories.txt b/examples/categories.txt index 8a9b5ecb37..bbe30f23ef 100644 --- a/examples/categories.txt +++ b/examples/categories.txt @@ -10,4 +10,5 @@ audio camera asyncio pen +misc demo diff --git a/examples/input/01-joystick-polling/joystick-polling.c b/examples/input/01-joystick-polling/joystick-polling.c index 647cdef94c..2eb8466e36 100644 --- a/examples/input/01-joystick-polling/joystick-polling.c +++ b/examples/input/01-joystick-polling/joystick-polling.c @@ -13,8 +13,8 @@ and knows how to map arbitrary buttons and such to look like an Xbox/PlayStation/etc gamepad. This is easier, and better, for many games, but isn't necessarily a good fit for complex apps and hardware. A flight - simulator, a realistic racing game, etc, might want this interface instead - of gamepads. */ + simulator, a realistic racing game, etc, might want the joystick interface + instead of gamepads. */ /* SDL can handle multiple joysticks, but for simplicity, this program only deals with the first stick it sees. */ diff --git a/examples/input/02-joystick-events/joystick-events.c b/examples/input/02-joystick-events/joystick-events.c index cc01d84aac..2c0b095255 100644 --- a/examples/input/02-joystick-events/joystick-events.c +++ b/examples/input/02-joystick-events/joystick-events.c @@ -13,8 +13,8 @@ and knows how to map arbitrary buttons and such to look like an Xbox/PlayStation/etc gamepad. This is easier, and better, for many games, but isn't necessarily a good fit for complex apps and hardware. A flight - simulator, a realistic racing game, etc, might want this interface instead - of gamepads. */ + simulator, a realistic racing game, etc, might want the joystick interface + instead of gamepads. */ #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ #include diff --git a/examples/input/02-joystick-events/onmouseover.webp b/examples/input/02-joystick-events/onmouseover.webp index 05a9b42671..08f40356f4 100644 Binary files a/examples/input/02-joystick-events/onmouseover.webp and b/examples/input/02-joystick-events/onmouseover.webp differ diff --git a/examples/input/03-gamepad-polling/README.txt b/examples/input/03-gamepad-polling/README.txt new file mode 100644 index 0000000000..d7e68b948b --- /dev/null +++ b/examples/input/03-gamepad-polling/README.txt @@ -0,0 +1,11 @@ +This example code looks for the current gamepad state once per frame, +and draws a visual representation of it. See 01-joystick-polling for the +equivalent example code for the lower-level joystick API. + +Please note that on the web, gamepads don't show up until you interact with +them, so press a button to "connect" the controller. + +Also note that on the web, gamepad triggers are treated as buttons (either +pressed or not) instead of axes (pressed 0 to 100 percent). This is a web +issue, not an SDL limitation. + diff --git a/examples/input/03-gamepad-polling/gamepad-polling.c b/examples/input/03-gamepad-polling/gamepad-polling.c new file mode 100644 index 0000000000..bf2685d692 --- /dev/null +++ b/examples/input/03-gamepad-polling/gamepad-polling.c @@ -0,0 +1,221 @@ +/* + * This example code looks for the current gamepad state once per frame, + * and draws a visual representation of it. See 01-joystick-polling for the + * equivalent example code for the lower-level joystick API. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +/* Joysticks are low-level interfaces: there's something with a bunch of + buttons, axes and hats, in no understood order or position. This is + a flexible interface, but you'll need to build some sort of configuration + UI to let people tell you what button, etc, does what. On top of this + interface, SDL offers the "gamepad" API, which works with lots of devices, + and knows how to map arbitrary buttons and such to look like an + Xbox/PlayStation/etc gamepad. This is easier, and better, for many games, + but isn't necessarily a good fit for complex apps and hardware. A flight + simulator, a realistic racing game, etc, might want the joystick interface + instead of gamepads. */ + +/* SDL can handle multiple gamepads, but for simplicity, this program only + deals with the first gamepad it sees. */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; +static SDL_Gamepad *gamepad = NULL; + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + char *bmp_path = NULL; + SDL_Surface *surface = NULL; + + SDL_SetAppMetadata("Example Input Gamepad Polling", "1.0", "com.example.input-gamepad-polling"); + + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/input/gamepad-polling", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &window, &renderer)) { + SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_STRETCH)) { + return SDL_APP_FAILURE; + } + + /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D + engines refer to these as "sprites." We'll do a static texture (upload once, draw many + times) with data from a bitmap file. */ + + /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access. + Load a .bmp into a surface, move it to a texture from there. */ + SDL_asprintf(&bmp_path, "%sgamepad_front.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */ + surface = SDL_LoadBMP(bmp_path); + if (!surface) { + SDL_Log("Couldn't load bitmap: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_free(bmp_path); /* done with this, the file is loaded. */ + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + SDL_Log("Couldn't create static texture: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */ + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } else if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + /* this event is sent for each hotplugged gamepad, but also each already-connected gamepad during SDL_Init(). */ + if (gamepad == NULL) { /* we don't have a stick yet and one was added, open it! */ + gamepad = SDL_OpenGamepad(event->gdevice.which); + if (!gamepad) { + SDL_Log("Failed to open gamepad ID %u: %s", (unsigned int) event->gdevice.which, SDL_GetError()); + } + } + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { + if (gamepad && (SDL_GetGamepadID(gamepad) == event->gdevice.which)) { + SDL_CloseGamepad(gamepad); /* our controller was unplugged. */ + gamepad = NULL; + } + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const char *text = "Plug in a gamepad, please."; + static Uint64 leftthumblast = 0xFFFFFFFF; + static Uint64 rightthumblast = 0xFFFFFFFF; + const Uint64 now = SDL_GetTicks(); + Sint16 axis_x, axis_y; + float x, y; + int i; + + if (gamepad) { /* we have a stick opened? */ + text = SDL_GetGamepadName(gamepad); + } + + SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); /* white */ + SDL_RenderClear(renderer); + + /* note that you can get input as events, instead of polling, which is + better since it won't miss button presses if the system is lagging, + but often times checking the current state per-frame is good enough, + and maybe better if you'd rather _drop_ inputs due to lag. */ + + if (gamepad) { /* we have a stick opened? */ + /* where to draw the buttons */ + const SDL_FRect buttons[] = { + { 497, 266, 38, 38 }, /* SDL_GAMEPAD_BUTTON_SOUTH */ + { 550, 217, 38, 38 }, /* SDL_GAMEPAD_BUTTON_EAST */ + { 445, 221, 38, 38 }, /* SDL_GAMEPAD_BUTTON_WEST */ + { 499, 173, 38, 38 }, /* SDL_GAMEPAD_BUTTON_NORTH */ + { 235, 228, 32, 29 }, /* SDL_GAMEPAD_BUTTON_BACK */ + { 287, 195, 69, 69 }, /* SDL_GAMEPAD_BUTTON_GUIDE */ + { 377, 228, 32, 29 }, /* SDL_GAMEPAD_BUTTON_START */ + { 91, 234, 63, 63 }, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ + { 381, 354, 63, 63 }, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ + { 74, 73, 102, 29 }, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */ + { 468, 73, 102, 29 }, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ + { 207, 316, 32, 32 }, /* SDL_GAMEPAD_BUTTON_DPAD_UP */ + { 207, 384, 32, 32 }, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */ + { 173, 351, 32, 32 }, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */ + { 242, 351, 32, 32 }, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */ + { 310, 286, 23, 27 }, /* SDL_GAMEPAD_BUTTON_MISC1 */ + /* there are other buttons: paddles on the back of the gamepad, touchpads, etc, but this is good enough for now. */ + }; + + SDL_RenderTexture(renderer, texture, NULL, NULL); /* draw the gamepad picture to the whole window. */ + + /* draw green boxes over buttons that are currently pressed. */ + SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF); /* green */ + for (i = 0; i < SDL_arraysize(buttons); i++) { + if (SDL_GetGamepadButton(gamepad, (SDL_GamepadButton) i)) { + SDL_RenderFillRect(renderer, &buttons[i]); + } + } + + SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0x00, 0xFF); /* yellow */ + + /* left thumb axis. */ + axis_x = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX); + axis_y = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY); + if ((SDL_abs(axis_x) > 1000) || (SDL_abs(axis_y) > 1000)) { /* zero means centered, but it might be a little off zero... */ + leftthumblast = now; /* keep drawing, we're still moving. */ + } + if ((now - leftthumblast) < 500) { /* draw if there was movement in the last half-second. */ + const SDL_FRect box = { 107 + ((axis_x / 32767.0f) * 30.0f), 252 + ((axis_y / 32767.0f) * 30.0f), 30, 30 }; + SDL_RenderFillRect(renderer, &box); + } + + /* right thumb axis. */ + axis_x = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX); + axis_y = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY); + if ((SDL_abs(axis_x) > 1000) || (SDL_abs(axis_y) > 1000)) { /* zero means centered, but it might be a little off zero... */ + rightthumblast = now; /* keep drawing, we're still moving. */ + } + if ((now - rightthumblast) < 500) { /* draw if there was movement in the last half-second. */ + const SDL_FRect box = { 397 + ((axis_x / 32767.0f) * 30.0f), 370 + ((axis_y / 32767.0f) * 30.0f), 30, 30 }; + SDL_RenderFillRect(renderer, &box); + } + + /* left trigger. */ + axis_y = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER); + if (axis_y > 1000) { /* zero means unpressed, but it might be a little off zero... */ + const float height = ((axis_y / 32767.0f) * 65.0f); + const SDL_FRect box = { 127, 1 + (65.0f - height), 37, height }; + SDL_RenderFillRect(renderer, &box); + } + + /* right trigger. */ + axis_y = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER); + if (axis_y > 1000) { /* zero means unpressed, but it might be a little off zero... */ + const float height = ((axis_y / 32767.0f) * 65.0f); + const SDL_FRect box = { 481, 1 + (65.0f - height), 37, height }; + SDL_RenderFillRect(renderer, &box); + } + } + + x = (((float) WINDOW_WIDTH) - (SDL_strlen(text) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2.0f; + if (gamepad) { + y = (float) (WINDOW_HEIGHT - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2)); + } else { + y = (((float) WINDOW_HEIGHT) - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) / 2.0f; + } + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0xFF, 0xFF); /* blue */ + SDL_RenderDebugText(renderer, x, y, text); + SDL_RenderPresent(renderer); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + SDL_DestroyTexture(texture); + SDL_CloseGamepad(gamepad); + /* SDL will clean up the window/renderer for us. */ +} diff --git a/examples/input/03-gamepad-polling/onmouseover.webp b/examples/input/03-gamepad-polling/onmouseover.webp new file mode 100644 index 0000000000..91c7bb0dca Binary files /dev/null and b/examples/input/03-gamepad-polling/onmouseover.webp differ diff --git a/examples/input/03-gamepad-polling/thumbnail.png b/examples/input/03-gamepad-polling/thumbnail.png new file mode 100644 index 0000000000..c5bc6e6431 Binary files /dev/null and b/examples/input/03-gamepad-polling/thumbnail.png differ diff --git a/examples/input/04-gamepad-events/README.txt b/examples/input/04-gamepad-events/README.txt new file mode 100644 index 0000000000..42f62d7857 --- /dev/null +++ b/examples/input/04-gamepad-events/README.txt @@ -0,0 +1,2 @@ +This example code looks for gamepad input in the event handler, and +reports any changes as a flood of info. diff --git a/examples/input/04-gamepad-events/gamepad-events.c b/examples/input/04-gamepad-events/gamepad-events.c new file mode 100644 index 0000000000..b01bfd9295 --- /dev/null +++ b/examples/input/04-gamepad-events/gamepad-events.c @@ -0,0 +1,212 @@ +/* + * This example code looks for gamepad input in the event handler, and + * reports any changes as a flood of info. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +/* Joysticks are low-level interfaces: there's something with a bunch of + buttons, axes and hats, in no understood order or position. This is + a flexible interface, but you'll need to build some sort of configuration + UI to let people tell you what button, etc, does what. On top of this + interface, SDL offers the "gamepad" API, which works with lots of devices, + and knows how to map arbitrary buttons and such to look like an + Xbox/PlayStation/etc gamepad. This is easier, and better, for many games, + but isn't necessarily a good fit for complex apps and hardware. A flight + simulator, a realistic racing game, etc, might want the joystick interface + instead of gamepads. */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Color colors[64]; + +#define MOTION_EVENT_COOLDOWN 40 + +typedef struct EventMessage +{ + char *str; + SDL_Color color; + Uint64 start_ticks; + struct EventMessage *next; +} EventMessage; + +static EventMessage messages; +static EventMessage *messages_tail = &messages; + +static const char *battery_state_string(SDL_PowerState state) +{ + switch (state) { + case SDL_POWERSTATE_ERROR: return "ERROR"; + case SDL_POWERSTATE_UNKNOWN: return "UNKNOWN"; + case SDL_POWERSTATE_ON_BATTERY: return "ON BATTERY"; + case SDL_POWERSTATE_NO_BATTERY: return "NO BATTERY"; + case SDL_POWERSTATE_CHARGING: return "CHARGING"; + case SDL_POWERSTATE_CHARGED: return "CHARGED"; + default: break; + } + return "UNKNOWN"; +} + +static void add_message(SDL_JoystickID jid, const char *fmt, ...) +{ + const SDL_Color *color = &colors[((size_t) jid) % SDL_arraysize(colors)]; + EventMessage *msg = NULL; + char *str = NULL; + va_list ap; + + msg = (EventMessage *) SDL_calloc(1, sizeof (*msg)); + if (!msg) { + return; // oh well. + } + + va_start(ap, fmt); + SDL_vasprintf(&str, fmt, ap); + va_end(ap); + if (!str) { + SDL_free(msg); + return; // oh well. + } + + msg->str = str; + SDL_copyp(&msg->color, color); + msg->start_ticks = SDL_GetTicks(); + msg->next = NULL; + + messages_tail->next = msg; + messages_tail = msg; +} + + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + int i; + + SDL_SetAppMetadata("Example Input Gamepad Events", "1.0", "com.example.input-gamepad-events"); + + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/input/gamepad-events", 640, 480, 0, &window, &renderer)) { + SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + colors[0].r = colors[0].g = colors[0].b = colors[0].a = 255; + for (i = 1; i < SDL_arraysize(colors); i++) { + colors[i].r = SDL_rand(255); + colors[i].g = SDL_rand(255); + colors[i].b = SDL_rand(255); + colors[i].a = 255; + } + + add_message(0, "Please plug in a gamepad."); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } else if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + /* this event is sent for each hotplugged stick, but also each already-connected gamepad during SDL_Init(). */ + const SDL_JoystickID which = event->gdevice.which; + SDL_Gamepad *gamepad = SDL_OpenGamepad(which); + if (!gamepad) { + add_message(which, "Gamepad #%u add, but not opened: %s", (unsigned int) which, SDL_GetError()); + } else { + char *mapping = SDL_GetGamepadMapping(gamepad); + add_message(which, "Gamepad #%u ('%s') added", (unsigned int) which, SDL_GetGamepadName(gamepad)); + if (mapping) { + add_message(which, "Gamepad #%u mapping: %s", (unsigned int) which, mapping); + SDL_free(mapping); + } + } + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { + const SDL_JoystickID which = event->gdevice.which; + SDL_Gamepad *gamepad = SDL_GetGamepadFromID(which); + if (gamepad) { + SDL_CloseGamepad(gamepad); /* the gamepad was unplugged. */ + } + add_message(which, "Gamepad #%u removed", (unsigned int) which); + } else if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION) { + static Uint64 axis_motion_cooldown_time = 0; /* these are spammy, only show every X milliseconds. */ + const Uint64 now = SDL_GetTicks(); + if (now >= axis_motion_cooldown_time) { + const SDL_JoystickID which = event->gaxis.which; + axis_motion_cooldown_time = now + MOTION_EVENT_COOLDOWN; + add_message(which, "Gamepad #%u axis %s -> %d", (unsigned int) which, SDL_GetGamepadStringForAxis((SDL_GamepadAxis) event->gaxis.axis), (int) event->gaxis.value); + } + } else if ((event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) || (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN)) { + const SDL_JoystickID which = event->gbutton.which; + add_message(which, "Gamepad #%u button %s -> %s", (unsigned int) which, SDL_GetGamepadStringForButton((SDL_GamepadButton) event->gbutton.button), event->gbutton.down ? "PRESSED" : "RELEASED"); + } else if (event->type == SDL_EVENT_JOYSTICK_BATTERY_UPDATED) { + const SDL_JoystickID which = event->jbattery.which; + if (SDL_IsGamepad(which)) { /* this is only reported for joysticks, so make sure this joystick is _actually_ a gamepad. */ + add_message(which, "Gamepad #%u battery -> %s - %d%%", (unsigned int) which, battery_state_string(event->jbattery.state), event->jbattery.percent); + } + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const Uint64 now = SDL_GetTicks(); + const float msg_lifetime = 3500.0f; /* milliseconds a message lives for. */ + EventMessage *msg = messages.next; + float prev_y = 0.0f; + int winw = 640, winh = 480; + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_GetWindowSize(window, &winw, &winh); + + while (msg) { + float x, y; + const float life_percent = ((float) (now - msg->start_ticks)) / msg_lifetime; + if (life_percent >= 1.0f) { /* msg is done. */ + messages.next = msg->next; + if (messages_tail == msg) { + messages_tail = &messages; + } + SDL_free(msg->str); + SDL_free(msg); + msg = messages.next; + continue; + } + x = (((float) winw) - (SDL_strlen(msg->str) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2.0f; + y = ((float) winh) * life_percent; + if ((prev_y != 0.0f) && ((prev_y - y) < ((float) SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE))) { + msg->start_ticks = now; + break; // wait for the previous message to tick up a little. + } + + SDL_SetRenderDrawColor(renderer, msg->color.r, msg->color.g, msg->color.b, (Uint8) (((float) msg->color.a) * (1.0f - life_percent))); + SDL_RenderDebugText(renderer, x, y, msg->str); + + prev_y = y; + msg = msg->next; + } + + SDL_RenderPresent(renderer); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + SDL_Quit(); + /* SDL will clean up the window/renderer for us. We let the gamepads leak. */ +} diff --git a/examples/input/04-gamepad-events/onmouseover.webp b/examples/input/04-gamepad-events/onmouseover.webp new file mode 100644 index 0000000000..b427739312 Binary files /dev/null and b/examples/input/04-gamepad-events/onmouseover.webp differ diff --git a/examples/input/04-gamepad-events/thumbnail.png b/examples/input/04-gamepad-events/thumbnail.png new file mode 100644 index 0000000000..1c817a5578 Binary files /dev/null and b/examples/input/04-gamepad-events/thumbnail.png differ diff --git a/examples/misc/01-power/README.txt b/examples/misc/01-power/README.txt new file mode 100644 index 0000000000..800153e1d0 --- /dev/null +++ b/examples/misc/01-power/README.txt @@ -0,0 +1,4 @@ +This example code reports power status (plugged in, battery level, etc). + +Note that only Chrome-based browsers support this API currently. Firefox and +Safari will report this as unknown, but this may change later! diff --git a/examples/misc/01-power/onmouseover.webp b/examples/misc/01-power/onmouseover.webp new file mode 100644 index 0000000000..a99b8d6f81 Binary files /dev/null and b/examples/misc/01-power/onmouseover.webp differ diff --git a/examples/misc/01-power/power.c b/examples/misc/01-power/power.c new file mode 100644 index 0000000000..fe0646dbba --- /dev/null +++ b/examples/misc/01-power/power.c @@ -0,0 +1,154 @@ +/* + * This example code reports power status (plugged in, battery level, etc). + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_SetAppMetadata("Example Misc Power", "1.0", "com.example.misc-power"); + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/misc/power", 640, 480, 0, &window, &renderer)) { + SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const SDL_FRect frame = { 100, 200, 440, 80 }; /* the percentage bar dimensions. */ + + /* Query for battery info */ + int seconds = 0, percent = 0; + const SDL_PowerState state = SDL_GetPowerInfo(&seconds, &percent); + + /* We set up different drawing details for each power state, then + run it all through the same drawing code. */ + int clearr = 0, clearg = 0, clearb = 0; /* clear window to this color. */ + int textr = 255, textg = 255, textb = 255; /* draw messages in this color. */ + int framer = 255, frameg = 255, frameb = 255; /* draw a percentage bar frame in this color. */ + int barr = 0, barg = 0, barb = 0; /* draw a percentage bar in this color. */ + const char *msg = NULL; + const char *msg2 = NULL; + + switch (state) { + case SDL_POWERSTATE_ERROR: + msg2 = "ERROR GETTING POWER STATE"; + msg = SDL_GetError(); + clearr = 255; /* red background */ + break; + + default: /* in case this does something unexpected later, treat it as unknown. */ + case SDL_POWERSTATE_UNKNOWN: + msg = "Power state is unknown."; + clearr = clearb = clearg = 50; /* grey background */ + break; + + case SDL_POWERSTATE_ON_BATTERY: + msg = "Running on battery."; + barr = 255; /* draw in red */ + break; + + case SDL_POWERSTATE_NO_BATTERY: + msg = "Plugged in, no battery available."; + clearg = 50; /* green background */ + break; + + case SDL_POWERSTATE_CHARGING: + msg = "Charging."; + barb = barg = 255; /* draw in cyan */ + break; + + case SDL_POWERSTATE_CHARGED: + msg = "Charged."; + barg = 255; /* draw in green */ + break; + } + + SDL_SetRenderDrawColor(renderer, clearr, clearg, clearb, 255); + SDL_RenderClear(renderer); + + if (percent >= 0) { + float x, y; + SDL_FRect pctrect; + char remainstr[64]; + char msgbuf[128]; + + SDL_copyp(&pctrect, &frame); + pctrect.w *= percent / 100.0f; + + if (seconds < 0) { + SDL_strlcpy(remainstr, "unknown time", sizeof (remainstr)); + } else { + int hours, minutes; + hours = seconds / (60 * 60); + seconds -= hours * (60 * 60); + minutes = seconds / 60; + seconds -= minutes * 60; + SDL_snprintf(remainstr, sizeof (remainstr), "%02d:%02d:%02d", hours, minutes, seconds); + } + + SDL_snprintf(msgbuf, sizeof (msgbuf), "Battery: %3d percent, %s remaining", percent, remainstr); + x = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msgbuf))) / 2.0f); + y = frame.y + frame.h + SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + + SDL_SetRenderDrawColor(renderer, barr, barg, barb, 255); /* draw percent bar. */ + SDL_RenderFillRect(renderer, &pctrect); + SDL_SetRenderDrawColor(renderer, framer, frameg, frameb, 255); /* draw frame on top of bar. */ + SDL_RenderRect(renderer, &frame); + SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255); + SDL_RenderDebugText(renderer, x, y, msgbuf); /* draw text about battery level */ + } + + if (msg) { + const float x = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msg))) / 2.0f); + const float y = frame.y - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2); + SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255); + SDL_RenderDebugText(renderer, x, y, msg); + } + + if (msg2) { + const float x = frame.x + ((frame.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(msg2))) / 2.0f); + const float y = frame.y - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 4); + SDL_SetRenderDrawColor(renderer, textr, textg, textb, 255); + SDL_RenderDebugText(renderer, x, y, msg2); + } + + /* put the new rendering on the screen. */ + SDL_RenderPresent(renderer); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/examples/misc/01-power/thumbnail.png b/examples/misc/01-power/thumbnail.png new file mode 100644 index 0000000000..970bdff6b0 Binary files /dev/null and b/examples/misc/01-power/thumbnail.png differ diff --git a/examples/misc/02-clipboard/README.txt b/examples/misc/02-clipboard/README.txt new file mode 100644 index 0000000000..b2721996f5 --- /dev/null +++ b/examples/misc/02-clipboard/README.txt @@ -0,0 +1,6 @@ +This example code lets the user copy and paste with the system clipboard. + +This only handles text, but SDL supports other data types, too. + +Note that only Chrome-based browsers support this API currently. This uses a +new Javascript API, so hopefully this will be available everywhere soon! diff --git a/examples/misc/02-clipboard/clipboard.c b/examples/misc/02-clipboard/clipboard.c new file mode 100644 index 0000000000..bb4131b7a6 --- /dev/null +++ b/examples/misc/02-clipboard/clipboard.c @@ -0,0 +1,233 @@ +/* + * This example code lets the user copy and paste with the system clipboard. + * + * This only handles text, but SDL supports other data types, too. + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include +#include + +/* We will use this renderer to draw into this window every frame. */ +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +static const char *copybuttonstr = "Click here to copy!"; +static const char *pastebuttonstr = "Click here to paste!"; +static SDL_FRect currenttimerect; +static SDL_FRect copybuttonrect; +static SDL_FRect pastetextrect; +static SDL_FRect pastebuttonrect; +static bool copy_pressed = false; +static bool paste_pressed = false; +static char current_time[64]; +static char *pasted_str = NULL; + +static void CalculateCurrentTimeString(void) +{ + SDL_Time ticks = 0; + SDL_DateTime dt; + if (!SDL_GetCurrentTime(&ticks) || !SDL_TimeToDateTime(ticks, &dt, true)) { + SDL_snprintf(current_time, sizeof (current_time), "(Don't know the current time, sorry.)"); + } else { + static const char *month[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; + static const char *day[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; + SDL_snprintf(current_time, sizeof (current_time), "%s, %s %d, %d %02d:%02d:%02d", day[dt.day_of_week], month[dt.month-1], dt.day, dt.year, dt.hour, dt.minute, dt.second); + } +} + +/* This function runs once at startup. */ +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + SDL_SetAppMetadata("Example Misc Clipboard", "1.0", "com.example.misc-clipboard"); + + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_CreateWindowAndRenderer("examples/misc/clipboard", 640, 480, 0, &window, &renderer)) { + SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + CalculateCurrentTimeString(); + + /* set up the locations where we'll draw stuff. */ + currenttimerect.x = 30; + currenttimerect.y = 10; + currenttimerect.w = 390; + currenttimerect.h = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 10; + + copybuttonrect.x = currenttimerect.x + currenttimerect.w + 30; + copybuttonrect.y = currenttimerect.y; + copybuttonrect.w = (float) ((SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(copybuttonstr)) + 10); + copybuttonrect.h = currenttimerect.h; + + pastetextrect.x = 10; + pastetextrect.y = currenttimerect.y + currenttimerect.h + 10; + pastetextrect.w = 620; + pastetextrect.h = ((480 - pastetextrect.y) - copybuttonrect.h) - 20; + + pastebuttonrect.w = (float) ((SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(pastebuttonstr)) + 10); + pastebuttonrect.x = (640 - pastebuttonrect.w) / 2.0f; + pastebuttonrect.y = pastetextrect.y + pastetextrect.h + 10; + pastebuttonrect.h = copybuttonrect.h; + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs when a new event (mouse input, keypresses, etc) occurs. */ +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + if (event->type == SDL_EVENT_QUIT) { + return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) { + if (event->button.button == SDL_BUTTON_LEFT) { + const SDL_FPoint p = { event->button.x, event->button.y }; + copy_pressed = SDL_PointInRectFloat(&p, ©buttonrect); + paste_pressed = SDL_PointInRectFloat(&p, &pastebuttonrect); + } + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + if (event->button.button == SDL_BUTTON_LEFT) { + const SDL_FPoint p = { event->button.x, event->button.y }; + if (copy_pressed && SDL_PointInRectFloat(&p, ©buttonrect)) { + SDL_SetClipboardText(current_time); + } else if (paste_pressed && SDL_PointInRectFloat(&p, &pastebuttonrect)) { + SDL_free(pasted_str); + pasted_str = SDL_GetClipboardText(); + } + copy_pressed = paste_pressed = false; + } + } + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +static void RenderPastedText(void) +{ + char *str = pasted_str; + if (str) { + float x = pastetextrect.x + 5; + float y = pastetextrect.y + 5; + const float w = pastetextrect.w - 10; + const float h = pastetextrect.h; + const size_t max_chars_per_line = (size_t) (w / SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE); + char *newline; + size_t slen; + char ch; + + /* this doesn't wordwrap, or deal with Unicode....this is just a simple example app! */ + while ((newline = SDL_strchr(str, '\n')) != NULL) { + const bool ignore_cr = ((newline > str) && (newline[-1] == '\r')); + + if (ignore_cr) { + newline[-1] = '\0'; + } + *newline = '\0'; + + slen = SDL_strlen(str); /* length to end of line. */ + slen = SDL_min(slen, max_chars_per_line); + ch = str[slen]; + str[slen] = '\0'; + SDL_RenderDebugText(renderer, x, y, str); + str[slen] = ch; + + if (ignore_cr) { + newline[-1] = '\r'; + } + *newline = '\n'; + + str = newline + 1; + y += (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2); + if ((h - y) < SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) { + break; // no space for another line, stop here. + } + } + + /* last text after newline, if there's room. */ + if ((h - y) >= SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) { + slen = SDL_strlen(str); /* length to end of line. */ + slen = SDL_min(slen, max_chars_per_line); + ch = str[slen]; + str[slen] = '\0'; + SDL_RenderDebugText(renderer, x, y, str); + str[slen] = ch; + } + } +} + +/* This function runs once per frame, and is the heart of the program. */ +SDL_AppResult SDL_AppIterate(void *appstate) +{ + float x, y; + + CalculateCurrentTimeString(); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black */ + SDL_RenderClear(renderer); + + /* draw a frame around the current time. */ + SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); + SDL_RenderFillRect(renderer, ¤ttimerect); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderRect(renderer, ¤ttimerect); + + /* draw the current time inside the frame. */ + x = currenttimerect.x + ((currenttimerect.w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(current_time))) / 2.0f); + y = currenttimerect.y + 5; + SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); + SDL_RenderDebugText(renderer, x, y, current_time); + + /* draw a frame for the "copy the current time to the clipboard" button. */ + if (copy_pressed) { + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); + } else { + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + } + SDL_RenderFillRect(renderer, ©buttonrect); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderRect(renderer, ©buttonrect); + + /* draw the "copy this text" button string. */ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDebugText(renderer, copybuttonrect.x + 5, copybuttonrect.y + 5, copybuttonstr); + + /* draw a frame for the pasted text area. */ + SDL_SetRenderDrawColor(renderer, 0, 53, 25, 255); + SDL_RenderFillRect(renderer, &pastetextrect); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderRect(renderer, &pastetextrect); + + /* draw pasted text. */ + SDL_SetRenderDrawColor(renderer, 0, 219, 107, 255); + RenderPastedText(); + + /* draw a frame for the "paste from the clipboard" button. */ + if (paste_pressed) { + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); + } else { + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + } + SDL_RenderFillRect(renderer, &pastebuttonrect); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderRect(renderer, &pastebuttonrect); + + /* draw the "paste some text" button string. */ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDebugText(renderer, pastebuttonrect.x + 5, pastebuttonrect.y + 5, pastebuttonstr); + + /* put the new rendering on the screen. */ + SDL_RenderPresent(renderer); + + return SDL_APP_CONTINUE; /* carry on with the program! */ +} + +/* This function runs once at shutdown. */ +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + SDL_free(pasted_str); + /* SDL will clean up the window/renderer for us. */ +} + diff --git a/examples/misc/02-clipboard/onmouseover.webp b/examples/misc/02-clipboard/onmouseover.webp new file mode 100644 index 0000000000..73476b475b Binary files /dev/null and b/examples/misc/02-clipboard/onmouseover.webp differ diff --git a/examples/misc/02-clipboard/thumbnail.png b/examples/misc/02-clipboard/thumbnail.png new file mode 100644 index 0000000000..76bc9d51cb Binary files /dev/null and b/examples/misc/02-clipboard/thumbnail.png differ diff --git a/examples/misc/description.txt b/examples/misc/description.txt new file mode 100644 index 0000000000..bd99b89d18 --- /dev/null +++ b/examples/misc/description.txt @@ -0,0 +1 @@ +Various examples from smaller subsystems \ No newline at end of file diff --git a/examples/renderer/15-cliprect/cliprect.c b/examples/renderer/15-cliprect/cliprect.c index 058072c3c2..69b3aa69c4 100644 --- a/examples/renderer/15-cliprect/cliprect.c +++ b/examples/renderer/15-cliprect/cliprect.c @@ -93,20 +93,20 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* Set a new clipping rectangle position */ cliprect_position.x += distance * cliprect_direction.x; - if (cliprect_position.x < 0.0f) { - cliprect_position.x = 0.0f; + if (cliprect_position.x < -CLIPRECT_SIZE) { + cliprect_position.x = -CLIPRECT_SIZE; cliprect_direction.x = 1.0f; - } else if (cliprect_position.x >= (WINDOW_WIDTH - CLIPRECT_SIZE)) { - cliprect_position.x = (WINDOW_WIDTH - CLIPRECT_SIZE) - 1; + } else if (cliprect_position.x >= WINDOW_WIDTH) { + cliprect_position.x = WINDOW_WIDTH - 1; cliprect_direction.x = -1.0f; } cliprect_position.y += distance * cliprect_direction.y; - if (cliprect_position.y < 0.0f) { - cliprect_position.y = 0.0f; + if (cliprect_position.y < -CLIPRECT_SIZE) { + cliprect_position.y = -CLIPRECT_SIZE; cliprect_direction.y = 1.0f; - } else if (cliprect_position.y >= (WINDOW_HEIGHT - CLIPRECT_SIZE)) { - cliprect_position.y = (WINDOW_HEIGHT - CLIPRECT_SIZE) - 1; + } else if (cliprect_position.y >= WINDOW_HEIGHT) { + cliprect_position.y = WINDOW_HEIGHT - 1; cliprect_direction.y = -1.0f; } SDL_SetRenderClipRect(renderer, &cliprect); diff --git a/examples/save-rendering-to-bitmaps.h b/examples/save-rendering-to-bitmaps.h new file mode 100644 index 0000000000..2216a1fc16 --- /dev/null +++ b/examples/save-rendering-to-bitmaps.h @@ -0,0 +1,49 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* +This is for generating thumbnails and videos of examples. Just include it +temporarily and let it override SDL_RenderPresent, etc, and it'll dump each +frame rendered to a new .bmp file. +*/ + +static bool SAVERENDERING_SDL_RenderPresent(SDL_Renderer *renderer) +{ + static unsigned int framenum = 0; + SDL_Surface *surface = SDL_RenderReadPixels(renderer, NULL); + if (!surface) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to read pixels for frame #%u! (%s)", framenum, SDL_GetError()); + } else { + char fname[64]; + SDL_snprintf(fname, sizeof (fname), "frame%05u.bmp", framenum); + if (!SDL_SaveBMP(surface, fname)) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to save bmp for frame #%u! (%s)", framenum, SDL_GetError()); + } + SDL_DestroySurface(surface); + } + + framenum++; + + return SDL_RenderPresent(renderer); +} + +#define SDL_RenderPresent SAVERENDERING_SDL_RenderPresent + diff --git a/examples/template-category.html b/examples/template-category.html index 909b2c6392..21f737d33d 100644 --- a/examples/template-category.html +++ b/examples/template-category.html @@ -6,6 +6,9 @@ @project_name@ Examples: @category_description@ + +@preload_images_html@ + -
@@ -31,7 +33,7 @@

@project_name@ examples: @category_description@

diff --git a/examples/template-homepage.html b/examples/template-homepage.html index 46951b287d..f02afb6016 100644 --- a/examples/template-homepage.html +++ b/examples/template-homepage.html @@ -6,6 +6,9 @@ @project_name@ Examples + +@preload_images_html@ +

@project_name@ examples

diff --git a/examples/template.html b/examples/template.html index 3e43946438..84568e4187 100644 --- a/examples/template.html +++ b/examples/template.html @@ -9,7 +9,7 @@ - + @@ -202,9 +202,9 @@

diff --git a/include/SDL3/SDL_assert.h b/include/SDL3/SDL_assert.h index 48f17f5fb2..2ab796a1ae 100644 --- a/include/SDL3/SDL_assert.h +++ b/include/SDL3/SDL_assert.h @@ -132,9 +132,6 @@ extern "C" { #define SDL_TriggerBreakpoint() __debugbreak() #elif defined(_MSC_VER) && defined(_M_IX86) #define SDL_TriggerBreakpoint() { _asm { int 0x03 } } -#elif defined(ANDROID) || defined(__SYMBIAN32__) - #include - #define SDL_TriggerBreakpoint() assert(0) #elif SDL_HAS_BUILTIN(__builtin_debugtrap) #define SDL_TriggerBreakpoint() __builtin_debugtrap() #elif SDL_HAS_BUILTIN(__builtin_trap) diff --git a/include/SDL3/SDL_camera.h b/include/SDL3/SDL_camera.h index 6dc79d3783..59ce73fe8a 100644 --- a/include/SDL3/SDL_camera.h +++ b/include/SDL3/SDL_camera.h @@ -360,8 +360,9 @@ extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id * on others the approval might be implicit and not alert the user at all. * * This function can be used to check the status of that approval. It will - * return 0 if still waiting for user response, 1 if the camera is approved - * for use, and -1 if the user denied access. + * return SDL_CAMERA_PERMISSION_STATE_PENDING if waiting for user response, + * SDL_CAMERA_PERMISSION_STATE_APPROVED if the camera is approved for use, and + * SDL_CAMERA_PERMISSION_STATE_DENIED if the user denied access. * * Instead of polling with this function, you can wait for a * SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event @@ -372,8 +373,9 @@ extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id * SDL_CloseCamera() to dispose of it. * * \param camera the opened camera device to query. - * \returns -1 if user denied access to the camera, 1 if user approved access, - * 0 if no decision has been made yet. + * \returns an SDL_CameraPermissionState value indicating if access is + * granted, or `SDL_CAMERA_PERMISSION_STATE_PENDING` if the decision + * is still pending. * * \threadsafety It is safe to call this function from any thread. * diff --git a/include/SDL3/SDL_endian.h b/include/SDL3/SDL_endian.h index 41ad0ce51a..f3ab18ffdc 100644 --- a/include/SDL3/SDL_endian.h +++ b/include/SDL3/SDL_endian.h @@ -46,7 +46,7 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1400) /* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version, so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */ -#ifdef __clang__ +#if defined(__clang__) && !SDL_HAS_BUILTIN(_m_prefetch) #ifndef __PRFCHWINTRIN_H #define __PRFCHWINTRIN_H static __inline__ void __attribute__((__always_inline__, __nodebug__)) diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 60155b8103..54e8292343 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -30,7 +30,7 @@ * coming and going, the system changing in some way, etc. * * An app generally takes a moment, perhaps at the start of a new frame, to - * examine any events that have occured since the last time and process or + * examine any events that have occurred since the last time and process or * ignore them. This is generally done by calling SDL_PollEvent() in a loop * until it returns false (or, if using the main callbacks, events are * provided one at a time in calls to SDL_AppEvent() before the next call to @@ -1396,7 +1396,10 @@ typedef bool (SDLCALL *SDL_EventFilter)(void *userdata, SDL_Event *event); * allows selective filtering of dynamically arriving events. * * **WARNING**: Be very careful of what you do in the event filter function, - * as it may run in a different thread! + * as it may run in a different thread! The exception is handling of + * SDL_EVENT_WINDOW_EXPOSED, which is guaranteed to be sent from the OS on the + * main thread and you are expected to redraw your window in response to this + * event. * * On platforms that support it, if the quit event is generated by an * interrupt signal (e.g. pressing Ctrl-C), it will be delivered to the @@ -1409,7 +1412,7 @@ typedef bool (SDLCALL *SDL_EventFilter)(void *userdata, SDL_Event *event); * the event filter, but events pushed onto the queue with SDL_PeepEvents() do * not. * - * \param filter an SDL_EventFilter function to call when an event happens. + * \param filter a function to call when an event happens. * \param userdata a pointer that is passed to `filter`. * * \threadsafety It is safe to call this function from any thread. diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h index dc21d0d068..d1a21ca252 100644 --- a/include/SDL3/SDL_gamepad.h +++ b/include/SDL3/SDL_gamepad.h @@ -424,6 +424,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddGamepadMappingsFromFile(const char *file) * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_ReloadGamepadMappings(void); @@ -438,6 +440,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReloadGamepadMappings(void); * single allocation that should be freed with SDL_free() when it is * no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC char ** SDLCALL SDL_GetGamepadMappings(int *count); @@ -450,6 +454,8 @@ extern SDL_DECLSPEC char ** SDLCALL SDL_GetGamepadMappings(int *count); * information. This should be freed with SDL_free() when it is no * longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUIDForID @@ -467,6 +473,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMappingForGUID(SDL_GUID guid); * available; call SDL_GetError() for more information. This should * be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddGamepadMapping @@ -487,6 +495,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMapping(SDL_Gamepad *gamepad); * \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_AddGamepadMapping @@ -499,6 +509,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadMapping(SDL_JoystickID instance_i * * \returns true if a gamepad is connected, 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_GetGamepads @@ -514,6 +526,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasGamepad(void); * call SDL_GetError() for more information. This should be freed * with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasGamepad @@ -528,6 +542,8 @@ extern SDL_DECLSPEC SDL_JoystickID * SDLCALL SDL_GetGamepads(int *count); * \returns true if the given joystick is supported by the gamepad interface, * false if it isn't or it's an invalid index. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoysticks @@ -544,6 +560,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsGamepad(SDL_JoystickID instance_id); * \returns the name of the selected gamepad. If no name can be found, this * function returns NULL; 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_GetGamepadName @@ -560,6 +578,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadNameForID(SDL_JoystickID * \returns the path of the selected gamepad. If no path can be found, this * function returns NULL; 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_GetGamepadPath @@ -575,6 +595,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadPathForID(SDL_JoystickID * \param instance_id the joystick instance ID. * \returns the player index of a gamepad, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPlayerIndex @@ -591,6 +613,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetGamepadPlayerIndexForID(SDL_JoystickID in * \returns the GUID of the selected gamepad. If called on an invalid index, * this function returns a zero GUID. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GUIDToString @@ -608,6 +632,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetGamepadGUIDForID(SDL_JoystickID inst * \returns the USB vendor ID of the selected gamepad. If called on an invalid * index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadVendor @@ -625,6 +651,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadVendorForID(SDL_JoystickID inst * \returns the USB product ID of the selected gamepad. If called on an * invalid index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProduct @@ -642,6 +670,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductForID(SDL_JoystickID ins * \returns the product version of the selected gamepad. If called on an * invalid index, this function returns zero. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductVersion @@ -657,6 +687,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductVersionForID(SDL_Joystic * \param instance_id the joystick instance ID. * \returns the gamepad type. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadType @@ -673,6 +705,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadTypeForID(SDL_Joystick * \param instance_id the joystick instance ID. * \returns the gamepad type. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeForID @@ -690,6 +724,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetRealGamepadTypeForID(SDL_Joys * \returns the mapping string. Returns NULL if no mapping is available. This * should be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepads @@ -704,6 +740,8 @@ extern SDL_DECLSPEC char * SDLCALL SDL_GetGamepadMappingForID(SDL_JoystickID ins * \returns a gamepad identifier or NULL if an error occurred; 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_CloseGamepad @@ -719,6 +757,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_OpenGamepad(SDL_JoystickID instanc * \returns an SDL_Gamepad on success or NULL on failure or if it hasn't been * opened yet; 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_Gamepad * SDLCALL SDL_GetGamepadFromID(SDL_JoystickID instance_id); @@ -729,6 +769,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_GetGamepadFromID(SDL_JoystickID in * \param player_index the player index, which different from the instance ID. * \returns the SDL_Gamepad associated with a player index. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPlayerIndex @@ -759,6 +801,8 @@ extern SDL_DECLSPEC SDL_Gamepad * SDLCALL SDL_GetGamepadFromPlayerIndex(int play * \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_GetGamepadProperties(SDL_Gamepad *gamepad); @@ -777,6 +821,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGamepadProperties(SDL_Gamepa * \returns the instance ID of the specified gamepad 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_JoystickID SDLCALL SDL_GetGamepadID(SDL_Gamepad *gamepad); @@ -789,6 +835,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetGamepadID(SDL_Gamepad *gamepad * \returns the implementation dependent name for the gamepad, or NULL if * there is no name or the identifier passed is invalid. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadNameForID @@ -803,6 +851,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadName(SDL_Gamepad *gamepad * \returns the implementation dependent path for the gamepad, or NULL if * there is no path or the identifier passed is invalid. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadPathForID @@ -816,6 +866,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadPath(SDL_Gamepad *gamepad * \returns the gamepad type, or SDL_GAMEPAD_TYPE_UNKNOWN if it's not * available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeForID @@ -829,6 +881,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadType(SDL_Gamepad *game * \returns the gamepad type, or SDL_GAMEPAD_TYPE_UNKNOWN if it's not * available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetRealGamepadTypeForID @@ -843,6 +897,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetRealGamepadType(SDL_Gamepad * * \param gamepad the gamepad object to query. * \returns the player index for gamepad, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetGamepadPlayerIndex @@ -858,6 +914,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetGamepadPlayerIndex(SDL_Gamepad *gamepad); * \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_GetGamepadPlayerIndex @@ -872,6 +930,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadPlayerIndex(SDL_Gamepad *gamepad, * \param gamepad the gamepad object to query. * \returns the USB vendor ID, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadVendorForID @@ -886,6 +946,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadVendor(SDL_Gamepad *gamepad); * \param gamepad the gamepad object to query. * \returns the USB product ID, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductForID @@ -900,6 +962,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProduct(SDL_Gamepad *gamepad); * \param gamepad the gamepad object to query. * \returns the USB product version, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadProductVersionForID @@ -914,6 +978,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadProductVersion(SDL_Gamepad *gam * \param gamepad the gamepad object to query. * \returns the gamepad firmware version, or zero if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadFirmwareVersion(SDL_Gamepad *gamepad); @@ -926,6 +992,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetGamepadFirmwareVersion(SDL_Gamepad *ga * \param gamepad the gamepad object to query. * \returns the serial number, or NULL if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamepad); @@ -939,6 +1007,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamep * \param gamepad the gamepad object to query. * \returns the gamepad handle, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad); @@ -951,6 +1021,8 @@ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepa * `SDL_JOYSTICK_CONNECTION_INVALID` 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_JoystickConnectionState SDLCALL SDL_GetGamepadConnectionState(SDL_Gamepad *gamepad); @@ -971,6 +1043,8 @@ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetGamepadConnection * battery. * \returns the current battery state. * + * \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_PowerState SDLCALL SDL_GetGamepadPowerInfo(SDL_Gamepad *gamepad, int *percent); @@ -983,6 +1057,8 @@ extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetGamepadPowerInfo(SDL_Gamepad * * \returns true if the gamepad has been opened and is currently connected, or * false if not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadConnected(SDL_Gamepad *gamepad); @@ -1003,6 +1079,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadConnected(SDL_Gamepad *gamepad); * \returns an SDL_Joystick object, 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. */ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetGamepadJoystick(SDL_Gamepad *gamepad); @@ -1015,6 +1093,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetGamepadJoystick(SDL_Gamepad *g * * \param enabled whether to process gamepad events or not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadEventsEnabled @@ -1030,6 +1110,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetGamepadEventsEnabled(bool enabled); * * \returns true if gamepad events are being processed, 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_SetGamepadEventsEnabled @@ -1046,6 +1128,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadEventsEnabled(void); * single allocation that should be freed with SDL_free() when it is * no longer needed. * + * \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_GamepadBinding ** SDLCALL SDL_GetGamepadBindings(SDL_Gamepad *gamepad, int *count); @@ -1057,6 +1141,8 @@ extern SDL_DECLSPEC SDL_GamepadBinding ** SDLCALL SDL_GetGamepadBindings(SDL_Gam * enabled. Under such circumstances, it will not be necessary to call this * function. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UpdateGamepads(void); @@ -1073,6 +1159,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UpdateGamepads(void); * \returns the SDL_GamepadType enum corresponding to the input string, or * `SDL_GAMEPAD_TYPE_UNKNOWN` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForType @@ -1087,6 +1175,8 @@ extern SDL_DECLSPEC SDL_GamepadType SDLCALL SDL_GetGamepadTypeFromString(const c * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTypeFromString @@ -1109,6 +1199,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForType(SDL_Gamepad * \returns the SDL_GamepadAxis enum corresponding to the input string, or * `SDL_GAMEPAD_AXIS_INVALID` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForAxis @@ -1123,6 +1215,8 @@ extern SDL_DECLSPEC SDL_GamepadAxis SDLCALL SDL_GetGamepadAxisFromString(const c * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAxisFromString @@ -1139,6 +1233,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForAxis(SDL_Gamepad * \param axis an axis enum value (an SDL_GamepadAxis value). * \returns true if the gamepad has this axis, 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_GamepadHasButton @@ -1165,6 +1261,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasAxis(SDL_Gamepad *gamepad, SDL_Ga * \param axis an axis index (one of the SDL_GamepadAxis values). * \returns axis state. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GamepadHasAxis @@ -1184,6 +1282,8 @@ extern SDL_DECLSPEC Sint16 SDLCALL SDL_GetGamepadAxis(SDL_Gamepad *gamepad, SDL_ * \returns the SDL_GamepadButton enum corresponding to the input string, or * `SDL_GAMEPAD_BUTTON_INVALID` if no match was found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadStringForButton @@ -1198,6 +1298,8 @@ extern SDL_DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadButtonFromString(con * specified. The string returned is of the format used by * SDL_Gamepad mapping strings. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonFromString @@ -1214,6 +1316,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadStringForButton(SDL_Gamep * \param button a button enum value (an SDL_GamepadButton value). * \returns true if the gamepad has this button, 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_GamepadHasAxis @@ -1227,6 +1331,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasButton(SDL_Gamepad *gamepad, SDL_ * \param button a button index (one of the SDL_GamepadButton values). * \returns true if the button is pressed, 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_GamepadHasButton @@ -1241,6 +1347,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadButton(SDL_Gamepad *gamepad, SDL_ * \param button a button index (one of the SDL_GamepadButton values). * \returns the SDL_GamepadButtonLabel enum corresponding to the button label. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonLabel @@ -1254,6 +1362,8 @@ extern SDL_DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabelForT * \param button a button index (one of the SDL_GamepadButton values). * \returns the SDL_GamepadButtonLabel enum corresponding to the button label. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadButtonLabelForType @@ -1266,6 +1376,8 @@ extern SDL_DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabel(SDL * \param gamepad a gamepad. * \returns number of touchpads. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumGamepadTouchpadFingers @@ -1280,6 +1392,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumGamepadTouchpads(SDL_Gamepad *gamepad) * \param touchpad a touchpad. * \returns number of supported simultaneous fingers. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadTouchpadFinger @@ -1303,6 +1417,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumGamepadTouchpadFingers(SDL_Gamepad *ga * \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_GetNumGamepadTouchpadFingers @@ -1316,6 +1432,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadTouchpadFinger(SDL_Gamepad *gamep * \param type the type of sensor to query. * \returns true if the sensor exists, 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_GetGamepadSensorData @@ -1333,6 +1451,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasSensor(SDL_Gamepad *gamepad, SDL_ * \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_GamepadHasSensor @@ -1347,6 +1467,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadSensorEnabled(SDL_Gamepad *gamepa * \param type the type of sensor to query. * \returns true if the sensor is 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_SetGamepadSensorEnabled @@ -1360,6 +1482,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadSensorEnabled(SDL_Gamepad *gamepad, * \param type the type of sensor to query. * \returns the data rate, or 0.0f if the data rate is not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC float SDLCALL SDL_GetGamepadSensorDataRate(SDL_Gamepad *gamepad, SDL_SensorType type); @@ -1377,6 +1501,8 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetGamepadSensorDataRate(SDL_Gamepad *game * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadSensorData(SDL_Gamepad *gamepad, SDL_SensorType type, float *data, int num_values); @@ -1399,6 +1525,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGamepadSensorData(SDL_Gamepad *gamepad, * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); @@ -1425,6 +1553,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 * \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_RumbleGamepad @@ -1447,6 +1577,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleGamepadTriggers(SDL_Gamepad *gamepad, * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadLED(SDL_Gamepad *gamepad, Uint8 red, Uint8 green, Uint8 blue); @@ -1460,6 +1592,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGamepadLED(SDL_Gamepad *gamepad, Uint8 r * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_SendGamepadEffect(SDL_Gamepad *gamepad, const void *data, int size); @@ -1470,6 +1604,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendGamepadEffect(SDL_Gamepad *gamepad, con * \param gamepad a gamepad identifier previously returned by * SDL_OpenGamepad(). * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_OpenGamepad @@ -1484,6 +1620,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseGamepad(SDL_Gamepad *gamepad); * \param button a button on the gamepad. * \returns the sfSymbolsName or NULL if the name can't be found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAppleSFSymbolsNameForAxis @@ -1497,6 +1635,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGamepadAppleSFSymbolsNameForButt * \param axis an axis on the gamepad. * \returns the sfSymbolsName or NULL if the name can't be found. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetGamepadAppleSFSymbolsNameForButton diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 2af19fa2e9..18ee000869 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -230,6 +230,15 @@ * - `drawIndirectFirstInstance` * - `sampleRateShading` * + * You can remove some of these requirements to increase compatibility with + * Android devices by using these properties when creating the GPU device with + * SDL_CreateGPUDeviceWithProperties(): + * + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN + * - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN + * * ### D3D12 * * SDL driver name: "direct3d12" @@ -238,6 +247,12 @@ * (GDK). Requires a GPU that supports DirectX 12 Feature Level 11_0 and * Resource Binding Tier 2 or above. * + * You can remove the Tier 2 resource binding requirement to support Intel + * Haswell and Broadwell GPUs by using this property when creating the GPU + * device with SDL_CreateGPUDeviceWithProperties(): + * + * - SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN + * * ### Metal * * SDL driver name: "metal" @@ -2055,6 +2070,9 @@ typedef struct SDL_GPUColorTargetInfo * * Note that depth/stencil targets do not support multisample resolves. * + * Due to ABI limitations, depth textures with more than 255 layers are not + * supported. + * * \since This struct is available since SDL 3.2.0. * * \sa SDL_BeginGPURenderPass @@ -2069,8 +2087,8 @@ typedef struct SDL_GPUDepthStencilTargetInfo SDL_GPUStoreOp stencil_store_op; /**< What is done with the stencil results of the render pass. */ bool cycle; /**< true cycles the texture if the texture is bound and any load ops are not LOAD */ Uint8 clear_stencil; /**< The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */ - Uint8 padding1; - Uint8 padding2; + Uint8 mip_level; /**< The mip level to use as the depth stencil target. */ + Uint8 layer; /**< The layer index to use as the depth stencil target. */ } SDL_GPUDepthStencilTargetInfo; /** @@ -2239,6 +2257,27 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( * useful debug information on device creation, defaults to true. * - `SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING`: the name of the GPU driver to * use, if a specific one is desired. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN`: Enable Vulkan + * device feature shaderClipDistance. If disabled, clip distances are not + * supported in shader code: gl_ClipDistance[] built-ins of GLSL, + * SV_ClipDistance0/1 semantics of HLSL and [[clip_distance]] attribute of + * Metal. Disabling optional features allows the application to run on some + * older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN`: Enable + * Vulkan device feature depthClamp. If disabled, there is no depth clamp + * support and enable_depth_clip in SDL_GPURasterizerState must always be + * set to true. Disabling optional features allows the application to run on + * some older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN`: + * Enable Vulkan device feature drawIndirectFirstInstance. If disabled, the + * argument first_instance of SDL_GPUIndirectDrawCommand must be set to + * zero. Disabling optional features allows the application to run on some + * older Android devices. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN`: Enable Vulkan + * device feature samplerAnisotropy. If disabled, enable_anisotropy of + * SDL_GPUSamplerCreateInfo must be set to false. Disabling optional + * features allows the application to run on some older Android devices. + * Defaults to true. * * These are the current shader format properties: * @@ -2259,25 +2298,14 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( * * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to * use for all vertex semantics, default is "TEXCOORD". - * - * With the Vulkan renderer: - * - * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN`: Enable - * device feature shaderClipDistance. If disabled, clip distances are not - * supported in shader code: gl_ClipDistance[] built-ins of GLSL, - * SV_ClipDistance0/1 semantics of HLSL and [[clip_distance]] attribute of - * Metal. Defaults to true. - * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN`: Enable device - * feature depthClamp. If disabled, there is no depth clamp support and - * enable_depth_clip in SDL_GPURasterizerState must always be set to true. - * Defaults to true. - * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN`: Enable - * device feature drawIndirectFirstInstance. If disabled, the argument - * first_instance of SDL_GPUIndirectDrawCommand must be set to zero. - * Defaults to true. - * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN`: Enable - * device feature samplerAnisotropy. If disabled, enable_anisotropy of - * SDL_GPUSamplerCreateInfo must be set to false. Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN`: By + * default, Resourcing Binding Tier 2 is required for D3D12 support. + * However, an application can set this property to true to enable Tier 1 + * support, if (and only if) the application uses 8 or fewer storage + * resources across all shader stages. As of writing, this property is + * useful for targeting Intel Haswell and Broadwell GPUs; other hardware + * either supports Tier 2 Resource Binding or does not support D3D12 in any + * capacity. Defaults to false. * * \param props the properties to use. * \returns a GPU context on success or NULL on failure; call SDL_GetError() @@ -2293,21 +2321,22 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( SDL_PropertiesID props); -#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" -#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower" -#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose" -#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" -#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" -#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" -#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN "SDL.gpu.device.create.vulkan.shaderclipdistance" -#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN "SDL.gpu.device.create.vulkan.depthclamp" -#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN "SDL.gpu.device.create.vulkan.drawindirectfirstinstance" -#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN "SDL.gpu.device.create.vulkan.sampleranisotropy" +#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" +#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower" +#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose" +#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN "SDL.gpu.device.create.feature.clip_distance" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN "SDL.gpu.device.create.feature.depth_clamping" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN "SDL.gpu.device.create.feature.indirect_draw_first_instance" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN "SDL.gpu.device.create.feature.anisotropy" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" +#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN "SDL.gpu.device.create.d3d12.allowtier1resourcebinding" +#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" /** * Destroys a GPU context previously returned by SDL_CreateGPUDevice. @@ -4420,6 +4449,29 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_CalculateGPUTextureFormatSize( Uint32 height, Uint32 depth_or_layer_count); +/** + * Get the SDL pixel format corresponding to a GPU texture format. + * + * \param format a texture format. + * \returns the corresponding pixel format, or SDL_PIXELFORMAT_UNKNOWN if + * there is no corresponding pixel format. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PixelFormat SDLCALL SDL_GetPixelFormatFromGPUTextureFormat(SDL_GPUTextureFormat format); + +/** + * Get the GPU texture format corresponding to an SDL pixel format. + * + * \param format a pixel format. + * \returns the corresponding GPU texture format, or + * SDL_GPU_TEXTUREFORMAT_INVALID if there is no corresponding GPU + * texture format. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUTextureFormatFromPixelFormat(SDL_PixelFormat format); + #ifdef SDL_PLATFORM_GDK /** @@ -4460,8 +4512,3 @@ extern SDL_DECLSPEC void SDLCALL SDL_GDKResumeGPU(SDL_GPUDevice *device); #include #endif /* SDL_gpu_h_ */ - - - - - diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index b3103ae7f7..aa5d13b286 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -685,6 +685,21 @@ extern "C" { */ #define SDL_HINT_DISPLAY_USABLE_BOUNDS "SDL_DISPLAY_USABLE_BOUNDS" +/** + * Set the level of checking for invalid parameters passed to SDL functions. + * + * The variable can be set to the following values: + * + * - "1": Enable fast parameter error checking, e.g. quick NULL checks, etc. + * - "2": Enable full parameter error checking, e.g. validating objects are + * the correct type, etc. (default) + * + * This hint can be set anytime. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_INVALID_PARAM_CHECKS "SDL_INVALID_PARAM_CHECKS" + /** * Disable giving back control to the browser automatically when running with * asyncify. @@ -738,6 +753,28 @@ extern "C" { */ #define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT" +/** + * Dictate that newly-created windows will fill the whole browser window. + * + * The canvas element fills the entire document. Resize events will be + * generated as the browser window is resized, as that will adjust the canvas + * size as well. The canvas will cover anything else on the page, including + * any controls provided by Emscripten in its generated HTML file. Often times + * this is desirable for a browser-based game, but it means several things + * that we expect of an SDL window on other platforms might not work as + * expected, such as minimum window sizes and aspect ratios. + * + * This hint overrides SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN + * properties when creating an SDL window. + * + * This hint only applies to the emscripten platform. + * + * This hint should be set before creating a window. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT "SDL_EMSCRIPTEN_FILL_DOCUMENT" + /** * A variable that controls whether the on-screen keyboard should be shown * when text input is active. @@ -1760,6 +1797,18 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_SINPUT "SDL_JOYSTICK_HIDAPI_SINPUT" +/** + * A variable controlling whether the HIDAPI driver for ZUIKI controllers + * should be used. + * + * This variable can be set to the following values: + * + * "0" - HIDAPI driver is not used. "1" - HIDAPI driver is used. + * + * The default is the value of SDL_HINT_JOYSTICK_HIDAPI + */ +#define SDL_HINT_JOYSTICK_HIDAPI_ZUIKI "SDL_JOYSTICK_HIDAPI_ZUIKI" + /** * A variable controlling whether the HIDAPI driver for Flydigi controllers * should be used. @@ -2227,8 +2276,8 @@ extern "C" { * * The variable can be set to the following values: * - * - "0": WGI is not used. - * - "1": WGI is used. (default) + * - "0": WGI is not used. (default) + * - "1": WGI is used. * * This hint should be set before SDL is initialized. * @@ -2410,6 +2459,11 @@ extern "C" { * * `app=info,assert=warn,test=verbose,*=error` * + * If the `DEBUG_INVOCATION` environment variable is set to "1", the default + * log levels are equivalent to: + * + * `assert=warn,test=verbose,*=debug` + * * This hint can be set anytime. * * \since This hint is available since SDL 3.2.0. @@ -2598,7 +2652,7 @@ extern "C" { * the window center occur within a short time period, SDL will emulate mouse * warps using relative mouse mode. This can provide smoother and more * reliable mouse motion for some older games, which continuously calculate - * the distance travelled by the mouse pointer and warp it back to the center + * the distance traveled by the mouse pointer and warp it back to the center * of the window, rather than using relative mouse motion. * * Note that relative mouse mode may have different mouse acceleration @@ -2964,6 +3018,24 @@ extern "C" { */ #define SDL_HINT_RENDER_DIRECT3D11_DEBUG "SDL_RENDER_DIRECT3D11_DEBUG" +/** + * A variable controlling whether to use the Direct3D 11 WARP software + * rasterizer. + * + * For more information, see: + * https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp + * + * The variable can be set to the following values: + * + * - "0": Disable WARP rasterizer. (default) + * - "1": Enable WARP rasterizer. + * + * This hint should be set before creating a renderer. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_RENDER_DIRECT3D11_WARP "SDL_RENDER_DIRECT3D11_WARP" + /** * A variable controlling whether to enable Vulkan Validation Layers. * @@ -3146,6 +3218,37 @@ extern "C" { */ #define SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED "SDL_ROG_GAMEPAD_MICE_EXCLUDED" +/** + * Variable controlling the width of the PS2's framebuffer in pixels + * + * By default, this variable is "640" + */ +#define SDL_HINT_PS2_GS_WIDTH "SDL_PS2_GS_WIDTH" + +/** + * Variable controlling the height of the PS2's framebuffer in pixels + * + * By default, this variable is "448" + */ +#define SDL_HINT_PS2_GS_HEIGHT "SDL_PS2_GS_HEIGHT" + +/** + * Variable controlling whether the signal is interlaced or progressive + * + * - "0": Image is interlaced. (default) + * - "1": Image is progressive + */ +#define SDL_HINT_PS2_GS_PROGRESSIVE "SDL_PS2_GS_PROGRESSIVE" + +/** + * Variable controlling the video mode of the console + * + * - "": Console-native. (default) + * - "NTSC": 60hz region + * - "PAL": 50hz region + */ +#define SDL_HINT_PS2_GS_MODE "SDL_PS2_GS_MODE" + /** * A variable controlling which Dispmanx layer to use on a Raspberry PI. * @@ -4194,7 +4297,7 @@ extern "C" { * * \since This hint is available since SDL 3.2.0. */ -#define SDL_HINT_WINDOWS_GAMEINPUT "SDL_WINDOWS_GAMEINPUT" +#define SDL_HINT_WINDOWS_GAMEINPUT "SDL_WINDOWS_GAMEINPUT" /** * A variable controlling whether raw keyboard events are used on Windows. @@ -4239,7 +4342,7 @@ extern "C" { * * \since This hint is available since SDL 3.2.0. */ -#define SDL_HINT_WINDOWS_INTRESOURCE_ICON "SDL_WINDOWS_INTRESOURCE_ICON" +#define SDL_HINT_WINDOWS_INTRESOURCE_ICON "SDL_WINDOWS_INTRESOURCE_ICON" /** * A variable to specify custom icon resource id from RC file on Windows @@ -4535,19 +4638,14 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetHints(void); * \param name the hint to query. * \returns the string value of a hint or NULL if the hint isn't set. * - * \threadsafety It is safe to call this function from any thread, however the - * return value only remains valid until the hint is changed; if - * another thread might do so, the app should supply locks - * and/or make a copy of the string. Note that using a hint - * callback instead is always thread-safe, as SDL holds a lock - * on the thread subsystem during the callback. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetHint * \sa SDL_SetHintWithPriority */ -extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); +extern SDL_DECLSPEC const char *SDLCALL SDL_GetHint(const char *name); /** * Get the boolean value of a hint variable. @@ -4623,8 +4721,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AddHintCallback(const char *name, SDL_HintC * \sa SDL_AddHintCallback */ extern SDL_DECLSPEC void SDLCALL SDL_RemoveHintCallback(const char *name, - SDL_HintCallback callback, - void *userdata); + SDL_HintCallback callback, + void *userdata); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/include/SDL3/SDL_joystick.h b/include/SDL3/SDL_joystick.h index 6f3a766f82..af04f0979e 100644 --- a/include/SDL3/SDL_joystick.h +++ b/include/SDL3/SDL_joystick.h @@ -182,6 +182,8 @@ typedef enum SDL_JoystickConnectionState * joysticks while processing to guarantee that the joystick list won't change * and joystick and gamepad events will not be delivered. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock); @@ -189,6 +191,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystic /** * Unlocking for atomic access to the joystick API. * + * \threadsafety This should be called from the same thread that called + * SDL_LockJoysticks(). + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock); @@ -198,6 +203,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joyst * * \returns true if a joystick is connected, 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_GetJoysticks @@ -213,6 +220,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasJoystick(void); * call SDL_GetError() for more information. This should be freed * with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_HasJoystick @@ -229,6 +238,8 @@ extern SDL_DECLSPEC SDL_JoystickID * SDLCALL SDL_GetJoysticks(int *count); * \returns the name of the selected joystick. If no name can be found, this * function returns NULL; 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_GetJoystickName @@ -245,6 +256,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickNameForID(SDL_JoystickID * \returns the path of the selected joystick. If no path can be found, this * function returns NULL; 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_GetJoystickPath @@ -260,6 +273,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickPathForID(SDL_JoystickID * \param instance_id the joystick instance ID. * \returns the player index of a joystick, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickPlayerIndex @@ -276,6 +291,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetJoystickPlayerIndexForID(SDL_JoystickID i * \returns the GUID of the selected joystick. If called with an invalid * instance_id, this function returns a zero GUID. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUID @@ -293,6 +310,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetJoystickGUIDForID(SDL_JoystickID ins * \returns the USB vendor ID of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickVendor @@ -310,6 +329,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickVendorForID(SDL_JoystickID ins * \returns the USB product ID of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProduct @@ -327,6 +348,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductForID(SDL_JoystickID in * \returns the product version of the selected joystick. If called with an * invalid instance_id, this function returns 0. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductVersion @@ -344,6 +367,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductVersionForID(SDL_Joysti * invalid instance_id, this function returns * `SDL_JOYSTICK_TYPE_UNKNOWN`. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickType @@ -361,6 +386,8 @@ extern SDL_DECLSPEC SDL_JoystickType SDLCALL SDL_GetJoystickTypeForID(SDL_Joysti * \returns a joystick identifier 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_CloseJoystick @@ -374,6 +401,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_OpenJoystick(SDL_JoystickID insta * \returns an SDL_Joystick on success or NULL on failure or if it hasn't been * opened yet; 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_Joystick * SDLCALL SDL_GetJoystickFromID(SDL_JoystickID instance_id); @@ -385,6 +414,8 @@ extern SDL_DECLSPEC SDL_Joystick * SDLCALL SDL_GetJoystickFromID(SDL_JoystickID * \returns an SDL_Joystick on success 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_GetJoystickPlayerIndex @@ -493,6 +524,8 @@ SDL_COMPILE_TIME_ASSERT(SDL_VirtualJoystickDesc_SIZE, * \returns the joystick instance ID, 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. * * \sa SDL_DetachVirtualJoystick @@ -513,6 +546,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_AttachVirtualJoystick(const SDL_V * \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_AttachVirtualJoystick @@ -525,6 +560,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_DetachVirtualJoystick(SDL_JoystickID instan * \param instance_id the joystick instance ID. * \returns true if the joystick is virtual, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_IsJoystickVirtual(SDL_JoystickID instance_id); @@ -548,6 +585,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsJoystickVirtual(SDL_JoystickID instance_i * \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_SetJoystickVirtualButton @@ -574,6 +613,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualAxis(SDL_Joystick *joysti * \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_SetJoystickVirtualAxis @@ -599,6 +640,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualBall(SDL_Joystick *joysti * \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_SetJoystickVirtualAxis @@ -624,6 +667,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualButton(SDL_Joystick *joys * \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_SetJoystickVirtualAxis @@ -656,6 +701,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualHat(SDL_Joystick *joystic * \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_SetJoystickVirtualAxis @@ -684,6 +731,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickVirtualTouchpad(SDL_Joystick *jo * \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_SetJoystickVirtualAxis @@ -714,6 +763,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickVirtualSensorData(SDL_Joystick * \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_GetJoystickProperties(SDL_Joystick *joystick); @@ -731,6 +782,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetJoystickProperties(SDL_Joyst * \returns the name of the selected joystick. If no name can be found, this * function returns NULL; 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_GetJoystickNameForID @@ -744,6 +797,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickName(SDL_Joystick *joyst * \returns the path of the selected joystick. If no path can be found, this * function returns NULL; 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_GetJoystickPathForID @@ -759,6 +814,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickPath(SDL_Joystick *joyst * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the player index, or -1 if it's not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetJoystickPlayerIndex @@ -774,6 +831,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetJoystickPlayerIndex(SDL_Joystick *joystic * \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_GetJoystickPlayerIndex @@ -790,6 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickPlayerIndex(SDL_Joystick *joysti * this function returns a zero GUID; 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_GetJoystickGUIDForID @@ -805,6 +866,8 @@ extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetJoystickGUID(SDL_Joystick *joystick) * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the USB vendor ID of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickVendorForID @@ -819,6 +882,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickVendor(SDL_Joystick *joystick) * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the USB product ID of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductForID @@ -833,6 +898,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProduct(SDL_Joystick *joystick * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the product version of the selected joystick, or 0 if unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickProductVersionForID @@ -848,6 +915,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickProductVersion(SDL_Joystick *j * \returns the firmware version of the selected joystick, or 0 if * unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickFirmwareVersion(SDL_Joystick *joystick); @@ -861,6 +930,8 @@ extern SDL_DECLSPEC Uint16 SDLCALL SDL_GetJoystickFirmwareVersion(SDL_Joystick * * \returns the serial number of the selected joystick, or NULL if * unavailable. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickSerial(SDL_Joystick *joystick); @@ -871,6 +942,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetJoystickSerial(SDL_Joystick *joy * \param joystick the SDL_Joystick obtained from SDL_OpenJoystick(). * \returns the SDL_JoystickType of the selected joystick. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickTypeForID @@ -890,6 +963,8 @@ extern SDL_DECLSPEC SDL_JoystickType SDLCALL SDL_GetJoystickType(SDL_Joystick *j * \param crc16 a pointer filled in with a CRC used to distinguish different * products with the same VID/PID, or 0 if not available. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetJoystickGUIDForID @@ -903,6 +978,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetJoystickGUIDInfo(SDL_GUID guid, Uint16 * * \returns true if the joystick has been opened, false if it has not; 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 bool SDLCALL SDL_JoystickConnected(SDL_Joystick *joystick); @@ -914,6 +991,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_JoystickConnected(SDL_Joystick *joystick); * \returns the instance ID of the specified joystick 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_JoystickID SDLCALL SDL_GetJoystickID(SDL_Joystick *joystick); @@ -929,6 +1008,8 @@ extern SDL_DECLSPEC SDL_JoystickID SDLCALL SDL_GetJoystickID(SDL_Joystick *joyst * \returns the number of axis controls/number of axes on success or -1 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_GetJoystickAxis @@ -950,6 +1031,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickAxes(SDL_Joystick *joystick); * \returns the number of trackballs on success or -1 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_GetJoystickBall @@ -966,6 +1049,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickBalls(SDL_Joystick *joystick); * \returns the number of POV hats on success or -1 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_GetJoystickHat @@ -982,6 +1067,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickHats(SDL_Joystick *joystick); * \returns the number of buttons on success or -1 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_GetJoystickButton @@ -1000,6 +1087,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumJoystickButtons(SDL_Joystick *joystick * * \param enabled whether to process joystick events or not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_JoystickEventsEnabled @@ -1016,6 +1105,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetJoystickEventsEnabled(bool enabled); * * \returns true if joystick events are being processed, 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_SetJoystickEventsEnabled @@ -1028,6 +1119,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_JoystickEventsEnabled(void); * This is called automatically by the event loop if any joystick events are * enabled. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC void SDLCALL SDL_UpdateJoysticks(void); @@ -1050,6 +1143,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UpdateJoysticks(void); * \returns a 16-bit signed integer representing the current position of the * axis 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. * * \sa SDL_GetNumJoystickAxes @@ -1068,6 +1163,8 @@ extern SDL_DECLSPEC Sint16 SDLCALL SDL_GetJoystickAxis(SDL_Joystick *joystick, i * \param state upon return, the initial value is supplied here. * \returns true if this axis has any initial value, or false if not. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state); @@ -1087,6 +1184,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickAxisInitialState(SDL_Joystick *j * \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_GetNumJoystickBalls @@ -1102,6 +1201,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickBall(SDL_Joystick *joystick, int * \param hat the hat index to get the state from; indices start at index 0. * \returns the current hat position. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetNumJoystickHats @@ -1126,6 +1227,8 @@ extern SDL_DECLSPEC Uint8 SDLCALL SDL_GetJoystickHat(SDL_Joystick *joystick, int * index 0. * \returns true if the button is pressed, 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_GetNumJoystickButtons @@ -1149,6 +1252,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetJoystickButton(SDL_Joystick *joystick, i * \param duration_ms the duration of the rumble effect, in milliseconds. * \returns true, or false if rumble isn't supported on this joystick. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystick(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); @@ -1176,6 +1281,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystick(SDL_Joystick *joystick, Uint * \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_RumbleJoystick @@ -1198,6 +1305,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RumbleJoystickTriggers(SDL_Joystick *joysti * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue); @@ -1211,6 +1320,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetJoystickLED(SDL_Joystick *joystick, Uint * \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. */ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, const void *data, int size); @@ -1220,6 +1331,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, * * \param joystick the joystick device to close. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_OpenJoystick @@ -1234,6 +1347,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseJoystick(SDL_Joystick *joystick); * `SDL_JOYSTICK_CONNECTION_INVALID` 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_JoystickConnectionState SDLCALL SDL_GetJoystickConnectionState(SDL_Joystick *joystick); @@ -1255,6 +1370,8 @@ extern SDL_DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetJoystickConnectio * \returns the current battery state or `SDL_POWERSTATE_ERROR` 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_PowerState SDLCALL SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent); diff --git a/include/SDL3/SDL_keyboard.h b/include/SDL3/SDL_keyboard.h index afa77b6c2c..eb984de585 100644 --- a/include/SDL3/SDL_keyboard.h +++ b/include/SDL3/SDL_keyboard.h @@ -174,8 +174,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetKeyboard(void); /** * Get the current key modifier state for the keyboard. * - * \returns an OR'd combination of the modifier keys for the keyboard. See - * SDL_Keymod for details. + * \returns an OR'd combination of the modifier keys for the keyboard. * * \threadsafety It is safe to call this function from any thread. * diff --git a/include/SDL3/SDL_log.h b/include/SDL3/SDL_log.h index 2019c3b462..aceaabe77e 100644 --- a/include/SDL3/SDL_log.h +++ b/include/SDL3/SDL_log.h @@ -266,7 +266,6 @@ extern SDL_DECLSPEC void SDLCALL SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fm * \sa SDL_LogInfo * \sa SDL_LogMessage * \sa SDL_LogMessageV - * \sa SDL_LogTrace * \sa SDL_LogVerbose * \sa SDL_LogWarn */ diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h index f9d6e9e308..6ef9854d39 100644 --- a/include/SDL3/SDL_pixels.h +++ b/include/SDL3/SDL_pixels.h @@ -1096,7 +1096,7 @@ typedef enum SDL_Colorspace SDL_CHROMA_LOCATION_LEFT), */ SDL_COLORSPACE_RGB_DEFAULT = SDL_COLORSPACE_SRGB, /**< The default colorspace for RGB surfaces if no colorspace is specified */ - SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_JPEG /**< The default colorspace for YUV surfaces if no colorspace is specified */ + SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_BT601_LIMITED /**< The default colorspace for YUV surfaces if no colorspace is specified */ } SDL_Colorspace; /** diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 135fd42437..23adec34b2 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -74,6 +74,13 @@ extern "C" { */ #define SDL_SOFTWARE_RENDERER "software" +/** + * The name of the GPU renderer. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_GPU_RENDERER "gpu" + /** * Vertex structure. * @@ -122,7 +129,7 @@ typedef enum SDL_RendererLogicalPresentation { SDL_LOGICAL_PRESENTATION_DISABLED, /**< There is no logical size in effect */ SDL_LOGICAL_PRESENTATION_STRETCH, /**< The rendered content is stretched to the output resolution */ - SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with black bars */ + SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with the clear color */ SDL_LOGICAL_PRESENTATION_OVERSCAN, /**< The rendered content is fit to the smallest dimension and the other dimension extends beyond the output bounds */ SDL_LOGICAL_PRESENTATION_INTEGER_SCALE /**< The rendered content is scaled up by integer multiples to fit the output resolution */ } SDL_RendererLogicalPresentation; @@ -285,6 +292,8 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window * * With the SDL GPU renderer (since SDL 3.4.0): * + * - `SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER`: the device to use with the + * renderer, optional. * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN`: the app is able to * provide SPIR-V shaders to SDL_GPURenderState, optional. * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN`: the app is able to @@ -328,6 +337,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ #define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "SDL.renderer.create.surface" #define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.create.output_colorspace" #define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER "SDL.renderer.create.present_vsync" +#define SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER "SDL.renderer.create.gpu.device" #define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN "SDL.renderer.create.gpu.shaders_spirv" #define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN "SDL.renderer.create.gpu.shaders_dxil" #define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN "SDL.renderer.create.gpu.shaders_msl" @@ -339,35 +349,51 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ #define SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.present_queue_family_index" /** - * Create a 2D GPU rendering context for a window, with support for the - * specified shader format. + * Create a 2D GPU rendering context. * - * This is a convenience function to create a SDL GPU backed renderer, - * intended to be used with SDL_GPURenderState. The resulting renderer will - * support shaders in one of the specified shader formats. + * The GPU device to use is passed in as a parameter. If this is NULL, then a + * device will be created normally and can be retrieved using + * SDL_GetGPURendererDevice(). * - * If no available GPU driver supports any of the specified shader formats, - * this function will fail. + * The window to use is passed in as a parameter. If this is NULL, then this + * will become an offscreen renderer. In that case, you should call + * SDL_SetRenderTarget() to setup rendering to a texture, and then call + * SDL_RenderPresent() normally to complete drawing a frame. * - * \param window the window where rendering is displayed. - * \param format_flags a bitflag indicating which shader formats the app is - * able to provide. - * \param device a pointer filled with the associated GPU device, or NULL on - * error. + * \param device the GPU device to use with the renderer, or NULL to create a + * device. + * \param window the window where rendering is displayed, or NULL to create an + * offscreen renderer. * \returns a valid rendering context or NULL if there was an error; call * SDL_GetError() for more information. * - * \threadsafety This function should only be called on the main thread. + * \threadsafety If this function is called with a valid GPU device, it should + * be called on the thread that created the device. If this + * function is called with a valid window, it should be called + * on the thread that created the window. * * \since This function is available since SDL 3.4.0. * * \sa SDL_CreateRendererWithProperties - * \sa SDL_GetGPUShaderFormats + * \sa SDL_GetGPURendererDevice * \sa SDL_CreateGPUShader * \sa SDL_CreateGPURenderState - * \sa SDL_SetRenderGPUState + * \sa SDL_SetGPURenderState */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateGPURenderer(SDL_Window *window, SDL_GPUShaderFormat format_flags, SDL_GPUDevice **device); +extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateGPURenderer(SDL_GPUDevice *device, SDL_Window *window); + +/** + * Return the GPU device used by a renderer. + * + * \param renderer the rendering context. + * \returns the GPU device used by the renderer, or NULL if the renderer is + * not a GPU renderer; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_GetGPURendererDevice(SDL_Renderer *renderer); /** * Create a 2D software rendering context for a surface. @@ -382,7 +408,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateGPURenderer(SDL_Window *win * \returns a valid rendering context or NULL if there was an error; call * SDL_GetError() for more information. * - * \threadsafety This function should only be called on the main thread. + * \threadsafety It is safe to call this function from any thread. * * \since This function is available since SDL 3.2.0. * @@ -660,6 +686,9 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende * pixels, required * - `SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER`: the height of the texture in * pixels, required + * - `SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER`: an SDL_Palette to use with + * palettized texture formats. This can be set later with + * SDL_SetTexturePalette() * - `SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT`: for HDR10 and floating * point textures, this defines the value of 100% diffuse white, with higher * values being displayed in the High Dynamic Range headroom. This defaults @@ -759,6 +788,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Re #define SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER "SDL.texture.create.access" #define SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER "SDL.texture.create.width" #define SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER "SDL.texture.create.height" +#define SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER "SDL.texture.create.palette" #define SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT "SDL.texture.create.SDR_white_point" #define SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT "SDL.texture.create.HDR_headroom" #define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER "SDL.texture.create.d3d11.texture" @@ -856,6 +886,17 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Re * - `SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER`: the GLenum for the * texture target (`GL_TEXTURE_2D`, `GL_TEXTURE_EXTERNAL_OES`, etc) * + * With the gpu renderer: + * + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER`: the SDL_GPUTexture associated + * with the texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER`: the SDL_GPUTexture associated + * with the UV plane of an NV12 texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER`: the SDL_GPUTexture associated + * with the U plane of a YUV texture + * - `SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER`: the SDL_GPUTexture associated + * with the V plane of a YUV texture + * * \param texture the texture to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -892,6 +933,10 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetTextureProperties(SDL_Textur #define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.opengles2.texture_v" #define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER "SDL.texture.opengles2.target" #define SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER "SDL.texture.vulkan.texture" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER "SDL.texture.gpu.texture" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER "SDL.texture.gpu.texture_uv" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER "SDL.texture.gpu.texture_u" +#define SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER "SDL.texture.gpu.texture_v" /** * Get the renderer that created an SDL_Texture. @@ -923,6 +968,43 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_GetRendererFromTexture(SDL_Textur */ extern SDL_DECLSPEC bool SDLCALL SDL_GetTextureSize(SDL_Texture *texture, float *w, float *h); +/** + * Set the palette used by a texture. + * + * Setting the palette keeps an internal reference to the palette, which can + * be safely destroyed afterwards. + * + * A single palette can be shared with many textures. + * + * \param texture the texture to update. + * \param palette the SDL_Palette structure to use. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_CreatePalette + * \sa SDL_GetTexturePalette + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetTexturePalette(SDL_Texture *texture, SDL_Palette *palette); + +/** + * Get the palette used by a texture. + * + * \param texture the texture to query. + * \returns a pointer to the palette used by the texture, or NULL if there is + * no palette used. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetTexturePalette + */ +extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetTexturePalette(SDL_Texture *texture); + /** * Set an additional color value multiplied into render copy operations. * @@ -1152,6 +1234,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetTextureBlendMode(SDL_Texture *texture, S * The default texture scale mode is SDL_SCALEMODE_LINEAR. * * If the scale mode is not supported, the closest supported mode is chosen. + * Palettized textures will use SDL_SCALEMODE_PIXELART instead of + * SDL_SCALEMODE_LINEAR. * * \param texture the texture to update. * \param scaleMode the SDL_ScaleMode to use for texture scaling. @@ -1445,14 +1529,6 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *rend * specific dimensions but to make fonts look sharp, the app turns off logical * presentation while drawing text, for example. * - * For the renderer's window, letterboxing is drawn into the framebuffer if - * logical presentation is enabled during SDL_RenderPresent; be sure to - * reenable it before presenting if you were toggling it, otherwise the - * letterbox areas might have artifacts from previous frames (or artifacts - * from external overlays, etc). Letterboxing is never drawn into texture - * render targets; be sure to call SDL_RenderClear() before drawing into the - * texture so the letterboxing areas are cleared, if appropriate. - * * You can convert coordinates in an event into rendering coordinates using * SDL_ConvertEventToRenderCoordinates(). * @@ -1477,15 +1553,16 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer * * Get device independent resolution and presentation mode for rendering. * * This function gets the width and height of the logical rendering output, or - * the output size in pixels if a logical resolution is not enabled. + * 0 if a logical resolution is not enabled. * * Each render target has its own logical presentation state. This function * gets the state for the current render target. * * \param renderer the rendering context. - * \param w an int to be filled with the width. - * \param h an int to be filled with the height. - * \param mode the presentation mode used. + * \param w an int filled with the logical presentation width. + * \param h an int filled with the logical presentation height. + * \param mode a variable filled with the logical presentation mode being + * used. * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -2720,8 +2797,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderVSync(SDL_Renderer *renderer, int * break. If the text goes out of the window, it's gone. * * For serious text rendering, there are several good options, such as - * [SDL_ttf](https://wiki.libsdl.org/SDL3_ttf/FrontPage) - * , stb_truetype, or other external libraries. + * SDL_ttf, stb_truetype, or other external libraries. * * On first use, this will create an internal texture for rendering glyphs. * This texture will live until the renderer is destroyed. @@ -2838,7 +2914,7 @@ typedef struct SDL_GPURenderStateCreateInfo * * \sa SDL_CreateGPURenderState * \sa SDL_SetGPURenderStateFragmentUniforms - * \sa SDL_SetRenderGPUState + * \sa SDL_SetGPURenderState * \sa SDL_DestroyGPURenderState */ typedef struct SDL_GPURenderState SDL_GPURenderState; @@ -2857,7 +2933,7 @@ typedef struct SDL_GPURenderState SDL_GPURenderState; * \since This function is available since SDL 3.4.0. * * \sa SDL_SetGPURenderStateFragmentUniforms - * \sa SDL_SetRenderGPUState + * \sa SDL_SetGPURenderState * \sa SDL_DestroyGPURenderState */ extern SDL_DECLSPEC SDL_GPURenderState * SDLCALL SDL_CreateGPURenderState(SDL_Renderer *renderer, SDL_GPURenderStateCreateInfo *createinfo); @@ -2898,7 +2974,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderStateFragmentUniforms(SDL_GPURe * * \since This function is available since SDL 3.4.0. */ -extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUState(SDL_Renderer *renderer, SDL_GPURenderState *state); +extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderState(SDL_Renderer *renderer, SDL_GPURenderState *state); /** * Destroy custom GPU render state. diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index fa8c9a50e8..00b024a86b 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -49,10 +49,30 @@ #include #include -#include #include #include +/* Most everything except Visual Studio 2008 and earlier has stdint.h now */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif +#endif +#else +#include +#endif + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ defined(SDL_INCLUDE_INTTYPES_H) #include diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h index 445142fee2..ad57a4d910 100644 --- a/include/SDL3/SDL_surface.h +++ b/include/SDL3/SDL_surface.h @@ -86,7 +86,7 @@ typedef enum SDL_ScaleMode SDL_SCALEMODE_INVALID = -1, SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */ SDL_SCALEMODE_LINEAR, /**< linear filtering */ - SDL_SCALEMODE_PIXELART /**< nearest pixel sampling with improved scaling for pixel art */ + SDL_SCALEMODE_PIXELART /**< nearest pixel sampling with improved scaling for pixel art, available since SDL 3.4.0 */ } SDL_ScaleMode; /** @@ -327,6 +327,9 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface * /** * Set the palette used by a surface. * + * Setting the palette keeps an internal reference to the palette, which can + * be safely destroyed afterwards. + * * A single palette can be shared with many surfaces. * * \param surface the SDL_Surface structure to update. diff --git a/include/SDL3/SDL_timer.h b/include/SDL3/SDL_timer.h index cee14c131e..490d13562f 100644 --- a/include/SDL3/SDL_timer.h +++ b/include/SDL3/SDL_timer.h @@ -34,7 +34,7 @@ * This category covers measuring time elapsed (SDL_GetTicks(), * SDL_GetPerformanceCounter()), putting a thread to sleep for a certain * amount of time (SDL_Delay(), SDL_DelayNS(), SDL_DelayPrecise()), and firing - * a callback function after a certain amount of time has elasped + * a callback function after a certain amount of time has elapsed * (SDL_AddTimer(), etc). * * There are also useful macros to convert between time units, like diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index e78ba111df..3adebc29a1 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -226,6 +226,8 @@ typedef Uint64 SDL_WindowFlags; * SDL_WINDOWPOS_UNDEFINED or SDL_WINDOWPOS_UNDEFINED_DISPLAY. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000u @@ -238,6 +240,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the SDL_DisplayID of the display to use. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) (SDL_WINDOWPOS_UNDEFINED_MASK|(X)) @@ -247,6 +251,8 @@ typedef Uint64 SDL_WindowFlags; * This always uses the primary display. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_DISPLAY(0) @@ -256,6 +262,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the window position value. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_ISUNDEFINED(X) (((X)&0xFFFF0000) == SDL_WINDOWPOS_UNDEFINED_MASK) @@ -266,6 +274,8 @@ typedef Uint64 SDL_WindowFlags; * SDL_WINDOWPOS_CENTERED or SDL_WINDOWPOS_CENTERED_DISPLAY. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED_MASK 0x2FFF0000u @@ -278,6 +288,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the SDL_DisplayID of the display to use. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED_DISPLAY(X) (SDL_WINDOWPOS_CENTERED_MASK|(X)) @@ -287,6 +299,8 @@ typedef Uint64 SDL_WindowFlags; * This always uses the primary display. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_SetWindowPosition */ #define SDL_WINDOWPOS_CENTERED SDL_WINDOWPOS_CENTERED_DISPLAY(0) @@ -296,6 +310,8 @@ typedef Uint64 SDL_WindowFlags; * \param X the window position value. * * \since This macro is available since SDL 3.2.0. + * + * \sa SDL_GetWindowPosition */ #define SDL_WINDOWPOS_ISCENTERED(X) \ (((X)&0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK) @@ -1337,6 +1353,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * * - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING`: the id given to the * canvas element. This should start with a '#' sign + * - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN`: true to make + * the canvas element fill the entire document. Resize events will be + * generated as the browser window is resized, as that will adjust the + * canvas size as well. The canvas will cover anything else on the page, + * including any controls provided by Emscripten in its generated HTML file. + * Often times this is desirable for a browser-based game, but it means + * several things that we expect of an SDL window on other platforms might + * not work as expected, such as minimum window sizes and aspect ratios. + * Default false. * - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: override the * binding element for keyboard inputs for this canvas. The variable can be * one of: @@ -1410,6 +1435,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop #define SDL_PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER "SDL.window.create.win32.pixel_format_hwnd" #define SDL_PROP_WINDOW_CREATE_X11_WINDOW_NUMBER "SDL.window.create.x11.window" #define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.create.emscripten.canvas_id" +#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN "SDL.window.create.emscripten.fill_document" #define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.create.emscripten.keyboard_element" /** @@ -1579,6 +1605,9 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window) * * - `SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING`: the id the canvas element * will have + * - `SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN`: true if the canvas is + * set to consume the entire browser window, bypassing some SDL window + * functionality. * - `SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: the keyboard * element that associates keyboard events to this window * @@ -1628,6 +1657,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window #define SDL_PROP_WINDOW_X11_SCREEN_NUMBER "SDL.window.x11.screen" #define SDL_PROP_WINDOW_X11_WINDOW_NUMBER "SDL.window.x11.window" #define SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.emscripten.canvas_id" +#define SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN "SDL.window.emscripten.fill_document" #define SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.emscripten.keyboard_element" /** diff --git a/include/build_config/SDL_build_config_ios.h b/include/build_config/SDL_build_config_ios.h index f278556a5f..2573257196 100644 --- a/include/build_config/SDL_build_config_ios.h +++ b/include/build_config/SDL_build_config_ios.h @@ -214,7 +214,7 @@ #define SDL_FSOPS_POSIX 1 /* enable camera support */ -#ifndef SDL_PLATFORM_TVOS +#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) #define SDL_CAMERA_DRIVER_COREMEDIA 1 #endif diff --git a/src/SDL.c b/src/SDL.c index 0a4e7993e5..81bc41097a 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -148,7 +148,7 @@ static bool SDL_ValidMetadataProperty(const char *name) bool SDL_SetAppMetadataProperty(const char *name, const char *value) { - if (!SDL_ValidMetadataProperty(name)) { + CHECK_PARAM(!SDL_ValidMetadataProperty(name)) { return SDL_InvalidParamError("name"); } @@ -157,7 +157,7 @@ bool SDL_SetAppMetadataProperty(const char *name, const char *value) const char *SDL_GetAppMetadataProperty(const char *name) { - if (!SDL_ValidMetadataProperty(name)) { + CHECK_PARAM(!SDL_ValidMetadataProperty(name)) { SDL_InvalidParamError("name"); return NULL; } @@ -845,9 +845,7 @@ SDL_Sandbox SDL_GetSandbox(void) #ifdef SDL_PLATFORM_WIN32 -#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB) -// FIXME: Still need to include DllMain() on Watcom C ? - +#if !defined(HAVE_LIBC) && !defined(SDL_STATIC_LIB) BOOL APIENTRY MINGW32_FORCEALIGN _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { diff --git a/src/SDL_assert.c b/src/SDL_assert.c index 2440d04b1e..59f36398af 100644 --- a/src/SDL_assert.c +++ b/src/SDL_assert.c @@ -120,23 +120,10 @@ static void SDL_GenerateAssertionReport(void) } } -/* This is not declared in any header, although it is shared between some - parts of SDL, because we don't want anything calling it without an - extremely good reason. */ -#ifdef __WATCOMC__ -extern void SDL_ExitProcess(int exitcode); -#pragma aux SDL_ExitProcess aborts; -#endif -extern SDL_NORETURN void SDL_ExitProcess(int exitcode); - -#ifdef __WATCOMC__ -static void SDL_AbortAssertion(void); -#pragma aux SDL_AbortAssertion aborts; -#endif static SDL_NORETURN void SDL_AbortAssertion(void) { SDL_Quit(); - SDL_ExitProcess(42); + SDL_abort(); } static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, void *userdata) @@ -361,7 +348,7 @@ SDL_AssertState SDL_ReportAssertion(SDL_AssertData *data, const char *func, cons if (assertion_running == 2) { SDL_AbortAssertion(); } else if (assertion_running == 3) { // Abort asserted! - SDL_ExitProcess(42); + SDL_abort(); } else { while (1) { // do nothing but spin; what else can you do?! } diff --git a/src/SDL_hashtable.c b/src/SDL_hashtable.c index 3124b41a8a..367b8e4681 100644 --- a/src/SDL_hashtable.c +++ b/src/SDL_hashtable.c @@ -292,7 +292,7 @@ static bool maybe_resize(SDL_HashTable *ht) bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace) { - if (!table) { + CHECK_PARAM(!table) { return SDL_InvalidParamError("table"); } @@ -338,7 +338,7 @@ bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void * bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value) { - if (!table) { + CHECK_PARAM(!table) { if (value) { *value = NULL; } @@ -364,7 +364,7 @@ bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key) { - if (!table) { + CHECK_PARAM(!table) { return SDL_InvalidParamError("table"); } @@ -384,9 +384,10 @@ bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key) bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata) { - if (!table) { + CHECK_PARAM(!table) { return SDL_InvalidParamError("table"); - } else if (!callback) { + } + CHECK_PARAM(!callback) { return SDL_InvalidParamError("callback"); } @@ -410,7 +411,7 @@ bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallba bool SDL_HashTableEmpty(SDL_HashTable *table) { - if (!table) { + CHECK_PARAM(!table) { return SDL_InvalidParamError("table"); } diff --git a/src/SDL_hints.c b/src/SDL_hints.c index 786d654a28..10a899f267 100644 --- a/src/SDL_hints.c +++ b/src/SDL_hints.c @@ -104,7 +104,7 @@ static const char *GetHintEnvironmentVariable(const char *name) bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriority priority) { - if (!name || !*name) { + CHECK_PARAM(!name || !*name) { return SDL_InvalidParamError("name"); } @@ -165,7 +165,7 @@ bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriori bool SDL_ResetHint(const char *name) { - if (!name || !*name) { + CHECK_PARAM(!name || !*name) { return SDL_InvalidParamError("name"); } @@ -316,9 +316,10 @@ bool SDL_GetHintBoolean(const char *name, bool default_value) bool SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) { - if (!name || !*name) { + CHECK_PARAM(!name || !*name) { return SDL_InvalidParamError("name"); - } else if (!callback) { + } + CHECK_PARAM(!callback) { return SDL_InvalidParamError("callback"); } diff --git a/src/SDL_internal.h b/src/SDL_internal.h index 0d5d203f8f..e891bb5095 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -266,12 +266,43 @@ extern "C" { #include "SDL_utils_c.h" #include "SDL_hashtable.h" +/* SDL_ExitProcess is not declared in any public header, although + it is shared between some parts of SDL, because we don't want + anything calling it without an extremely good reason. */ +extern SDL_NORETURN void SDL_ExitProcess(int exitcode); + +#ifdef HAVE_LIBC +#define SDL_abort() abort() +#else +#define SDL_abort() do { \ + SDL_TriggerBreakpoint(); \ + SDL_ExitProcess(42); \ + } while (0) +#endif + #define PUSH_SDL_ERROR() \ { char *_error = SDL_strdup(SDL_GetError()); #define POP_SDL_ERROR() \ SDL_SetError("%s", _error); SDL_free(_error); } +#if defined(SDL_DISABLE_INVALID_PARAMS) +#ifdef DEBUG +// If you define SDL_DISABLE_INVALID_PARAMS, you're promising that you'll +// never pass an invalid parameter to SDL, since it may crash or lead to +// hard to diagnose bugs. Let's assert that this is true in debug builds. +#define OBJECT_VALIDATION_REQUIRED +#define CHECK_PARAM(invalid) SDL_assert_always(!(invalid)); if (false) +#else +#define CHECK_PARAM(invalid) if (false) +#endif +#elif defined(SDL_ASSERT_INVALID_PARAMS) +#define OBJECT_VALIDATION_REQUIRED +#define CHECK_PARAM(invalid) SDL_assert_always(!(invalid)); if (invalid) +#else +#define CHECK_PARAM(invalid) if (invalid) +#endif + // Do any initialization that needs to happen before threads are started extern void SDL_InitMainThread(void); diff --git a/src/SDL_log.c b/src/SDL_log.c index 2e159fba7b..fafc45b210 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -392,6 +392,9 @@ void SDL_ResetLogPriorities(void) SDL_LockMutex(SDL_log_lock); { + const char *env = SDL_getenv("DEBUG_INVOCATION"); + bool debug = (env && *env && *env != '0'); + CleanupLogPriorities(); SDL_log_default_priority = SDL_LOG_PRIORITY_INVALID; @@ -414,7 +417,11 @@ void SDL_ResetLogPriorities(void) switch (i) { case SDL_LOG_CATEGORY_APPLICATION: - SDL_log_priorities[i] = SDL_LOG_PRIORITY_INFO; + if (debug) { + SDL_log_priorities[i] = SDL_LOG_PRIORITY_DEBUG; + } else { + SDL_log_priorities[i] = SDL_LOG_PRIORITY_INFO; + } break; case SDL_LOG_CATEGORY_ASSERT: SDL_log_priorities[i] = SDL_LOG_PRIORITY_WARN; @@ -423,7 +430,11 @@ void SDL_ResetLogPriorities(void) SDL_log_priorities[i] = SDL_LOG_PRIORITY_VERBOSE; break; default: - SDL_log_priorities[i] = SDL_LOG_PRIORITY_ERROR; + if (debug) { + SDL_log_priorities[i] = SDL_LOG_PRIORITY_DEBUG; + } else { + SDL_log_priorities[i] = SDL_LOG_PRIORITY_ERROR; + } break; } } @@ -467,7 +478,7 @@ bool SDL_SetLogPriorityPrefix(SDL_LogPriority priority, const char *prefix) { char *prefix_copy; - if (priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) { + CHECK_PARAM(priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) { return SDL_InvalidParamError("priority"); } diff --git a/src/SDL_properties.c b/src/SDL_properties.c index 166ea0f918..dc3053f820 100644 --- a/src/SDL_properties.c +++ b/src/SDL_properties.c @@ -250,10 +250,10 @@ static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) { - if (!src) { + CHECK_PARAM(!src) { return SDL_InvalidParamError("src"); } - if (!dst) { + CHECK_PARAM(!dst) { return SDL_InvalidParamError("dst"); } @@ -261,11 +261,11 @@ bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) SDL_Properties *dst_properties = NULL; SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties); - if (!src_properties) { + CHECK_PARAM(!src_properties) { return SDL_InvalidParamError("src"); } SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); - if (!dst_properties) { + CHECK_PARAM(!dst_properties) { return SDL_InvalidParamError("dst"); } @@ -287,12 +287,12 @@ bool SDL_LockProperties(SDL_PropertiesID props) { SDL_Properties *properties = NULL; - if (!props) { + CHECK_PARAM(!props) { return SDL_InvalidParamError("props"); } SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); - if (!properties) { + CHECK_PARAM(!properties) { return SDL_InvalidParamError("props"); } @@ -321,17 +321,17 @@ static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL SDL_Properties *properties = NULL; bool result = true; - if (!props) { + CHECK_PARAM(!props) { SDL_FreePropertyWithCleanup(NULL, property, NULL, true); return SDL_InvalidParamError("props"); } - if (!name || !*name) { + CHECK_PARAM(!name || !*name) { SDL_FreePropertyWithCleanup(NULL, property, NULL, true); return SDL_InvalidParamError("name"); } SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); - if (!properties) { + CHECK_PARAM(!properties) { SDL_FreePropertyWithCleanup(NULL, property, NULL, true); return SDL_InvalidParamError("props"); } @@ -755,15 +755,15 @@ bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCall { SDL_Properties *properties = NULL; - if (!props) { + CHECK_PARAM(!props) { return SDL_InvalidParamError("props"); } - if (!callback) { + CHECK_PARAM(!callback) { return SDL_InvalidParamError("callback"); } SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); - if (!properties) { + CHECK_PARAM(!properties) { return SDL_InvalidParamError("props"); } diff --git a/src/SDL_utils.c b/src/SDL_utils.c index 47fa28c06d..097213c9f9 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -137,6 +137,30 @@ Uint32 SDL_GetNextObjectID(void) static SDL_InitState SDL_objects_init; static SDL_HashTable *SDL_objects; +bool SDL_object_validation = true; + +static void SDLCALL SDL_InvalidParamChecksChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + bool validation_enabled = true; + +#ifndef OBJECT_VALIDATION_REQUIRED + if (hint) { + switch (*hint) { + case '0': + case '1': + validation_enabled = false; + break; + case '2': + validation_enabled = true; + break; + default: + break; + } + } +#endif // !OBJECT_VALIDATION_REQUIRED + + SDL_object_validation = validation_enabled; +} static Uint32 SDLCALL SDL_HashObject(void *unused, const void *key) { @@ -159,6 +183,7 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid) if (!initialized) { return; } + SDL_AddHintCallback(SDL_HINT_INVALID_PARAM_CHECKS, SDL_InvalidParamChecksChanged, NULL); } if (valid) { @@ -168,12 +193,8 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid) } } -bool SDL_ObjectValid(void *object, SDL_ObjectType type) +bool SDL_FindObject(void *object, SDL_ObjectType type) { - if (!object) { - return false; - } - const void *object_type; if (!SDL_FindInHashTable(SDL_objects, object, &object_type)) { return false; @@ -242,6 +263,7 @@ void SDL_SetObjectsInvalid(void) SDL_DestroyHashTable(SDL_objects); SDL_objects = NULL; SDL_SetInitialized(&SDL_objects_init, false); + SDL_RemoveHintCallback(SDL_HINT_INVALID_PARAM_CHECKS, SDL_InvalidParamChecksChanged, NULL); } } diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h index b70b64e963..93d1abe47c 100644 --- a/src/SDL_utils_c.h +++ b/src/SDL_utils_c.h @@ -67,10 +67,25 @@ typedef enum extern Uint32 SDL_GetNextObjectID(void); extern void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid); -extern bool SDL_ObjectValid(void *object, SDL_ObjectType type); +extern bool SDL_FindObject(void *object, SDL_ObjectType type); extern int SDL_GetObjects(SDL_ObjectType type, void **objects, int count); extern void SDL_SetObjectsInvalid(void); +extern bool SDL_object_validation; + +SDL_FORCE_INLINE bool SDL_ObjectValid(void *object, SDL_ObjectType type) +{ + if (!object) { + return false; + } + + if (!SDL_object_validation) { + return true; + } + + return SDL_FindObject(object, type); +} + extern const char *SDL_GetPersistentString(const char *string); extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name); diff --git a/src/atomic/SDL_atomic.c b/src/atomic/SDL_atomic.c index c51ba710a5..9286d63b18 100644 --- a/src/atomic/SDL_atomic.c +++ b/src/atomic/SDL_atomic.c @@ -48,35 +48,6 @@ #endif #endif -/* *INDENT-OFF* */ // clang-format off -#if defined(__WATCOMC__) && defined(__386__) -SDL_COMPILE_TIME_ASSERT(intsize, 4==sizeof(int)); -#define HAVE_WATCOM_ATOMICS -extern __inline int _SDL_xchg_watcom(volatile int *a, int v); -#pragma aux _SDL_xchg_watcom = \ - "lock xchg [ecx], eax" \ - parm [ecx] [eax] \ - value [eax] \ - modify exact [eax]; - -extern __inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval); -#pragma aux _SDL_cmpxchg_watcom = \ - "lock cmpxchg [edx], ecx" \ - "setz al" \ - parm [edx] [ecx] [eax] \ - value [al] \ - modify exact [eax]; - -extern __inline int _SDL_xadd_watcom(volatile int *a, int v); -#pragma aux _SDL_xadd_watcom = \ - "lock xadd [ecx], eax" \ - parm [ecx] [eax] \ - value [eax] \ - modify exact [eax]; - -#endif // __WATCOMC__ && __386__ -/* *INDENT-ON* */ // clang-format on - /* If any of the operations are not provided then we must emulate some of them. That means we need a nice implementation of spin locks @@ -100,7 +71,7 @@ extern __inline int _SDL_xadd_watcom(volatile int *a, int v); Contributed by Bob Pendleton, bob@pendleton.com */ -#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_SOLARIS) && !defined(HAVE_WATCOM_ATOMICS) +#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_SOLARIS) #define EMULATE_CAS 1 #endif @@ -127,8 +98,6 @@ bool SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value)); return _InterlockedCompareExchange((long *)&a->value, (long)newval, (long)oldval) == (long)oldval; -#elif defined(HAVE_WATCOM_ATOMICS) - return _SDL_cmpxchg_watcom((volatile int *)&a->value, newval, oldval); #elif defined(HAVE_GCC_ATOMICS) return __sync_bool_compare_and_swap(&a->value, oldval, newval); #elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics. @@ -157,9 +126,6 @@ bool SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value)); return _InterlockedCompareExchange((long *)&a->value, (long)newval, (long)oldval) == (long)oldval; -#elif defined(HAVE_WATCOM_ATOMICS) - SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(int) == sizeof(a->value)); - return _SDL_cmpxchg_watcom((volatile int *)&a->value, (int)newval, (int)oldval); #elif defined(HAVE_GCC_ATOMICS) return __sync_bool_compare_and_swap(&a->value, oldval, newval); #elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics. @@ -187,8 +153,6 @@ bool SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval) { #ifdef HAVE_MSC_ATOMICS return _InterlockedCompareExchangePointer(a, newval, oldval) == oldval; -#elif defined(HAVE_WATCOM_ATOMICS) - return _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval); #elif defined(HAVE_GCC_ATOMICS) return __sync_bool_compare_and_swap(a, oldval, newval); #elif defined(SDL_PLATFORM_MACOS) && defined(__LP64__) // this is deprecated in 10.12 sdk; favor gcc atomics. @@ -218,8 +182,6 @@ int SDL_SetAtomicInt(SDL_AtomicInt *a, int v) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_set, sizeof(long) == sizeof(a->value)); return _InterlockedExchange((long *)&a->value, v); -#elif defined(HAVE_WATCOM_ATOMICS) - return _SDL_xchg_watcom(&a->value, v); #elif defined(HAVE_GCC_ATOMICS) return __sync_lock_test_and_set(&a->value, v); #elif defined(SDL_PLATFORM_SOLARIS) @@ -239,8 +201,6 @@ Uint32 SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_set, sizeof(long) == sizeof(a->value)); return _InterlockedExchange((long *)&a->value, v); -#elif defined(HAVE_WATCOM_ATOMICS) - return _SDL_xchg_watcom(&a->value, v); #elif defined(HAVE_GCC_ATOMICS) return __sync_lock_test_and_set(&a->value, v); #elif defined(SDL_PLATFORM_SOLARIS) @@ -259,8 +219,6 @@ void *SDL_SetAtomicPointer(void **a, void *v) { #ifdef HAVE_MSC_ATOMICS return _InterlockedExchangePointer(a, v); -#elif defined(HAVE_WATCOM_ATOMICS) - return (void *)_SDL_xchg_watcom((int *)a, (long)v); #elif defined(HAVE_GCC_ATOMICS) return __sync_lock_test_and_set(a, v); #elif defined(SDL_PLATFORM_SOLARIS) @@ -279,9 +237,6 @@ int SDL_AddAtomicInt(SDL_AtomicInt *a, int v) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(long) == sizeof(a->value)); return _InterlockedExchangeAdd((long *)&a->value, v); -#elif defined(HAVE_WATCOM_ATOMICS) - SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(int) == sizeof(a->value)); - return _SDL_xadd_watcom((volatile int *)&a->value, v); #elif defined(HAVE_GCC_ATOMICS) return __sync_fetch_and_add(&a->value, v); #elif defined(SDL_PLATFORM_SOLARIS) @@ -303,9 +258,6 @@ Uint32 SDL_AddAtomicU32(SDL_AtomicU32 *a, int v) #ifdef HAVE_MSC_ATOMICS SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(long) == sizeof(a->value)); return (Uint32)_InterlockedExchangeAdd((long *)&a->value, v); -#elif defined(HAVE_WATCOM_ATOMICS) - SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(int) == sizeof(a->value)); - return (Uint32)_SDL_xadd_watcom((volatile int *)&a->value, v); #elif defined(HAVE_GCC_ATOMICS) return __sync_fetch_and_add(&a->value, v); #elif defined(SDL_PLATFORM_SOLARIS) @@ -329,8 +281,6 @@ int SDL_GetAtomicInt(SDL_AtomicInt *a) #elif defined(HAVE_MSC_ATOMICS) SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(long) == sizeof(a->value)); return _InterlockedOr((long *)&a->value, 0); -#elif defined(HAVE_WATCOM_ATOMICS) - return _SDL_xadd_watcom(&a->value, 0); #elif defined(HAVE_GCC_ATOMICS) return __sync_or_and_fetch(&a->value, 0); #elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics. @@ -353,9 +303,6 @@ Uint32 SDL_GetAtomicU32(SDL_AtomicU32 *a) #elif defined(HAVE_MSC_ATOMICS) SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(long) == sizeof(a->value)); return (Uint32)_InterlockedOr((long *)&a->value, 0); -#elif defined(HAVE_WATCOM_ATOMICS) - SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(int) == sizeof(a->value)); - return (Uint32)_SDL_xadd_watcom((volatile int *)&a->value, 0); #elif defined(HAVE_GCC_ATOMICS) return __sync_or_and_fetch(&a->value, 0); #elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics. diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index 8e35c8a74b..75bacda7c9 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -44,18 +44,6 @@ #include #endif -/* *INDENT-OFF* */ // clang-format off -#if defined(__WATCOMC__) && defined(__386__) -SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock)); -extern __inline int _SDL_xchg_watcom(volatile int *a, int v); -#pragma aux _SDL_xchg_watcom = \ - "lock xchg [ecx], eax" \ - parm [ecx] [eax] \ - value [eax] \ - modify exact [eax]; -#endif // __WATCOMC__ && __386__ -/* *INDENT-ON* */ // clang-format on - // This function is where all the magic happens... bool SDL_TryLockSpinlock(SDL_SpinLock *lock) { @@ -69,9 +57,6 @@ bool SDL_TryLockSpinlock(SDL_SpinLock *lock) SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); return InterlockedExchange((long *)lock, 1) == 0; -#elif defined(__WATCOMC__) && defined(__386__) - return _SDL_xchg_watcom(lock, 1) == 0; - #elif defined(__GNUC__) && defined(__arm__) && \ (defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \ defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ @@ -188,10 +173,6 @@ void SDL_UnlockSpinlock(SDL_SpinLock *lock) _ReadWriteBarrier(); *lock = 0; -#elif defined(__WATCOMC__) && defined(__386__) - SDL_CompilerBarrier(); - *lock = 0; - #elif defined(SDL_PLATFORM_SOLARIS) // Used for Solaris when not using gcc. *lock = 0; diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index cc20b47b12..54da689a92 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -136,11 +136,11 @@ int SDL_GetNumAudioDrivers(void) const char *SDL_GetAudioDriver(int index) { - if (index >= 0 && index < SDL_GetNumAudioDrivers()) { - return deduped_bootstrap[index]->name; + CHECK_PARAM(index < 0 || index >= SDL_GetNumAudioDrivers()) { + SDL_InvalidParamError("index"); + return NULL; } - SDL_InvalidParamError("index"); - return NULL; + return deduped_bootstrap[index]->name; } const char *SDL_GetCurrentAudioDriver(void) @@ -171,10 +171,13 @@ int SDL_GetDefaultSampleFramesFromFreq(const int freq) int *SDL_ChannelMapDup(const int *origchmap, int channels) { - const size_t chmaplen = sizeof (*origchmap) * channels; - int *chmap = (int *)SDL_malloc(chmaplen); - if (chmap) { - SDL_memcpy(chmap, origchmap, chmaplen); + int *chmap = NULL; + if ((channels > 0) && origchmap) { + const size_t chmaplen = sizeof (*origchmap) * channels; + chmap = (int *)SDL_malloc(chmaplen); + if (chmap) { + SDL_memcpy(chmap, origchmap, chmaplen); + } } return chmap; } @@ -734,11 +737,10 @@ SDL_AudioDevice *SDL_AddAudioDevice(bool recording, const char *name, const SDL_ } // Called when a device is removed from the system, or it fails unexpectedly, from any thread, possibly even the audio device's thread. -void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device) +static void SDLCALL SDL_AudioDeviceDisconnected_OnMainThread(void *userdata) { - if (!device) { - return; - } + SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; + SDL_assert(device != NULL); // Save off removal info in a list so we can send events for each, next // time the event queue pumps, in case something tries to close a device @@ -808,6 +810,23 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device) UnrefPhysicalAudioDevice(device); } + + // We always ref this in SDL_AudioDeviceDisconnected(), so if multiple attempts + // to disconnect are queued, the pointer stays valid until the last one comes + // through. + UnrefPhysicalAudioDevice(device); +} + +void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device) +{ + // lots of risk of various audio backends deadlocking because they're calling + // this while holding a backend-specific lock, which causes problems when we + // want to obtain the device lock while its audio thread is also waiting for + // that lock to be released. So just queue the work on the main thread. + if (device) { + RefPhysicalAudioDevice(device); + SDL_RunOnMainThread(SDL_AudioDeviceDisconnected_OnMainThread, device, false); + } } @@ -1576,7 +1595,7 @@ const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid) bool SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec, int *sample_frames) { - if (!spec) { + CHECK_PARAM(!spec) { return SDL_InvalidParamError("spec"); } @@ -1601,9 +1620,7 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count) SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid); if (device) { channels = device->spec.channels; - if (channels > 0 && device->chmap) { - result = SDL_ChannelMapDup(device->chmap, channels); - } + result = SDL_ChannelMapDup(device->chmap, channels); } ReleaseAudioDevice(device); @@ -1937,7 +1954,7 @@ float SDL_GetAudioDeviceGain(SDL_AudioDeviceID devid) bool SDL_SetAudioDeviceGain(SDL_AudioDeviceID devid, float gain) { - if (gain < 0.0f) { + CHECK_PARAM(gain < 0.0f) { return SDL_InvalidParamError("gain"); } @@ -1986,11 +2003,15 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre if (num_streams == 0) { return true; // nothing to do - } else if (num_streams < 0) { + } + + CHECK_PARAM(num_streams < 0) { return SDL_InvalidParamError("num_streams"); - } else if (!streams) { + } + CHECK_PARAM(!streams) { return SDL_InvalidParamError("streams"); - } else if (SDL_IsAudioDevicePhysical(devid)) { + } + CHECK_PARAM(SDL_IsAudioDevicePhysical(devid)) { return SDL_SetError("Audio streams are bound to device ids from SDL_OpenAudioDevice, not raw physical devices"); } @@ -2150,7 +2171,7 @@ SDL_AudioDeviceID SDL_GetAudioStreamDevice(SDL_AudioStream *stream) { SDL_AudioDeviceID result = 0; - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return 0; } diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 5b768ade06..5b42751170 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -474,10 +474,11 @@ SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_ SDL_PropertiesID SDL_GetAudioStreamProperties(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return 0; } + SDL_LockMutex(stream->lock); if (stream->props == 0) { stream->props = SDL_CreateProperties(); @@ -488,9 +489,10 @@ SDL_PropertiesID SDL_GetAudioStreamProperties(SDL_AudioStream *stream) bool SDL_SetAudioStreamGetCallback(SDL_AudioStream *stream, SDL_AudioStreamCallback callback, void *userdata) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } + SDL_LockMutex(stream->lock); stream->get_callback = callback; stream->get_callback_userdata = userdata; @@ -500,9 +502,10 @@ bool SDL_SetAudioStreamGetCallback(SDL_AudioStream *stream, SDL_AudioStreamCallb bool SDL_SetAudioStreamPutCallback(SDL_AudioStream *stream, SDL_AudioStreamCallback callback, void *userdata) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } + SDL_LockMutex(stream->lock); stream->put_callback = callback; stream->put_callback_userdata = userdata; @@ -512,25 +515,27 @@ bool SDL_SetAudioStreamPutCallback(SDL_AudioStream *stream, SDL_AudioStreamCallb bool SDL_LockAudioStream(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } + SDL_LockMutex(stream->lock); return true; } bool SDL_UnlockAudioStream(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } + SDL_UnlockMutex(stream->lock); return true; } bool SDL_GetAudioStreamFormat(SDL_AudioStream *stream, SDL_AudioSpec *src_spec, SDL_AudioSpec *dst_spec) { - if (!stream) { + CHECK_PARAM(!stream) { if (src_spec) { SDL_zerop(src_spec); } @@ -560,7 +565,7 @@ bool SDL_GetAudioStreamFormat(SDL_AudioStream *stream, SDL_AudioSpec *src_spec, bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_spec, const SDL_AudioSpec *dst_spec) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } @@ -569,21 +574,25 @@ bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_ // like 196608000Hz. File a bug. :P if (src_spec) { - if (!SDL_IsSupportedAudioFormat(src_spec->format)) { + CHECK_PARAM(!SDL_IsSupportedAudioFormat(src_spec->format)) { return SDL_InvalidParamError("src_spec->format"); - } else if (!SDL_IsSupportedChannelCount(src_spec->channels)) { + } + CHECK_PARAM(!SDL_IsSupportedChannelCount(src_spec->channels)) { return SDL_InvalidParamError("src_spec->channels"); - } else if (src_spec->freq <= 0) { + } + CHECK_PARAM(src_spec->freq <= 0) { return SDL_InvalidParamError("src_spec->freq"); } } if (dst_spec) { - if (!SDL_IsSupportedAudioFormat(dst_spec->format)) { + CHECK_PARAM(!SDL_IsSupportedAudioFormat(dst_spec->format)) { return SDL_InvalidParamError("dst_spec->format"); - } else if (!SDL_IsSupportedChannelCount(dst_spec->channels)) { + } + CHECK_PARAM(!SDL_IsSupportedChannelCount(dst_spec->channels)) { return SDL_InvalidParamError("dst_spec->channels"); - } else if (dst_spec->freq <= 0) { + } + CHECK_PARAM(dst_spec->freq <= 0) { return SDL_InvalidParamError("dst_spec->freq"); } } @@ -622,7 +631,7 @@ bool SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_ bool SetAudioStreamChannelMap(SDL_AudioStream *stream, const SDL_AudioSpec *spec, int **stream_chmap, const int *chmap, int channels, int isinput) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } @@ -708,7 +717,7 @@ int *SDL_GetAudioStreamOutputChannelMap(SDL_AudioStream *stream, int *count) float SDL_GetAudioStreamFrequencyRatio(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return 0.0f; } @@ -722,7 +731,7 @@ float SDL_GetAudioStreamFrequencyRatio(SDL_AudioStream *stream) bool SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float freq_ratio) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } @@ -745,7 +754,7 @@ bool SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float freq_ratio) float SDL_GetAudioStreamGain(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return -1.0f; } @@ -759,9 +768,10 @@ float SDL_GetAudioStreamGain(SDL_AudioStream *stream) bool SDL_SetAudioStreamGain(SDL_AudioStream *stream, float gain) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); - } else if (gain < 0.0f) { + } + CHECK_PARAM(gain < 0.0f) { return SDL_InvalidParamError("gain"); } @@ -847,13 +857,17 @@ static void SDLCALL FreeAllocatedAudioBuffer(void *userdata, const void *buf, in bool SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); - } else if (!buf) { + } + CHECK_PARAM(!buf) { return SDL_InvalidParamError("buf"); - } else if (len < 0) { + } + CHECK_PARAM(len < 0) { return SDL_InvalidParamError("len"); - } else if (len == 0) { + } + + if (len == 0) { return true; // nothing to do. } @@ -965,13 +979,17 @@ static void InterleaveAudioChannels(void *output, const void * const *channel_bu bool SDL_PutAudioStreamPlanarData(SDL_AudioStream *stream, const void * const *channel_buffers, int num_channels, int num_samples) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); - } else if (!channel_buffers) { + } + CHECK_PARAM(!channel_buffers) { return SDL_InvalidParamError("channel_buffers"); - } else if (num_samples < 0) { + } + CHECK_PARAM(num_samples < 0) { return SDL_InvalidParamError("num_samples"); - } else if (num_samples == 0) { + } + + if (num_samples == 0) { return true; // nothing to do. } @@ -1039,13 +1057,17 @@ static void SDLCALL DontFreeThisAudioBuffer(void *userdata, const void *buf, int bool SDL_PutAudioStreamDataNoCopy(SDL_AudioStream *stream, const void *buf, int len, SDL_AudioStreamDataCompleteCallback callback, void *userdata) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); - } else if (!buf) { + } + CHECK_PARAM(!buf) { return SDL_InvalidParamError("buf"); - } else if (len < 0) { + } + CHECK_PARAM(len < 0) { return SDL_InvalidParamError("len"); - } else if (len == 0) { + } + + if (len == 0) { if (callback) { callback(userdata, buf, len); } @@ -1057,7 +1079,7 @@ bool SDL_PutAudioStreamDataNoCopy(SDL_AudioStream *stream, const void *buf, int bool SDL_FlushAudioStream(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } @@ -1320,16 +1342,20 @@ int SDL_GetAudioStreamDataAdjustGain(SDL_AudioStream *stream, void *voidbuf, int SDL_Log("AUDIOSTREAM: want to get %d converted bytes", len); #endif - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return -1; - } else if (!buf) { + } + CHECK_PARAM(!buf) { SDL_InvalidParamError("buf"); return -1; - } else if (len < 0) { + } + CHECK_PARAM(len < 0) { SDL_InvalidParamError("len"); return -1; - } else if (len == 0) { + } + + if (len == 0) { return 0; // nothing to do. } @@ -1427,7 +1453,7 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len) // number of converted/resampled bytes available for output int SDL_GetAudioStreamAvailable(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return -1; } @@ -1453,7 +1479,7 @@ int SDL_GetAudioStreamAvailable(SDL_AudioStream *stream) // number of sample frames that are currently queued as input. int SDL_GetAudioStreamQueued(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { SDL_InvalidParamError("stream"); return -1; } @@ -1470,7 +1496,7 @@ int SDL_GetAudioStreamQueued(SDL_AudioStream *stream) bool SDL_ClearAudioStream(SDL_AudioStream *stream) { - if (!stream) { + CHECK_PARAM(!stream) { return SDL_InvalidParamError("stream"); } @@ -1522,13 +1548,16 @@ bool SDL_ConvertAudioSamples(const SDL_AudioSpec *src_spec, const Uint8 *src_dat *dst_len = 0; } - if (!src_data) { + CHECK_PARAM(!src_data) { return SDL_InvalidParamError("src_data"); - } else if (src_len < 0) { + } + CHECK_PARAM(src_len < 0) { return SDL_InvalidParamError("src_len"); - } else if (!dst_data) { + } + CHECK_PARAM(!dst_data) { return SDL_InvalidParamError("dst_data"); - } else if (!dst_len) { + } + CHECK_PARAM(!dst_len) { return SDL_InvalidParamError("dst_len"); } diff --git a/src/audio/SDL_wave.c b/src/audio/SDL_wave.c index ceee99814e..fd26e71b46 100644 --- a/src/audio/SDL_wave.c +++ b/src/audio/SDL_wave.c @@ -1775,6 +1775,7 @@ static bool WaveLoad(SDL_IOStream *src, WaveFile *file, SDL_AudioSpec *spec, Uin int result; Uint32 chunkcount = 0; Uint32 chunkcountlimit = 10000; + const Sint64 flen = SDL_GetIOSize(src); // this might be -1 if the IOStream can't determine the total size. const char *hint; Sint64 RIFFstart, RIFFend, lastchunkpos; bool RIFFlengthknown = false; @@ -1883,6 +1884,14 @@ static bool WaveLoad(SDL_IOStream *src, WaveFile *file, SDL_AudioSpec *spec, Uin fmtchunk = *chunk; } } else if (chunk->fourcc == DATA) { + /* If the data chunk is bigger than the file, it might be corrupt + or the file is truncated. Try to recover by clamping the file + size. This also means a malicious file can't allocate 4 gigabytes + for the chunks without actually supplying a 4 gigabyte file. */ + if ((flen > 0) && ((chunk->position + chunk->length) > flen)) { + chunk->length = (Uint32) (flen - chunk->position); + } + /* Only use the first data chunk. Handling the wavl list madness * may require a different approach. */ @@ -2092,16 +2101,19 @@ bool SDL_LoadWAV_IO(SDL_IOStream *src, bool closeio, SDL_AudioSpec *spec, Uint8 } // Make sure we are passed a valid data source - if (!src) { + CHECK_PARAM(!src) { SDL_InvalidParamError("src"); goto done; - } else if (!spec) { + } + CHECK_PARAM(!spec) { SDL_InvalidParamError("spec"); goto done; - } else if (!audio_buf) { + } + CHECK_PARAM(!audio_buf) { SDL_InvalidParamError("audio_buf"); goto done; - } else if (!audio_len) { + } + CHECK_PARAM(!audio_len) { SDL_InvalidParamError("audio_len"); goto done; } diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index ab4dd0cc53..c7d5db525f 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -40,16 +40,16 @@ static bool SupportsIMMDevice = false; // DirectX function pointers for audio static SDL_SharedObject *DSoundDLL = NULL; -typedef HRESULT(WINAPI *fnDirectSoundCreate8)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); -typedef HRESULT(WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); -typedef HRESULT(WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID, LPDIRECTSOUNDCAPTURE8 *, LPUNKNOWN); -typedef HRESULT(WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); -typedef HRESULT(WINAPI *fnGetDeviceID)(LPCGUID, LPGUID); -static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL; -static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL; -static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL; -static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL; -static fnGetDeviceID pGetDeviceID = NULL; +typedef HRESULT (WINAPI *pfnDirectSoundCreate8)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); +typedef HRESULT (WINAPI *pfnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); +typedef HRESULT (WINAPI *pfnDirectSoundCaptureCreate8)(LPCGUID, LPDIRECTSOUNDCAPTURE8 *, LPUNKNOWN); +typedef HRESULT (WINAPI *pfnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); +typedef HRESULT (WINAPI *pfnGetDeviceID)(LPCGUID, LPGUID); +static pfnDirectSoundCreate8 pDirectSoundCreate8 = NULL; +static pfnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL; +static pfnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL; +static pfnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL; +static pfnGetDeviceID pGetDeviceID = NULL; #include DEFINE_GUID(SDL_DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); @@ -85,7 +85,7 @@ static bool DSOUND_Load(void) // Now make sure we have DirectX 8 or better... #define DSOUNDLOAD(f) \ { \ - p##f = (fn##f)SDL_LoadFunction(DSoundDLL, #f); \ + p##f = (pfn##f)SDL_LoadFunction(DSoundDLL, #f); \ if (!p##f) \ loaded = false; \ } diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index 4be919104f..cba47bb5fb 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -155,11 +155,8 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device) Module['SDL3'] = {}; } var SDL3 = Module['SDL3']; - if (!$0) { - SDL3.audio_playback = {}; - } else { - SDL3.audio_recording = {}; - } + SDL3.audio_playback = {}; + SDL3.audio_recording = {}; if (!SDL3.audioContext) { if (typeof(AudioContext) !== 'undefined') { diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index 46e2ac005f..cbd643efee 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -45,8 +45,8 @@ // handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). static HMODULE libavrt = NULL; -typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD); -typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE); +typedef HANDLE (WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD); +typedef BOOL (WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE); static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL; static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; @@ -164,21 +164,10 @@ bool WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, b return true; // successfully added (and possibly executed)! } -static bool mgmtthrtask_AudioDeviceDisconnected(void *userdata) -{ - SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; - SDL_AudioDeviceDisconnected(device); - UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes. - return true; -} static void AudioDeviceDisconnected(SDL_AudioDevice *device) { - // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock. - if (device) { - RefPhysicalAudioDevice(device); // make sure this lives until the task completes. - WASAPI_ProxyToManagementThread(mgmtthrtask_AudioDeviceDisconnected, device, NULL); - } + WASAPI_DisconnectDevice(device); } static bool mgmtthrtask_DefaultAudioDeviceChanged(void *userdata) @@ -351,19 +340,11 @@ static void WASAPI_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe WASAPI_ProxyToManagementThread(mgmtthrtask_DetectDevices, &data, &rc); } -static bool mgmtthrtask_DisconnectDevice(void *userdata) -{ - SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; - SDL_AudioDeviceDisconnected(device); - UnrefPhysicalAudioDevice(device); - return true; -} - void WASAPI_DisconnectDevice(SDL_AudioDevice *device) { - if (SDL_CompareAndSwapAtomicInt(&device->hidden->device_disconnecting, 0, 1)) { - RefPhysicalAudioDevice(device); // will unref when the task ends. - WASAPI_ProxyToManagementThread(mgmtthrtask_DisconnectDevice, device, NULL); + // don't block in here; IMMDevice's own thread needs to return or everything will deadlock. + if (device->hidden && SDL_CompareAndSwapAtomicInt(&device->hidden->device_disconnecting, 0, 1)) { + SDL_AudioDeviceDisconnected(device); // this proxies the work to the main thread now, so no point in proxying to the management thread. } } diff --git a/src/camera/SDL_camera.c b/src/camera/SDL_camera.c index 855c9be6aa..10320613a4 100644 --- a/src/camera/SDL_camera.c +++ b/src/camera/SDL_camera.c @@ -69,11 +69,11 @@ int SDL_GetNumCameraDrivers(void) const char *SDL_GetCameraDriver(int index) { - if (index >= 0 && index < SDL_GetNumCameraDrivers()) { - return bootstrap[index]->name; + CHECK_PARAM(index < 0 || index >= SDL_GetNumCameraDrivers()) { + SDL_InvalidParamError("index"); + return NULL; } - SDL_InvalidParamError("index"); - return NULL; + return bootstrap[index]->name; } const char *SDL_GetCurrentCameraDriver(void) @@ -657,9 +657,10 @@ bool SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec) { bool result; - if (!camera) { + CHECK_PARAM(!camera) { return SDL_InvalidParamError("camera"); - } else if (!spec) { + } + CHECK_PARAM(!spec) { return SDL_InvalidParamError("spec"); } @@ -1255,7 +1256,7 @@ SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS) *timestampNS = 0; } - if (!camera) { + CHECK_PARAM(!camera) { SDL_InvalidParamError("camera"); return NULL; } @@ -1340,49 +1341,55 @@ void SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame) SDL_CameraID SDL_GetCameraID(SDL_Camera *camera) { - SDL_CameraID result = 0; - if (!camera) { + SDL_CameraID result; + + CHECK_PARAM(!camera) { SDL_InvalidParamError("camera"); - } else { - SDL_Camera *device = camera; // currently there's no separation between physical and logical device. - ObtainPhysicalCameraObj(device); - result = device->instance_id; - ReleaseCamera(device); + return 0; } + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. + ObtainPhysicalCameraObj(device); + result = device->instance_id; + ReleaseCamera(device); + return result; } SDL_PropertiesID SDL_GetCameraProperties(SDL_Camera *camera) { - SDL_PropertiesID result = 0; - if (!camera) { + SDL_PropertiesID result; + + CHECK_PARAM(!camera) { SDL_InvalidParamError("camera"); - } else { - SDL_Camera *device = camera; // currently there's no separation between physical and logical device. - ObtainPhysicalCameraObj(device); - if (device->props == 0) { - device->props = SDL_CreateProperties(); - } - result = device->props; - ReleaseCamera(device); + return 0; } + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. + ObtainPhysicalCameraObj(device); + if (device->props == 0) { + device->props = SDL_CreateProperties(); + } + result = device->props; + ReleaseCamera(device); + return result; } SDL_CameraPermissionState SDL_GetCameraPermissionState(SDL_Camera *camera) { SDL_CameraPermissionState result; - if (!camera) { + + CHECK_PARAM(!camera) { SDL_InvalidParamError("camera"); - result = SDL_CAMERA_PERMISSION_STATE_DENIED; - } else { - SDL_Camera *device = camera; // currently there's no separation between physical and logical device. - ObtainPhysicalCameraObj(device); - result = device->permission; - ReleaseCamera(device); + return SDL_CAMERA_PERMISSION_STATE_DENIED; } + + SDL_Camera *device = camera; // currently there's no separation between physical and logical device. + ObtainPhysicalCameraObj(device); + result = device->permission; + ReleaseCamera(device); + return result; } diff --git a/src/camera/mediafoundation/SDL_camera_mediafoundation.c b/src/camera/mediafoundation/SDL_camera_mediafoundation.c index 433be4d86b..a059b131fe 100644 --- a/src/camera/mediafoundation/SDL_camera_mediafoundation.c +++ b/src/camera/mediafoundation/SDL_camera_mediafoundation.c @@ -324,18 +324,18 @@ static const GUID *SDLFmtToMFVidFmtGuid(SDL_PixelFormat format) // mf.dll ... static HMODULE libmf = NULL; -typedef HRESULT(WINAPI *pfnMFEnumDeviceSources)(IMFAttributes *,IMFActivate ***,UINT32 *); -typedef HRESULT(WINAPI *pfnMFCreateDeviceSource)(IMFAttributes *, IMFMediaSource **); +typedef HRESULT (WINAPI *pfnMFEnumDeviceSources)(IMFAttributes *,IMFActivate ***,UINT32 *); +typedef HRESULT (WINAPI *pfnMFCreateDeviceSource)(IMFAttributes *, IMFMediaSource **); static pfnMFEnumDeviceSources pMFEnumDeviceSources = NULL; static pfnMFCreateDeviceSource pMFCreateDeviceSource = NULL; // mfplat.dll ... static HMODULE libmfplat = NULL; -typedef HRESULT(WINAPI *pfnMFStartup)(ULONG, DWORD); -typedef HRESULT(WINAPI *pfnMFShutdown)(void); -typedef HRESULT(WINAPI *pfnMFCreateAttributes)(IMFAttributes **, UINT32); -typedef HRESULT(WINAPI *pfnMFCreateMediaType)(IMFMediaType **); -typedef HRESULT(WINAPI *pfnMFGetStrideForBitmapInfoHeader)(DWORD, DWORD, LONG *); +typedef HRESULT (WINAPI *pfnMFStartup)(ULONG, DWORD); +typedef HRESULT (WINAPI *pfnMFShutdown)(void); +typedef HRESULT (WINAPI *pfnMFCreateAttributes)(IMFAttributes **, UINT32); +typedef HRESULT (WINAPI *pfnMFCreateMediaType)(IMFMediaType **); +typedef HRESULT (WINAPI *pfnMFGetStrideForBitmapInfoHeader)(DWORD, DWORD, LONG *); static pfnMFStartup pMFStartup = NULL; static pfnMFShutdown pMFShutdown = NULL; @@ -345,7 +345,7 @@ static pfnMFGetStrideForBitmapInfoHeader pMFGetStrideForBitmapInfoHeader = NULL; // mfreadwrite.dll ... static HMODULE libmfreadwrite = NULL; -typedef HRESULT(WINAPI *pfnMFCreateSourceReaderFromMediaSource)(IMFMediaSource *, IMFAttributes *, IMFSourceReader **); +typedef HRESULT (WINAPI *pfnMFCreateSourceReaderFromMediaSource)(IMFMediaSource *, IMFAttributes *, IMFSourceReader **); static pfnMFCreateSourceReaderFromMediaSource pMFCreateSourceReaderFromMediaSource = NULL; diff --git a/src/core/SDL_core_unsupported.c b/src/core/SDL_core_unsupported.c index 9ace0e0bba..ecc862c2f1 100644 --- a/src/core/SDL_core_unsupported.c +++ b/src/core/SDL_core_unsupported.c @@ -20,18 +20,18 @@ */ #include "SDL_internal.h" +#include "SDL_core_unsupported.h" + #ifndef SDL_VIDEO_DRIVER_X11 -SDL_DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata); void SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata) { } -#endif +#endif /* !SDL_VIDEO_DRIVER_X11 */ #ifndef SDL_PLATFORM_LINUX -SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriority(Sint64 threadID, int priority); bool SDL_SetLinuxThreadPriority(Sint64 threadID, int priority) { (void)threadID; @@ -39,7 +39,6 @@ bool SDL_SetLinuxThreadPriority(Sint64 threadID, int priority) return SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy); bool SDL_SetLinuxThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy) { (void)threadID; @@ -48,37 +47,32 @@ bool SDL_SetLinuxThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int s return SDL_Unsupported(); } -#endif +#endif /* !SDL_PLATFORM_LINUX */ #ifndef SDL_PLATFORM_GDK -SDL_DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void); void SDL_GDKSuspendComplete(void) { SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_GetGDKDefaultUser(void *outUserHandle); /* XUserHandle *outUserHandle */ -bool SDL_GetGDKDefaultUser(void *outUserHandle) +bool SDL_GetGDKDefaultUser(XUserHandle *outUserHandle) { return SDL_Unsupported(); } -SDL_DECLSPEC void SDLCALL SDL_GDKSuspendGPU(SDL_GPUDevice *device); void SDL_GDKSuspendGPU(SDL_GPUDevice *device) { } -SDL_DECLSPEC void SDLCALL SDL_GDKResumeGPU(SDL_GPUDevice *device); void SDL_GDKResumeGPU(SDL_GPUDevice *device) { } -#endif +#endif /* !SDL_PLATFORM_GDK */ #if !defined(SDL_PLATFORM_WINDOWS) -SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst); bool SDL_RegisterApp(const char *name, Uint32 style, void *hInst) { (void)name; @@ -87,7 +81,6 @@ bool SDL_RegisterApp(const char *name, Uint32 style, void *hInst) return SDL_Unsupported(); } -SDL_DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(void *callback, void *userdata); // SDL_WindowsMessageHook callback void SDL_SetWindowsMessageHook(void *callback, void *userdata) { (void)callback; @@ -95,30 +88,26 @@ void SDL_SetWindowsMessageHook(void *callback, void *userdata) SDL_Unsupported(); } -SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void); void SDL_UnregisterApp(void) { SDL_Unsupported(); } -#endif +#endif /* !SDL_PLATFORM_WINDOWS */ #ifndef SDL_PLATFORM_ANDROID -SDL_DECLSPEC void SDLCALL SDL_SendAndroidBackButton(void); void SDL_SendAndroidBackButton(void) { SDL_Unsupported(); } -SDL_DECLSPEC void * SDLCALL SDL_GetAndroidActivity(void); void *SDL_GetAndroidActivity(void) { SDL_Unsupported(); return NULL; } -SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidCachePath(void); const char *SDL_GetAndroidCachePath(void) { SDL_Unsupported(); @@ -126,35 +115,29 @@ const char *SDL_GetAndroidCachePath(void) } -SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidExternalStoragePath(void); const char *SDL_GetAndroidExternalStoragePath(void) { SDL_Unsupported(); return NULL; } -SDL_DECLSPEC Uint32 SDLCALL SDL_GetAndroidExternalStorageState(void); Uint32 SDL_GetAndroidExternalStorageState(void) { SDL_Unsupported(); return 0; } -SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidInternalStoragePath(void); const char *SDL_GetAndroidInternalStoragePath(void) { SDL_Unsupported(); return NULL; } -SDL_DECLSPEC void * SDLCALL SDL_GetAndroidJNIEnv(void); void *SDL_GetAndroidJNIEnv(void) { SDL_Unsupported(); return NULL; } -typedef void (SDLCALL *SDL_RequestAndroidPermissionCallback)(void *userdata, const char *permission, bool granted); -SDL_DECLSPEC bool SDLCALL SDL_RequestAndroidPermission(const char *permission, SDL_RequestAndroidPermissionCallback cb, void *userdata); bool SDL_RequestAndroidPermission(const char *permission, SDL_RequestAndroidPermissionCallback cb, void *userdata) { (void)permission; @@ -163,7 +146,6 @@ bool SDL_RequestAndroidPermission(const char *permission, SDL_RequestAndroidPerm return SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_SendAndroidMessage(Uint32 command, int param); bool SDL_SendAndroidMessage(Uint32 command, int param) { (void)command; @@ -171,7 +153,6 @@ bool SDL_SendAndroidMessage(Uint32 command, int param) return SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_ShowAndroidToast(const char *message, int duration, int gravity, int xoffset, int yoffset); bool SDL_ShowAndroidToast(const char *message, int duration, int gravity, int xoffset, int yoffset) { (void)message; @@ -182,28 +163,24 @@ bool SDL_ShowAndroidToast(const char *message, int duration, int gravity, int xo return SDL_Unsupported(); } -SDL_DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void); int SDL_GetAndroidSDKVersion(void) { return SDL_Unsupported(); } -SDL_DECLSPEC bool SDLCALL SDL_IsChromebook(void); bool SDL_IsChromebook(void) { SDL_Unsupported(); return false; } -SDL_DECLSPEC bool SDLCALL SDL_IsDeXMode(void); bool SDL_IsDeXMode(void) { SDL_Unsupported(); return false; } -SDL_DECLSPEC Sint32 SDLCALL JNI_OnLoad(void *vm, void *reserved); -Sint32 JNI_OnLoad(void *vm, void *reserved) +Sint32 JNI_OnLoad(JavaVM *vm, void *reserved) { (void)vm; (void)reserved; diff --git a/src/core/SDL_core_unsupported.h b/src/core/SDL_core_unsupported.h new file mode 100644 index 0000000000..63b4264f77 --- /dev/null +++ b/src/core/SDL_core_unsupported.h @@ -0,0 +1,65 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_VIDEO_DRIVER_X11 +extern SDL_DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata); +#endif + +#ifndef SDL_PLATFORM_LINUX +extern SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriority(Sint64 threadID, int priority); +extern SDL_DECLSPEC bool SDLCALL SDL_SetLinuxThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy); +#endif + +#if !defined(SDL_PLATFORM_GDK) +typedef struct XUserHandle XUserHandle; + +extern SDL_DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void); +extern SDL_DECLSPEC bool SDLCALL SDL_GetGDKDefaultUser(XUserHandle *outUserHandle); +extern SDL_DECLSPEC void SDLCALL SDL_GDKSuspendGPU(SDL_GPUDevice *device); +extern SDL_DECLSPEC void SDLCALL SDL_GDKResumeGPU(SDL_GPUDevice *device); +#endif /* !SDL_PLATFORM_GDK */ + +#if !defined(SDL_PLATFORM_WINDOWS) +extern SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst); +extern SDL_DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(void *callback, void *userdata); +extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void); +#endif /* !SDL_PLATFORM_WINDOWS */ + +#if !defined(SDL_PLATFORM_ANDROID) + +typedef void *SDL_RequestAndroidPermissionCallback; +typedef void *JavaVM; + +extern SDL_DECLSPEC void SDLCALL SDL_SendAndroidBackButton(void); +extern SDL_DECLSPEC void * SDLCALL SDL_GetAndroidActivity(void); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidCachePath(void); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidExternalStoragePath(void); +extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAndroidExternalStorageState(void); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetAndroidInternalStoragePath(void); +extern SDL_DECLSPEC void * SDLCALL SDL_GetAndroidJNIEnv(void); +extern SDL_DECLSPEC bool SDLCALL SDL_RequestAndroidPermission(const char *permission, SDL_RequestAndroidPermissionCallback cb, void *userdata); +extern SDL_DECLSPEC bool SDLCALL SDL_SendAndroidMessage(Uint32 command, int param); +extern SDL_DECLSPEC bool SDLCALL SDL_ShowAndroidToast(const char *message, int duration, int gravity, int xoffset, int yoffset); +extern SDL_DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void); +extern SDL_DECLSPEC bool SDLCALL SDL_IsChromebook(void); +extern SDL_DECLSPEC bool SDLCALL SDL_IsDeXMode(void); +extern SDL_DECLSPEC Sint32 SDLCALL JNI_OnLoad(JavaVM *vm, void *reserved); +#endif /* !SDL_PLATFORM_ANDROID */ diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 6e9d2e7389..33d7815ff4 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -198,7 +198,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)( static JNINativeMethod SDLActivity_tab[] = { { "nativeGetVersion", "()Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetVersion) }, - { "nativeSetupJNI", "()I", SDL_JAVA_INTERFACE(nativeSetupJNI) }, + { "nativeSetupJNI", "()V", SDL_JAVA_INTERFACE(nativeSetupJNI) }, { "nativeInitMainThread", "()V", SDL_JAVA_INTERFACE(nativeInitMainThread) }, { "nativeCleanupMainThread", "()V", SDL_JAVA_INTERFACE(nativeCleanupMainThread) }, { "nativeRunMain", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) }, @@ -265,7 +265,7 @@ JNIEXPORT void JNICALL jint device_id); static JNINativeMethod SDLAudioManager_tab[] = { - { "nativeSetupJNI", "()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }, + { "nativeSetupJNI", "()V", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }, { "nativeAddAudioDevice", "(ZLjava/lang/String;I)V", SDL_JAVA_AUDIO_INTERFACE(nativeAddAudioDevice) }, { "nativeRemoveAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(nativeRemoveAudioDevice) } }; @@ -308,7 +308,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)( jint device_id); static JNINativeMethod SDLControllerManager_tab[] = { - { "nativeSetupJNI", "()I", SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI) }, + { "nativeSetupJNI", "()V", SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI) }, { "onNativePadDown", "(II)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown) }, { "onNativePadUp", "(II)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) }, { "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) }, @@ -635,7 +635,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardSetText", "(Ljava/lang/String;)V"); midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I"); midDestroyCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "destroyCustomCursor", "(I)V"); - midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;"); + midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/app/Activity;"); midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z"); midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface", "()Landroid/view/Surface;"); midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V"); @@ -2113,7 +2113,7 @@ void Android_JNI_HapticStop(int device_id) bool SDL_SendAndroidMessage(Uint32 command, int param) { - if (command < 0x8000) { + CHECK_PARAM(command < 0x8000) { return SDL_InvalidParamError("command"); } return Android_JNI_SendMessage(command, param); @@ -2227,7 +2227,7 @@ bool Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *b mid = (*env)->GetMethodID(env, clazz, "messageboxShowMessageBox", "(ILjava/lang/String;Ljava/lang/String;[I[I[Ljava/lang/String;[I)I"); *buttonID = (*env)->CallIntMethod(env, context, mid, - messageboxdata->flags, + (jint)messageboxdata->flags, title, message, button_flags, @@ -2481,7 +2481,7 @@ const char *SDL_GetAndroidCachePath(void) // fileObj = context.getExternalFilesDir(); mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context), "getCacheDir", "()Ljava/io/File;"); - fileObject = (*env)->CallObjectMethod(env, context, mid, NULL); + fileObject = (*env)->CallObjectMethod(env, context, mid); if (!fileObject) { SDL_SetError("Couldn't get cache directory"); LocalReferenceHolder_Cleanup(&refs); diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c index 902f7e69ae..a966bfcfaf 100644 --- a/src/core/linux/SDL_evdev.c +++ b/src/core/linux/SDL_evdev.c @@ -322,10 +322,6 @@ void SDL_EVDEV_Poll(void) return; } -#ifdef SDL_USE_LIBUDEV - SDL_UDEV_Poll(); -#endif - SDL_EVDEV_kbd_update(_this->kbd); mouse = SDL_GetMouse(); @@ -612,14 +608,14 @@ static bool SDL_EVDEV_init_keyboard(SDL_evdevlist_item *item, int udev_class) name[0] = '\0'; ioctl(item->fd, EVIOCGNAME(sizeof(name)), name); - SDL_AddKeyboard((SDL_KeyboardID)item->fd, name, true); + SDL_AddKeyboard((SDL_KeyboardID)item->fd, name); return true; } static void SDL_EVDEV_destroy_keyboard(SDL_evdevlist_item *item) { - SDL_RemoveKeyboard((SDL_KeyboardID)item->fd, true); + SDL_RemoveKeyboard((SDL_KeyboardID)item->fd); } static bool SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class) @@ -631,7 +627,7 @@ static bool SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class) name[0] = '\0'; ioctl(item->fd, EVIOCGNAME(sizeof(name)), name); - SDL_AddMouse((SDL_MouseID)item->fd, name, true); + SDL_AddMouse((SDL_MouseID)item->fd, name); ret = ioctl(item->fd, EVIOCGABS(ABS_X), &abs_info); if (ret < 0) { @@ -656,7 +652,7 @@ static bool SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class) static void SDL_EVDEV_destroy_mouse(SDL_evdevlist_item *item) { - SDL_RemoveMouse((SDL_MouseID)item->fd, true); + SDL_RemoveMouse((SDL_MouseID)item->fd); } static bool SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class) diff --git a/src/core/linux/SDL_progressbar.c b/src/core/linux/SDL_progressbar.c index ac0789b2d2..9f98e6acfd 100644 --- a/src/core/linux/SDL_progressbar.c +++ b/src/core/linux/SDL_progressbar.c @@ -120,8 +120,6 @@ bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window) const char *progress_visible_str = "progress-visible"; const char *progress_str = "progress"; - int dbus_type_boolean_str = DBUS_TYPE_BOOLEAN; - int dbus_type_double_str = DBUS_TYPE_DOUBLE; const int progress_visible = ShouldShowProgress(window->progress_state); double progress = (double)window->progress_value; @@ -134,14 +132,14 @@ bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window) // Set progress visible property dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it); dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_visible_str); // Append progress-visible key data - dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_boolean_str, &value_it); + dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, "b", &value_it); dbus->message_iter_append_basic(&value_it, DBUS_TYPE_BOOLEAN, &progress_visible); // Append progress-visible value data dbus->message_iter_close_container(&key_it, &value_it); dbus->message_iter_close_container(&props, &key_it); // Set progress value property dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it); dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_str); // Append progress key data - dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_double_str, &value_it); + dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, "d", &value_it); dbus->message_iter_append_basic(&value_it, DBUS_TYPE_DOUBLE, &progress); // Append progress value data dbus->message_iter_close_container(&key_it, &value_it); dbus->message_iter_close_container(&props, &key_it); diff --git a/src/core/openbsd/SDL_wscons_kbd.c b/src/core/openbsd/SDL_wscons_kbd.c index 5a71044f31..723283908b 100644 --- a/src/core/openbsd/SDL_wscons_kbd.c +++ b/src/core/openbsd/SDL_wscons_kbd.c @@ -433,7 +433,7 @@ static SDL_WSCONS_input_data *SDL_WSCONS_Init_Keyboard(const char *dev) } input->keyboardID = SDL_GetNextObjectID(); - SDL_AddKeyboard(input->keyboardID, NULL, false); + SDL_AddKeyboard(input->keyboardID, NULL); input->keymap.map = SDL_calloc(KS_NUMKEYCODES, sizeof(struct wscons_keymap)); if (!input->keymap.map) { diff --git a/src/core/openbsd/SDL_wscons_mouse.c b/src/core/openbsd/SDL_wscons_mouse.c index 51195f39f4..e6d2ec0002 100644 --- a/src/core/openbsd/SDL_wscons_mouse.c +++ b/src/core/openbsd/SDL_wscons_mouse.c @@ -52,7 +52,7 @@ SDL_WSCONS_mouse_input_data *SDL_WSCONS_Init_Mouse(void) } input->mouseID = SDL_GetNextObjectID(); - SDL_AddMouse(input->mouseID, NULL, false); + SDL_AddMouse(input->mouseID, NULL); #ifdef WSMOUSEIO_SETMODE ioctl(input->fd, WSMOUSEIO_SETMODE, WSMOUSE_COMPAT); diff --git a/src/core/windows/SDL_gameinput.cpp b/src/core/windows/SDL_gameinput.cpp index e2ea3fb4ab..9ed6dc8b6b 100644 --- a/src/core/windows/SDL_gameinput.cpp +++ b/src/core/windows/SDL_gameinput.cpp @@ -38,15 +38,15 @@ bool SDL_InitGameInput(IGameInput **ppGameInput) return false; } - typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput **gameInput); - GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate"); - if (!GameInputCreateFunc) { + typedef HRESULT (WINAPI *pfnGameInputCreate)(IGameInput **gameInput); + pfnGameInputCreate pGameInputCreate = (pfnGameInputCreate)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate"); + if (!pGameInputCreate) { SDL_UnloadObject(g_hGameInputDLL); return false; } IGameInput *pGameInput = NULL; - HRESULT hr = GameInputCreateFunc(&pGameInput); + HRESULT hr = pGameInputCreate(&pGameInput); if (FAILED(hr)) { SDL_UnloadObject(g_hGameInputDLL); return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr); diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index b402a94c1f..7c433b252c 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -37,16 +37,6 @@ typedef enum RO_INIT_TYPE } RO_INIT_TYPE; #endif -#ifndef _WIN32_WINNT_VISTA -#define _WIN32_WINNT_VISTA 0x0600 -#endif -#ifndef _WIN32_WINNT_WIN7 -#define _WIN32_WINNT_WIN7 0x0601 -#endif -#ifndef _WIN32_WINNT_WIN8 -#define _WIN32_WINNT_WIN8 0x0602 -#endif - #ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index 1cd1aca334..80eb0997e5 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -21,10 +21,39 @@ // This is an include file for windows.h with the SDL build settings -#ifndef _INCLUDED_WINDOWS_H -#define _INCLUDED_WINDOWS_H +#ifndef SDL_windows_h_ +#define SDL_windows_h_ #ifdef SDL_PLATFORM_WIN32 + +#ifndef _WIN32_WINNT_NT4 +#define _WIN32_WINNT_NT4 0x0400 +#endif +#ifndef _WIN32_WINNT_WIN2K +#define _WIN32_WINNT_WIN2K 0x0500 +#endif +#ifndef _WIN32_WINNT_WINXP +#define _WIN32_WINNT_WINXP 0x0501 +#endif +#ifndef _WIN32_WINNT_WS03 +#define _WIN32_WINNT_WS03 0x0502 +#endif +#ifndef _WIN32_WINNT_VISTA +#define _WIN32_WINNT_VISTA 0x0600 +#endif +#ifndef _WIN32_WINNT_WIN7 +#define _WIN32_WINNT_WIN7 0x0601 +#endif +#ifndef _WIN32_WINNT_WIN8 +#define _WIN32_WINNT_WIN8 0x0602 +#endif +#ifndef _WIN32_WINNT_WINBLUE +#define _WIN32_WINNT_WINBLUE 0x0603 +#endif +#ifndef _WIN32_WINNT_WIN10 +#define _WIN32_WINNT_WIN10 0x0A00 +#endif + #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif @@ -37,11 +66,17 @@ #undef WINVER #undef _WIN32_WINNT #if defined(SDL_VIDEO_RENDER_D3D12) || defined(HAVE_DXGI1_6_H) -#define _WIN32_WINNT 0xA00 // For D3D12, 0xA00 is required +#define _WIN32_WINNT _WIN32_WINNT_WIN10 // For D3D12, 0xA00 is required #elif defined(HAVE_SHELLSCALINGAPI_H) -#define _WIN32_WINNT 0x603 // For DPI support +#define _WIN32_WINNT _WIN32_WINNT_WINBLUE // For DPI support +#elif defined(HAVE_ROAPI_H) +#define _WIN32_WINNT _WIN32_WINNT_WIN8 +#elif defined(HAVE_SENSORSAPI_H) +#define _WIN32_WINNT _WIN32_WINNT_WIN7 +#elif defined(HAVE_MMDEVICEAPI_H) +#define _WIN32_WINNT _WIN32_WINNT_VISTA #else -#define _WIN32_WINNT 0x501 // Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input +#define _WIN32_WINNT _WIN32_WINNT_WINXP // Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input #endif #define WINVER _WIN32_WINNT @@ -173,4 +208,4 @@ extern int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCh } #endif -#endif // _INCLUDED_WINDOWS_H +#endif // SDL_windows_h_ diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c index fc747c1944..1ec1655135 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -38,13 +38,12 @@ #endif #if defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__)) #include // For AltiVec check -#elif defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__) +#elif defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__) && !defined(HAVE_ELF_AUX_INFO) #include #include // For AltiVec check #include -#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__) +#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__) && defined(HAVE_ELF_AUX_INFO) #include -#include #elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) #include #include @@ -174,7 +173,7 @@ static int CPU_haveCPUID(void) : : "%rax", "%rcx" ); -#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) +#elif defined(_MSC_VER) && defined(_M_IX86) __asm { pushfd ; Get original EFLAGS pop eax @@ -247,7 +246,7 @@ done: " popq %%rbx \n" \ : "=a"(a), "=S"(b), "=c"(c), "=d"(d) \ : "a"(func)) -#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) +#elif defined(_MSC_VER) && defined(_M_IX86) #define cpuid(func, a, b, c, d) \ __asm { \ __asm mov eax, func \ @@ -311,7 +310,7 @@ static void CPU_calcCPUIDFeatures(void) : "%edx"); #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) // VS2010 SP1 a = (int)_xgetbv(0); -#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) +#elif defined(_MSC_VER) && defined(_M_IX86) __asm { xor ecx, ecx @@ -331,7 +330,12 @@ static int CPU_haveAltiVec(void) { volatile int altivec = 0; #ifndef SDL_CPUINFO_DISABLED -#if (defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__)) +#if (defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_OPENBSD)) && defined(__powerpc__) && defined(HAVE_ELF_AUX_INFO) + unsigned long cpufeatures = 0; + elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)); + altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC; + return altivec; +#elif (defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__)) #ifdef SDL_PLATFORM_OPENBSD int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC }; #else @@ -343,11 +347,6 @@ static int CPU_haveAltiVec(void) if (0 == error) { altivec = (hasVectorUnit != 0); } -#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__) - unsigned long cpufeatures = 0; - 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) @@ -483,8 +482,6 @@ static int CPU_haveNEON(void) return 0; // assume anything else from Apple doesn't have NEON. #elif !defined(__arm__) return 0; // not an ARM CPU at all. -#elif defined(SDL_PLATFORM_OPENBSD) - return 1; // OpenBSD only supports ARMv7 CPUs that have NEON. #elif defined(HAVE_ELF_AUX_INFO) unsigned long hasneon = 0; if (elf_aux_info(AT_HWCAP, (void *)&hasneon, (int)sizeof(hasneon)) != 0) { @@ -519,6 +516,8 @@ static int CPU_haveNEON(void) } return 0; } +#elif defined(SDL_PLATFORM_OPENBSD) + return 1; // OpenBSD only supports ARMv7 CPUs that have NEON. #elif defined(SDL_PLATFORM_EMSCRIPTEN) return 0; #else diff --git a/src/dialog/unix/SDL_zenitymessagebox.c b/src/dialog/unix/SDL_zenitymessagebox.c new file mode 100644 index 0000000000..01ca673d3c --- /dev/null +++ b/src/dialog/unix/SDL_zenitymessagebox.c @@ -0,0 +1,185 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_internal.h" + +#include "SDL_zenitymessagebox.h" + +#define ZENITY_VERSION_LEN 32 // Number of bytes to read from zenity --version (including NUL) + +#define MAX_BUTTONS 8 // Maximum number of buttons supported + +static bool parse_zenity_version(const char *version, int *major, int *minor) +{ + /* We expect the version string is in the form of MAJOR.MINOR.MICRO + * as described in meson.build. We'll ignore everything after that. + */ + const char *version_ptr = version; + char *end_ptr = NULL; + int tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10); + if (tmp == 0 && end_ptr == version_ptr) { + return SDL_SetError("failed to get zenity major version number"); + } + *major = tmp; + + if (*end_ptr == '.') { + version_ptr = end_ptr + 1; // skip the dot + tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10); + if (tmp == 0 && end_ptr == version_ptr) { + return SDL_SetError("failed to get zenity minor version number"); + } + *minor = tmp; + } else { + *minor = 0; + } + return true; +} + +static bool get_zenity_version(int *major, int *minor) +{ + const char *argv[] = { "zenity", "--version", NULL }; + bool result = false; + + SDL_Process *process = SDL_CreateProcess(argv, true); + if (!process) { + return false; + } + + char *output = SDL_ReadProcess(process, NULL, NULL); + if (output) { + result = parse_zenity_version(output, major, minor); + SDL_free(output); + } + SDL_DestroyProcess(process); + + return result; +} + +bool SDL_Zenity_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) +{ + int zenity_major = 0, zenity_minor = 0, output_len = 0; + int argc = 5, i; + const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = { + "zenity", "--question", "--switch", "--no-wrap", "--no-markup" + }; + SDL_Process *process; + + if (messageboxdata->numbuttons > MAX_BUTTONS) { + return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS); + } + + // get zenity version so we know which arg to use + if (!get_zenity_version(&zenity_major, &zenity_minor)) { + return false; // get_zenity_version() calls SDL_SetError(), so message is already set + } + + /* https://gitlab.gnome.org/GNOME/zenity/-/commit/c686bdb1b45e95acf010efd9ca0c75527fbb4dea + * This commit removed --icon-name without adding a deprecation notice. + * We need to handle it gracefully, otherwise no message box will be shown. + */ + argv[argc++] = zenity_major > 3 || (zenity_major == 3 && zenity_minor >= 90) ? "--icon" : "--icon-name"; + switch (messageboxdata->flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { + case SDL_MESSAGEBOX_ERROR: + argv[argc++] = "dialog-error"; + break; + case SDL_MESSAGEBOX_WARNING: + argv[argc++] = "dialog-warning"; + break; + case SDL_MESSAGEBOX_INFORMATION: + default: + argv[argc++] = "dialog-information"; + break; + } + + if (messageboxdata->title && messageboxdata->title[0]) { + argv[argc++] = "--title"; + argv[argc++] = messageboxdata->title; + } else { + argv[argc++] = "--title="; + } + + if (messageboxdata->message && messageboxdata->message[0]) { + argv[argc++] = "--text"; + argv[argc++] = messageboxdata->message; + } else { + argv[argc++] = "--text="; + } + + for (i = 0; i < messageboxdata->numbuttons; ++i) { + if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) { + int len = SDL_strlen(messageboxdata->buttons[i].text); + if (len > output_len) { + output_len = len; + } + + argv[argc++] = "--extra-button"; + argv[argc++] = messageboxdata->buttons[i].text; + } else { + argv[argc++] = "--extra-button="; + } + } + if (messageboxdata->numbuttons == 0) { + argv[argc++] = "--extra-button=OK"; + } + argv[argc] = NULL; + + SDL_PropertiesID props = SDL_CreateProperties(); + if (!props) { + return false; + } + SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, argv); + // If buttonID is set we need to wait and read the results + if (buttonID) { + SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); + } else { + SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); + } + process = SDL_CreateProcessWithProperties(props); + SDL_DestroyProperties(props); + if (!process) { + return false; + } + if (buttonID) { + char *output = SDL_ReadProcess(process, NULL, NULL); + if (output) { + // It likes to add a newline... + char *tmp = SDL_strrchr(output, '\n'); + if (tmp) { + *tmp = '\0'; + } + + // Check which button got pressed + for (i = 0; i < messageboxdata->numbuttons; i += 1) { + if (messageboxdata->buttons[i].text) { + if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) { + *buttonID = messageboxdata->buttons[i].buttonID; + break; + } + } + } + SDL_free(output); + } + } + SDL_DestroyProcess(process); + + return true; +} + diff --git a/src/dialog/unix/SDL_zenitymessagebox.h b/src/dialog/unix/SDL_zenitymessagebox.h new file mode 100644 index 0000000000..52ee6a5cc1 --- /dev/null +++ b/src/dialog/unix/SDL_zenitymessagebox.h @@ -0,0 +1,27 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_zenitymessagebox_h_ +#define SDL_zenitymessagebox_h_ + +extern bool SDL_Zenity_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID); + +#endif // SDL_waylandmessagebox_h_ diff --git a/src/dialog/windows/SDL_windowsdialog.c b/src/dialog/windows/SDL_windowsdialog.c index d1d034ea6f..3009df58be 100644 --- a/src/dialog/windows/SDL_windowsdialog.c +++ b/src/dialog/windows/SDL_windowsdialog.c @@ -19,19 +19,236 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_internal.h" +#include "../../core/windows/SDL_windows.h" #include "../SDL_dialog.h" #include "../SDL_dialog_utils.h" -#include +#include #include #include #include -#include "../../core/windows/SDL_windows.h" #include "../../thread/SDL_systhread.h" +#if WINVER < _WIN32_WINNT_VISTA +typedef struct _COMDLG_FILTERSPEC +{ + LPCWSTR pszName; + LPCWSTR pszSpec; +} COMDLG_FILTERSPEC; + +typedef enum FDE_OVERWRITE_RESPONSE +{ + FDEOR_DEFAULT + FDEOR_ACCEPT + FDEOR_REFUSE +} FDE_OVERWRITE_RESPONSE; + +typedef enum FDE_SHAREVIOLATION_RESPONSE +{ + FDESVR_DEFAULT + FDESVR_ACCEPT + FDESVR_REFUSE +} FDE_SHAREVIOLATION_RESPONSE; + +typedef enum FDAP +{ + FDAP_BOTTOM + FDAP_TOP +} FDAP; + +typedef ULONG SFGAOF; + +typedef enum GETPROPERTYSTOREFLAGS +{ + GPS_DEFAULT = 0x0, + GPS_HANDLERPROPERTIESONLY = 0x1, + GPS_READWRITE = 0x2, + GPS_TEMPORARY = 0x4, + GPS_FASTPROPERTIESONLY = 0x8, + GPS_OPENSLOWITEM = 0x10, + GPS_DELAYCREATION = 0x20, + GPS_BESTEFFORT = 0x40, + GPS_NO_OPLOCK = 0x80, + GPS_PREFERQUERYPROPERTIES = 0x100, + GPS_EXTRINSICPROPERTIES = 0x200, + GPS_EXTRINSICPROPERTIESONLY = 0x400, + GPS_VOLATILEPROPERTIES = 0x800, + GPS_VOLATILEPROPERTIESONLY = 0x1000, + GPS_MASK_VALID = 0x1FFF +} GETPROPERTYSTOREFLAGS; + +typedef struct _tagpropertykey { + GUID fmtid; + DWORD pid; +} PROPERTYKEY; + +#define REFPROPERTYKEY const PROPERTYKEY * const + +typedef DWORD SHCONTF; + +#endif // WINVER < _WIN32_WINNT_VISTA + +#ifndef __IFileDialog_FWD_DEFINED__ +typedef struct IFileDialog IFileDialog; +#endif +#ifndef __IShellItem_FWD_DEFINED__ +typedef struct IShellItem IShellItem; +#endif +#ifndef __IFileOpenDialog_FWD_DEFINED__ +typedef struct IFileOpenDialog IFileOpenDialog; +#endif +#ifndef __IFileDialogEvents_FWD_DEFINED__ +typedef struct IFileDialogEvents IFileDialogEvents; +#endif +#ifndef __IShellItemArray_FWD_DEFINED__ +typedef struct IShellItemArray IShellItemArray; +#endif +#ifndef __IEnumShellItems_FWD_DEFINED__ +typedef struct IEnumShellItems IEnumShellItems; +#endif +#ifndef __IShellItemFilter_FWD_DEFINED__ +typedef struct IShellItemFilter IShellItemFilter; +#endif +#ifndef __IFileDialog2_FWD_DEFINED__ +typedef struct IFileDialog2 IFileDialog2; +#endif + +#ifndef __IShellItemFilter_INTERFACE_DEFINED__ +typedef struct IShellItemFilterVtbl +{ + HRESULT (__stdcall *QueryInterface)(IShellItemFilter *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IShellItemFilter *This); + ULONG (__stdcall *Release)(IShellItemFilter *This); + HRESULT (__stdcall *IncludeItem)(IShellItemFilter *This, IShellItem *psi); + HRESULT (__stdcall *GetEnumFlagsForItem)(IShellItemFilter *This, IShellItem *psi, SHCONTF *pgrfFlags); +} IShellItemFilterVtbl; + +struct IShellItemFilter +{ + IShellItemFilterVtbl *lpVtbl; +}; + +#endif // #ifndef __IShellItemFilter_INTERFACE_DEFINED__ + +#ifndef __IFileDialogEvents_INTERFACE_DEFINED__ +typedef struct IFileDialogEventsVtbl +{ + HRESULT (__stdcall *QueryInterface)(IFileDialogEvents *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IFileDialogEvents *This); + ULONG (__stdcall *Release)(IFileDialogEvents *This); + HRESULT (__stdcall *OnFileOk)(IFileDialogEvents *This, IFileDialog *pfd); + HRESULT (__stdcall *OnFolderChanging)(IFileDialogEvents *This, IFileDialog *pfd, IShellItem *psiFolder); + HRESULT (__stdcall *OnFolderChange)(IFileDialogEvents *This, IFileDialog *pfd); + HRESULT (__stdcall *OnSelectionChange)(IFileDialogEvents *This, IFileDialog *pfd); + HRESULT (__stdcall *OnShareViolation)(IFileDialogEvents *This, IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse); + HRESULT (__stdcall *OnTypeChange)(IFileDialogEvents *This, IFileDialog *pfd); + HRESULT (__stdcall *OnOverwrite)(IFileDialogEvents *This, IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse); +} IFileDialogEventsVtbl; + +struct IFileDialogEvents +{ + IFileDialogEventsVtbl *lpVtbl; +}; + +#endif // #ifndef __IFileDialogEvents_INTERFACE_DEFINED__ + +#ifndef __IShellItem_INTERFACE_DEFINED__ +typedef enum _SIGDN { + SIGDN_NORMALDISPLAY = 0x00000000, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004C000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007C001, + SIGDN_PARENTRELATIVE = 0x80080001, + SIGDN_PARENTRELATIVEFORUI = 0x80094001 +} SIGDN; + +enum _SICHINTF { + SICHINT_DISPLAY = 0x00000000, + SICHINT_ALLFIELDS = 0x80000000, + SICHINT_CANONICAL = 0x10000000, + SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000 +}; +typedef DWORD SICHINTF; + +extern const IID IID_IShellItem; + +typedef struct IShellItemVtbl +{ + HRESULT (__stdcall *QueryInterface)(IShellItem *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IShellItem *This); + ULONG (__stdcall *Release)(IShellItem *This); + HRESULT (__stdcall *BindToHandler)(IShellItem *This, IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv); + HRESULT (__stdcall *GetParent)(IShellItem *This, IShellItem **ppsi); + HRESULT (__stdcall *GetDisplayName)(IShellItem *This, SIGDN sigdnName, LPWSTR *ppszName); + HRESULT (__stdcall *GetAttributes)(IShellItem *This, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs); + HRESULT (__stdcall *Compare)(IShellItem *This, IShellItem *psi, SICHINTF hint, int *piOrder); +} IShellItemVtbl; + +struct IShellItem +{ + IShellItemVtbl *lpVtbl; +}; + +#endif // #ifndef __IShellItem_INTERFACE_DEFINED__ + +#ifndef __IEnumShellItems_INTERFACE_DEFINED__ +typedef struct IEnumShellItemsVtbl +{ + HRESULT (__stdcall *QueryInterface)(IEnumShellItems *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IEnumShellItems *This); + ULONG (__stdcall *Release)(IEnumShellItems *This); + HRESULT (__stdcall *Next)(IEnumShellItems *This, ULONG celt, IShellItem **rgelt, ULONG *pceltFetched); + HRESULT (__stdcall *Skip)(IEnumShellItems *This, ULONG celt); + HRESULT (__stdcall *Reset)(IEnumShellItems *This); + HRESULT (__stdcall *Clone)(IEnumShellItems *This, IEnumShellItems **ppenum); +} IEnumShellItemsVtbl; + +struct IEnumShellItems +{ + IEnumShellItemsVtbl *lpVtbl; +}; + +#endif // #ifndef __IEnumShellItems_INTERFACE_DEFINED__ + +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +typedef enum SIATTRIBFLAGS +{ + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000 +} SIATTRIBFLAGS; + +typedef struct IShellItemArrayVtbl +{ + HRESULT (__stdcall *QueryInterface)(IShellItemArray *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IShellItemArray *This); + ULONG (__stdcall *Release)(IShellItemArray *This); + HRESULT (__stdcall *BindToHandler)(IShellItemArray *This, IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut); + HRESULT (__stdcall *GetPropertyStore)(IShellItemArray *This, GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv); + HRESULT (__stdcall *GetPropertyDescriptionList)(IShellItemArray *This, REFPROPERTYKEY keyType, REFIID riid, void **ppv); + HRESULT (__stdcall *GetAttributes)(IShellItemArray *This, SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs); + HRESULT (__stdcall *GetCount)(IShellItemArray *This, DWORD *pdwNumItems); + HRESULT (__stdcall *GetItemAt)(IShellItemArray *This, DWORD dwIndex, IShellItem **ppsi); + HRESULT (__stdcall *EnumItems)(IShellItemArray *This, IEnumShellItems **ppenumShellItems); +} IShellItemArrayVtbl; + +struct IShellItemArray +{ + IShellItemArrayVtbl *lpVtbl; +}; + +#endif // #ifndef __IShellItemArray_INTERFACE_DEFINED__ + // Flags/GUIDs defined for compatibility with pre-Vista headers #ifndef __IFileDialog_INTERFACE_DEFINED__ -enum _FILEOPENDIALOGOPTIONS { +enum _FILEOPENDIALOGOPTIONS +{ FOS_OVERWRITEPROMPT = 0x2, FOS_STRICTFILETYPES = 0x4, FOS_NOCHANGEDIR = 0x8, @@ -49,6 +266,7 @@ enum _FILEOPENDIALOGOPTIONS { FOS_HIDEMRUPLACES = 0x20000, FOS_HIDEPINNEDPLACES = 0x40000, FOS_NODEREFERENCELINKS = 0x100000, + FOS_OKBUTTONNEEDSINTERACTION = 0x200000, FOS_DONTADDTORECENT = 0x2000000, FOS_FORCESHOWHIDDEN = 0x10000000, FOS_DEFAULTNOMINIMODE = 0x20000000, @@ -58,133 +276,127 @@ enum _FILEOPENDIALOGOPTIONS { typedef DWORD FILEOPENDIALOGOPTIONS; -typedef enum FDAP { - FDAP_BOTTOM = 0, - FDAP_TOP = 1 -} FDAP; +extern const IID IID_IFileDialog; -/* *INDENT-OFF* */ // clang-format off typedef struct IFileDialogVtbl { - HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileDialog *, REFIID, void **); - ULONG (STDMETHODCALLTYPE *AddRef)(IFileDialog *); - ULONG (STDMETHODCALLTYPE *Release)(IFileDialog *); - HRESULT (STDMETHODCALLTYPE *Show)(IFileDialog *, HWND); - HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileDialog *, UINT, const COMDLG_FILTERSPEC *); - HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileDialog *, UINT); - HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileDialog *, UINT *); - HRESULT (STDMETHODCALLTYPE *Advise)(IFileDialog *, IFileDialogEvents *, DWORD *); - HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileDialog *, DWORD); - HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileDialog *, FILEOPENDIALOGOPTIONS); - HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileDialog *, FILEOPENDIALOGOPTIONS *); - HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileDialog *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileDialog *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileDialog *, LPWSTR *); - HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetResult)(IFileDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileDialog *, IShellItem *, FDAP); - HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *Close)(IFileDialog *, HRESULT); - HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *, REFGUID); - HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileDialog *); - HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileDialog *,IShellItemFilter *); + HRESULT (__stdcall *QueryInterface)(IFileDialog *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IFileDialog *This); + ULONG (__stdcall *Release)(IFileDialog *This); + HRESULT (__stdcall *Show)(IFileDialog *This, HWND hwndOwner); + HRESULT (__stdcall *SetFileTypes)(IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT (__stdcall *SetFileTypeIndex)(IFileDialog *This, UINT iFileType); + HRESULT (__stdcall *GetFileTypeIndex)(IFileDialog *This, UINT *piFileType); + HRESULT (__stdcall *Advise)(IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie); + HRESULT (__stdcall *Unadvise)(IFileDialog *This, DWORD dwCookie); + HRESULT (__stdcall *SetOptions)(IFileDialog *This, FILEOPENDIALOGOPTIONS fos); + HRESULT (__stdcall *GetOptions)(IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos); + HRESULT (__stdcall *SetDefaultFolder)(IFileDialog *This, IShellItem *psi); + HRESULT (__stdcall *SetFolder)(IFileDialog *This, IShellItem *psi); + HRESULT (__stdcall *GetFolder)(IFileDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *GetCurrentSelection)(IFileDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *SetFileName)(IFileDialog *This, LPCWSTR pszName); + HRESULT (__stdcall *GetFileName)(IFileDialog *This, LPWSTR *pszName); + HRESULT (__stdcall *SetTitle)(IFileDialog *This, LPCWSTR pszTitle); + HRESULT (__stdcall *SetOkButtonLabel)(IFileDialog *This, LPCWSTR pszText); + HRESULT (__stdcall *SetFileNameLabel)(IFileDialog *This, LPCWSTR pszLabel); + HRESULT (__stdcall *GetResult)(IFileDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *AddPlace)(IFileDialog *This, IShellItem *psi, FDAP fdap); + HRESULT (__stdcall *SetDefaultExtension)(IFileDialog *This, LPCWSTR pszDefaultExtension); + HRESULT (__stdcall *Close)(IFileDialog *This, HRESULT hr); + HRESULT (__stdcall *SetClientGuid)(IFileDialog *This, REFGUID guid); + HRESULT (__stdcall *ClearClientData)(IFileDialog *This); + HRESULT (__stdcall *SetFilter)(IFileDialog *This, IShellItemFilter *pFilter); } IFileDialogVtbl; -/* *INDENT-ON* */ // clang-format on struct IFileDialog { - const struct IFileDialogVtbl *lpVtbl; + IFileDialogVtbl *lpVtbl; }; -#endif -#ifndef __IFileDialog2_INTERFACE_DEFINED__ -/* *INDENT-OFF* */ // clang-format off -typedef struct IFileDialog2Vtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileDialog2 *, REFIID, void **); - ULONG (STDMETHODCALLTYPE *AddRef)(IFileDialog2 *); - ULONG (STDMETHODCALLTYPE *Release)(IFileDialog2 *); - HRESULT (STDMETHODCALLTYPE *Show)(IFileDialog2 *, HWND); - HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileDialog2 *, UINT, const COMDLG_FILTERSPEC *); - HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileDialog2 *, UINT); - HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileDialog2 *, UINT *); - HRESULT (STDMETHODCALLTYPE *Advise)(IFileDialog2 *, IFileDialogEvents *, DWORD *); - HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileDialog2 *, DWORD); - HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileDialog2 *, FILEOPENDIALOGOPTIONS); - HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileDialog2 *, FILEOPENDIALOGOPTIONS *); - HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileDialog2 *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileDialog2 *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileDialog2 *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileDialog2 *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileDialog2 *, LPWSTR *); - HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetResult)(IFileDialog2 *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileDialog2 *, IShellItem *, FDAP); - HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *Close)(IFileDialog2 *, HRESULT); - HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileDialog2 *, REFGUID); - HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileDialog2 *); - HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileDialog2 *, IShellItemFilter *); - HRESULT (STDMETHODCALLTYPE *SetCancelButtonLabel)(IFileDialog2 *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetNavigationRoot)(IFileDialog2 *, IShellItem *); -} IFileDialog2Vtbl; -/* *INDENT-ON* */ // clang-format on - -struct IFileDialog2 -{ - const struct IFileDialog2Vtbl *lpVtbl; -}; -#endif +#endif // #ifndef __IFileDialog_INTERFACE_DEFINED__ #ifndef __IFileOpenDialog_INTERFACE_DEFINED__ -/* *INDENT-OFF* */ // clang-format off typedef struct IFileOpenDialogVtbl { - HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileOpenDialog *, REFIID, void **); - ULONG (STDMETHODCALLTYPE *AddRef)(IFileOpenDialog *); - ULONG (STDMETHODCALLTYPE *Release)(IFileOpenDialog *); - HRESULT (STDMETHODCALLTYPE *Show)(IFileOpenDialog *, HWND); - HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileOpenDialog *, UINT, const COMDLG_FILTERSPEC *); - HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileOpenDialog *, UINT); - HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileOpenDialog *, UINT *); - HRESULT (STDMETHODCALLTYPE *Advise)(IFileOpenDialog *, IFileDialogEvents *, DWORD *); - HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileOpenDialog *, DWORD); - HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileOpenDialog *, FILEOPENDIALOGOPTIONS); - HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileOpenDialog *, FILEOPENDIALOGOPTIONS *); - HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileOpenDialog *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileOpenDialog *, IShellItem *); - HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileOpenDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileOpenDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileOpenDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileOpenDialog *, LPWSTR *); - HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileOpenDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileOpenDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileOpenDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *GetResult)(IFileOpenDialog *, IShellItem **); - HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileOpenDialog *, IShellItem *, FDAP); - HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileOpenDialog *, LPCWSTR); - HRESULT (STDMETHODCALLTYPE *Close)(IFileOpenDialog *, HRESULT); - HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileOpenDialog *, REFGUID); - HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileOpenDialog *); - HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileOpenDialog *, IShellItemFilter *); - HRESULT (STDMETHODCALLTYPE *GetResults)(IFileOpenDialog *, IShellItemArray **); - HRESULT (STDMETHODCALLTYPE *GetSelectedItems)(IFileOpenDialog *, IShellItemArray **); + HRESULT (__stdcall *QueryInterface)(IFileOpenDialog *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IFileOpenDialog *This); + ULONG (__stdcall *Release)(IFileOpenDialog *This); + HRESULT (__stdcall *Show)(IFileOpenDialog *This, HWND hwndOwner); + HRESULT (__stdcall *SetFileTypes)(IFileOpenDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT (__stdcall *SetFileTypeIndex)(IFileOpenDialog *This, UINT iFileType); + HRESULT (__stdcall *GetFileTypeIndex)(IFileOpenDialog *This, UINT *piFileType); + HRESULT (__stdcall *Advise)(IFileOpenDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie); + HRESULT (__stdcall *Unadvise)(IFileOpenDialog *This, DWORD dwCookie); + HRESULT (__stdcall *SetOptions)(IFileOpenDialog *This, FILEOPENDIALOGOPTIONS fos); + HRESULT (__stdcall *GetOptions)(IFileOpenDialog *This, FILEOPENDIALOGOPTIONS *pfos); + HRESULT (__stdcall *SetDefaultFolder)(IFileOpenDialog *This, IShellItem *psi); + HRESULT (__stdcall *SetFolder)(IFileOpenDialog *This, IShellItem *psi); + HRESULT (__stdcall *GetFolder)(IFileOpenDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *GetCurrentSelection)(IFileOpenDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *SetFileName)(IFileOpenDialog *This, LPCWSTR pszName); + HRESULT (__stdcall *GetFileName)(IFileOpenDialog *This, LPWSTR *pszName); + HRESULT (__stdcall *SetTitle)(IFileOpenDialog *This, LPCWSTR pszTitle); + HRESULT (__stdcall *SetOkButtonLabel)(IFileOpenDialog *This, LPCWSTR pszText); + HRESULT (__stdcall *SetFileNameLabel)(IFileOpenDialog *This, LPCWSTR pszLabel); + HRESULT (__stdcall *GetResult)(IFileOpenDialog *This, IShellItem **ppsi); + HRESULT (__stdcall *AddPlace)(IFileOpenDialog *This, IShellItem *psi, FDAP fdap); + HRESULT (__stdcall *SetDefaultExtension)(IFileOpenDialog *This, LPCWSTR pszDefaultExtension); + HRESULT (__stdcall *Close)(IFileOpenDialog *This, HRESULT hr); + HRESULT (__stdcall *SetClientGuid)(IFileOpenDialog *This, REFGUID guid); + HRESULT (__stdcall *ClearClientData)(IFileOpenDialog *This); + HRESULT (__stdcall *SetFilter)(IFileOpenDialog *This, IShellItemFilter *pFilter); + HRESULT (__stdcall *GetResults)(IFileOpenDialog *This, IShellItemArray **ppenum); + HRESULT (__stdcall *GetSelectedItems)(IFileOpenDialog *This, IShellItemArray **ppsai); } IFileOpenDialogVtbl; -/* *INDENT-ON* */ // clang-format on struct IFileOpenDialog { - const struct IFileOpenDialogVtbl *lpVtbl; + IFileOpenDialogVtbl *lpVtbl; }; -#endif + +#endif // #ifndef __IFileOpenDialog_INTERFACE_DEFINED__ + +#ifndef __IFileDialog2_INTERFACE_DEFINED__ +typedef struct IFileDialog2Vtbl +{ + HRESULT (__stdcall *QueryInterface)(IFileDialog2 *This, REFIID riid, void **ppvObject); + ULONG (__stdcall *AddRef)(IFileDialog2 *This); + ULONG (__stdcall *Release)(IFileDialog2 *This); + HRESULT (__stdcall *Show)(IFileDialog2 *This, HWND hwndOwner); + HRESULT (__stdcall *SetFileTypes)(IFileDialog2 *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT (__stdcall *SetFileTypeIndex)(IFileDialog2 *This, UINT iFileType); + HRESULT (__stdcall *GetFileTypeIndex)(IFileDialog2 *This, UINT *piFileType); + HRESULT (__stdcall *Advise)(IFileDialog2 *This, IFileDialogEvents *pfde, DWORD *pdwCookie); + HRESULT (__stdcall *Unadvise)(IFileDialog2 *This, DWORD dwCookie); + HRESULT (__stdcall *SetOptions)(IFileDialog2 *This, FILEOPENDIALOGOPTIONS fos); + HRESULT (__stdcall *GetOptions)(IFileDialog2 *This, FILEOPENDIALOGOPTIONS *pfos); + HRESULT (__stdcall *SetDefaultFolder)(IFileDialog2 *This, IShellItem *psi); + HRESULT (__stdcall *SetFolder)(IFileDialog2 *This, IShellItem *psi); + HRESULT (__stdcall *GetFolder)(IFileDialog2 *This, IShellItem **ppsi); + HRESULT (__stdcall *GetCurrentSelection)(IFileDialog2 *This, IShellItem **ppsi); + HRESULT (__stdcall *SetFileName)(IFileDialog2 *This, LPCWSTR pszName); + HRESULT (__stdcall *GetFileName)(IFileDialog2 *This, LPWSTR *pszName); + HRESULT (__stdcall *SetTitle)(IFileDialog2 *This, LPCWSTR pszTitle); + HRESULT (__stdcall *SetOkButtonLabel)(IFileDialog2 *This, LPCWSTR pszText); + HRESULT (__stdcall *SetFileNameLabel)(IFileDialog2 *This, LPCWSTR pszLabel); + HRESULT (__stdcall *GetResult)(IFileDialog2 *This, IShellItem **ppsi); + HRESULT (__stdcall *AddPlace)(IFileDialog2 *This, IShellItem *psi, FDAP fdap); + HRESULT (__stdcall *SetDefaultExtension)(IFileDialog2 *This, LPCWSTR pszDefaultExtension); + HRESULT (__stdcall *Close)(IFileDialog2 *This, HRESULT hr); + HRESULT (__stdcall *SetClientGuid)(IFileDialog2 *This, REFGUID guid); + HRESULT (__stdcall *ClearClientData)(IFileDialog2 *This); + HRESULT (__stdcall *SetFilter)(IFileDialog2 *This, IShellItemFilter *pFilter); + HRESULT (__stdcall *SetCancelButtonLabel)(IFileDialog2 *This, LPCWSTR pszLabel); + HRESULT (__stdcall *SetNavigationRoot)(IFileDialog2 *This, IShellItem *psi); +} IFileDialog2Vtbl; + +struct IFileDialog2 +{ + IFileDialog2Vtbl *lpVtbl; +}; + +#endif // #ifndef __IFileDialog2_INTERFACE_DEFINED__ /* *INDENT-OFF* */ // clang-format off static const CLSID SDL_CLSID_FileOpenDialog = { 0xdc1c5a9c, 0xe88a, 0x4dde, { 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7 } }; @@ -410,11 +622,9 @@ bool windows_ShowModernFileFolderDialog(SDL_FileDialogType dialog_type, const ch CHECK(pFileDialog->lpVtbl->SetFileTypes(pFileDialog, nfilters, filter_data)); } - // SetFolder would enforce using the same location each and every time, but - // Windows docs recommend against it if (default_folder_w) { CHECK(pSHCreateItemFromParsingName(default_folder_w, NULL, &IID_IShellItem, (void**)&pFolderItem)); - CHECK(pFileDialog->lpVtbl->SetDefaultFolder(pFileDialog, pFolderItem)); + CHECK(pFileDialog->lpVtbl->SetFolder(pFileDialog, pFolderItem)); } if (default_file_w) { diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c index a7b51af6be..7b0ac7afad 100644 --- a/src/dynapi/SDL_dynapi.c +++ b/src/dynapi/SDL_dynapi.c @@ -40,6 +40,8 @@ #include #define SDL_MAIN_NOIMPL // don't drag in header-only implementation of SDL_main #include +#include "../core/SDL_core_unsupported.h" +#include "../video/SDL_video_unsupported.h" // These headers have system specific definitions, so aren't included above @@ -86,7 +88,7 @@ static void SDL_InitDynamicAPI(void); } #define SDL_DYNAPI_VARARGS(_static, name, initcall) \ - _static bool SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ + _static bool SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ { \ char buf[128], *str = buf; \ int result; \ @@ -98,7 +100,7 @@ static void SDL_InitDynamicAPI(void); if (result >= 0 && (size_t)result >= sizeof(buf)) { \ str = NULL; \ va_start(ap, fmt); \ - result = jump_table.SDL_vasprintf(&str, fmt, ap); \ + result = jump_table.SDL_vasprintf(&str, fmt, ap); \ va_end(ap); \ } \ if (result >= 0) { \ @@ -107,7 +109,7 @@ static void SDL_InitDynamicAPI(void); if (str != buf) { \ jump_table.SDL_free(str); \ } \ - return false; \ + return false; \ } \ _static int SDLCALL SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) \ { \ @@ -149,7 +151,7 @@ static void SDL_InitDynamicAPI(void); va_end(ap); \ return result; \ } \ - _static size_t SDLCALL SDL_IOprintf##name(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ + _static size_t SDLCALL SDL_IOprintf##name(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ { \ size_t result; \ va_list ap; \ @@ -199,7 +201,7 @@ static void SDL_InitDynamicAPI(void); jump_table.SDL_LogMessageV(category, priority, fmt, ap); \ va_end(ap); \ } \ - SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Trace, TRACE) \ + SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Trace, TRACE) \ SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \ SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \ SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \ @@ -500,9 +502,6 @@ static void dynapi_warn(const char *msg) extern "C" { #endif extern SDL_NORETURN void SDL_ExitProcess(int exitcode); -#ifdef __WATCOMC__ -#pragma aux SDL_ExitProcess aborts; -#endif #ifdef __cplusplus } #endif diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 0627fe9ed7..967a424970 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1240,7 +1240,7 @@ SDL3_0.0.0 { SDL_GetDefaultTextureScaleMode; SDL_CreateGPURenderState; SDL_SetGPURenderStateFragmentUniforms; - SDL_SetRenderGPUState; + SDL_SetGPURenderState; SDL_DestroyGPURenderState; SDL_SetWindowProgressState; SDL_SetWindowProgressValue; @@ -1255,6 +1255,11 @@ SDL3_0.0.0 { SDL_PutAudioStreamDataNoCopy; SDL_AddAtomicU32; SDL_hid_get_properties; + SDL_GetPixelFormatFromGPUTextureFormat; + SDL_GetGPUTextureFormatFromPixelFormat; + SDL_SetTexturePalette; + SDL_GetTexturePalette; + SDL_GetGPURendererDevice; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index c074941858..b0693c5471 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1265,7 +1265,7 @@ #define SDL_GetDefaultTextureScaleMode SDL_GetDefaultTextureScaleMode_REAL #define SDL_CreateGPURenderState SDL_CreateGPURenderState_REAL #define SDL_SetGPURenderStateFragmentUniforms SDL_SetGPURenderStateFragmentUniforms_REAL -#define SDL_SetRenderGPUState SDL_SetRenderGPUState_REAL +#define SDL_SetGPURenderState SDL_SetGPURenderState_REAL #define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL #define SDL_SetWindowProgressState SDL_SetWindowProgressState_REAL #define SDL_SetWindowProgressValue SDL_SetWindowProgressValue_REAL @@ -1280,3 +1280,9 @@ #define SDL_PutAudioStreamDataNoCopy SDL_PutAudioStreamDataNoCopy_REAL #define SDL_AddAtomicU32 SDL_AddAtomicU32_REAL #define SDL_hid_get_properties SDL_hid_get_properties_REAL +#define SDL_GetPixelFormatFromGPUTextureFormat SDL_GetPixelFormatFromGPUTextureFormat_REAL +#define SDL_GetGPUTextureFormatFromPixelFormat SDL_GetGPUTextureFormatFromPixelFormat_REAL +#define JNI_OnLoad JNI_OnLoad_REAL +#define SDL_SetTexturePalette SDL_SetTexturePalette_REAL +#define SDL_GetTexturePalette SDL_GetTexturePalette_REAL +#define SDL_GetGPURendererDevice SDL_GetGPURendererDevice_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 9876a3de8d..18195db8a8 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1273,7 +1273,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetDefaultTextureScaleMode,(SDL_Renderer *a,SDL_ScaleMo SDL_DYNAPI_PROC(bool,SDL_GetDefaultTextureScaleMode,(SDL_Renderer *a,SDL_ScaleMode *b),(a,b),return) SDL_DYNAPI_PROC(SDL_GPURenderState*,SDL_CreateGPURenderState,(SDL_Renderer *a,SDL_GPURenderStateCreateInfo *b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateFragmentUniforms,(SDL_GPURenderState *a,Uint32 b,const void *c,Uint32 d),(a,b,c,d),return) -SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_SetGPURenderState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_DestroyGPURenderState,(SDL_GPURenderState *a),(a),) SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressState,(SDL_Window *a,SDL_ProgressState b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressValue,(SDL_Window *a,float b),(a,b),return) @@ -1282,9 +1282,15 @@ SDL_DYNAPI_PROC(float,SDL_GetWindowProgressValue,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_SetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode b,SDL_TextureAddressMode c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_GetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode *b,SDL_TextureAddressMode *c),(a,b,c),return) SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetGPUDeviceProperties,(SDL_GPUDevice *a),(a),return) -SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateGPURenderer,(SDL_Window *a,SDL_GPUShaderFormat b,SDL_GPUDevice **c),(a,b,c),return) +SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateGPURenderer,(SDL_GPUDevice *a,SDL_Window *b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamPlanarData,(SDL_AudioStream *a,const void * const*b,int c,int d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_GetEventDescription,(const SDL_Event *a,char *b,int c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamDataNoCopy,(SDL_AudioStream *a,const void *b,int c,SDL_AudioStreamDataCompleteCallback d,void *e),(a,b,c,d,e),return) SDL_DYNAPI_PROC(Uint32,SDL_AddAtomicU32,(SDL_AtomicU32 *a,int b),(a,b),return) SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_hid_get_properties,(SDL_hid_device *a),(a),return) +SDL_DYNAPI_PROC(SDL_PixelFormat,SDL_GetPixelFormatFromGPUTextureFormat,(SDL_GPUTextureFormat a),(a),return) +SDL_DYNAPI_PROC(SDL_GPUTextureFormat,SDL_GetGPUTextureFormatFromPixelFormat,(SDL_PixelFormat a),(a),return) +SDL_DYNAPI_PROC(Sint32,JNI_OnLoad,(JavaVM *a, void *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_SetTexturePalette,(SDL_Texture *a,SDL_Palette *b),(a,b),return) +SDL_DYNAPI_PROC(SDL_Palette*,SDL_GetTexturePalette,(SDL_Texture *a),(a),return) +SDL_DYNAPI_PROC(SDL_GPUDevice*,SDL_GetGPURendererDevice,(SDL_Renderer *a),(a),return) diff --git a/src/dynapi/SDL_dynapi_unsupported.h b/src/dynapi/SDL_dynapi_unsupported.h index 143943abcc..394f837ae5 100644 --- a/src/dynapi/SDL_dynapi_unsupported.h +++ b/src/dynapi/SDL_dynapi_unsupported.h @@ -33,20 +33,4 @@ typedef struct ID3D11Device ID3D11Device; typedef struct IDirect3DDevice9 IDirect3DDevice9; #endif -#ifndef SDL_PLATFORM_GDK -typedef struct XTaskQueueHandle XTaskQueueHandle; -#endif - -#ifndef SDL_PLATFORM_GDK -typedef struct XUserHandle XUserHandle; -#endif - -#ifndef SDL_PLATFORM_ANDROID -typedef void *SDL_RequestAndroidPermissionCallback; -#endif - -#ifndef SDL_PLATFORM_IOS -typedef void *SDL_iOSAnimationCallback; -#endif - #endif diff --git a/src/dynapi/gendynapi.py b/src/dynapi/gendynapi.py index 6aba3cb25b..6cf9050081 100755 --- a/src/dynapi/gendynapi.py +++ b/src/dynapi/gendynapi.py @@ -45,6 +45,7 @@ SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3" SDL_DYNAPI_PROCS_H = SDL_ROOT / "src/dynapi/SDL_dynapi_procs.h" SDL_DYNAPI_OVERRIDES_H = SDL_ROOT / "src/dynapi/SDL_dynapi_overrides.h" SDL_DYNAPI_SYM = SDL_ROOT / "src/dynapi/SDL_dynapi.sym" +TESTSYMBOLS = SDL_ROOT / "test/testsymbols.c" RE_EXTERN_C = re.compile(r'.*extern[ "]*C[ "].*') RE_COMMENT_REMOVE_CONTENT = re.compile(r'\/\*.*\*/') @@ -511,6 +512,20 @@ def add_dyn_api(proc: SdlProcedure) -> None: for line in new_input: f.write(line) + # File: test/testsymbols.c + # + # Add before "extra symbols go here" line + with TESTSYMBOLS.open() as f: + new_input = [] + for line in f: + if "extra symbols go here" in line: + new_input.append(f" SDL_SYMBOL_ITEM({proc.name}),\n") + new_input.append(line) + + with TESTSYMBOLS.open("w", newline="") as f: + for line in new_input: + f.write(line) + def main(): parser = argparse.ArgumentParser() diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index c04d52b282..ef3510320a 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -29,6 +29,7 @@ #include "../audio/SDL_audio_c.h" #include "../camera/SDL_camera_c.h" #include "../timer/SDL_timer_c.h" +#include "../core/linux/SDL_udev.h" #ifndef SDL_JOYSTICK_DISABLED #include "../joystick/SDL_joystick_c.h" #endif @@ -532,7 +533,6 @@ int SDL_GetEventDescription(const SDL_Event *event, char *buf, int buflen) SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESIZED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_METAL_VIEW_RESIZED); - SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SAFE_AREA_CHANGED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MINIMIZED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MAXIMIZED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESTORED); @@ -545,6 +545,7 @@ int SDL_GetEventDescription(const SDL_Event *event, char *buf, int buflen) SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ICCPROF_CHANGED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_CHANGED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SAFE_AREA_CHANGED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_OCCLUDED); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ENTER_FULLSCREEN); SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_LEAVE_FULLSCREEN); @@ -1131,7 +1132,7 @@ static int SDL_PeepEventsInternal(SDL_Event *events, int numevents, SDL_EventAct return -1; } if (action == SDL_ADDEVENT) { - if (!events) { + CHECK_PARAM(!events) { SDL_UnlockMutex(SDL_EventQ.lock); return SDL_InvalidParamError("events"); } @@ -1423,6 +1424,10 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w void SDL_PumpEventMaintenance(void) { +#ifdef SDL_USE_LIBUDEV + SDL_UDEV_Poll(); +#endif + #ifndef SDL_AUDIO_DISABLED SDL_UpdateAudio(); #endif @@ -1671,6 +1676,8 @@ bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) #ifdef SDL_PLATFORM_ANDROID for (;;) { + SDL_PumpEventsInternal(true); + if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { return true; } diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index bb43206024..e7d5e2f9f0 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -44,12 +44,6 @@ #define KEYCODE_OPTION_LATIN_LETTERS 0x04 #define DEFAULT_KEYCODE_OPTIONS (KEYCODE_OPTION_FRENCH_NUMBERS | KEYCODE_OPTION_LATIN_LETTERS) -typedef struct SDL_KeyboardInstance -{ - SDL_KeyboardID instance_id; - char *name; -} SDL_KeyboardInstance; - typedef struct SDL_Keyboard { // Data common to all keyboards @@ -65,7 +59,9 @@ typedef struct SDL_Keyboard static SDL_Keyboard SDL_keyboard; static int SDL_keyboard_count; -static SDL_KeyboardInstance *SDL_keyboards; +static SDL_KeyboardID *SDL_keyboards; +static SDL_HashTable *SDL_keyboard_names; +static bool SDL_keyboard_quitting; static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) { @@ -94,6 +90,9 @@ bool SDL_InitKeyboard(void) { SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS, SDL_KeycodeOptionsChanged, &SDL_keyboard); + + SDL_keyboard_names = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL); + return true; } @@ -111,14 +110,14 @@ bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys) static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID) { for (int i = 0; i < SDL_keyboard_count; ++i) { - if (keyboardID == SDL_keyboards[i].instance_id) { + if (keyboardID == SDL_keyboards[i]) { return i; } } return -1; } -void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_event) +void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name) { int keyboard_index = SDL_GetKeyboardIndex(keyboardID); if (keyboard_index >= 0) { @@ -128,26 +127,27 @@ void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_even SDL_assert(keyboardID != 0); - SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards)); + SDL_KeyboardID *keyboards = (SDL_KeyboardID *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards)); if (!keyboards) { return; } - SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count]; - instance->instance_id = keyboardID; - instance->name = SDL_strdup(name ? name : ""); + keyboards[SDL_keyboard_count] = keyboardID; SDL_keyboards = keyboards; ++SDL_keyboard_count; - if (send_event) { - SDL_Event event; - SDL_zero(event); - event.type = SDL_EVENT_KEYBOARD_ADDED; - event.kdevice.which = keyboardID; - SDL_PushEvent(&event); + if (!name) { + name = "Keyboard"; } + SDL_InsertIntoHashTable(SDL_keyboard_names, (const void *)(uintptr_t)keyboardID, SDL_strdup(name), true); + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_KEYBOARD_ADDED; + event.kdevice.which = keyboardID; + SDL_PushEvent(&event); } -void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event) +void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID) { int keyboard_index = SDL_GetKeyboardIndex(keyboardID); if (keyboard_index < 0) { @@ -155,14 +155,12 @@ void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event) return; } - SDL_free(SDL_keyboards[keyboard_index].name); - if (keyboard_index != SDL_keyboard_count - 1) { SDL_memmove(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index])); } --SDL_keyboard_count; - if (send_event) { + if (!SDL_keyboard_quitting) { SDL_Event event; SDL_zero(event); event.type = SDL_EVENT_KEYBOARD_REMOVED; @@ -188,7 +186,7 @@ SDL_KeyboardID *SDL_GetKeyboards(int *count) } for (i = 0; i < SDL_keyboard_count; ++i) { - keyboards[i] = SDL_keyboards[i].instance_id; + keyboards[i] = SDL_keyboards[i]; } keyboards[i] = 0; } else { @@ -202,12 +200,17 @@ SDL_KeyboardID *SDL_GetKeyboards(int *count) const char *SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id) { - int keyboard_index = SDL_GetKeyboardIndex(instance_id); - if (keyboard_index < 0) { + const char *name = NULL; + if (!SDL_FindInHashTable(SDL_keyboard_names, (const void *)(uintptr_t)instance_id, (const void **)&name)) { SDL_SetError("Keyboard %" SDL_PRIu32 " not found", instance_id); return NULL; } - return SDL_GetPersistentString(SDL_keyboards[keyboard_index].name); + if (!name) { + // SDL_strdup() failed during insert + SDL_OutOfMemory(); + return NULL; + } + return name; } void SDL_ResetKeyboard(void) @@ -869,12 +872,17 @@ void SDL_SendEditingTextCandidates(char **candidates, int num_candidates, int se void SDL_QuitKeyboard(void) { + SDL_keyboard_quitting = true; + for (int i = SDL_keyboard_count; i--;) { - SDL_RemoveKeyboard(SDL_keyboards[i].instance_id, false); + SDL_RemoveKeyboard(SDL_keyboards[i]); } SDL_free(SDL_keyboards); SDL_keyboards = NULL; + SDL_DestroyHashTable(SDL_keyboard_names); + SDL_keyboard_names = NULL; + if (SDL_keyboard.keymap && SDL_keyboard.keymap->auto_release) { SDL_DestroyKeymap(SDL_keyboard.keymap); SDL_keyboard.keymap = NULL; @@ -882,13 +890,15 @@ void SDL_QuitKeyboard(void) SDL_RemoveHintCallback(SDL_HINT_KEYCODE_OPTIONS, SDL_KeycodeOptionsChanged, &SDL_keyboard); + + SDL_keyboard_quitting = false; } const bool *SDL_GetKeyboardState(int *numkeys) { SDL_Keyboard *keyboard = &SDL_keyboard; - if (numkeys != (int *)0) { + if (numkeys) { *numkeys = SDL_SCANCODE_COUNT; } return keyboard->keystate; diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h index ddfb5c5747..1e26a54c31 100644 --- a/src/events/SDL_keyboard_c.h +++ b/src/events/SDL_keyboard_c.h @@ -38,10 +38,10 @@ extern bool SDL_InitKeyboard(void); extern bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys); // A keyboard has been added to the system -extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_event); +extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name); // A keyboard has been removed from the system -extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event); +extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID); // Set the mapping of scancode to key codes extern void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event); diff --git a/src/events/SDL_keymap.c b/src/events/SDL_keymap.c index 9960aa9d60..c17e487a48 100644 --- a/src/events/SDL_keymap.c +++ b/src/events/SDL_keymap.c @@ -290,7 +290,7 @@ static const struct static SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate) { - if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + CHECK_PARAM(((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { SDL_InvalidParamError("scancode"); return SDLK_UNKNOWN; } @@ -1053,7 +1053,7 @@ static const char *SDL_extended_key_names[] = { bool SDL_SetScancodeName(SDL_Scancode scancode, const char *name) { - if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + CHECK_PARAM(((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { return SDL_InvalidParamError("scancode"); } @@ -1064,7 +1064,8 @@ bool SDL_SetScancodeName(SDL_Scancode scancode, const char *name) const char *SDL_GetScancodeName(SDL_Scancode scancode) { const char *name; - if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { + + CHECK_PARAM(((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_SCANCODE_COUNT) { SDL_InvalidParamError("scancode"); return ""; } @@ -1081,7 +1082,7 @@ SDL_Scancode SDL_GetScancodeFromName(const char *name) { int i; - if (!name || !*name) { + CHECK_PARAM(!name || !*name) { SDL_InvalidParamError("name"); return SDL_SCANCODE_UNKNOWN; } diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 170e4335b3..95e31b2ffe 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -34,16 +34,12 @@ #define WARP_EMULATION_THRESHOLD_NS SDL_MS_TO_NS(30) -typedef struct SDL_MouseInstance -{ - SDL_MouseID instance_id; - char *name; -} SDL_MouseInstance; - // The mouse state static SDL_Mouse SDL_mouse; static int SDL_mouse_count; -static SDL_MouseInstance *SDL_mice; +static SDL_MouseID *SDL_mice; +static SDL_HashTable *SDL_mouse_names; +static bool SDL_mouse_quitting; // for mapping mouse events to touch static bool track_mouse_down = false; @@ -310,6 +306,8 @@ bool SDL_PreInitMouse(void) mouse->cursor_visible = true; + SDL_mouse_names = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL); + return true; } @@ -339,14 +337,14 @@ bool SDL_IsMouse(Uint16 vendor, Uint16 product) static int SDL_GetMouseIndex(SDL_MouseID mouseID) { for (int i = 0; i < SDL_mouse_count; ++i) { - if (mouseID == SDL_mice[i].instance_id) { + if (mouseID == SDL_mice[i]) { return i; } } return -1; } -void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event) +void SDL_AddMouse(SDL_MouseID mouseID, const char *name) { int mouse_index = SDL_GetMouseIndex(mouseID); if (mouse_index >= 0) { @@ -356,26 +354,27 @@ void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event) SDL_assert(mouseID != 0); - SDL_MouseInstance *mice = (SDL_MouseInstance *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice)); + SDL_MouseID *mice = (SDL_MouseID *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice)); if (!mice) { return; } - SDL_MouseInstance *instance = &mice[SDL_mouse_count]; - instance->instance_id = mouseID; - instance->name = SDL_strdup(name ? name : ""); + mice[SDL_mouse_count] = mouseID; SDL_mice = mice; ++SDL_mouse_count; - if (send_event) { - SDL_Event event; - SDL_zero(event); - event.type = SDL_EVENT_MOUSE_ADDED; - event.mdevice.which = mouseID; - SDL_PushEvent(&event); + if (!name) { + name = "Mouse"; } + SDL_InsertIntoHashTable(SDL_mouse_names, (const void *)(uintptr_t)mouseID, SDL_strdup(name), true); + + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_MOUSE_ADDED; + event.mdevice.which = mouseID; + SDL_PushEvent(&event); } -void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event) +void SDL_RemoveMouse(SDL_MouseID mouseID) { int mouse_index = SDL_GetMouseIndex(mouseID); if (mouse_index < 0) { @@ -383,8 +382,6 @@ void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event) return; } - SDL_free(SDL_mice[mouse_index].name); - if (mouse_index != SDL_mouse_count - 1) { SDL_memmove(&SDL_mice[mouse_index], &SDL_mice[mouse_index + 1], (SDL_mouse_count - mouse_index - 1) * sizeof(SDL_mice[mouse_index])); } @@ -404,7 +401,7 @@ void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event) } } - if (send_event) { + if (!SDL_mouse_quitting) { SDL_Event event; SDL_zero(event); event.type = SDL_EVENT_MOUSE_REMOVED; @@ -430,7 +427,7 @@ SDL_MouseID *SDL_GetMice(int *count) } for (i = 0; i < SDL_mouse_count; ++i) { - mice[i] = SDL_mice[i].instance_id; + mice[i] = SDL_mice[i]; } mice[i] = 0; } else { @@ -444,12 +441,17 @@ SDL_MouseID *SDL_GetMice(int *count) const char *SDL_GetMouseNameForID(SDL_MouseID instance_id) { - int mouse_index = SDL_GetMouseIndex(instance_id); - if (mouse_index < 0) { + const char *name = NULL; + if (!SDL_FindInHashTable(SDL_mouse_names, (const void *)(uintptr_t)instance_id, (const void **)&name)) { SDL_SetError("Mouse %" SDL_PRIu32 " not found", instance_id); return NULL; } - return SDL_GetPersistentString(SDL_mice[mouse_index].name); + if (!name) { + // SDL_strdup() failed during insert + SDL_OutOfMemory(); + return NULL; + } + return name; } void SDL_SetDefaultCursor(SDL_Cursor *cursor) @@ -1078,6 +1080,8 @@ void SDL_QuitMouse(void) SDL_Cursor *cursor, *next; SDL_Mouse *mouse = SDL_GetMouse(); + SDL_mouse_quitting = true; + if (mouse->added_mouse_touch_device) { SDL_DelTouch(SDL_MOUSE_TOUCHID); mouse->added_mouse_touch_device = false; @@ -1164,16 +1168,21 @@ void SDL_QuitMouse(void) SDL_MouseIntegerModeChanged, mouse); for (int i = SDL_mouse_count; i--; ) { - SDL_RemoveMouse(SDL_mice[i].instance_id, false); + SDL_RemoveMouse(SDL_mice[i]); } SDL_free(SDL_mice); SDL_mice = NULL; + SDL_DestroyHashTable(SDL_mouse_names); + SDL_mouse_names = NULL; + if (mouse->internal) { SDL_free(mouse->internal); mouse->internal = NULL; } SDL_zerop(mouse); + + SDL_mouse_quitting = false; } bool SDL_SetRelativeMouseTransform(SDL_MouseMotionTransformCallback transform, void *userdata) @@ -1549,7 +1558,7 @@ SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) SDL_Surface *temp = NULL; SDL_Cursor *cursor; - if (!surface) { + CHECK_PARAM(!surface) { SDL_InvalidParamError("surface"); return NULL; } @@ -1560,8 +1569,8 @@ SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) hot_y = (int)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER, hot_y); // Sanity check the hot spot - if ((hot_x < 0) || (hot_y < 0) || - (hot_x >= surface->w) || (hot_y >= surface->h)) { + CHECK_PARAM((hot_x < 0) || (hot_y < 0) || + (hot_x >= surface->w) || (hot_y >= surface->h)) { SDL_SetError("Cursor hot spot doesn't lie within cursor"); return NULL; } diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index c25974ba82..0114f2da84 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -164,10 +164,10 @@ extern void SDL_PostInitMouse(void); extern bool SDL_IsMouse(Uint16 vendor, Uint16 product); // A mouse has been added to the system -extern void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event); +extern void SDL_AddMouse(SDL_MouseID mouseID, const char *name); // A mouse has been removed from the system -extern void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event); +extern void SDL_RemoveMouse(SDL_MouseID mouseID); // Get the mouse state structure extern SDL_Mouse *SDL_GetMouse(void); diff --git a/src/filesystem/SDL_filesystem.c b/src/filesystem/SDL_filesystem.c index 8bd7980aaa..aa6e507006 100644 --- a/src/filesystem/SDL_filesystem.c +++ b/src/filesystem/SDL_filesystem.c @@ -27,7 +27,7 @@ bool SDL_RemovePath(const char *path) { - if (!path) { + CHECK_PARAM(!path) { return SDL_InvalidParamError("path"); } return SDL_SYS_RemovePath(path); @@ -35,9 +35,10 @@ bool SDL_RemovePath(const char *path) bool SDL_RenamePath(const char *oldpath, const char *newpath) { - if (!oldpath) { + CHECK_PARAM(!oldpath) { return SDL_InvalidParamError("oldpath"); - } else if (!newpath) { + } + CHECK_PARAM(!newpath) { return SDL_InvalidParamError("newpath"); } return SDL_SYS_RenamePath(oldpath, newpath); @@ -45,9 +46,10 @@ bool SDL_RenamePath(const char *oldpath, const char *newpath) bool SDL_CopyFile(const char *oldpath, const char *newpath) { - if (!oldpath) { + CHECK_PARAM(!oldpath) { return SDL_InvalidParamError("oldpath"); - } else if (!newpath) { + } + CHECK_PARAM(!newpath) { return SDL_InvalidParamError("newpath"); } return SDL_SYS_CopyFile(oldpath, newpath); @@ -55,7 +57,7 @@ bool SDL_CopyFile(const char *oldpath, const char *newpath) bool SDL_CreateDirectory(const char *path) { - if (!path) { + CHECK_PARAM(!path) { return SDL_InvalidParamError("path"); } @@ -116,9 +118,10 @@ bool SDL_CreateDirectory(const char *path) bool SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata) { - if (!path) { + CHECK_PARAM(!path) { return SDL_InvalidParamError("path"); - } else if (!callback) { + } + CHECK_PARAM(!callback) { return SDL_InvalidParamError("callback"); } return SDL_SYS_EnumerateDirectory(path, callback, userdata); @@ -133,10 +136,9 @@ bool SDL_GetPathInfo(const char *path, SDL_PathInfo *info) } SDL_zerop(info); - if (!path) { + CHECK_PARAM(!path) { return SDL_InvalidParamError("path"); } - return SDL_SYS_GetPathInfo(path, info); } @@ -364,7 +366,7 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob } *count = 0; - if (!path) { + CHECK_PARAM(!path) { SDL_InvalidParamError("path"); return NULL; } @@ -488,7 +490,8 @@ static char *CachedUserFolders[SDL_FOLDER_COUNT]; const char *SDL_GetUserFolder(SDL_Folder folder) { const int idx = (int) folder; - if ((idx < 0) || (idx >= SDL_arraysize(CachedUserFolders))) { + + CHECK_PARAM((idx < 0) || (idx >= SDL_arraysize(CachedUserFolders))) { SDL_InvalidParamError("folder"); return NULL; } @@ -502,7 +505,7 @@ const char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_GetPrefPath(const char *org, const char *app) { - if (!app) { + CHECK_PARAM(!app) { SDL_InvalidParamError("app"); return NULL; } diff --git a/src/filesystem/dummy/SDL_sysfilesystem.c b/src/filesystem/dummy/SDL_sysfilesystem.c index 5634c70299..a487161d28 100644 --- a/src/filesystem/dummy/SDL_sysfilesystem.c +++ b/src/filesystem/dummy/SDL_sysfilesystem.c @@ -47,8 +47,12 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetCurrentDirectory(void) { - SDL_Unsupported(); - return NULL; + const char *base = SDL_GetBasePath(); + if (!base) { + return NULL; + } + + return SDL_strdup(base); } #endif // SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED diff --git a/src/filesystem/gdk/SDL_sysfilesystem.cpp b/src/filesystem/gdk/SDL_sysfilesystem.cpp index 17baafb720..a32d6703aa 100644 --- a/src/filesystem/gdk/SDL_sysfilesystem.cpp +++ b/src/filesystem/gdk/SDL_sysfilesystem.cpp @@ -137,9 +137,12 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) return NULL; } -// TODO char *SDL_SYS_GetCurrentDirectory(void) { - SDL_Unsupported(); - return NULL; + const char *base = SDL_GetBasePath(); + if (!base) { + return NULL; + } + + return SDL_strdup(base); } diff --git a/src/filesystem/posix/SDL_sysfsops.c b/src/filesystem/posix/SDL_sysfsops.c index 64e47886a1..07539ad95b 100644 --- a/src/filesystem/posix/SDL_sysfsops.c +++ b/src/filesystem/posix/SDL_sysfsops.c @@ -41,6 +41,42 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) { +#ifdef SDL_PLATFORM_ANDROID + if (*path != '/') { + char *apath = NULL; + SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path); + if (!apath) { + return false; + } + const bool retval = SDL_SYS_EnumerateDirectory(apath, cb, userdata); + SDL_free(apath); + if (retval) { + return true; + } + } +#endif + +#ifdef SDL_PLATFORM_IOS + if (*path != '/') { + char *base = SDL_GetPrefPath("", ""); + if (!base) { + return false; + } + + char *apath = NULL; + SDL_asprintf(&apath, "%s%s", base, path); + SDL_free(base); + if (!apath) { + return false; + } + const bool retval = SDL_SYS_EnumerateDirectory(apath, cb, userdata); + SDL_free(apath); + if (retval) { + return true; + } + } +#endif + char *pathwithsep = NULL; int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", path); if ((pathwithseplen == -1) || (!pathwithsep)) { @@ -88,7 +124,41 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback bool SDL_SYS_RemovePath(const char *path) { - int rc = remove(path); + int rc; + +#ifdef SDL_PLATFORM_ANDROID + if (*path == '/') { + rc = remove(path); + } else { + char *apath = NULL; + SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path); + if (!apath) { + return false; + } + rc = remove(apath); + SDL_free(apath); + } +#elif defined(SDL_PLATFORM_IOS) + if (*path == '/') { + rc = remove(path); + } else { + char *base = SDL_GetPrefPath("", ""); + if (!base) { + return false; + } + + char *apath = NULL; + SDL_asprintf(&apath, "%s%s", base, path); + SDL_free(base); + if (!apath) { + return false; + } + rc = remove(apath); + SDL_free(apath); + } +#else + rc = remove(path); +#endif if (rc < 0) { if (errno == ENOENT) { // It's already gone, this is a success @@ -101,7 +171,65 @@ bool SDL_SYS_RemovePath(const char *path) bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath) { - if (rename(oldpath, newpath) < 0) { + int rc; + +#ifdef SDL_PLATFORM_ANDROID + char *aoldpath = NULL; + char *anewpath = NULL; + if (*oldpath != '/') { + SDL_asprintf(&aoldpath, "%s/%s", SDL_GetAndroidInternalStoragePath(), oldpath); + if (!aoldpath) { + return false; + } + oldpath = aoldpath; + } + if (*newpath != '/') { + SDL_asprintf(&anewpath, "%s/%s", SDL_GetAndroidInternalStoragePath(), newpath); + if (!anewpath) { + SDL_free(aoldpath); + return false; + } + newpath = anewpath; + } + rc = rename(oldpath, newpath); + SDL_free(aoldpath); + SDL_free(anewpath); +#elif defined(SDL_PLATFORM_IOS) + char *base = NULL; + if (*oldpath != '/' || *newpath != '/') { + base = SDL_GetPrefPath("", ""); + if (!base) { + return false; + } + } + + char *aoldpath = NULL; + char *anewpath = NULL; + if (*oldpath != '/') { + SDL_asprintf(&aoldpath, "%s%s", base, oldpath); + if (!aoldpath) { + SDL_free(base); + return false; + } + oldpath = aoldpath; + } + if (*newpath != '/') { + SDL_asprintf(&anewpath, "%s%s", base, newpath); + if (!anewpath) { + SDL_free(base); + SDL_free(aoldpath); + return false; + } + newpath = anewpath; + } + rc = rename(oldpath, newpath); + SDL_free(base); + SDL_free(aoldpath); + SDL_free(anewpath); +#else + rc = rename(oldpath, newpath); +#endif + if (rc < 0) { return SDL_SetError("Can't rename path: %s", strerror(errno)); } return true; @@ -164,7 +292,41 @@ done: bool SDL_SYS_CreateDirectory(const char *path) { - const int rc = mkdir(path, 0770); + int rc; + +#ifdef SDL_PLATFORM_ANDROID + if (*path == '/') { + rc = mkdir(path, 0770); + } else { + char *apath = NULL; + SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path); + if (!apath) { + return false; + } + rc = mkdir(apath, 0770); + SDL_free(apath); + } +#elif defined(SDL_PLATFORM_IOS) + if (*path == '/') { + rc = mkdir(path, 0770); + } else { + char *base = SDL_GetPrefPath("", ""); + if (!base) { + return false; + } + + char *apath = NULL; + SDL_asprintf(&apath, "%s%s", base, path); + SDL_free(base); + if (!apath) { + return false; + } + rc = mkdir(apath, 0770); + SDL_free(apath); + } +#else + rc = mkdir(path, 0770); +#endif if (rc < 0) { const int origerrno = errno; if (origerrno == EEXIST) { @@ -181,13 +343,46 @@ bool SDL_SYS_CreateDirectory(const char *path) bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info) { struct stat statbuf; - const int rc = stat(path, &statbuf); + int rc; + +#ifdef SDL_PLATFORM_ANDROID + if (*path == '/') { + rc = stat(path, &statbuf); + } else { + char *apath = NULL; + SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path); + if (!apath) { + return false; + } + rc = stat(apath, &statbuf); + SDL_free(apath); + } if (rc < 0) { - #ifdef SDL_PLATFORM_ANDROID // Maybe it's an asset...? return Android_JNI_GetAssetPathInfo(path, info); - #else + } +#elif defined(SDL_PLATFORM_IOS) + if (*path == '/') { + rc = stat(path, &statbuf); + } else { + char *base = SDL_GetPrefPath("", ""); + if (!base) { + return false; + } + + char *apath = NULL; + SDL_asprintf(&apath, "%s%s", base, path); + SDL_free(base); + if (!apath) { + return false; + } + rc = stat(apath, &statbuf); + SDL_free(apath); + } +#else + rc = stat(path, &statbuf); +#endif + if (rc < 0) { return SDL_SetError("Can't stat: %s", strerror(errno)); - #endif } else if (S_ISREG(statbuf.st_mode)) { info->type = SDL_PATHTYPE_FILE; info->size = (Uint64) statbuf.st_size; diff --git a/src/filesystem/windows/SDL_sysfsops.c b/src/filesystem/windows/SDL_sysfsops.c index 9c48ba957b..91394ed7ee 100644 --- a/src/filesystem/windows/SDL_sysfsops.c +++ b/src/filesystem/windows/SDL_sysfsops.c @@ -29,6 +29,10 @@ #include "../../core/windows/SDL_windows.h" #include "../SDL_sysfilesystem.h" +#ifndef COPY_FILE_NO_BUFFERING +#define COPY_FILE_NO_BUFFERING 0x00001000 +#endif + bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) { SDL_EnumerationResult result = SDL_ENUM_CONTINUE; diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index dfc5f8a26b..3b786d4680 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -23,7 +23,7 @@ // FIXME: This could probably use SDL_ObjectValid #define CHECK_DEVICE_MAGIC(device, retval) \ - if (device == NULL) { \ + CHECK_PARAM(device == NULL) { \ SDL_SetError("Invalid GPU device"); \ return retval; \ } @@ -375,6 +375,7 @@ SDL_GPUGraphicsPipeline *SDL_GPU_FetchBlitPipeline( } else { blit_pipeline_create_info.fragment_shader = blit_from_2d_shader; } + blit_pipeline_create_info.rasterizer_state.enable_depth_clip = device->default_enable_depth_clip; blit_pipeline_create_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; blit_pipeline_create_info.multisample_state.enable_mask = false; @@ -719,6 +720,15 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props) if (result != NULL) { result->backend = selectedBackend->name; result->debug_mode = debug_mode; + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true)) { + result->default_enable_depth_clip = false; + } else { + result->default_enable_depth_clip = true; + result->validate_feature_depth_clamp_disabled = true; + } + if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true)) { + result->validate_feature_anisotropy_disabled = true; + } } } return result; @@ -731,7 +741,6 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props) void SDL_DestroyGPUDevice(SDL_GPUDevice *device) { CHECK_DEVICE_MAGIC(device, ); - device->DestroyDevice(device); } @@ -746,7 +755,7 @@ int SDL_GetNumGPUDrivers(void) const char * SDL_GetGPUDriver(int index) { - if (index < 0 || index >= SDL_GetNumGPUDrivers()) { + CHECK_PARAM(index < 0 || index >= SDL_GetNumGPUDrivers()) { SDL_InvalidParamError("index"); return NULL; } @@ -760,21 +769,18 @@ const char * SDL_GetGPUDriver(int index) const char * SDL_GetGPUDeviceDriver(SDL_GPUDevice *device) { CHECK_DEVICE_MAGIC(device, NULL); - return device->backend; } SDL_GPUShaderFormat SDL_GetGPUShaderFormats(SDL_GPUDevice *device) { CHECK_DEVICE_MAGIC(device, SDL_GPU_SHADERFORMAT_INVALID); - return device->shader_formats; } SDL_PropertiesID SDL_GetGPUDeviceProperties(SDL_GPUDevice *device) { CHECK_DEVICE_MAGIC(device, 0); - return device->GetDeviceProperties(device); } @@ -951,6 +957,7 @@ SDL_GPUComputePipeline *SDL_CreateGPUComputePipeline( const SDL_GPUComputePipelineCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); + if (createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; @@ -991,7 +998,8 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( const SDL_GPUGraphicsPipelineCreateInfo *graphicsPipelineCreateInfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (graphicsPipelineCreateInfo == NULL) { + + CHECK_PARAM(graphicsPipelineCreateInfo == NULL) { SDL_InvalidParamError("graphicsPipelineCreateInfo"); return NULL; } @@ -1106,6 +1114,12 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( CHECK_STENCILOP_ENUM_INVALID(stencil_state->pass_op, NULL) CHECK_STENCILOP_ENUM_INVALID(stencil_state->depth_fail_op, NULL) } + + if (device->validate_feature_depth_clamp_disabled && + !graphicsPipelineCreateInfo->rasterizer_state.enable_depth_clip) { + SDL_assert_release(!"Rasterizer state enable_depth_clip must be set to true (FEATURE_DEPTH_CLAMPING disabled)"); + return NULL; + } } return device->CreateGraphicsPipeline( @@ -1118,11 +1132,20 @@ SDL_GPUSampler *SDL_CreateGPUSampler( const SDL_GPUSamplerCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (createinfo == NULL) { + + CHECK_PARAM(createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; } + if (device->debug_mode) { + if (device->validate_feature_anisotropy_disabled && + createinfo->enable_anisotropy) { + SDL_assert_release(!"enable_anisotropy must be set to false (FEATURE_ANISOTROPY disabled)"); + return NULL; + } + } + return device->CreateSampler( device->driverData, createinfo); @@ -1133,7 +1156,8 @@ SDL_GPUShader *SDL_CreateGPUShader( const SDL_GPUShaderCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (createinfo == NULL) { + + CHECK_PARAM(createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; } @@ -1159,7 +1183,8 @@ SDL_GPUTexture *SDL_CreateGPUTexture( const SDL_GPUTextureCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (createinfo == NULL) { + + CHECK_PARAM(createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; } @@ -1301,7 +1326,8 @@ SDL_GPUBuffer *SDL_CreateGPUBuffer( const SDL_GPUBufferCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (createinfo == NULL) { + + CHECK_PARAM(createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; } @@ -1320,7 +1346,8 @@ SDL_GPUTransferBuffer *SDL_CreateGPUTransferBuffer( const SDL_GPUTransferBufferCreateInfo *createinfo) { CHECK_DEVICE_MAGIC(device, NULL); - if (createinfo == NULL) { + + CHECK_PARAM(createinfo == NULL) { SDL_InvalidParamError("createinfo"); return NULL; } @@ -1342,11 +1369,12 @@ void SDL_SetGPUBufferName( const char *text) { CHECK_DEVICE_MAGIC(device, ); - if (buffer == NULL) { + + CHECK_PARAM(buffer == NULL) { SDL_InvalidParamError("buffer"); return; } - if (text == NULL) { + CHECK_PARAM(text == NULL) { SDL_InvalidParamError("text"); } @@ -1362,11 +1390,12 @@ void SDL_SetGPUTextureName( const char *text) { CHECK_DEVICE_MAGIC(device, ); - if (texture == NULL) { + + CHECK_PARAM(texture == NULL) { SDL_InvalidParamError("texture"); return; } - if (text == NULL) { + CHECK_PARAM(text == NULL) { SDL_InvalidParamError("text"); } @@ -1380,11 +1409,11 @@ void SDL_InsertGPUDebugLabel( SDL_GPUCommandBuffer *command_buffer, const char *text) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (text == NULL) { + CHECK_PARAM(text == NULL) { SDL_InvalidParamError("text"); return; } @@ -1402,11 +1431,11 @@ void SDL_PushGPUDebugGroup( SDL_GPUCommandBuffer *command_buffer, const char *name) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (name == NULL) { + CHECK_PARAM(name == NULL) { SDL_InvalidParamError("name"); return; } @@ -1423,7 +1452,7 @@ void SDL_PushGPUDebugGroup( void SDL_PopGPUDebugGroup( SDL_GPUCommandBuffer *command_buffer) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } @@ -1443,7 +1472,8 @@ void SDL_ReleaseGPUTexture( SDL_GPUTexture *texture) { CHECK_DEVICE_MAGIC(device, ); - if (texture == NULL) { + + CHECK_PARAM(texture == NULL) { return; } @@ -1457,7 +1487,8 @@ void SDL_ReleaseGPUSampler( SDL_GPUSampler *sampler) { CHECK_DEVICE_MAGIC(device, ); - if (sampler == NULL) { + + CHECK_PARAM(sampler == NULL) { return; } @@ -1471,7 +1502,8 @@ void SDL_ReleaseGPUBuffer( SDL_GPUBuffer *buffer) { CHECK_DEVICE_MAGIC(device, ); - if (buffer == NULL) { + + CHECK_PARAM(buffer == NULL) { return; } @@ -1485,7 +1517,8 @@ void SDL_ReleaseGPUTransferBuffer( SDL_GPUTransferBuffer *transfer_buffer) { CHECK_DEVICE_MAGIC(device, ); - if (transfer_buffer == NULL) { + + CHECK_PARAM(transfer_buffer == NULL) { return; } @@ -1499,7 +1532,8 @@ void SDL_ReleaseGPUShader( SDL_GPUShader *shader) { CHECK_DEVICE_MAGIC(device, ); - if (shader == NULL) { + + CHECK_PARAM(shader == NULL) { return; } @@ -1513,7 +1547,8 @@ void SDL_ReleaseGPUComputePipeline( SDL_GPUComputePipeline *compute_pipeline) { CHECK_DEVICE_MAGIC(device, ); - if (compute_pipeline == NULL) { + + CHECK_PARAM(compute_pipeline == NULL) { return; } @@ -1527,7 +1562,8 @@ void SDL_ReleaseGPUGraphicsPipeline( SDL_GPUGraphicsPipeline *graphics_pipeline) { CHECK_DEVICE_MAGIC(device, ); - if (graphics_pipeline == NULL) { + + CHECK_PARAM(graphics_pipeline == NULL) { return; } @@ -1592,11 +1628,11 @@ void SDL_PushGPUVertexUniformData( const void *data, Uint32 length) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (data == NULL) { + CHECK_PARAM(data == NULL) { SDL_InvalidParamError("data"); return; } @@ -1618,11 +1654,11 @@ void SDL_PushGPUFragmentUniformData( const void *data, Uint32 length) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (data == NULL) { + CHECK_PARAM(data == NULL) { SDL_InvalidParamError("data"); return; } @@ -1644,11 +1680,11 @@ void SDL_PushGPUComputeUniformData( const void *data, Uint32 length) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (data == NULL) { + CHECK_PARAM(data == NULL) { SDL_InvalidParamError("data"); return; } @@ -1674,16 +1710,16 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass( { CommandBufferCommonHeader *commandBufferHeader; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return NULL; } - if (color_target_infos == NULL && num_color_targets > 0) { + CHECK_PARAM(color_target_infos == NULL && num_color_targets > 0) { SDL_InvalidParamError("color_target_infos"); return NULL; } - if (num_color_targets > MAX_COLOR_TARGET_BINDINGS) { + CHECK_PARAM(num_color_targets > MAX_COLOR_TARGET_BINDINGS) { SDL_SetError("num_color_targets exceeds MAX_COLOR_TARGET_BINDINGS"); return NULL; } @@ -1741,13 +1777,17 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass( } if (depth_stencil_target_info != NULL) { - 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 (textureHeader->info.layer_count_or_depth > 255) { + SDL_assert_release("Cannot bind a depth texture with more than 255 layers!"); + 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; @@ -1791,11 +1831,11 @@ void SDL_BindGPUGraphicsPipeline( SDL_GPURenderPass *render_pass, SDL_GPUGraphicsPipeline *graphics_pipeline) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (graphics_pipeline == NULL) { + CHECK_PARAM(graphics_pipeline == NULL) { SDL_InvalidParamError("graphics_pipeline"); return; } @@ -1814,11 +1854,11 @@ void SDL_SetGPUViewport( SDL_GPURenderPass *render_pass, const SDL_GPUViewport *viewport) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (viewport == NULL) { + CHECK_PARAM(viewport == NULL) { SDL_InvalidParamError("viewport"); return; } @@ -1836,11 +1876,11 @@ void SDL_SetGPUScissor( SDL_GPURenderPass *render_pass, const SDL_Rect *scissor) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (scissor == NULL) { + CHECK_PARAM(scissor == NULL) { SDL_InvalidParamError("scissor"); return; } @@ -1858,7 +1898,7 @@ void SDL_SetGPUBlendConstants( SDL_GPURenderPass *render_pass, SDL_FColor blend_constants) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -1876,7 +1916,7 @@ void SDL_SetGPUStencilReference( SDL_GPURenderPass *render_pass, Uint8 reference) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -1896,7 +1936,7 @@ void SDL_BindGPUVertexBuffers( const SDL_GPUBufferBinding *bindings, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -1921,7 +1961,7 @@ void SDL_BindGPUIndexBuffer( const SDL_GPUBufferBinding *binding, SDL_GPUIndexElementSize index_element_size) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -1946,11 +1986,11 @@ void SDL_BindGPUVertexSamplers( const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (texture_sampler_bindings == NULL && num_bindings > 0) { + CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) { SDL_InvalidParamError("texture_sampler_bindings"); return; } @@ -1981,11 +2021,11 @@ void SDL_BindGPUVertexStorageTextures( SDL_GPUTexture *const *storage_textures, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (storage_textures == NULL && num_bindings > 0) { + CHECK_PARAM(storage_textures == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_textures"); return; } @@ -2012,11 +2052,11 @@ void SDL_BindGPUVertexStorageBuffers( SDL_GPUBuffer *const *storage_buffers, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (storage_buffers == NULL && num_bindings > 0) { + CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_buffers"); return; } @@ -2042,11 +2082,11 @@ void SDL_BindGPUFragmentSamplers( const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (texture_sampler_bindings == NULL && num_bindings > 0) { + CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) { SDL_InvalidParamError("texture_sampler_bindings"); return; } @@ -2076,11 +2116,11 @@ void SDL_BindGPUFragmentStorageTextures( SDL_GPUTexture *const *storage_textures, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (storage_textures == NULL && num_bindings > 0) { + CHECK_PARAM(storage_textures == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_textures"); return; } @@ -2107,11 +2147,11 @@ void SDL_BindGPUFragmentStorageBuffers( SDL_GPUBuffer *const *storage_buffers, Uint32 num_bindings) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (storage_buffers == NULL && num_bindings > 0) { + CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_buffers"); return; } @@ -2139,7 +2179,7 @@ void SDL_DrawGPUIndexedPrimitives( Sint32 vertex_offset, Uint32 first_instance) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -2166,7 +2206,7 @@ void SDL_DrawGPUPrimitives( Uint32 first_vertex, Uint32 first_instance) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -2191,11 +2231,11 @@ void SDL_DrawGPUPrimitivesIndirect( Uint32 offset, Uint32 draw_count) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (buffer == NULL) { + CHECK_PARAM(buffer == NULL) { SDL_InvalidParamError("buffer"); return; } @@ -2219,11 +2259,11 @@ void SDL_DrawGPUIndexedPrimitivesIndirect( Uint32 offset, Uint32 draw_count) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } - if (buffer == NULL) { + CHECK_PARAM(buffer == NULL) { SDL_InvalidParamError("buffer"); return; } @@ -2244,7 +2284,7 @@ void SDL_DrawGPUIndexedPrimitivesIndirect( void SDL_EndGPURenderPass( SDL_GPURenderPass *render_pass) { - if (render_pass == NULL) { + CHECK_PARAM(render_pass == NULL) { SDL_InvalidParamError("render_pass"); return; } @@ -2288,26 +2328,27 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass( { CommandBufferCommonHeader *commandBufferHeader; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return NULL; } - if (storage_texture_bindings == NULL && num_storage_texture_bindings > 0) { + CHECK_PARAM(storage_texture_bindings == NULL && num_storage_texture_bindings > 0) { SDL_InvalidParamError("storage_texture_bindings"); return NULL; } - if (storage_buffer_bindings == NULL && num_storage_buffer_bindings > 0) { + CHECK_PARAM(storage_buffer_bindings == NULL && num_storage_buffer_bindings > 0) { SDL_InvalidParamError("storage_buffer_bindings"); return NULL; } - if (num_storage_texture_bindings > MAX_COMPUTE_WRITE_TEXTURES) { + CHECK_PARAM(num_storage_texture_bindings > MAX_COMPUTE_WRITE_TEXTURES) { SDL_InvalidParamError("num_storage_texture_bindings"); return NULL; } - if (num_storage_buffer_bindings > MAX_COMPUTE_WRITE_BUFFERS) { + CHECK_PARAM(num_storage_buffer_bindings > MAX_COMPUTE_WRITE_BUFFERS) { SDL_InvalidParamError("num_storage_buffer_bindings"); return NULL; } + if (COMMAND_BUFFER_DEVICE->debug_mode) { CHECK_COMMAND_BUFFER_RETURN_NULL CHECK_ANY_PASS_IN_PROGRESS("Cannot begin compute pass during another pass!", NULL) @@ -2361,11 +2402,11 @@ void SDL_BindGPUComputePipeline( SDL_GPUComputePass *compute_pass, SDL_GPUComputePipeline *compute_pipeline) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } - if (compute_pipeline == NULL) { + CHECK_PARAM(compute_pipeline == NULL) { SDL_InvalidParamError("compute_pipeline"); return; } @@ -2390,11 +2431,11 @@ void SDL_BindGPUComputeSamplers( const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, Uint32 num_bindings) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } - if (texture_sampler_bindings == NULL && num_bindings > 0) { + CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) { SDL_InvalidParamError("texture_sampler_bindings"); return; } @@ -2420,11 +2461,11 @@ void SDL_BindGPUComputeStorageTextures( SDL_GPUTexture *const *storage_textures, Uint32 num_bindings) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } - if (storage_textures == NULL && num_bindings > 0) { + CHECK_PARAM(storage_textures == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_textures"); return; } @@ -2450,11 +2491,11 @@ void SDL_BindGPUComputeStorageBuffers( SDL_GPUBuffer *const *storage_buffers, Uint32 num_bindings) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } - if (storage_buffers == NULL && num_bindings > 0) { + CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) { SDL_InvalidParamError("storage_buffers"); return; } @@ -2480,7 +2521,7 @@ void SDL_DispatchGPUCompute( Uint32 groupcount_y, Uint32 groupcount_z) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } @@ -2503,7 +2544,7 @@ void SDL_DispatchGPUComputeIndirect( SDL_GPUBuffer *buffer, Uint32 offset) { - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } @@ -2525,7 +2566,7 @@ void SDL_EndGPUComputePass( { CommandBufferCommonHeader *commandBufferCommonHeader; - if (compute_pass == NULL) { + CHECK_PARAM(compute_pass == NULL) { SDL_InvalidParamError("compute_pass"); return; } @@ -2557,7 +2598,8 @@ void *SDL_MapGPUTransferBuffer( bool cycle) { CHECK_DEVICE_MAGIC(device, NULL); - if (transfer_buffer == NULL) { + + CHECK_PARAM(transfer_buffer == NULL) { SDL_InvalidParamError("transfer_buffer"); return NULL; } @@ -2573,7 +2615,8 @@ void SDL_UnmapGPUTransferBuffer( SDL_GPUTransferBuffer *transfer_buffer) { CHECK_DEVICE_MAGIC(device, ); - if (transfer_buffer == NULL) { + + CHECK_PARAM(transfer_buffer == NULL) { SDL_InvalidParamError("transfer_buffer"); return; } @@ -2590,7 +2633,7 @@ SDL_GPUCopyPass *SDL_BeginGPUCopyPass( { CommandBufferCommonHeader *commandBufferHeader; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return NULL; } @@ -2618,11 +2661,11 @@ void SDL_UploadToGPUTexture( const SDL_GPUTextureRegion *destination, bool cycle) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } @@ -2656,15 +2699,15 @@ void SDL_UploadToGPUBuffer( const SDL_GPUBufferRegion *destination, bool cycle) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } - if (destination == NULL) { + CHECK_PARAM(destination == NULL) { SDL_InvalidParamError("destination"); return; } @@ -2697,15 +2740,15 @@ void SDL_CopyGPUTextureToTexture( Uint32 d, bool cycle) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } - if (destination == NULL) { + CHECK_PARAM(destination == NULL) { SDL_InvalidParamError("destination"); return; } @@ -2746,15 +2789,15 @@ void SDL_CopyGPUBufferToBuffer( Uint32 size, bool cycle) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } - if (destination == NULL) { + CHECK_PARAM(destination == NULL) { SDL_InvalidParamError("destination"); return; } @@ -2784,15 +2827,15 @@ void SDL_DownloadFromGPUTexture( const SDL_GPUTextureRegion *source, const SDL_GPUTextureTransferInfo *destination) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } - if (destination == NULL) { + CHECK_PARAM(destination == NULL) { SDL_InvalidParamError("destination"); return; } @@ -2820,15 +2863,15 @@ void SDL_DownloadFromGPUBuffer( const SDL_GPUBufferRegion *source, const SDL_GPUTransferBufferLocation *destination) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } - if (source == NULL) { + CHECK_PARAM(source == NULL) { SDL_InvalidParamError("source"); return; } - if (destination == NULL) { + CHECK_PARAM(destination == NULL) { SDL_InvalidParamError("destination"); return; } @@ -2854,7 +2897,7 @@ void SDL_DownloadFromGPUBuffer( void SDL_EndGPUCopyPass( SDL_GPUCopyPass *copy_pass) { - if (copy_pass == NULL) { + CHECK_PARAM(copy_pass == NULL) { SDL_InvalidParamError("copy_pass"); return; } @@ -2875,11 +2918,11 @@ void SDL_GenerateMipmapsForGPUTexture( SDL_GPUCommandBuffer *command_buffer, SDL_GPUTexture *texture) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (texture == NULL) { + CHECK_PARAM(texture == NULL) { SDL_InvalidParamError("texture"); return; } @@ -2917,11 +2960,11 @@ void SDL_BlitGPUTexture( SDL_GPUCommandBuffer *command_buffer, const SDL_GPUBlitInfo *info) { - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return; } - if (info == NULL) { + CHECK_PARAM(info == NULL) { SDL_InvalidParamError("info"); return; } @@ -2982,7 +3025,8 @@ bool SDL_WindowSupportsGPUSwapchainComposition( SDL_GPUSwapchainComposition swapchain_composition) { CHECK_DEVICE_MAGIC(device, false); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { SDL_InvalidParamError("window"); return false; } @@ -3003,7 +3047,8 @@ bool SDL_WindowSupportsGPUPresentMode( SDL_GPUPresentMode present_mode) { CHECK_DEVICE_MAGIC(device, false); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { SDL_InvalidParamError("window"); return false; } @@ -3023,7 +3068,8 @@ bool SDL_ClaimWindowForGPUDevice( SDL_Window *window) { CHECK_DEVICE_MAGIC(device, false); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { return SDL_InvalidParamError("window"); } @@ -3041,7 +3087,8 @@ void SDL_ReleaseWindowFromGPUDevice( SDL_Window *window) { CHECK_DEVICE_MAGIC(device, ); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { SDL_InvalidParamError("window"); return; } @@ -3058,7 +3105,8 @@ bool SDL_SetGPUSwapchainParameters( SDL_GPUPresentMode present_mode) { CHECK_DEVICE_MAGIC(device, false); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { SDL_InvalidParamError("window"); return false; } @@ -3099,7 +3147,8 @@ SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat( SDL_Window *window) { CHECK_DEVICE_MAGIC(device, SDL_GPU_TEXTUREFORMAT_INVALID); - if (window == NULL) { + + CHECK_PARAM(window == NULL) { SDL_InvalidParamError("window"); return SDL_GPU_TEXTUREFORMAT_INVALID; } @@ -3118,13 +3167,13 @@ bool SDL_AcquireGPUSwapchainTexture( { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { return SDL_InvalidParamError("command_buffer"); } - if (window == NULL) { + CHECK_PARAM(window == NULL) { return SDL_InvalidParamError("window"); } - if (swapchain_texture == NULL) { + CHECK_PARAM(swapchain_texture == NULL) { return SDL_InvalidParamError("swapchain_texture"); } @@ -3153,7 +3202,7 @@ bool SDL_WaitForGPUSwapchain( { CHECK_DEVICE_MAGIC(device, false); - if (window == NULL) { + CHECK_PARAM(window == NULL) { return SDL_InvalidParamError("window"); } @@ -3171,13 +3220,13 @@ bool SDL_WaitAndAcquireGPUSwapchainTexture( { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { return SDL_InvalidParamError("command_buffer"); } - if (window == NULL) { + CHECK_PARAM(window == NULL) { return SDL_InvalidParamError("window"); } - if (swapchain_texture == NULL) { + CHECK_PARAM(swapchain_texture == NULL) { return SDL_InvalidParamError("swapchain_texture"); } @@ -3205,7 +3254,7 @@ bool SDL_SubmitGPUCommandBuffer( { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return false; } @@ -3232,7 +3281,7 @@ SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence( { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return NULL; } @@ -3259,7 +3308,7 @@ bool SDL_CancelGPUCommandBuffer( { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; - if (command_buffer == NULL) { + CHECK_PARAM(command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); return false; } @@ -3291,7 +3340,8 @@ bool SDL_WaitForGPUFences( Uint32 num_fences) { CHECK_DEVICE_MAGIC(device, false); - if (fences == NULL && num_fences > 0) { + + CHECK_PARAM(fences == NULL && num_fences > 0) { SDL_InvalidParamError("fences"); return false; } @@ -3308,7 +3358,8 @@ bool SDL_QueryGPUFence( SDL_GPUFence *fence) { CHECK_DEVICE_MAGIC(device, false); - if (fence == NULL) { + + CHECK_PARAM(fence == NULL) { SDL_InvalidParamError("fence"); return false; } @@ -3323,7 +3374,8 @@ void SDL_ReleaseGPUFence( SDL_GPUFence *fence) { CHECK_DEVICE_MAGIC(device, ); - if (fence == NULL) { + + CHECK_PARAM(fence == NULL) { return; } @@ -3344,3 +3396,67 @@ Uint32 SDL_CalculateGPUTextureFormatSize( Uint32 blocksPerColumn = (height + blockHeight - 1) / blockHeight; return depth_or_layer_count * blocksPerRow * blocksPerColumn * SDL_GPUTextureFormatTexelBlockSize(format); } + +SDL_PixelFormat SDL_GetPixelFormatFromGPUTextureFormat(SDL_GPUTextureFormat format) +{ + switch (format) { + case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM: + return SDL_PIXELFORMAT_BGRA4444; + case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM: + return SDL_PIXELFORMAT_BGR565; + case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM: + return SDL_PIXELFORMAT_BGRA5551; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT: + return SDL_PIXELFORMAT_RGBA32; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM: + return SDL_PIXELFORMAT_RGBA32; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM: + return SDL_PIXELFORMAT_RGBA32; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_RGBA32; + case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM: + return SDL_PIXELFORMAT_BGRA32; + case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_BGRA32; + case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM: + return SDL_PIXELFORMAT_ABGR2101010; + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: + return SDL_PIXELFORMAT_RGBA64; + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM: + return SDL_PIXELFORMAT_RGBA64; + case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT: + return SDL_PIXELFORMAT_RGBA64_FLOAT; + case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT: + return SDL_PIXELFORMAT_RGBA128_FLOAT; + default: + return SDL_PIXELFORMAT_UNKNOWN; + } +} + +SDL_GPUTextureFormat SDL_GetGPUTextureFormatFromPixelFormat(SDL_PixelFormat format) +{ + switch (format) { + case SDL_PIXELFORMAT_BGRA4444: + return SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM; + case SDL_PIXELFORMAT_BGR565: + return SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM; + case SDL_PIXELFORMAT_BGRA5551: + return SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM; + case SDL_PIXELFORMAT_BGRA32: + case SDL_PIXELFORMAT_BGRX32: + return SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_RGBA32: + case SDL_PIXELFORMAT_RGBX32: + return SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + case SDL_PIXELFORMAT_ABGR2101010: + return SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM; + case SDL_PIXELFORMAT_RGBA64: + return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM; + case SDL_PIXELFORMAT_RGBA64_FLOAT: + return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT; + case SDL_PIXELFORMAT_RGBA128_FLOAT: + return SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; + default: + return SDL_GPU_TEXTUREFORMAT_INVALID; + } +} diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index b4b54b2693..44ce625698 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -35,7 +35,7 @@ #define UNIFORM_BUFFER_SIZE 32768 #define MAX_VERTEX_BUFFERS 16 #define MAX_VERTEX_ATTRIBUTES 16 -#define MAX_COLOR_TARGET_BINDINGS 4 +#define MAX_COLOR_TARGET_BINDINGS 8 #define MAX_PRESENT_COUNT 16 #define MAX_FRAMES_IN_FLIGHT 3 @@ -1096,6 +1096,9 @@ struct SDL_GPUDevice // Store this for SDL_gpu.c's debug layer bool debug_mode; + bool default_enable_depth_clip; + bool validate_feature_depth_clamp_disabled; + bool validate_feature_anisotropy_disabled; }; #define ASSIGN_DRIVER_FUNC(func, name) \ diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index c277ced36c..28a7c5ce57 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -128,8 +128,8 @@ #endif // Function Pointer Signatures -typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY1)(const GUID *riid, void **ppFactory); -typedef HRESULT(WINAPI *PFN_DXGI_GET_DEBUG_INTERFACE)(const GUID *riid, void **ppDebug); +typedef HRESULT (WINAPI *pfnCreateDXGIFactory1)(const GUID *riid, void **ppFactory); +typedef HRESULT (WINAPI *pfnDXGIGetDebugInterface)(const GUID *riid, void **ppDebug); // IIDs (from https://www.magnumdb.com/) static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78, 0xf26f, 0x4dba, { 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87 } }; @@ -863,7 +863,7 @@ struct D3D12Renderer BOOL supportsTearing; SDL_SharedObject *d3d12_dll; ID3D12Device *device; - PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignature_func; + PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pD3D12SerializeRootSignature; const char *semantic; SDL_iconv_t iconv; @@ -1700,7 +1700,7 @@ static void D3D12_INTERNAL_DestroyRenderer(D3D12Renderer *renderer) renderer->dxgidebug_dll = NULL; } #endif - renderer->D3D12SerializeRootSignature_func = NULL; + renderer->pD3D12SerializeRootSignature = NULL; if (renderer->iconv) { SDL_iconv_close(renderer->iconv); @@ -2556,7 +2556,7 @@ static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature( // Serialize the root signature ID3DBlob *serializedRootSignature; ID3DBlob *errorBlob; - HRESULT res = renderer->D3D12SerializeRootSignature_func(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, &errorBlob); + HRESULT res = renderer->pD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, &errorBlob); if (FAILED(res)) { if (errorBlob) { @@ -2786,7 +2786,7 @@ static D3D12ComputeRootSignature *D3D12_INTERNAL_CreateComputeRootSignature( ID3DBlob *serializedRootSignature; ID3DBlob *errorBlob; - HRESULT res = renderer->D3D12SerializeRootSignature_func( + HRESULT res = renderer->pD3D12SerializeRootSignature( &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, @@ -4289,8 +4289,8 @@ static void D3D12_BeginRenderPass( if (depthStencilTargetInfo != NULL) { D3D12TextureContainer *container = (D3D12TextureContainer *)depthStencilTargetInfo->texture; - Uint32 h = container->header.info.height; - Uint32 w = container->header.info.width; + Uint32 h = container->header.info.height >> depthStencilTargetInfo->mip_level; + Uint32 w = container->header.info.width >> depthStencilTargetInfo->mip_level; // The framebuffer cannot be larger than the smallest target. @@ -4359,8 +4359,8 @@ static void D3D12_BeginRenderPass( D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( d3d12CommandBuffer, container, - 0, - 0, + depthStencilTargetInfo->layer, + depthStencilTargetInfo->mip_level, depthStencilTargetInfo->cycle, D3D12_RESOURCE_STATE_DEPTH_WRITE); @@ -8339,8 +8339,8 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) #else SDL_SharedObject *d3d12Dll; SDL_SharedObject *dxgiDll; - PFN_D3D12_CREATE_DEVICE D3D12CreateDeviceFunc; - PFN_CREATE_DXGI_FACTORY1 CreateDXGIFactoryFunc; + PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice; + pfnCreateDXGIFactory1 pCreateDXGIFactory1; HRESULT res; ID3D12Device *device; IDXGIFactory1 *factory; @@ -8368,10 +8368,10 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) return false; } - D3D12CreateDeviceFunc = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( + pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( d3d12Dll, D3D12_CREATE_DEVICE_FUNC); - if (D3D12CreateDeviceFunc == NULL) { + if (pD3D12CreateDevice == NULL) { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " D3D12_CREATE_DEVICE_FUNC " in " D3D12_DLL); SDL_UnloadObject(d3d12Dll); return false; @@ -8385,10 +8385,10 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) return false; } - CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY1)SDL_LoadFunction( + pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction( dxgiDll, CREATE_DXGI_FACTORY1_FUNC); - if (CreateDXGIFactoryFunc == NULL) { + if (pCreateDXGIFactory1 == NULL) { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " CREATE_DXGI_FACTORY1_FUNC " in " DXGI_DLL); SDL_UnloadObject(dxgiDll); return false; @@ -8397,7 +8397,7 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) // Can we create a device? // Create the DXGI factory - res = CreateDXGIFactoryFunc( + res = pCreateDXGIFactory1( &D3D_IID_IDXGIFactory1, (void **)&factory); if (FAILED(res)) { @@ -8450,7 +8450,7 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) SDL_COMPILE_TIME_ASSERT(featurelevel, D3D_FEATURE_LEVEL_CHOICE < D3D_FEATURE_LEVEL_11_1); // Check feature level 11_1 first, guarantees 64+ UAVs unlike 11_0 Tier1 - res = D3D12CreateDeviceFunc( + res = pD3D12CreateDevice( (IUnknown *)adapter, D3D_FEATURE_LEVEL_11_1, D3D_GUID(D3D_IID_ID3D12Device), @@ -8459,7 +8459,7 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) if (SUCCEEDED(res)) { supports_64UAVs = true; } else { - res = D3D12CreateDeviceFunc( + res = pD3D12CreateDevice( (IUnknown *)adapter, D3D_FEATURE_LEVEL_CHOICE, D3D_GUID(D3D_IID_ID3D12Device), @@ -8501,8 +8501,8 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) SDL_UnloadObject(d3d12Dll); SDL_UnloadObject(dxgiDll); - if (!supports_64UAVs) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Tier 2 Resource binding is not supported"); + if (!supports_64UAVs && !SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN, false)) { + SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Tier 2 Resource Binding is not supported"); return false; } @@ -8523,7 +8523,7 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) #if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) && defined(HAVE_IDXGIINFOQUEUE) static bool D3D12_INTERNAL_TryInitializeDXGIDebug(D3D12Renderer *renderer) { - PFN_DXGI_GET_DEBUG_INTERFACE DXGIGetDebugInterfaceFunc; + pfnDXGIGetDebugInterface pDXGIGetDebugInterface; HRESULT res; renderer->dxgidebug_dll = SDL_LoadObject(DXGIDEBUG_DLL); @@ -8531,19 +8531,19 @@ static bool D3D12_INTERNAL_TryInitializeDXGIDebug(D3D12Renderer *renderer) return false; } - DXGIGetDebugInterfaceFunc = (PFN_DXGI_GET_DEBUG_INTERFACE)SDL_LoadFunction( + pDXGIGetDebugInterface = (pfnDXGIGetDebugInterface)SDL_LoadFunction( renderer->dxgidebug_dll, DXGI_GET_DEBUG_INTERFACE_FUNC); - if (DXGIGetDebugInterfaceFunc == NULL) { + if (pDXGIGetDebugInterface == NULL) { return false; } - res = DXGIGetDebugInterfaceFunc(&D3D_IID_IDXGIDebug, (void **)&renderer->dxgiDebug); + res = pDXGIGetDebugInterface(&D3D_IID_IDXGIDebug, (void **)&renderer->dxgiDebug); if (FAILED(res)) { return false; } - res = DXGIGetDebugInterfaceFunc(&D3D_IID_IDXGIInfoQueue, (void **)&renderer->dxgiInfoQueue); + res = pDXGIGetDebugInterface(&D3D_IID_IDXGIInfoQueue, (void **)&renderer->dxgiInfoQueue); if (FAILED(res)) { return false; } @@ -8554,17 +8554,17 @@ static bool D3D12_INTERNAL_TryInitializeDXGIDebug(D3D12Renderer *renderer) static bool D3D12_INTERNAL_TryInitializeD3D12Debug(D3D12Renderer *renderer) { - PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterfaceFunc; + PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface; HRESULT res; - D3D12GetDebugInterfaceFunc = (PFN_D3D12_GET_DEBUG_INTERFACE)SDL_LoadFunction( + pD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)SDL_LoadFunction( renderer->d3d12_dll, D3D12_GET_DEBUG_INTERFACE_FUNC); - if (D3D12GetDebugInterfaceFunc == NULL) { + if (pD3D12GetDebugInterface == NULL) { return false; } - res = D3D12GetDebugInterfaceFunc(D3D_GUID(D3D_IID_ID3D12Debug), (void **)&renderer->d3d12Debug); + res = pD3D12GetDebugInterface(D3D_GUID(D3D_IID_ID3D12Debug), (void **)&renderer->d3d12Debug); if (FAILED(res)) { return false; } @@ -8727,13 +8727,13 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD PFN_D3D12_XBOX_CREATE_DEVICE D3D12XboxCreateDeviceFunc; D3D12XBOX_CREATE_DEVICE_PARAMETERS createDeviceParams; #else - PFN_CREATE_DXGI_FACTORY1 CreateDXGIFactoryFunc; + pfnCreateDXGIFactory1 pCreateDXGIFactory1; IDXGIFactory1 *factory1; IDXGIFactory5 *factory5; IDXGIFactory6 *factory6; DXGI_ADAPTER_DESC1 adapterDesc; LARGE_INTEGER umdVersion; - PFN_D3D12_CREATE_DEVICE D3D12CreateDeviceFunc; + PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice; #endif D3D12_FEATURE_DATA_ARCHITECTURE architecture; D3D12_COMMAND_QUEUE_DESC queueDesc; @@ -8764,16 +8764,16 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD #endif // Load the CreateDXGIFactory1 function - CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY1)SDL_LoadFunction( + pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction( renderer->dxgi_dll, CREATE_DXGI_FACTORY1_FUNC); - if (CreateDXGIFactoryFunc == NULL) { + if (pCreateDXGIFactory1 == NULL) { D3D12_INTERNAL_DestroyRenderer(renderer); SET_STRING_ERROR_AND_RETURN("Could not load function: " CREATE_DXGI_FACTORY1_FUNC, NULL); } // Create the DXGI factory - res = CreateDXGIFactoryFunc( + res = pCreateDXGIFactory1( &D3D_IID_IDXGIFactory1, (void **)&factory1); if (FAILED(res)) { @@ -8898,19 +8898,19 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD SET_STRING_ERROR_AND_RETURN("Could not load function: D3D12XboxCreateDevice", NULL); } #else - D3D12CreateDeviceFunc = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( + pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( renderer->d3d12_dll, D3D12_CREATE_DEVICE_FUNC); - if (D3D12CreateDeviceFunc == NULL) { + if (pD3D12CreateDevice == NULL) { D3D12_INTERNAL_DestroyRenderer(renderer); SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_CREATE_DEVICE_FUNC, NULL); } #endif - renderer->D3D12SerializeRootSignature_func = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)SDL_LoadFunction( + renderer->pD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)SDL_LoadFunction( renderer->d3d12_dll, D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC); - if (renderer->D3D12SerializeRootSignature_func == NULL) { + if (renderer->pD3D12SerializeRootSignature == NULL) { D3D12_INTERNAL_DestroyRenderer(renderer); SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC, NULL); } @@ -8971,7 +8971,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD s_Device = renderer->device; } #else - res = D3D12CreateDeviceFunc( + res = pD3D12CreateDevice( (IUnknown *)renderer->adapter, D3D_FEATURE_LEVEL_CHOICE, D3D_GUID(D3D_IID_ID3D12Device), diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index fff9282f86..fd6c399d9a 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -1116,6 +1116,13 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline( SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage"); } } +#ifdef SDL_PLATFORM_VISIONOS + // The default is depth clipping enabled and it can't be changed + if (!createinfo->rasterizer_state.enable_depth_clip) { + SDL_assert_release(!"Rasterizer state enable_depth_clip must be true on this platform"); + } +#endif + pipelineDescriptor = [MTLRenderPipelineDescriptor new]; // Blend @@ -1805,7 +1812,8 @@ static void METAL_UploadToTexture( copyFromBuffer:bufferContainer->activeBuffer->handle sourceOffset:source->offset sourceBytesPerRow:BytesPerRow(destination->w, textureContainer->header.info.format) - sourceBytesPerImage:SDL_CalculateGPUTextureFormatSize(textureContainer->header.info.format, destination->w, destination->h, destination->d) + // sourceBytesPerImage expects the stride between 2D images (slices) of a 3D texture, not the size of the entire region + sourceBytesPerImage:SDL_CalculateGPUTextureFormatSize(textureContainer->header.info.format, destination->w, destination->h, 1) sourceSize:MTLSizeMake(destination->w, destination->h, destination->d) toTexture:metalTexture->handle destinationSlice:destination->layer @@ -2319,6 +2327,8 @@ static void METAL_BeginRenderPass( depthStencilTargetInfo->cycle); passDescriptor.depthAttachment.texture = texture->handle; + passDescriptor.depthAttachment.level = depthStencilTargetInfo->mip_level; + passDescriptor.depthAttachment.slice = depthStencilTargetInfo->layer; passDescriptor.depthAttachment.loadAction = SDLToMetal_LoadOp[depthStencilTargetInfo->load_op]; passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp[depthStencilTargetInfo->store_op]; passDescriptor.depthAttachment.clearDepth = depthStencilTargetInfo->clear_depth; @@ -2352,8 +2362,8 @@ static void METAL_BeginRenderPass( if (depthStencilTargetInfo != NULL) { MetalTextureContainer *container = (MetalTextureContainer *)depthStencilTargetInfo->texture; - Uint32 w = container->header.info.width; - Uint32 h = container->header.info.height; + Uint32 w = container->header.info.width >> depthStencilTargetInfo->mip_level; + Uint32 h = container->header.info.height >> depthStencilTargetInfo->mip_level; if (w < vpWidth) { vpWidth = w; @@ -2411,7 +2421,9 @@ static void METAL_BindGraphicsPipeline( [metalCommandBuffer->renderEncoder setTriangleFillMode:SDLToMetal_PolygonMode[pipeline->rasterizerState.fill_mode]]; [metalCommandBuffer->renderEncoder setCullMode:SDLToMetal_CullMode[pipeline->rasterizerState.cull_mode]]; [metalCommandBuffer->renderEncoder setFrontFacingWinding:SDLToMetal_FrontFace[pipeline->rasterizerState.front_face]]; +#ifndef SDL_PLATFORM_VISIONOS [metalCommandBuffer->renderEncoder setDepthClipMode:SDLToMetal_DepthClipMode(pipeline->rasterizerState.enable_depth_clip)]; +#endif [metalCommandBuffer->renderEncoder setDepthBias:((rast->enable_depth_bias) ? rast->depth_bias_constant_factor : 0) slopeScale:((rast->enable_depth_bias) ? rast->depth_bias_slope_factor : 0) @@ -4508,6 +4520,8 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD } else if (@available(macOS 10.14, *)) { hasHardwareSupport = [device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1]; } +#elif defined(SDL_PLATFORM_VISIONOS) + hasHardwareSupport = true; #else if (@available(iOS 13.0, tvOS 13.0, *)) { hasHardwareSupport = [device supportsFamily:MTLGPUFamilyApple3]; diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 069c2e585f..25b05581ca 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -7276,8 +7276,8 @@ static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( } else { VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( (VulkanTextureContainer *)depthStencilTargetInfo->texture, - 0, - 0); + depthStencilTargetInfo->layer, + depthStencilTargetInfo->mip_level); key.depthStencilAttachmentView = subresource->depthStencilView; } @@ -7332,8 +7332,8 @@ static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( if (depthStencilTargetInfo != NULL) { VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( (VulkanTextureContainer *)depthStencilTargetInfo->texture, - 0, - 0); + depthStencilTargetInfo->layer, + depthStencilTargetInfo->mip_level); imageViewAttachments[attachmentCount] = subresource->depthStencilView; attachmentCount += 1; @@ -7813,8 +7813,8 @@ static void VULKAN_BeginRenderPass( if (depthStencilTargetInfo != NULL) { VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; - w = textureContainer->header.info.width; - h = textureContainer->header.info.height; + w = textureContainer->header.info.width >> depthStencilTargetInfo->mip_level; + h = textureContainer->header.info.height >> depthStencilTargetInfo->mip_level; // The framebuffer cannot be larger than the smallest attachment. @@ -7869,8 +7869,8 @@ static void VULKAN_BeginRenderPass( renderer, vulkanCommandBuffer, textureContainer, - 0, - 0, + depthStencilTargetInfo->layer, + depthStencilTargetInfo->mip_level, depthStencilTargetInfo->cycle, VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT); @@ -7910,15 +7910,17 @@ static void VULKAN_BeginRenderPass( clearValues = SDL_stack_alloc(VkClearValue, clearCount); - for (i = 0; i < totalColorAttachmentCount; i += 1) { - clearValues[i].color.float32[0] = colorTargetInfos[i].clear_color.r; - clearValues[i].color.float32[1] = colorTargetInfos[i].clear_color.g; - clearValues[i].color.float32[2] = colorTargetInfos[i].clear_color.b; - clearValues[i].color.float32[3] = colorTargetInfos[i].clear_color.a; + int clearIndex = 0; + for (i = 0; i < numColorTargets; i += 1) { + clearValues[clearIndex].color.float32[0] = colorTargetInfos[i].clear_color.r; + clearValues[clearIndex].color.float32[1] = colorTargetInfos[i].clear_color.g; + clearValues[clearIndex].color.float32[2] = colorTargetInfos[i].clear_color.b; + clearValues[clearIndex].color.float32[3] = colorTargetInfos[i].clear_color.a; + clearIndex += 1; if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { // Skip over the resolve texture, we're not clearing it - i += 1; + clearIndex += 1; } } @@ -9521,7 +9523,8 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( VulkanCommandBuffer *commandBuffer = VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); - commandBuffer->descriptorSetCache = VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); + DescriptorSetCache *descriptorSetCache = + VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); SDL_UnlockMutex(renderer->acquireCommandBufferLock); @@ -9529,6 +9532,8 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( return NULL; } + commandBuffer->descriptorSetCache = descriptorSetCache; + // Reset state commandBuffer->currentComputePipeline = NULL; @@ -11734,10 +11739,10 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); if (renderer) { // Opt out device features (higher compatibility in exchange for reduced functionality) - renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; // These features have near universal support so they are always enabled renderer->desiredDeviceFeatures.independentBlend = VK_TRUE; @@ -11783,10 +11788,10 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S renderer->allowedFramesInFlight = 2; // Opt out device features (higher compatibility in exchange for reduced functionality) - renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; - renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; // These features have near universal support so they are always enabled renderer->desiredDeviceFeatures.independentBlend = VK_TRUE; @@ -11909,7 +11914,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S } // FIXME: just move this into this function - result = (SDL_GPUDevice *)SDL_malloc(sizeof(SDL_GPUDevice)); + result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice)); ASSIGN_DRIVER(VULKAN) result->driverData = (SDL_GPURenderer *)renderer; diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c index 2e8024fa94..76e2da3c18 100644 --- a/src/haptic/SDL_haptic.c +++ b/src/haptic/SDL_haptic.c @@ -107,10 +107,10 @@ static int SDL_Haptic_Get_Naxes(Uint16 vid, Uint16 pid) static SDL_Haptic *SDL_haptics = NULL; -#define CHECK_HAPTIC_MAGIC(haptic, result) \ - if (!SDL_ObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC)) { \ - SDL_InvalidParamError("haptic"); \ - return result; \ +#define CHECK_HAPTIC_MAGIC(haptic, result) \ + CHECK_PARAM(!SDL_ObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC)) { \ + SDL_InvalidParamError("haptic"); \ + return result; \ } bool SDL_InitHaptics(void) @@ -512,7 +512,7 @@ bool SDL_HapticEffectSupported(SDL_Haptic *haptic, const SDL_HapticEffect *effec { CHECK_HAPTIC_MAGIC(haptic, false); - if (!effect) { + CHECK_PARAM(!effect) { return false; } @@ -528,7 +528,7 @@ SDL_HapticEffectID SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEf CHECK_HAPTIC_MAGIC(haptic, -1); - if (!effect) { + CHECK_PARAM(!effect) { SDL_InvalidParamError("effect"); return -1; } @@ -577,25 +577,25 @@ bool SDL_UpdateHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect, const { CHECK_HAPTIC_MAGIC(haptic, false); + CHECK_PARAM(!ValidEffect(haptic, effect)) { + return false; + } + + CHECK_PARAM(!data) { + return SDL_InvalidParamError("data"); + } + + // Can't change type dynamically. + CHECK_PARAM(data->type != haptic->effects[effect].effect.type) { + return SDL_SetError("Haptic: Updating effect type is illegal."); + } + #ifdef SDL_JOYSTICK_HIDAPI if (SDL_HIDAPI_HapticIsHidapi(haptic)) { return SDL_HIDAPI_HapticUpdateEffect(haptic, effect, data); } #endif - if (!ValidEffect(haptic, effect)) { - return false; - } - - if (!data) { - return SDL_InvalidParamError("data"); - } - - // Can't change type dynamically. - if (data->type != haptic->effects[effect].effect.type) { - return SDL_SetError("Haptic: Updating effect type is illegal."); - } - // Updates the effect if (!SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data)) { return false; diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c index 3020cfb3f4..71731a45ef 100644 --- a/src/hidapi/libusb/hid.c +++ b/src/hidapi/libusb/hid.c @@ -671,6 +671,8 @@ static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_devic cur_dev->usage_page = page; cur_dev->usage = usage; + + free(hid_report_descriptor); } #ifdef INVASIVE_GET_USAGE diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c index 87aa639e24..8a8224302e 100644 --- a/src/hidapi/windows/hid.c +++ b/src/hidapi/windows/hid.c @@ -1399,6 +1399,11 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char } } if (!res) { + if (GetLastError() == ERROR_OPERATION_ABORTED) { + /* The read request was issued on another thread. + This is harmless, so just ignore it. */ + return 0; + } register_winapi_error(dev, L"hid_read_timeout/GetOverlappedResult"); } diff --git a/src/io/SDL_asyncio.c b/src/io/SDL_asyncio.c index 51adf6b007..7696b7bf24 100644 --- a/src/io/SDL_asyncio.c +++ b/src/io/SDL_asyncio.c @@ -42,10 +42,11 @@ static const char *AsyncFileModeValid(const char *mode) SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode) { - if (!file) { + CHECK_PARAM(!file) { SDL_InvalidParamError("file"); return NULL; - } else if (!mode) { + } + CHECK_PARAM(!mode) { SDL_InvalidParamError("mode"); return NULL; } @@ -78,7 +79,7 @@ SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode) Sint64 SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio) { - if (!asyncio) { + CHECK_PARAM(!asyncio) { SDL_InvalidParamError("asyncio"); return -1; } @@ -87,11 +88,13 @@ Sint64 SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio) static bool RequestAsyncIO(bool reading, SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata) { - if (!asyncio) { + CHECK_PARAM(!asyncio) { return SDL_InvalidParamError("asyncio"); - } else if (!ptr) { + } + CHECK_PARAM(!ptr) { return SDL_InvalidParamError("ptr"); - } else if (!queue) { + } + CHECK_PARAM(!queue) { return SDL_InvalidParamError("queue"); } @@ -143,9 +146,10 @@ bool SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 siz bool SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata) { - if (!asyncio) { + CHECK_PARAM(!asyncio) { return SDL_InvalidParamError("asyncio"); - } else if (!queue) { + } + CHECK_PARAM(!queue) { return SDL_InvalidParamError("queue"); } @@ -298,9 +302,10 @@ void SDL_QuitAsyncIO(void) bool SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata) { - if (!file) { + CHECK_PARAM(!file) { return SDL_InvalidParamError("file"); - } else if (!queue) { + } + CHECK_PARAM(!queue) { return SDL_InvalidParamError("queue"); } diff --git a/src/io/SDL_iostream.c b/src/io/SDL_iostream.c index 2c1544144f..cc435da2fb 100644 --- a/src/io/SDL_iostream.c +++ b/src/io/SDL_iostream.c @@ -219,7 +219,6 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, DWORD error = GetLastError(); switch (error) { case ERROR_BROKEN_PIPE: - case ERROR_HANDLE_EOF: *status = SDL_IO_STATUS_EOF; break; case ERROR_NO_DATA: @@ -231,6 +230,8 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, break; } return 0; // !!! FIXME: this should return the bytes read from any readahead we finished out before this (the `iodata->left > 0` code above). In that case, fail on the next read. + } else if (bytes == 0) { + *status = SDL_IO_STATUS_EOF; } read_ahead = SDL_min(total_need, bytes); SDL_memcpy(ptr, iodata->data, read_ahead); @@ -242,7 +243,6 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, DWORD error = GetLastError(); switch (error) { case ERROR_BROKEN_PIPE: - case ERROR_HANDLE_EOF: *status = SDL_IO_STATUS_EOF; break; case ERROR_NO_DATA: @@ -254,6 +254,8 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, break; } return 0; // !!! FIXME: this should return the bytes read from any readahead we finished out before this (the `iodata->left > 0` code above). In that case, fail on the next read. + } else if (bytes == 0) { + *status = SDL_IO_STATUS_EOF; } total_read += bytes; } @@ -421,18 +423,36 @@ static size_t SDLCALL fd_read(void *userdata, void *ptr, size_t size, SDL_IOStat ssize_t bytes; do { bytes = read(iodata->fd, ptr, size); - } while (bytes < 0 && errno == EINTR); + } while ((bytes < 0) && (errno == EINTR)); - if (bytes < 0) { + ssize_t result = bytes; + if ((bytes > 0) && (bytes < size)) { // was it a short read, EOF, or error? + // try to read the difference, so we can rule out a short read. + do { + result = read(iodata->fd, ((Uint8 *) ptr) + bytes, size - bytes); + } while ((result < 0) && (errno == EINTR)); + + if (result > 0) { + bytes += result; + result = bytes; + SDL_assert(bytes <= size); + } + } + + if (result < 0) { if (errno == EAGAIN) { *status = SDL_IO_STATUS_NOT_READY; } else { *status = SDL_IO_STATUS_ERROR; SDL_SetError("Error reading from datastream: %s", strerror(errno)); } - bytes = 0; - } else if (bytes < size) { + if (bytes < 0) { + bytes = 0; + } + } else if (result == 0) { *status = SDL_IO_STATUS_EOF; + } else if (result < size) { + *status = SDL_IO_STATUS_NOT_READY;; } return (size_t)bytes; } @@ -443,17 +463,36 @@ static size_t SDLCALL fd_write(void *userdata, const void *ptr, size_t size, SDL ssize_t bytes; do { bytes = write(iodata->fd, ptr, size); - } while (bytes < 0 && errno == EINTR); + } while ((bytes < 0) && (errno == EINTR)); - if (bytes < 0) { + ssize_t result = bytes; + if ((bytes > 0) && (bytes < size)) { // was it a short write, or error? + // try to write the difference, so we can rule out a short read. + do { + result = write(iodata->fd, ((Uint8 *) ptr) + bytes, size - bytes); + } while ((result < 0) && (errno == EINTR)); + + if (result > 0) { + bytes += result; + result = bytes; + SDL_assert(bytes <= size); + } + } + + if (result < 0) { if (errno == EAGAIN) { *status = SDL_IO_STATUS_NOT_READY; } else { *status = SDL_IO_STATUS_ERROR; SDL_SetError("Error writing to datastream: %s", strerror(errno)); } - bytes = 0; + if (bytes < 0) { + bytes = 0; + } + } else if (result < size) { + *status = SDL_IO_STATUS_NOT_READY;; } + return (size_t)bytes; } @@ -465,7 +504,8 @@ static bool SDLCALL fd_flush(void *userdata, SDL_IOStatus *status) result = SDL_fdatasync(iodata->fd); } while (result < 0 && errno == EINTR); - if (result < 0) { + // We get EINVAL when flushing a pipe, just make that a no-op + if (result < 0 && errno != EINVAL) { return SDL_SetError("Error flushing datastream: %s", strerror(errno)); } return true; @@ -835,11 +875,11 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode) { SDL_IOStream *iostr = NULL; - if (!file || !*file) { + CHECK_PARAM(!file || !*file) { SDL_InvalidParamError("file"); return NULL; } - if (!mode || !*mode) { + CHECK_PARAM(!mode || !*mode) { SDL_InvalidParamError("mode"); return NULL; } @@ -917,6 +957,39 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode) } } +#elif defined(SDL_PLATFORM_IOS) + + // Try to open the file on the filesystem first + FILE *fp = NULL; + if (*file == '/') { + fp = fopen(file, mode); + } else { + // We can't write to the current directory, so use a writable path + char *base = SDL_GetPrefPath("", ""); + if (!base) { + return NULL; + } + + char *path = NULL; + SDL_asprintf(&path, "%s%s", base, file); + SDL_free(base); + if (!path) { + return NULL; + } + + fp = fopen(path, mode); + SDL_free(path); + } + + if (!fp) { + SDL_SetError("Couldn't open %s: %s", file, strerror(errno)); + } else if (!IsRegularFileOrPipe(fp)) { + fclose(fp); + SDL_SetError("%s is not a regular file or pipe", file); + } else { + iostr = SDL_IOFromFP(fp, true); + } + #elif defined(SDL_PLATFORM_WINDOWS) HANDLE handle = windows_file_open(file, mode); if (handle != INVALID_HANDLE_VALUE) { @@ -935,7 +1008,6 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode) SDL_SetError("Couldn't open %s: %s", file, strerror(errno)); } else if (!IsRegularFileOrPipe(fp)) { fclose(fp); - fp = NULL; SDL_SetError("%s is not a regular file or pipe", file); } else { iostr = SDL_IOFromFP(fp, true); @@ -951,12 +1023,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode) SDL_IOStream *SDL_IOFromMem(void *mem, size_t size) { - if (!mem) { + CHECK_PARAM(size && !mem) { SDL_InvalidParamError("mem"); return NULL; - } else if (!size) { - SDL_InvalidParamError("size"); - return NULL; } IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata)); @@ -992,12 +1061,9 @@ SDL_IOStream *SDL_IOFromMem(void *mem, size_t size) SDL_IOStream *SDL_IOFromConstMem(const void *mem, size_t size) { - if (!mem) { + CHECK_PARAM(size && !mem) { SDL_InvalidParamError("mem"); return NULL; - } else if (!size) { - SDL_InvalidParamError("size"); - return NULL; } IOStreamMemData *iodata = (IOStreamMemData *) SDL_calloc(1, sizeof (*iodata)); @@ -1138,7 +1204,7 @@ SDL_IOStream *SDL_IOFromDynamicMem(void) SDL_IOStatus SDL_GetIOStatus(SDL_IOStream *context) { - if (!context) { + CHECK_PARAM(!context) { SDL_InvalidParamError("context"); return SDL_IO_STATUS_ERROR; } @@ -1147,11 +1213,11 @@ SDL_IOStatus SDL_GetIOStatus(SDL_IOStream *context) SDL_IOStream *SDL_OpenIO(const SDL_IOStreamInterface *iface, void *userdata) { - if (!iface) { + CHECK_PARAM(!iface) { SDL_InvalidParamError("iface"); return NULL; } - if (iface->version < sizeof(*iface)) { + CHECK_PARAM(iface->version < sizeof(*iface)) { // Update this to handle older versions of this interface SDL_SetError("Invalid interface, should be initialized with SDL_INIT_INTERFACE()"); return NULL; @@ -1187,7 +1253,7 @@ void *SDL_LoadFile_IO(SDL_IOStream *src, size_t *datasize, bool closeio) char *data = NULL, *newdata; bool loading_chunks = false; - if (!src) { + CHECK_PARAM(!src) { SDL_InvalidParamError("src"); goto done; } @@ -1268,12 +1334,12 @@ bool SDL_SaveFile_IO(SDL_IOStream *src, const void *data, size_t datasize, bool size_t size_total = 0; bool success = true; - if (!src) { + CHECK_PARAM(!src) { SDL_InvalidParamError("src"); goto done; } - if (!data && datasize > 0) { + CHECK_PARAM(!data && datasize > 0) { SDL_InvalidParamError("data"); goto done; } @@ -1316,7 +1382,7 @@ bool SDL_SaveFile(const char *file, const void *data, size_t datasize) SDL_PropertiesID SDL_GetIOProperties(SDL_IOStream *context) { - if (!context) { + CHECK_PARAM(!context) { SDL_InvalidParamError("context"); return 0; } @@ -1329,9 +1395,10 @@ SDL_PropertiesID SDL_GetIOProperties(SDL_IOStream *context) Sint64 SDL_GetIOSize(SDL_IOStream *context) { - if (!context) { + CHECK_PARAM(!context) { return SDL_InvalidParamError("context"); } + if (!context->iface.size) { Sint64 pos, size; @@ -1349,10 +1416,12 @@ Sint64 SDL_GetIOSize(SDL_IOStream *context) Sint64 SDL_SeekIO(SDL_IOStream *context, Sint64 offset, SDL_IOWhence whence) { - if (!context) { + CHECK_PARAM(!context) { SDL_InvalidParamError("context"); return -1; - } else if (!context->iface.seek) { + } + + if (!context->iface.seek) { SDL_Unsupported(); return -1; } @@ -1366,14 +1435,18 @@ Sint64 SDL_TellIO(SDL_IOStream *context) size_t SDL_ReadIO(SDL_IOStream *context, void *ptr, size_t size) { - if (!context) { + CHECK_PARAM(!context) { SDL_InvalidParamError("context"); return 0; - } else if (!context->iface.read) { + } + + if (!context->iface.read) { context->status = SDL_IO_STATUS_WRITEONLY; SDL_Unsupported(); return 0; - } else if (size == 0) { + } + + if (size == 0) { return 0; // context->status doesn't change for this. } @@ -1385,14 +1458,18 @@ size_t SDL_ReadIO(SDL_IOStream *context, void *ptr, size_t size) size_t SDL_WriteIO(SDL_IOStream *context, const void *ptr, size_t size) { - if (!context) { + CHECK_PARAM(!context) { SDL_InvalidParamError("context"); return 0; - } else if (!context->iface.write) { + } + + if (!context->iface.write) { context->status = SDL_IO_STATUS_READONLY; SDL_Unsupported(); return 0; - } else if (size == 0) { + } + + if (size == 0) { return 0; // context->status doesn't change for this. } @@ -1441,7 +1518,7 @@ bool SDL_FlushIO(SDL_IOStream *context) { bool result = true; - if (!context) { + CHECK_PARAM(!context) { return SDL_InvalidParamError("context"); } diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index ce9c870e46..481278931c 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -31,6 +31,7 @@ #include "usb_ids.h" #include "hidapi/SDL_hidapi_flydigi.h" #include "hidapi/SDL_hidapi_nintendo.h" +#include "hidapi/SDL_hidapi_sinput.h" #include "../events/SDL_events_c.h" @@ -55,6 +56,22 @@ #define SDL_GAMEPAD_SDKLE_FIELD "sdk<=:" #define SDL_GAMEPAD_SDKLE_FIELD_SIZE SDL_strlen(SDL_GAMEPAD_SDKLE_FIELD) +// Helper function to add button mapping +#define SDL_ADD_BUTTON_MAPPING(sdl_name, button_id, maxlen) \ + do { \ + char temp[32]; \ + (void)SDL_snprintf(temp, sizeof(temp), "%s:b%d,", sdl_name, button_id); \ + SDL_strlcat(mapping_string, temp, maxlen); \ + } while (0) + +// Helper function to add axis mapping +#define SDL_ADD_AXIS_MAPPING(sdl_name, axis_id, maxlen) \ + do { \ + char temp[32]; \ + (void)SDL_snprintf(temp, sizeof(temp), "%s:a%d,", sdl_name, axis_id); \ + SDL_strlcat(mapping_string, temp, maxlen); \ + } while (0) + static bool SDL_gamepads_initialized; static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL; @@ -130,12 +147,12 @@ struct SDL_Gamepad #undef _guarded -#define CHECK_GAMEPAD_MAGIC(gamepad, result) \ - if (!SDL_ObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD) || \ - !SDL_IsJoystickValid(gamepad->joystick)) { \ - SDL_InvalidParamError("gamepad"); \ - SDL_UnlockJoysticks(); \ - return result; \ +#define CHECK_GAMEPAD_MAGIC(gamepad, result) \ + CHECK_PARAM(!SDL_ObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD) || \ + !SDL_IsJoystickValid(gamepad->joystick)) { \ + SDL_InvalidParamError("gamepad"); \ + SDL_UnlockJoysticks(); \ + return result; \ } static SDL_vidpid_list SDL_allowed_gamepads = { @@ -566,10 +583,14 @@ static void PopMappingChangeTracking(void) GamepadMapping_t *old_mapping = gamepad ? gamepad->mapping : tracker->joystick_mappings[i]; if (new_mapping && !old_mapping) { - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)true, true); + if (s_gamepadInstanceIDs) { + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)true, true); + } SDL_PrivateGamepadAdded(joystick); } else if (old_mapping && !new_mapping) { - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)false, true); + if (s_gamepadInstanceIDs) { + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)joystick, (const void *)false, true); + } SDL_PrivateGamepadRemoved(joystick); } else if (old_mapping != new_mapping || HasMappingChangeTracking(tracker, new_mapping)) { if (gamepad) { @@ -689,6 +710,304 @@ static GamepadMapping_t *SDL_CreateMappingForAndroidGamepad(SDL_GUID guid) } #endif // SDL_PLATFORM_ANDROID +/* +* Helper function to apply SInput decoded styles to the mapping string +*/ +static inline void SDL_SInputStylesMapExtraction(SDL_SInputStyles_t* styles, char* mapping_string, size_t mapping_string_len) +{ + int current_button = 0; + int current_axis = 0; + int misc_buttons = 0; + bool digital_triggers = false; + bool dualstage_triggers = false; + int bumpers = 0; + bool left_stick = false; + bool right_stick = false; + int paddle_pairs = 0; + + // Determine how many misc buttons are used + switch (styles->misc_style) { + case SINPUT_MISCSTYLE_1: + misc_buttons = 1; + break; + + case SINPUT_MISCSTYLE_2: + misc_buttons = 2; + break; + + case SINPUT_MISCSTYLE_3: + misc_buttons = 3; + break; + + case SINPUT_MISCSTYLE_4: + misc_buttons = 4; + break; + + default: + break; + } + + // Analog joysticks (always come first in axis mapping) + switch (styles->analog_style) { + case SINPUT_ANALOGSTYLE_LEFTONLY: + SDL_ADD_AXIS_MAPPING("leftx", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("lefty", current_axis++, mapping_string_len); + left_stick = true; + break; + + case SINPUT_ANALOGSTYLE_LEFTRIGHT: + SDL_ADD_AXIS_MAPPING("leftx", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("lefty", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("rightx", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("righty", current_axis++, mapping_string_len); + left_stick = true; + right_stick = true; + break; + + case SINPUT_ANALOGSTYLE_RIGHTONLY: + SDL_ADD_AXIS_MAPPING("rightx", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("righty", current_axis++, mapping_string_len); + right_stick = true; + break; + + default: + break; + } + + // Bumpers + switch (styles->bumper_style) { + case SINPUT_BUMPERSTYLE_ONE: + bumpers = 1; + break; + + case SINPUT_BUMPERSTYLE_TWO: + bumpers = 2; + break; + + default: + break; + } + + // Analog triggers + switch (styles->trigger_style) { + // Analog triggers + case SINPUT_TRIGGERSTYLE_ANALOG: + SDL_ADD_AXIS_MAPPING("lefttrigger", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("righttrigger", current_axis++, mapping_string_len); + break; + + // Digital triggers + case SINPUT_TRIGGERSTYLE_DIGITAL: + digital_triggers = true; + break; + + // Analog triggers with digital press + case SINPUT_TRIGGERSTYLE_DUALSTAGE: + SDL_ADD_AXIS_MAPPING("lefttrigger", current_axis++, mapping_string_len); + SDL_ADD_AXIS_MAPPING("righttrigger", current_axis++, mapping_string_len); + dualstage_triggers = true; + break; + + default: + break; + } + + switch (styles->paddle_style) { + case SINPUT_PADDLESTYLE_TWO: + paddle_pairs = 1; + break; + + case SINPUT_PADDLESTYLE_FOUR: + paddle_pairs = 2; + break; + + default: + break; + } + + // Digital button mappings + // ABXY buttons (always applied as South, East, West, North) + SDL_ADD_BUTTON_MAPPING("a", current_button++, mapping_string_len); // South (typically A on Xbox, X on PlayStation) + SDL_ADD_BUTTON_MAPPING("b", current_button++, mapping_string_len); // East (typically B on Xbox, Circle on PlayStation) + SDL_ADD_BUTTON_MAPPING("x", current_button++, mapping_string_len); // West (typically X on Xbox, Square on PlayStation) + SDL_ADD_BUTTON_MAPPING("y", current_button++, mapping_string_len); // North (typically Y on Xbox, Triangle on PlayStation) + + // D-Pad (always applied) + SDL_strlcat(mapping_string, "dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,", mapping_string_len); + + // Left and Right stick buttons + if (left_stick) { + SDL_ADD_BUTTON_MAPPING("leftstick", current_button++, mapping_string_len); + } + if (right_stick) { + SDL_ADD_BUTTON_MAPPING("rightstick", current_button++, mapping_string_len); + } + + // Digital shoulder buttons (L/R Shoulder) + if (bumpers > 0) { + SDL_ADD_BUTTON_MAPPING("leftshoulder", current_button++, mapping_string_len); + } + if (bumpers > 1) { + SDL_ADD_BUTTON_MAPPING("rightshoulder", current_button++, mapping_string_len); + } + + // Digital trigger buttons (capability overrides analog) + if (digital_triggers) { + SDL_ADD_BUTTON_MAPPING("lefttrigger", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("righttrigger", current_button++, mapping_string_len); + } else if (dualstage_triggers) { + // Dual-stage trigger buttons are appended as MISC buttons + // but only if we have the space to use them. + if (misc_buttons <= 2) { + switch (misc_buttons) { + case 0: + SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len); + break; + + case 1: + SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len); + break; + + case 2: + SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc6", current_button++, mapping_string_len); + break; + + default: + // We do not overwrite other misc buttons if they are used. + break; + } + } + } + + // Paddle 1/2 + if (paddle_pairs > 0) { + SDL_ADD_BUTTON_MAPPING("paddle1", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("paddle2", current_button++, mapping_string_len); + } + + // Start/Plus + SDL_ADD_BUTTON_MAPPING("start", current_button++, mapping_string_len); + + // Back/Minus, Guide/Home, Share/Capture + switch (styles->meta_style) { + case SINPUT_METASTYLE_BACK: + SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len); + break; + + case SINPUT_METASTYLE_BACKGUIDE: + SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("guide", current_button++, mapping_string_len); + break; + + case SINPUT_METASTYLE_BACKGUIDESHARE: + SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("guide", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc1", current_button++, mapping_string_len); + break; + + default: + break; + } + + // Paddle 3/4 + if (paddle_pairs > 1) { + SDL_ADD_BUTTON_MAPPING("paddle3", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("paddle4", current_button++, mapping_string_len); + } + + // Touchpad buttons + switch (styles->touch_style) { + case SINPUT_TOUCHSTYLE_SINGLE: + SDL_ADD_BUTTON_MAPPING("touchpad", current_button++, mapping_string_len); + break; + + case SINPUT_TOUCHSTYLE_DOUBLE: + SDL_ADD_BUTTON_MAPPING("touchpad", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc2", current_button++, mapping_string_len); + break; + + default: + break; + } + + switch (misc_buttons) { + case 1: + SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len); + break; + + case 2: + SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len); + break; + + case 3: + SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len); + break; + + case 4: + SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len); + SDL_ADD_BUTTON_MAPPING("misc6", current_button++, mapping_string_len); + break; + + default: + break; + } +} + +/* +* Helper function to decode SInput features information packed into version +*/ +static void SDL_CreateMappingStringForSInputGamepad(Uint16 vendor, Uint16 product, Uint8 sub_product, Uint16 version, Uint8 face_style, char* mapping_string, size_t mapping_string_len) +{ + SDL_SInputStyles_t decoded = { 0 }; + + switch (face_style) { + default: + SDL_strlcat(mapping_string, "face:abxy,", mapping_string_len); + break; + case 2: + SDL_strlcat(mapping_string, "face:axby,", mapping_string_len); + break; + case 3: + SDL_strlcat(mapping_string, "face:bayx,", mapping_string_len); + break; + case 4: + SDL_strlcat(mapping_string, "face:sony,", mapping_string_len); + break; + } + + // Interpret the mapping string + // dynamically based on the feature responses + decoded.misc_style = (SInput_MiscStyleType)(version % SINPUT_MISCSTYLE_MAX); + version /= SINPUT_MISCSTYLE_MAX; + + decoded.touch_style = (SInput_TouchStyleType)(version % SINPUT_TOUCHSTYLE_MAX); + version /= SINPUT_TOUCHSTYLE_MAX; + + decoded.meta_style = (SInput_MetaStyleType)(version % SINPUT_METASTYLE_MAX); + version /= SINPUT_METASTYLE_MAX; + + decoded.paddle_style = (SInput_PaddleStyleType)(version % SINPUT_PADDLESTYLE_MAX); + version /= SINPUT_PADDLESTYLE_MAX; + + decoded.trigger_style = (SInput_TriggerStyleType)(version % SINPUT_TRIGGERSTYLE_MAX); + version /= SINPUT_TRIGGERSTYLE_MAX; + + decoded.bumper_style = (SInput_BumperStyleType)(version % SINPUT_BUMPERSTYLE_MAX); + version /= SINPUT_BUMPERSTYLE_MAX; + + decoded.analog_style = (SInput_AnalogStyleType)(version % SINPUT_ANALOGSTYLE_MAX); + + SDL_SInputStylesMapExtraction(&decoded, mapping_string, mapping_string_len); +} + /* * Helper function to guess at a mapping for HIDAPI gamepads */ @@ -698,10 +1017,11 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) char mapping_string[1024]; Uint16 vendor; Uint16 product; + Uint16 version; SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string)); - SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); + SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version, NULL); if (SDL_IsJoystickWheel(vendor, product)) { // We don't want to pick up Logitech FFB wheels here @@ -827,56 +1147,11 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) // This controller has no guide button SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string)); } else if (SDL_IsJoystickSInputController(vendor, product)) { + Uint8 face_style = (guid.data[15] & 0xE0) >> 5; - Uint8 sub_type = guid.data[15] & 0x1F; + Uint8 sub_product = guid.data[15] & 0x1F; - // Apply face style according to gamepad response - switch (face_style) { - default: - SDL_strlcat(mapping_string, "face:abxy,", sizeof(mapping_string)); - break; - case 2: - SDL_strlcat(mapping_string, "face:axby,", sizeof(mapping_string)); - break; - case 3: - SDL_strlcat(mapping_string, "face:bayx,", sizeof(mapping_string)); - break; - case 4: - SDL_strlcat(mapping_string, "face:sony,", sizeof(mapping_string)); - break; - } - - switch (product) { - case USB_PRODUCT_HANDHELDLEGEND_PROGCC: - switch (sub_type) { - default: - // ProGCC Primary Mapping - SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string)); - break; - } - break; - case USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE: - switch (sub_type) { - default: - // GC Ultimate Primary Map - SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string)); - break; - } - break; - case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC: - switch (sub_type) { - default: - // Default Fully Exposed Mapping (Development Purposes) - SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,a:b0,b:b1,x:b2,y:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b10,paddle2:b11,start:b12,back:b13,guide:b14,misc1:b15,paddle3:b16,paddle4:b17,touchpad:b18,misc2:b19,misc3:b20,misc4:b21,misc5:b22,misc6:b23", sizeof(mapping_string)); - break; - } - break; - - case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD: - default: - // Unmapped device - return NULL; - } + SDL_CreateMappingStringForSInputGamepad(vendor, product, sub_product, version, face_style, mapping_string, sizeof(mapping_string)); } else { // All other gamepads have the standard set of 19 buttons and 6 axes if (SDL_IsJoystickGameCube(vendor, product)) { @@ -2071,7 +2346,11 @@ int SDL_AddGamepadMappingsFromIO(SDL_IOStream *src, bool closeio) int SDL_AddGamepadMappingsFromFile(const char *file) { - return SDL_AddGamepadMappingsFromIO(SDL_IOFromFile(file, "rb"), true); + SDL_IOStream *stream = SDL_IOFromFile(file, "rb"); + if (!stream) { + return -1; + } + return SDL_AddGamepadMappingsFromIO(stream, true); } bool SDL_ReloadGamepadMappings(void) @@ -2184,7 +2463,7 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa SDL_AssertJoysticksLocked(); - if (!mappingString) { + CHECK_PARAM(!mappingString) { SDL_InvalidParamError("mappingString"); return -1; } @@ -2280,7 +2559,7 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa } } -#ifdef ANDROID +#ifdef SDL_PLATFORM_ANDROID { // Extract and verify the SDK version const char *tmp; @@ -2519,7 +2798,7 @@ bool SDL_SetGamepadMapping(SDL_JoystickID instance_id, const char *mapping) SDL_GUID guid = SDL_GetJoystickGUIDForID(instance_id); bool result = false; - if (SDL_memcmp(&guid, &s_zeroGUID, sizeof(guid)) == 0) { + CHECK_PARAM(SDL_memcmp(&guid, &s_zeroGUID, sizeof(guid)) == 0) { return SDL_InvalidParamError("instance_id"); } @@ -2838,7 +3117,8 @@ bool SDL_IsGamepad(SDL_JoystickID instance_id) SDL_LockJoysticks(); { const void *value; - if (SDL_FindInHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, &value)) { + if (s_gamepadInstanceIDs && + SDL_FindInHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, &value)) { result = (bool)(uintptr_t)value; } else { if (SDL_PrivateGetGamepadMapping(instance_id, true) != NULL) { @@ -2846,11 +3126,12 @@ bool SDL_IsGamepad(SDL_JoystickID instance_id) } else { result = false; } - if (!s_gamepadInstanceIDs) { s_gamepadInstanceIDs = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); } - SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, (void *)(uintptr_t)result, true); + if (s_gamepadInstanceIDs) { + SDL_InsertIntoHashTable(s_gamepadInstanceIDs, (void *)(uintptr_t)instance_id, (void *)(uintptr_t)result, true); + } } } SDL_UnlockJoysticks(); diff --git a/src/joystick/SDL_gamepad_db.h b/src/joystick/SDL_gamepad_db.h index 94b164f0ea..072d96c1a3 100644 --- a/src/joystick/SDL_gamepad_db.h +++ b/src/joystick/SDL_gamepad_db.h @@ -897,7 +897,7 @@ static const char *s_GamepadMappings[] = { "050000005e040000e0020000ff070000,Xbox Wireless Controller,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,", #endif #ifdef SDL_JOYSTICK_EMSCRIPTEN - "default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,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,", + "default,Standard Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", #endif #ifdef SDL_JOYSTICK_PS2 "0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,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,", diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index a6d047bd14..5f77348474 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -439,6 +439,7 @@ static Uint32 initial_blacklist_devices[] = { MAKE_VIDPID(0x04d9, 0x8009), // OBINLB USB-HID Keyboard (Anne Pro II) MAKE_VIDPID(0x04d9, 0xa292), // OBINLB USB-HID Keyboard (Anne Pro II) MAKE_VIDPID(0x04d9, 0xa293), // OBINLB USB-HID Keyboard (Anne Pro II) + MAKE_VIDPID(0x04f2, 0xa13c), // HP Deluxe Webcam KQ246AA MAKE_VIDPID(0x0e6f, 0x018a), // PDP REALMz Wireless Controller for Switch, USB charging MAKE_VIDPID(0x1532, 0x0266), // Razer Huntsman V2 Analog, non-functional DInput device MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device @@ -614,18 +615,18 @@ static SDL_vidpid_list zero_centered_devices = { false }; -#define CHECK_JOYSTICK_MAGIC(joystick, result) \ - if (!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \ - SDL_InvalidParamError("joystick"); \ - SDL_UnlockJoysticks(); \ - return result; \ +#define CHECK_JOYSTICK_MAGIC(joystick, result) \ + CHECK_PARAM(!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \ + SDL_InvalidParamError("joystick"); \ + SDL_UnlockJoysticks(); \ + return result; \ } -#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \ - if (!joystick->is_virtual) { \ - SDL_SetError("joystick isn't virtual"); \ - SDL_UnlockJoysticks(); \ - return result; \ +#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \ + CHECK_PARAM(!joystick->is_virtual) { \ + SDL_SetError("joystick isn't virtual"); \ + SDL_UnlockJoysticks(); \ + return result; \ } bool SDL_JoysticksInitialized(void) @@ -3221,7 +3222,8 @@ bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id) if (product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC || product_id == USB_PRODUCT_HANDHELDLEGEND_PROGCC || product_id == USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE || - product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD) { + product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD || + product_id == USB_PRODUCT_VOIDGAMING_PS4FIREBIRD) { return true; } } diff --git a/src/joystick/apple/SDL_mfijoystick.m b/src/joystick/apple/SDL_mfijoystick.m index 001ef3145d..a7ab051ebe 100644 --- a/src/joystick/apple/SDL_mfijoystick.m +++ b/src/joystick/apple/SDL_mfijoystick.m @@ -300,8 +300,14 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle * struct, and ARC doesn't work with structs. */ device->controller = (__bridge GCController *)CFBridgingRetain(controller); - if (controller.vendorName) { - name = controller.vendorName.UTF8String; + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { + if (controller.productCategory) { + name = controller.productCategory.UTF8String; + } + } else { + if (controller.vendorName) { + name = controller.vendorName.UTF8String; + } } if (!name) { @@ -314,7 +320,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle NSLog(@"Product name: %@\n", controller.vendorName); NSLog(@"Product category: %@\n", controller.productCategory); NSLog(@"Elements available:\n"); - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { NSDictionary *elements = controller.physicalInputProfile.elements; for (id key in controller.physicalInputProfile.buttons) { NSLog(@"\tButton: %@ (%s)\n", key, elements[key].analog ? "analog" : "digital"); @@ -364,7 +370,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle return false; } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton] != nil) { device->has_dualshock_touchpad = TRUE; } @@ -419,7 +425,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle } else if (device->is_switch_joyconR) { vendor = USB_VENDOR_NINTENDO; product = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT; - } else if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + } else if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { vendor = USB_VENDOR_APPLE; product = 4; subtype = 4; @@ -442,7 +448,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle return false; } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { NSDictionary *elements = controller.physicalInputProfile.elements; // Provide both axes and analog buttons as SDL axes @@ -573,7 +579,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle } Uint16 signature; - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { signature = 0; signature = SDL_crc16(signature, device->name, SDL_strlen(device->name)); for (id key in device->axes) { @@ -727,7 +733,7 @@ static bool IOS_JoystickInit(void) } #ifdef SDL_PLATFORM_MACOS - if (@available(macOS 10.16, *)) { + if (@available(macOS 11.0, *)) { // Continue with initialization on macOS 11+ } else { return true; @@ -889,7 +895,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index) }; } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = joystick->hwdata->controller; GCMotion *motion = controller.motion; if (motion && motion.hasRotationRate) { @@ -900,7 +906,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index) } } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = joystick->hwdata->controller; for (id key in controller.physicalInputProfile.buttons) { GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key]; @@ -910,7 +916,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index) } } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = device->controller; if (controller.light) { SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true); @@ -971,7 +977,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) Uint64 timestamp = SDL_GetTicksNS(); #ifdef DEBUG_CONTROLLER_STATE - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (controller.physicalInputProfile) { for (id key in controller.physicalInputProfile.buttons) { GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key]; @@ -997,7 +1003,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) } #endif // DEBUG_CONTROLLER_STATE - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { NSDictionary *elements = controller.physicalInputProfile.elements; NSDictionary *buttons = controller.physicalInputProfile.buttons; @@ -1127,7 +1133,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) } } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (device->has_dualshock_touchpad) { GCControllerDirectionPad *dpad; @@ -1147,7 +1153,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) } } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCMotion *motion = controller.motion; if (motion && motion.sensorsActive) { float data[3]; @@ -1169,7 +1175,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) } } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCDeviceBattery *battery = controller.battery; if (battery) { SDL_PowerState state = SDL_POWERSTATE_UNKNOWN; @@ -1198,8 +1204,8 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) #ifdef SDL_JOYSTICK_MFI @interface SDL3_RumbleMotor : NSObject -@property(nonatomic, strong) CHHapticEngine *engine API_AVAILABLE(macos(10.16), ios(13.0), tvos(14.0)); -@property(nonatomic, strong) id player API_AVAILABLE(macos(10.16), ios(13.0), tvos(14.0)); +@property(nonatomic, strong) CHHapticEngine *engine API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0)); +@property(nonatomic, strong) id player API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0)); @property bool active; @end @@ -1210,7 +1216,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) - (void)cleanup { @autoreleasepool { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (self.player != nil) { [self.player cancelAndReturnError:nil]; self.player = nil; @@ -1226,7 +1232,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) - (bool)setIntensity:(float)intensity { @autoreleasepool { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { NSError *error = nil; CHHapticDynamicParameter *param; @@ -1273,7 +1279,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) } } -- (id)initWithController:(GCController *)controller locality:(GCHapticsLocality)locality API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0)) +- (id)initWithController:(GCController *)controller locality:(GCHapticsLocality)locality API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { @autoreleasepool { NSError *error; @@ -1375,7 +1381,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick) static SDL3_RumbleContext *IOS_JoystickInitRumble(GCController *controller) { @autoreleasepool { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { SDL3_RumbleMotor *low_frequency_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftHandle]; SDL3_RumbleMotor *high_frequency_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityRightHandle]; SDL3_RumbleMotor *left_trigger_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftTrigger]; @@ -1402,7 +1408,7 @@ static bool IOS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumb return SDL_SetError("Controller is no longer connected"); } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (!device->rumble && device->controller && device->controller.haptics) { SDL3_RumbleContext *rumble = IOS_JoystickInitRumble(device->controller); if (rumble) { @@ -1428,7 +1434,7 @@ static bool IOS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumbl return SDL_SetError("Controller is no longer connected"); } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (!device->rumble && device->controller && device->controller.haptics) { SDL3_RumbleContext *rumble = IOS_JoystickInitRumble(device->controller); if (rumble) { @@ -1454,7 +1460,7 @@ static bool IOS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, U return SDL_SetError("Controller is no longer connected"); } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = device->controller; GCDeviceLight *light = controller.light; if (light) { @@ -1482,7 +1488,7 @@ static bool IOS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) return SDL_SetError("Controller is no longer connected"); } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = device->controller; GCMotion *motion = controller.motion; if (motion) { @@ -1533,7 +1539,7 @@ static void IOS_JoystickClose(SDL_Joystick *joystick) controller.controllerPausedHandler = nil; controller.playerIndex = -1; - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { for (id key in controller.physicalInputProfile.buttons) { GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key]; if ([button isBoundToSystemGesture]) { @@ -1587,7 +1593,7 @@ static bool IOS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping * return false; } - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { int axis = 0; for (id key in device->axes) { if ([(NSString *)key isEqualToString:@"Left Thumbstick X Axis"] || @@ -1724,7 +1730,7 @@ bool IOS_SupportedHIDDevice(IOHIDDeviceRef device) return false; } - if (@available(macOS 10.16, *)) { + if (@available(macOS 11.0, *)) { const int MAX_ATTEMPTS = 3; for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) { if ([GCController supportsHIDDevice:device]) { @@ -1743,7 +1749,7 @@ bool IOS_SupportedHIDDevice(IOHIDDeviceRef device) /* NOLINTNEXTLINE(readability-non-const-parameter): getCString takes a non-const char* */ static void GetAppleSFSymbolsNameForElement(GCControllerElement *element, char *name) { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { if (element) { [element.sfSymbolsName getCString:name maxLength:255 encoding:NSASCIIStringEncoding]; } @@ -1752,7 +1758,7 @@ static void GetAppleSFSymbolsNameForElement(GCControllerElement *element, char * static GCControllerDirectionPad *GetDirectionalPadForController(GCController *controller) { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { return controller.physicalInputProfile.dpads[GCInputDirectionPad]; } @@ -1775,7 +1781,7 @@ const char *IOS_GetAppleSFSymbolsNameForButton(SDL_Gamepad *gamepad, SDL_Gamepad #ifdef SDL_JOYSTICK_MFI if (gamepad && SDL_GetGamepadJoystick(gamepad)->driver == &SDL_IOS_JoystickDriver) { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = SDL_GetGamepadJoystick(gamepad)->hwdata->controller; NSDictionary *elements = controller.physicalInputProfile.elements; switch (button) { @@ -1891,7 +1897,7 @@ const char *IOS_GetAppleSFSymbolsNameForAxis(SDL_Gamepad *gamepad, SDL_GamepadAx #ifdef SDL_JOYSTICK_MFI if (gamepad && SDL_GetGamepadJoystick(gamepad)->driver == &SDL_IOS_JoystickDriver) { - if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { GCController *controller = SDL_GetGamepadJoystick(gamepad)->hwdata->controller; NSDictionary *elements = controller.physicalInputProfile.elements; switch (axis) { diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 6c51f8eaf6..fc02eb6172 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -27,6 +27,7 @@ #include "SDL_sysjoystick_c.h" #include "../SDL_joystick_c.h" +#include "../usb_ids.h" static SDL_joylist_item *JoystickByIndex(int index); @@ -34,10 +35,60 @@ static SDL_joylist_item *SDL_joylist = NULL; static SDL_joylist_item *SDL_joylist_tail = NULL; static int numjoysticks = 0; +EM_JS(int, SDL_GetEmscriptenJoystickVendor, (int device_index), { + // Let's assume that if we're calling these function then the gamepad object definitely exists + let gamepad = navigator['getGamepads']()[device_index]; + + // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) + let vendor_str = 'Vendor: '; + if (gamepad['id']['indexOf'](vendor_str) > 0) { + let vendor_str_index = gamepad['id']['indexOf'](vendor_str) + vendor_str['length']; + return parseInt(gamepad['id']['substr'](vendor_str_index, 4), 16); + } + + // Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action) + let id_split = gamepad['id']['split']('-'); + if (id_split['length'] > 1 && !isNaN(parseInt(id_split[0], 16))) { + return parseInt(id_split[0], 16); + } + + return 0; +}); + +EM_JS(int, SDL_GetEmscriptenJoystickProduct, (int device_index), { + let gamepad = navigator['getGamepads']()[device_index]; + + // Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc) + let product_str = 'Product: '; + if (gamepad['id']['indexOf'](product_str) > 0) { + let product_str_index = gamepad['id']['indexOf'](product_str) + product_str['length']; + return parseInt(gamepad['id']['substr'](product_str_index, 4), 16); + } + + // Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action) + let id_split = gamepad['id']['split']('-'); + if (id_split['length'] > 1 && !isNaN(parseInt(id_split[1], 16))) { + return parseInt(id_split[1], 16); + } + + return 0; +}); + +EM_JS(int, SDL_IsEmscriptenJoystickXInput, (int device_index), { + let gamepad = navigator['getGamepads']()[device_index]; + + // Chrome, Edge, Opera: Xbox 360 Controller (XInput STANDARD GAMEPAD) + // Firefox: xinput + // TODO: Safari + return gamepad['id']['toLowerCase']()['indexOf']('xinput') >= 0; +}); + static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { SDL_joylist_item *item; int i; + Uint16 vendor, product; + bool is_xinput; SDL_LockJoysticks(); @@ -53,12 +104,32 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep SDL_zerop(item); item->index = gamepadEvent->index; - item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id); + vendor = SDL_GetEmscriptenJoystickVendor(gamepadEvent->index); + product = SDL_GetEmscriptenJoystickProduct(gamepadEvent->index); + is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index); + + // Use a generic VID/PID representing an XInput controller + if (!vendor && !product && is_xinput) { + vendor = USB_VENDOR_MICROSOFT; + product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER; + } + + item->name = SDL_CreateJoystickName(vendor, product, NULL, gamepadEvent->id); if (!item->name) { SDL_free(item); goto done; } + if (vendor && product) { + item->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, vendor, product, 0, NULL, item->name, 0, 0); + } else { + item->guid = SDL_CreateJoystickGUIDForName(item->name); + } + + if (is_xinput) { + item->guid.data[14] = 'x'; // See SDL_IsJoystickXInput + } + item->mapping = SDL_strdup(gamepadEvent->mapping); if (!item->mapping) { SDL_free(item->name); @@ -66,46 +137,71 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep goto done; } + const int real_button_count = gamepadEvent->numButtons; + const int real_axis_count = gamepadEvent->numAxes; + int first_trigger_button = -1; int first_hat_button = -1; int num_buttons = gamepadEvent->numButtons; - if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat. - num_buttons -= 4; + int num_axes = gamepadEvent->numAxes; + bool triggers_are_buttons = false; + if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat, treat triggers as analog. + num_buttons -= 4; // 4 dpad buttons become a hat. first_hat_button = 12; + + if (num_axes == 4) { // Chrome gives the triggers analog button values, Firefox exposes them as extra axes. Both have the digital buttons. + num_axes += 2; // the two trigger "buttons" + triggers_are_buttons = true; + } + + // dump the digital trigger buttons in any case. + first_trigger_button = 6; + num_buttons -= 2; } item->first_hat_button = first_hat_button; + item->first_trigger_button = first_trigger_button; + item->triggers_are_buttons = triggers_are_buttons; item->nhats = (first_hat_button >= 0) ? 1 : 0; - item->naxes = gamepadEvent->numAxes; + item->naxes = num_axes; item->nbuttons = num_buttons; item->device_instance = SDL_GetNextObjectID(); item->timestamp = gamepadEvent->timestamp; - for (i = 0; i < item->naxes; i++) { - item->axis[i] = gamepadEvent->axis[i]; - } - int buttonidx = 0; - for (i = 0; i < item->nbuttons; i++, buttonidx++) { + for (i = 0; i < real_button_count; i++, buttonidx++) { if (buttonidx == first_hat_button) { - buttonidx += 3; // skip these buttons, we're treating them as hat input. + buttonidx += 4; // skip these buttons, we're treating them as hat input. + } else if (buttonidx == first_trigger_button) { + buttonidx += 2; // skip these buttons, we're treating them as axes. } item->analogButton[i] = gamepadEvent->analogButton[buttonidx]; item->digitalButton[i] = gamepadEvent->digitalButton[buttonidx]; } + for (i = 0; i < real_axis_count; i++) { + item->axis[i] = gamepadEvent->axis[i]; + } + + if (item->triggers_are_buttons) { + item->axis[real_axis_count] = (gamepadEvent->analogButton[first_trigger_button] * 2.0f) - 1.0f; + item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f; + } + SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. - if (item->nhats) { + if (first_hat_button != -1) { Uint8 value = SDL_HAT_CENTERED; // this currently expects the first button to be up, then down, then left, then right. if (gamepadEvent->digitalButton[first_hat_button + 0]) { value |= SDL_HAT_UP; - } else if (gamepadEvent->digitalButton[first_hat_button + 1]) { + } + if (gamepadEvent->digitalButton[first_hat_button + 1]) { value |= SDL_HAT_DOWN; } if (gamepadEvent->digitalButton[first_hat_button + 2]) { value |= SDL_HAT_LEFT; - } else if (gamepadEvent->digitalButton[first_hat_button + 3]) { + } + if (gamepadEvent->digitalButton[first_hat_button + 3]) { value |= SDL_HAT_RIGHT; } item->hat = value; @@ -391,14 +487,19 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) if (result == EMSCRIPTEN_RESULT_SUCCESS) { if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) { const int first_hat_button = item->first_hat_button; + const int first_trigger_button = item->first_trigger_button; + const int real_button_count = gamepadState.numButtons; + const int real_axis_count = gamepadState.numAxes; int buttonidx = 0; - for (i = 0; i < item->nbuttons; i++, buttonidx++) { + for (i = 0; i < real_button_count; i++, buttonidx++) { if (buttonidx == first_hat_button) { buttonidx += 4; // skip these buttons, we're treating them as hat input. + } else if (buttonidx == first_trigger_button) { + buttonidx += 2; // skip these buttons, we're treating them as axes. } if (item->digitalButton[i] != gamepadState.digitalButton[buttonidx]) { - bool down = (gamepadState.digitalButton[buttonidx] != 0); + const bool down = (gamepadState.digitalButton[buttonidx] != 0); SDL_SendJoystickButton(timestamp, item->joystick, i, down); } @@ -407,15 +508,20 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) item->digitalButton[i] = gamepadState.digitalButton[buttonidx]; } - for (i = 0; i < item->naxes; i++) { + for (i = 0; i < real_axis_count; i++) { if (item->axis[i] != gamepadState.axis[i]) { - // do we need to do conversion? - SDL_SendJoystickAxis(timestamp, item->joystick, i, - (Sint16)(32767. * gamepadState.axis[i])); + SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i])); + item->axis[i] = gamepadState.axis[i]; } + } - // store to compare in next update - item->axis[i] = gamepadState.axis[i]; + if (item->triggers_are_buttons) { + for (i = 0; i < 2; i++) { + if (item->axis[real_axis_count+i] != gamepadState.analogButton[first_trigger_button+i]) { + SDL_SendJoystickAxis(timestamp, item->joystick, real_axis_count+i, (Sint16)(32767.0f * ((gamepadState.analogButton[first_trigger_button+i] * 2.0f) - 1.0f))); + item->axis[real_axis_count+i] = gamepadState.analogButton[first_trigger_button+i]; + } + } } SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons. @@ -456,9 +562,7 @@ static void EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick) static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index) { - // the GUID is just the name for now - const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index); - return SDL_CreateJoystickGUIDForName(name); + return JoystickByDeviceIndex(device_index)->guid; } static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) diff --git a/src/joystick/emscripten/SDL_sysjoystick_c.h b/src/joystick/emscripten/SDL_sysjoystick_c.h index 991959a759..a9b312aebe 100644 --- a/src/joystick/emscripten/SDL_sysjoystick_c.h +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -35,11 +35,14 @@ typedef struct SDL_joylist_item SDL_JoystickID device_instance; SDL_Joystick *joystick; int first_hat_button; + int first_trigger_button; + bool triggers_are_buttons; int nhats; + SDL_GUID guid; int nbuttons; int naxes; double timestamp; - double axis[64]; + double axis[64]; // !!! FIXME: don't hardcode 64 on all of these. double analogButton[64]; EM_BOOL digitalButton[64]; Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons. diff --git a/src/joystick/hidapi/SDL_hidapi_gip.c b/src/joystick/hidapi/SDL_hidapi_gip.c index a61906d822..68161181c7 100644 --- a/src/joystick/hidapi/SDL_hidapi_gip.c +++ b/src/joystick/hidapi/SDL_hidapi_gip.c @@ -1249,7 +1249,7 @@ static bool GIP_SendInitSequence(GIP_Attachment *attachment) } if (attachment->attachment_type == GIP_TYPE_CHATPAD && !attachment->keyboard) { attachment->keyboard = (SDL_KeyboardID)(uintptr_t) attachment; - SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad", true); + SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad"); } return true; } @@ -2335,7 +2335,7 @@ static bool GIP_HandleSystemMessage( if (header->message_type == GIP_CMD_HID_REPORT && num_bytes == 8) { if (!attachment->keyboard) { attachment->keyboard = (SDL_KeyboardID)(uintptr_t) attachment; - SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad", true); + SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad"); } attachment->attachment_type = GIP_TYPE_CHATPAD; attachment->metadata.device.in_system_messages[0] |= (1u << GIP_CMD_HID_REPORT); @@ -2931,7 +2931,7 @@ static void HIDAPI_DriverGIP_FreeDevice(SDL_HIDAPI_Device *device) attachment->fragment_data = NULL; } if (attachment->keyboard) { - SDL_RemoveKeyboard(attachment->keyboard, true); + SDL_RemoveKeyboard(attachment->keyboard); } GIP_MetadataFree(&attachment->metadata); SDL_free(attachment); diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index 4249578e80..1abde08494 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -251,6 +251,7 @@ typedef struct Uint64 last_packet; int player_index; bool player_lights; + bool enhanced_rumble; Uint8 rumble_left; Uint8 rumble_right; bool color_set; @@ -432,6 +433,14 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) } } + if (device->vendor_id == USB_VENDOR_SONY) { + if (device->product_id == USB_PRODUCT_SONY_DS5_EDGE || + ctx->firmware_version == 0 || // Assume that it's updated firmware over Bluetooth + ctx->firmware_version >= 0x0224) { + ctx->enhanced_rumble = true; + } + } + // Get the device capabilities if (device->vendor_id == USB_VENDOR_SONY) { ctx->sensors_supported = true; @@ -684,17 +693,17 @@ static bool HIDAPI_DriverPS5_UpdateEffects(SDL_DriverPS5_Context *ctx, int effec if (ctx->vibration_supported) { if (ctx->rumble_left || ctx->rumble_right) { - if (ctx->firmware_version < 0x0224) { + if (ctx->enhanced_rumble) { + effects.ucEnableBits3 |= 0x04; // Enable improved rumble emulation on 2.24 firmware and newer + + effects.ucRumbleLeft = ctx->rumble_left; + effects.ucRumbleRight = ctx->rumble_right; + } else { effects.ucEnableBits1 |= 0x01; // Enable rumble emulation // Shift to reduce effective rumble strength to match Xbox controllers effects.ucRumbleLeft = ctx->rumble_left >> 1; effects.ucRumbleRight = ctx->rumble_right >> 1; - } else { - effects.ucEnableBits3 |= 0x04; // Enable improved rumble emulation on 2.24 firmware and newer - - effects.ucRumbleLeft = ctx->rumble_left; - effects.ucRumbleRight = ctx->rumble_right; } effects.ucEnableBits1 |= 0x02; // Disable audio haptics } else { @@ -1038,6 +1047,9 @@ static bool HIDAPI_DriverPS5_InternalSendJoystickEffect(SDL_DriverPS5_Context *c if (!ctx->enhanced_mode) { if (application_usage) { HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx); + + // Wait briefly before sending additional effects + SDL_Delay(10); } if (!ctx->enhanced_mode) { diff --git a/src/joystick/hidapi/SDL_hidapi_sinput.c b/src/joystick/hidapi/SDL_hidapi_sinput.c index 5bb708d1e9..b53df62e29 100644 --- a/src/joystick/hidapi/SDL_hidapi_sinput.c +++ b/src/joystick/hidapi/SDL_hidapi_sinput.c @@ -27,12 +27,13 @@ #include "SDL_hidapijoystick_c.h" #include "SDL_hidapi_rumble.h" +#include "SDL_hidapi_sinput.h" #ifdef SDL_JOYSTICK_HIDAPI_SINPUT /*****************************************************************************************************/ // This protocol is documented at: -// https://docs.handheldlegend.com/s/sinput/doc/sinput-hid-protocol-TkPYWlDMAg +// https://docs.handheldlegend.com/s/sinput /*****************************************************************************************************/ // Define this if you want to log all packets from the controller @@ -119,6 +120,39 @@ #define SINPUT_BUTTON_IDX_MISC9 30 #define SINPUT_BUTTON_IDX_MISC10 31 +#define SINPUT_BUTTONMASK_EAST 0x01 +#define SINPUT_BUTTONMASK_SOUTH 0x02 +#define SINPUT_BUTTONMASK_NORTH 0x04 +#define SINPUT_BUTTONMASK_WEST 0x08 +#define SINPUT_BUTTONMASK_DPAD_UP 0x10 +#define SINPUT_BUTTONMASK_DPAD_DOWN 0x20 +#define SINPUT_BUTTONMASK_DPAD_LEFT 0x40 +#define SINPUT_BUTTONMASK_DPAD_RIGHT 0x80 +#define SINPUT_BUTTONMASK_LEFT_STICK 0x01 +#define SINPUT_BUTTONMASK_RIGHT_STICK 0x02 +#define SINPUT_BUTTONMASK_LEFT_BUMPER 0x04 +#define SINPUT_BUTTONMASK_RIGHT_BUMPER 0x08 +#define SINPUT_BUTTONMASK_LEFT_TRIGGER 0x10 +#define SINPUT_BUTTONMASK_RIGHT_TRIGGER 0x20 +#define SINPUT_BUTTONMASK_LEFT_PADDLE1 0x40 +#define SINPUT_BUTTONMASK_RIGHT_PADDLE1 0x80 +#define SINPUT_BUTTONMASK_START 0x01 +#define SINPUT_BUTTONMASK_BACK 0x02 +#define SINPUT_BUTTONMASK_GUIDE 0x04 +#define SINPUT_BUTTONMASK_CAPTURE 0x08 +#define SINPUT_BUTTONMASK_LEFT_PADDLE2 0x10 +#define SINPUT_BUTTONMASK_RIGHT_PADDLE2 0x20 +#define SINPUT_BUTTONMASK_TOUCHPAD1 0x40 +#define SINPUT_BUTTONMASK_TOUCHPAD2 0x80 +#define SINPUT_BUTTONMASK_POWER 0x01 +#define SINPUT_BUTTONMASK_MISC4 0x02 +#define SINPUT_BUTTONMASK_MISC5 0x04 +#define SINPUT_BUTTONMASK_MISC6 0x08 +#define SINPUT_BUTTONMASK_MISC7 0x10 +#define SINPUT_BUTTONMASK_MISC8 0x20 +#define SINPUT_BUTTONMASK_MISC9 0x40 +#define SINPUT_BUTTONMASK_MISC10 0x80 + #define SINPUT_REPORT_IDX_COMMAND_RESPONSE_ID 1 #define SINPUT_REPORT_IDX_COMMAND_RESPONSE_BULK 2 @@ -139,7 +173,6 @@ #define EXTRACTUINT32(data, idx) ((Uint32)((data)[(idx)] | ((data)[(idx) + 1] << 8) | ((data)[(idx) + 2] << 16) | ((data)[(idx) + 3] << 24))) #endif - typedef struct { uint8_t type; @@ -183,6 +216,7 @@ typedef struct { SDL_HIDAPI_Device *device; Uint16 protocol_version; + Uint16 usb_device_version; bool sensors_enabled; Uint8 player_idx; @@ -203,8 +237,8 @@ typedef struct Uint8 touchpad_count; // 2 touchpads maximum Uint8 touchpad_finger_count; // 2 fingers for one touchpad, or 1 per touchpad (2 max) - Uint8 polling_rate_ms; - Uint8 sub_type; // Subtype of the device, 0 in most cases + Uint16 polling_rate_us; + Uint8 sub_product; // Subtype of the device, 0 in most cases Uint16 accelRange; // Example would be 2,4,8,16 +/- (g-force) Uint16 gyroRange; // Example would be 1000,2000,4000 +/- (degrees per second) @@ -213,6 +247,7 @@ typedef struct float gyroScale; // Scale factor for gyroscope values Uint8 last_state[USB_PACKET_LENGTH]; + Uint8 axes_count; Uint8 buttons_count; Uint8 usage_masks[4]; @@ -233,6 +268,172 @@ static inline float CalculateAccelScale(uint16_t g_range) return SDL_STANDARD_GRAVITY / (32768.0f / (float)g_range); } +// This function uses base-n encoding to encode features into the version GUID bytes +// that properly represents the supported device features +// This also sets the driver context button mask correctly based on the features +static void DeviceDynamicEncodingSetup(SDL_HIDAPI_Device *device) +{ + SDL_DriverSInput_Context *ctx = device->context; + + // A new button mask is generated to provide + // SDL with a mapping string that is sane. In case of + // an unconventional gamepad setup, the closest sane + // mapping is provided to the driver. + Uint8 mask[4] = { 0 }; + + // For all gamepads, there is a minimum SInput expectation + // to have dpad, abxy, and start buttons + + // ABXY + D-Pad + mask[0] = 0xFF; + ctx->dpad_supported = true; + + // Start button + mask[2] |= SINPUT_BUTTONMASK_START; + + // Bumpers + bool left_bumper = (ctx->usage_masks[1] & SINPUT_BUTTONMASK_LEFT_BUMPER) != 0; + bool right_bumper = (ctx->usage_masks[1] & SINPUT_BUTTONMASK_RIGHT_BUMPER) != 0; + + int bumperStyle = SINPUT_BUMPERSTYLE_NONE; + if (left_bumper && right_bumper) { + bumperStyle = SINPUT_BUMPERSTYLE_TWO; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_BUMPER | SINPUT_BUTTONMASK_RIGHT_BUMPER); + } else if (left_bumper || right_bumper) { + bumperStyle = SINPUT_BUMPERSTYLE_ONE; + + if (left_bumper) { + mask[1] |= SINPUT_BUTTONMASK_LEFT_BUMPER; + } else if (right_bumper) { + mask[1] |= SINPUT_BUTTONMASK_RIGHT_BUMPER; + } + } + + // Trigger bits live in mask[1] + bool digital_triggers = (ctx->usage_masks[1] & (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER)) != 0; + + bool analog_triggers = ctx->left_analog_trigger_supported || ctx->right_analog_trigger_supported; + + // Touchpads + bool t1 = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_TOUCHPAD1) != 0; + bool t2 = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_TOUCHPAD2) != 0; + + int analogStyle = SINPUT_ANALOGSTYLE_NONE; + if (ctx->left_analog_stick_supported && ctx->right_analog_stick_supported) { + analogStyle = SINPUT_ANALOGSTYLE_LEFTRIGHT; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_STICK | SINPUT_BUTTONMASK_RIGHT_STICK); + } else if (ctx->left_analog_stick_supported) { + analogStyle = SINPUT_ANALOGSTYLE_LEFTONLY; + mask[1] |= SINPUT_BUTTONMASK_LEFT_STICK; + } else if (ctx->right_analog_stick_supported) { + analogStyle = SINPUT_ANALOGSTYLE_RIGHTONLY; + mask[1] |= SINPUT_BUTTONMASK_RIGHT_STICK; + } + + int triggerStyle = SINPUT_TRIGGERSTYLE_NONE; + + if (analog_triggers && digital_triggers) { + // When we have both analog triggers and digital triggers + // this is interpreted as having dual-stage triggers + triggerStyle = SINPUT_TRIGGERSTYLE_DUALSTAGE; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER); + } else if (analog_triggers) { + triggerStyle = SINPUT_TRIGGERSTYLE_ANALOG; + } else if (digital_triggers) { + triggerStyle = SINPUT_TRIGGERSTYLE_DIGITAL; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER); + } + + // Paddle bits may touch mask[1] and mask[2] + bool pg1 = (ctx->usage_masks[1] & (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1)) != 0; + bool pg2 = (ctx->usage_masks[2] & (SINPUT_BUTTONMASK_LEFT_PADDLE2 | SINPUT_BUTTONMASK_RIGHT_PADDLE2)) != 0; + + int paddleStyle = SINPUT_PADDLESTYLE_NONE; + if (pg1 && pg2) { + paddleStyle = SINPUT_PADDLESTYLE_FOUR; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1); + mask[2] |= (SINPUT_BUTTONMASK_LEFT_PADDLE2 | SINPUT_BUTTONMASK_RIGHT_PADDLE2); + } else if (pg1) { + paddleStyle = SINPUT_PADDLESTYLE_TWO; + mask[1] |= (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1); + } + + + // Meta Buttons (Back, Guide, Share) + bool back = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_BACK) != 0; + bool guide = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_GUIDE) != 0; + bool share = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_CAPTURE) != 0; + + int metaStyle = SINPUT_METASTYLE_NONE; + if (share) { + metaStyle = SINPUT_METASTYLE_BACKGUIDESHARE; + mask[2] |= (SINPUT_BUTTONMASK_BACK | SINPUT_BUTTONMASK_GUIDE | SINPUT_BUTTONMASK_CAPTURE); + } else if (guide) { + metaStyle = SINPUT_METASTYLE_BACKGUIDE; + mask[2] |= (SINPUT_BUTTONMASK_BACK | SINPUT_BUTTONMASK_GUIDE); + } else if (back) { + metaStyle = SINPUT_METASTYLE_BACK; + mask[2] |= (SINPUT_BUTTONMASK_BACK); + } + + int touchStyle = SINPUT_TOUCHSTYLE_NONE; + if (t1 && t2) { + touchStyle = SINPUT_TOUCHSTYLE_DOUBLE; + mask[2] |= (SINPUT_BUTTONMASK_TOUCHPAD1 | SINPUT_BUTTONMASK_TOUCHPAD2); + } else if (t1) { + touchStyle = SINPUT_TOUCHSTYLE_SINGLE; + mask[2] |= SINPUT_BUTTONMASK_TOUCHPAD1; + } + + // Misc Buttons + int miscStyle = SINPUT_MISCSTYLE_NONE; + Uint8 extra_misc = ctx->usage_masks[3] & 0x0F; + switch (extra_misc) { + case 0x0F: + miscStyle = SINPUT_MISCSTYLE_4; + mask[3] = 0x0F; + break; + case 0x07: + miscStyle = SINPUT_MISCSTYLE_3; + mask[3] = 0x07; + break; + case 0x03: + miscStyle = SINPUT_MISCSTYLE_2; + mask[3] = 0x03; + break; + case 0x01: + miscStyle = SINPUT_MISCSTYLE_1; + mask[3] = 0x01; + break; + default: + miscStyle = SINPUT_MISCSTYLE_NONE; + mask[3] = 0x00; + break; + } + + int version = analogStyle; + version = (version * (int)SINPUT_BUMPERSTYLE_MAX) + bumperStyle; + version = (version * (int)SINPUT_TRIGGERSTYLE_MAX) + triggerStyle; + version = (version * (int)SINPUT_PADDLESTYLE_MAX) + paddleStyle; + version = (version * (int)SINPUT_METASTYLE_MAX) + metaStyle; + version = (version * (int)SINPUT_TOUCHSTYLE_MAX) + touchStyle; + version = (version * (int)SINPUT_MISCSTYLE_MAX) + miscStyle; + + // Overwrite our button usage masks + // with our sanitized masks + ctx->usage_masks[0] = mask[0]; + ctx->usage_masks[1] = mask[1]; + ctx->usage_masks[2] = mask[2]; + ctx->usage_masks[3] = mask[3]; + + version = SDL_clamp(version, 0, UINT16_MAX); + + // Overwrite 'Version' field of the GUID data + device->guid.data[12] = (Uint8)(version & 0xFF); + device->guid.data[13] = (Uint8)(version >> 8); +} + + static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data) { SDL_DriverSInput_Context *ctx = (SDL_DriverSInput_Context *)device->context; @@ -266,69 +467,26 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data) // The 5 LSB represent a device sub-type device->guid.data[15] = data[5]; - ctx->sub_type = (data[5] & 0x1F); + ctx->sub_product = (data[5] & 0x1F); #if defined(DEBUG_SINPUT_INIT) SDL_Log("SInput Face Style: %d", (data[5] & 0xE0) >> 5); - SDL_Log("SInput Sub-type: %d", (data[5] & 0x1F)); + SDL_Log("SInput Sub-product: %d", (data[5] & 0x1F)); #endif - ctx->polling_rate_ms = data[6]; + ctx->polling_rate_us = EXTRACTUINT16(data, 6); + +#if defined(DEBUG_SINPUT_INIT) + SDL_Log("SInput polling interval (microseconds): %d", ctx->polling_rate_us); +#endif ctx->accelRange = EXTRACTUINT16(data, 8); ctx->gyroRange = EXTRACTUINT16(data, 10); - - if ((device->product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC) && (device->vendor_id == USB_VENDOR_RASPBERRYPI)) { - switch (ctx->sub_type) { - // SInput generic device, exposes all buttons - default: - case 0: - ctx->usage_masks[0] = 0xFF; - ctx->usage_masks[1] = 0xFF; - ctx->usage_masks[2] = 0xFF; - ctx->usage_masks[3] = 0xFF; - break; - } - } else { - // Masks in LSB to MSB - // South, East, West, North, DUp, DDown, DLeft, DRight - ctx->usage_masks[0] = data[12]; - - // Stick Left, Stick Right, L Shoulder, R Shoulder, - // L Digital Trigger, R Digital Trigger, L Paddle 1, R Paddle 1 - ctx->usage_masks[1] = data[13]; - - // Start, Back, Guide, Capture, L Paddle 2, R Paddle 2, Touchpad L, Touchpad R - ctx->usage_masks[2] = data[14]; - - // Power, Misc 4 to 10 - ctx->usage_masks[3] = data[15]; - } - - // Derive button count from mask - for (Uint8 byte = 0; byte < 4; ++byte) { - for (Uint8 bit = 0; bit < 8; ++bit) { - if ((ctx->usage_masks[byte] & (1 << bit)) != 0) { - ++ctx->buttons_count; - } - } - } - - // Convert DPAD to hat - const int DPAD_MASK = (1 << SINPUT_BUTTON_IDX_DPAD_UP) | - (1 << SINPUT_BUTTON_IDX_DPAD_DOWN) | - (1 << SINPUT_BUTTON_IDX_DPAD_LEFT) | - (1 << SINPUT_BUTTON_IDX_DPAD_RIGHT); - if ((ctx->usage_masks[0] & DPAD_MASK) == DPAD_MASK) { - ctx->dpad_supported = true; - ctx->usage_masks[0] &= ~DPAD_MASK; - ctx->buttons_count -= 4; - } - -#if defined(DEBUG_SINPUT_INIT) - SDL_Log("Buttons count: %d", ctx->buttons_count); -#endif + ctx->usage_masks[0] = data[12]; + ctx->usage_masks[1] = data[13]; + ctx->usage_masks[2] = data[14]; + ctx->usage_masks[3] = data[15]; // Get and validate touchpad parameters ctx->touchpad_count = data[16]; @@ -354,6 +512,48 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data) ctx->accelScale = CalculateAccelScale(ctx->accelRange); ctx->gyroScale = CalculateGyroScale(ctx->gyroRange); + + Uint8 axes = 0; + if (ctx->left_analog_stick_supported) { + axes += 2; + } + + if (ctx->right_analog_stick_supported) { + axes += 2; + } + + if (ctx->left_analog_trigger_supported || ctx->right_analog_trigger_supported) { + // Always add both analog trigger axes if one is present + axes += 2; + } + + ctx->axes_count = axes; + + DeviceDynamicEncodingSetup(device); + + // Derive button count from mask + for (Uint8 byte = 0; byte < 4; ++byte) { + for (Uint8 bit = 0; bit < 8; ++bit) { + if ((ctx->usage_masks[byte] & (1 << bit)) != 0) { + ++ctx->buttons_count; + } + } + } + + // Convert DPAD to hat + const int DPAD_MASK = (1 << SINPUT_BUTTON_IDX_DPAD_UP) | + (1 << SINPUT_BUTTON_IDX_DPAD_DOWN) | + (1 << SINPUT_BUTTON_IDX_DPAD_LEFT) | + (1 << SINPUT_BUTTON_IDX_DPAD_RIGHT); + if ((ctx->usage_masks[0] & DPAD_MASK) == DPAD_MASK) { + ctx->dpad_supported = true; + ctx->usage_masks[0] &= ~DPAD_MASK; + ctx->buttons_count -= 4; + } + +#if defined(DEBUG_SINPUT_INIT) + SDL_Log("Buttons count: %d", ctx->buttons_count); +#endif } static bool RetrieveSDLFeatures(SDL_HIDAPI_Device *device) @@ -460,6 +660,9 @@ static bool HIDAPI_DriverSInput_InitDevice(SDL_HIDAPI_Device *device) return false; } + // Store the USB Device Version because we will overwrite this data + ctx->usb_device_version = device->version; + switch (device->product_id) { case USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE: HIDAPI_SetDeviceName(device, "HHL GC Ultimate"); @@ -467,8 +670,11 @@ static bool HIDAPI_DriverSInput_InitDevice(SDL_HIDAPI_Device *device) case USB_PRODUCT_HANDHELDLEGEND_PROGCC: HIDAPI_SetDeviceName(device, "HHL ProGCC"); break; + case USB_PRODUCT_VOIDGAMING_PS4FIREBIRD: + HIDAPI_SetDeviceName(device, "Void Gaming PS4 FireBird"); + break; case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD: - HIDAPI_SetDeviceName(device, "Bonziri Firebird"); + HIDAPI_SetDeviceName(device, "Bonziri FireBird"); break; case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC: default: @@ -523,45 +729,18 @@ static bool HIDAPI_DriverSInput_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys SDL_zeroa(ctx->last_state); - int axes = 0; - if (ctx->left_analog_stick_supported) { - axes += 2; - } - - if (ctx->right_analog_stick_supported) { - axes += 2; - } - - if (ctx->left_analog_trigger_supported) { - ++axes; - } - - if (ctx->right_analog_trigger_supported) { - ++axes; - } - - if ((device->product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC) && (device->vendor_id == USB_VENDOR_RASPBERRYPI)) { - switch (ctx->sub_type) { - // Default generic device, exposes all axes - default: - case 0: - axes = 6; - break; - } - } - - joystick->naxes = axes; + joystick->naxes = ctx->axes_count; if (ctx->dpad_supported) { joystick->nhats = 1; } if (ctx->accelerometer_supported) { - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 1000.0f / ctx->polling_rate_ms); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 1000000.0f / ctx->polling_rate_us); } if (ctx->gyroscope_supported) { - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 1000.0f / ctx->polling_rate_ms); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 1000000.0f / ctx->polling_rate_us); } if (ctx->touchpad_supported) { diff --git a/src/joystick/hidapi/SDL_hidapi_sinput.h b/src/joystick/hidapi/SDL_hidapi_sinput.h new file mode 100644 index 0000000000..8bcc70d7fc --- /dev/null +++ b/src/joystick/hidapi/SDL_hidapi_sinput.h @@ -0,0 +1,92 @@ +/* + Simple DirectMedia Layer + Copyright (C) 2025 Mitchell Cairns + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +typedef enum +{ + SINPUT_ANALOGSTYLE_NONE, + SINPUT_ANALOGSTYLE_LEFTONLY, + SINPUT_ANALOGSTYLE_RIGHTONLY, + SINPUT_ANALOGSTYLE_LEFTRIGHT, + SINPUT_ANALOGSTYLE_MAX, +} SInput_AnalogStyleType; + +typedef enum +{ + SINPUT_BUMPERSTYLE_NONE, + SINPUT_BUMPERSTYLE_ONE, + SINPUT_BUMPERSTYLE_TWO, + SINPUT_BUMPERSTYLE_MAX, +} SInput_BumperStyleType; + +typedef enum +{ + SINPUT_TRIGGERSTYLE_NONE, + SINPUT_TRIGGERSTYLE_ANALOG, + SINPUT_TRIGGERSTYLE_DIGITAL, + SINPUT_TRIGGERSTYLE_DUALSTAGE, + SINPUT_TRIGGERSTYLE_MAX, +} SInput_TriggerStyleType; + +typedef enum +{ + SINPUT_PADDLESTYLE_NONE, + SINPUT_PADDLESTYLE_TWO, + SINPUT_PADDLESTYLE_FOUR, + SINPUT_PADDLESTYLE_MAX, +} SInput_PaddleStyleType; + +typedef enum +{ + SINPUT_METASTYLE_NONE, + SINPUT_METASTYLE_BACK, + SINPUT_METASTYLE_BACKGUIDE, + SINPUT_METASTYLE_BACKGUIDESHARE, + SINPUT_METASTYLE_MAX, +} SInput_MetaStyleType; + +typedef enum +{ + SINPUT_TOUCHSTYLE_NONE, + SINPUT_TOUCHSTYLE_SINGLE, + SINPUT_TOUCHSTYLE_DOUBLE, + SINPUT_TOUCHSTYLE_MAX, +} SInput_TouchStyleType; + +typedef enum +{ + SINPUT_MISCSTYLE_NONE, + SINPUT_MISCSTYLE_1, + SINPUT_MISCSTYLE_2, + SINPUT_MISCSTYLE_3, + SINPUT_MISCSTYLE_4, + SINPUT_MISCSTYLE_MAX, +} SInput_MiscStyleType; + +typedef struct +{ + Uint16 analog_style; + Uint16 bumper_style; + Uint16 trigger_style; + Uint16 paddle_style; + Uint16 meta_style; + Uint16 touch_style; + Uint16 misc_style; +} SDL_SInputStyles_t; diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index 6b366515d3..c3902c800c 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -457,6 +457,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew DPRINTF("ResetSteamController hid=%p\n", dev); + SDL_zero(buf); buf[0] = 0; buf[1] = ID_GET_ATTRIBUTES_VALUES; res = SetFeatureReport(dev, buf, 2); @@ -510,6 +511,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew } // Clear digital button mappings + SDL_zero(buf); buf[0] = 0; buf[1] = ID_CLEAR_DIGITAL_MAPPINGS; res = SetFeatureReport(dev, buf, 2); @@ -521,7 +523,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew } // Reset the default settings - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_LOAD_DEFAULT_SETTINGS; buf[2] = 0; res = SetFeatureReport(dev, buf, 3); @@ -539,7 +541,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew buf[3 + nSettings * 3 + 2] = ((uint16_t)VALUE) >> 8; \ ++nSettings; - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_SETTINGS_VALUES; ADD_SETTING(SETTING_WIRELESS_PACKET_VERSION, 2); ADD_SETTING(SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE); @@ -567,7 +569,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew bool bMappingsCleared = false; int iRetry; for (iRetry = 0; iRetry < 2; ++iRetry) { - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_GET_DIGITAL_MAPPINGS; buf[2] = 1; // one byte - requesting from index 0 buf[3] = 0; @@ -596,7 +598,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew } // Set our new mappings - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_DIGITAL_MAPPINGS; buf[2] = 6; // 2 settings x 3 bytes buf[3] = IO_DIGITAL_BUTTON_RIGHT_TRIGGER; @@ -634,7 +636,7 @@ static int ReadSteamController(SDL_hid_device *dev, uint8_t *pData, int nDataSiz static void SetPairingState(SDL_HIDAPI_Device *dev, bool bEnablePairing) { unsigned char buf[65]; - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_ENABLE_PAIRING; buf[2] = 2; // 2 payload bytes: bool + timeout buf[3] = bEnablePairing ? 1 : 0; @@ -648,7 +650,7 @@ static void SetPairingState(SDL_HIDAPI_Device *dev, bool bEnablePairing) static void CommitPairing(SDL_HIDAPI_Device *dev) { unsigned char buf[65]; - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_DONGLE_COMMIT_DEVICE; SetFeatureReport(dev, buf, 2); } @@ -663,18 +665,18 @@ static void CloseSteamController(SDL_HIDAPI_Device *dev) int nSettings = 0; // Reset digital button mappings - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_DEFAULT_DIGITAL_MAPPINGS; SetFeatureReport(dev, buf, 2); // Reset the default settings - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_LOAD_DEFAULT_SETTINGS; buf[2] = 0; SetFeatureReport(dev, buf, 3); // Reset mouse mode for lizard mode - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_SETTINGS_VALUES; ADD_SETTING(SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE); buf[2] = (unsigned char)(nSettings * 3); @@ -1138,6 +1140,7 @@ static bool HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device) unsigned char buf[65]; int res; + SDL_zero(buf); buf[0] = 0; buf[1] = ID_DONGLE_GET_WIRELESS_STATE; res = SetFeatureReport(device, buf, 2); @@ -1199,7 +1202,7 @@ static bool SetHomeLED(SDL_HIDAPI_Device *device, Uint8 value) unsigned char buf[65]; int nSettings = 0; - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_SETTINGS_VALUES; ADD_SETTING(SETTING_LED_USER_BRIGHTNESS, value); buf[2] = (unsigned char)(nSettings * 3); @@ -1310,7 +1313,7 @@ static bool HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_ unsigned char buf[65]; int nSettings = 0; - SDL_memset(buf, 0, 65); + SDL_zero(buf); buf[1] = ID_SET_SETTINGS_VALUES; if (enabled) { ADD_SETTING(SETTING_IMU_MODE, SETTING_GYRO_MODE_SEND_RAW_ACCEL | SETTING_GYRO_MODE_SEND_RAW_GYRO); diff --git a/src/joystick/hidapi/SDL_hidapi_switch2.c b/src/joystick/hidapi/SDL_hidapi_switch2.c index d7c4e8d98a..1eb39bcc2c 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch2.c +++ b/src/joystick/hidapi/SDL_hidapi_switch2.c @@ -355,25 +355,24 @@ static bool HIDAPI_DriverSwitch2_InitUSB(SDL_HIDAPI_Device *device) flash_read_command[12] = 0x80; res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request factory calibration data: %d", res); } else { res = RecvBulkData(ctx, calibration_data, sizeof(calibration_data)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); } else { ParseStickCalibration(&ctx->left_stick, &calibration_data[0x38]); } } - flash_read_command[12] = 0xC0; res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request factory calibration data: %d", res); } else { res = RecvBulkData(ctx, calibration_data, sizeof(calibration_data)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); } else { ParseStickCalibration(&ctx->right_stick, &calibration_data[0x38]); } @@ -384,11 +383,11 @@ static bool HIDAPI_DriverSwitch2_InitUSB(SDL_HIDAPI_Device *device) flash_read_command[13] = 0x31; res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request factory calibration data: %d", res); } else { res = RecvBulkData(ctx, calibration_data, sizeof(calibration_data)); if (res < 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read calibration data: %d", res); + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); } else { ctx->left_trigger_max = calibration_data[0x10]; ctx->right_trigger_max = calibration_data[0x11]; @@ -396,6 +395,34 @@ static bool HIDAPI_DriverSwitch2_InitUSB(SDL_HIDAPI_Device *device) } } + flash_read_command[12] = 0x40; + flash_read_command[13] = 0xC0; + flash_read_command[14] = 0x1F; + res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); + if (res < 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request user calibration data: %d", res); + } else { + res = RecvBulkData(ctx, calibration_data, sizeof(calibration_data)); + if (res < 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read user calibration data: %d", res); + } else if (calibration_data[0x10] == 0xb2 && calibration_data[0x11] == 0xa1) { + ParseStickCalibration(&ctx->left_stick, &calibration_data[0x12]); + } + } + + flash_read_command[12] = 0x80; + res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); + if (res < 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't request user calibration data: %d", res); + } else { + res = RecvBulkData(ctx, calibration_data, sizeof(calibration_data)); + if (res < 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read user calibration data: %d", res); + } else if (calibration_data[0x10] == 0xb2 && calibration_data[0x11] == 0xa1) { + ParseStickCalibration(&ctx->right_stick, &calibration_data[0x12]); + } + } + return true; } diff --git a/src/joystick/hidapi/SDL_hidapi_zuiki.c b/src/joystick/hidapi/SDL_hidapi_zuiki.c new file mode 100644 index 0000000000..4797bf8a58 --- /dev/null +++ b/src/joystick/hidapi/SDL_hidapi_zuiki.c @@ -0,0 +1,297 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 2025 Zuiki Inc. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_JOYSTICK_HIDAPI + +#include "../SDL_sysjoystick.h" +#include "SDL_hidapijoystick_c.h" +#include "SDL_hidapi_rumble.h" + +#ifdef SDL_JOYSTICK_HIDAPI_ZUIKI + +// Define this if you want to log all packets from the controller +#if 0 +#define DEBUG_ZUIKI_PROTOCOL +#endif + +typedef struct +{ + Uint8 last_state[USB_PACKET_LENGTH]; +} SDL_DriverZUIKI_Context; + +static void HIDAPI_DriverZUIKI_RegisterHints(SDL_HintCallback callback, void *userdata) +{ + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, callback, userdata); +} + +static void HIDAPI_DriverZUIKI_UnregisterHints(SDL_HintCallback callback, void *userdata) +{ + SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, callback, userdata); +} + +static bool HIDAPI_DriverZUIKI_IsEnabled(void) +{ + return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)); +} + +static bool HIDAPI_DriverZUIKI_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) +{ + if (vendor_id == USB_VENDOR_ZUIKI) { + switch (product_id) { + case USB_PRODUCT_ZUIKI_MASCON_PRO: + return true; + default: + break; + } + } + return false; +} + +static bool HIDAPI_DriverZUIKI_InitDevice(SDL_HIDAPI_Device *device) +{ + SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + return false; + } + device->context = ctx; + + if (device->product_id == USB_PRODUCT_ZUIKI_MASCON_PRO) { + HIDAPI_SetDeviceName(device, "ZUIKI MASCON PRO"); + } + + return HIDAPI_JoystickConnected(device, NULL); +} + +static int HIDAPI_DriverZUIKI_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) +{ + return -1; +} + +static void HIDAPI_DriverZUIKI_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) +{ +} + +#ifndef DEG2RAD +#define DEG2RAD(x) ((float)(x) * (float)(SDL_PI_F / 180.f)) +#endif + +static bool HIDAPI_DriverZUIKI_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ + SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)device->context; + + SDL_AssertJoysticksLocked(); + + SDL_zeroa(ctx->last_state); + + joystick->nbuttons = 11; + joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; + joystick->nhats = 1; + + return true; +} + +static bool HIDAPI_DriverZUIKI_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +{ + Uint8 rumble_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + rumble_packet[4] = low_frequency_rumble >> 8; + rumble_packet[5] = high_frequency_rumble >> 8; + if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) { + return SDL_SetError("Couldn't send rumble packet"); + } + return true; +} + +static bool HIDAPI_DriverZUIKI_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) +{ + return SDL_Unsupported(); +} + +static Uint32 HIDAPI_DriverZUIKI_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ + Uint32 caps = 0; + caps |= SDL_JOYSTICK_CAP_RUMBLE; + return caps; +} + +static bool HIDAPI_DriverZUIKI_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static bool HIDAPI_DriverZUIKI_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + if (SDL_HIDAPI_SendRumble(device, data, size) != size) { + return SDL_SetError("Couldn't send rumble packet"); + } + return true; +} + +static bool HIDAPI_DriverZUIKI_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) +{ + return SDL_Unsupported(); +} + +static void HIDAPI_DriverZUIKI_HandleOldStatePacket(SDL_Joystick *joystick, SDL_DriverZUIKI_Context *ctx, Uint8 *data, int size) +{ + Sint16 axis; + Uint64 timestamp = SDL_GetTicksNS(); + + if (ctx->last_state[2] != data[2]) { + Uint8 hat; + + switch (data[2]) { + case 0: + hat = SDL_HAT_UP; + break; + case 1: + hat = SDL_HAT_RIGHTUP; + break; + case 2: + hat = SDL_HAT_RIGHT; + break; + case 3: + hat = SDL_HAT_RIGHTDOWN; + break; + case 4: + hat = SDL_HAT_DOWN; + break; + case 5: + hat = SDL_HAT_LEFTDOWN; + break; + case 6: + hat = SDL_HAT_LEFT; + break; + case 7: + hat = SDL_HAT_LEFTUP; + break; + default: + hat = SDL_HAT_CENTERED; + break; + } + SDL_SendJoystickHat(timestamp, joystick, 0, hat); + } + + if (ctx->last_state[0] != data[0]) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x01) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x02) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x04) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x08) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x10) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x20) != 0)); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[0] & 0x40) ? SDL_MAX_SINT16 : SDL_MIN_SINT16); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[0] & 0x80) ? SDL_MAX_SINT16 : SDL_MIN_SINT16); + } + + if (ctx->last_state[1] != data[1]) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x01) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x02) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x04) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x08) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0)); + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC1, ((data[1] & 0x20) != 0)); + /* todo for switch C key */ + } + +#define READ_STICK_AXIS(offset) \ + (data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16)) + { + axis = READ_STICK_AXIS(3); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); + axis = READ_STICK_AXIS(4); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); + axis = READ_STICK_AXIS(5); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); + axis = READ_STICK_AXIS(6); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); + } +#undef READ_STICK_AXIS + + SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); +} + +static bool HIDAPI_DriverZUIKI_UpdateDevice(SDL_HIDAPI_Device *device) +{ + SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)device->context; + SDL_Joystick *joystick = NULL; + Uint8 data[USB_PACKET_LENGTH]; + int size = 0; + + if (device->num_joysticks > 0) { + joystick = SDL_GetJoystickFromID(device->joysticks[0]); + } else { + return false; + } + + while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { +#ifdef DEBUG_ZUIKI_PROTOCOL + HIDAPI_DumpPacket("ZUIKI packet: size = %d", data, size); +#endif + if (!joystick) { + continue; + } + + if (size == 8) { + HIDAPI_DriverZUIKI_HandleOldStatePacket(joystick, ctx, data, size); + } + } + + if (size < 0) { + // Read error, device is disconnected + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); + } + return (size >= 0); +} + +static void HIDAPI_DriverZUIKI_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ +} + +static void HIDAPI_DriverZUIKI_FreeDevice(SDL_HIDAPI_Device *device) +{ +} + +SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverZUIKI = { + SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, + true, + HIDAPI_DriverZUIKI_RegisterHints, + HIDAPI_DriverZUIKI_UnregisterHints, + HIDAPI_DriverZUIKI_IsEnabled, + HIDAPI_DriverZUIKI_IsSupportedDevice, + HIDAPI_DriverZUIKI_InitDevice, + HIDAPI_DriverZUIKI_GetDevicePlayerIndex, + HIDAPI_DriverZUIKI_SetDevicePlayerIndex, + HIDAPI_DriverZUIKI_UpdateDevice, + HIDAPI_DriverZUIKI_OpenJoystick, + HIDAPI_DriverZUIKI_RumbleJoystick, + HIDAPI_DriverZUIKI_RumbleJoystickTriggers, + HIDAPI_DriverZUIKI_GetJoystickCapabilities, + HIDAPI_DriverZUIKI_SetJoystickLED, + HIDAPI_DriverZUIKI_SendJoystickEffect, + HIDAPI_DriverZUIKI_SetJoystickSensorsEnabled, + HIDAPI_DriverZUIKI_CloseJoystick, + HIDAPI_DriverZUIKI_FreeDevice, +}; + +#endif // SDL_JOYSTICK_HIDAPI_ZUIKI + +#endif // SDL_JOYSTICK_HIDAPI diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index e05ee930b3..ef3370675e 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -103,6 +103,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = { #ifdef SDL_JOYSTICK_HIDAPI_SINPUT &SDL_HIDAPI_DriverSInput, #endif +#ifdef SDL_JOYSTICK_HIDAPI_ZUIKI + &SDL_HIDAPI_DriverZUIKI, +#endif }; static int SDL_HIDAPI_numdrivers = 0; static SDL_AtomicInt SDL_HIDAPI_updating_devices; diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index a8962468fb..64a0f53ce1 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -48,6 +48,7 @@ #define SDL_JOYSTICK_HIDAPI_FLYDIGI #define SDL_JOYSTICK_HIDAPI_GIP #define SDL_JOYSTICK_HIDAPI_SINPUT +#define SDL_JOYSTICK_HIDAPI_ZUIKI // Joystick capability definitions #define SDL_JOYSTICK_CAP_MONO_LED 0x00000001 @@ -171,6 +172,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLg4ff; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverFlydigi; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSInput; +extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverZUIKI; // Return true if a HID device is present and supported as a joystick of the given type extern bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type); diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 224a3dce37..dba4d2258c 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -973,7 +973,7 @@ static void LINUX_JoystickDetect(void) { #ifdef SDL_USE_LIBUDEV if (enumeration_method == ENUMERATION_LIBUDEV) { - SDL_UDEV_Poll(); + // Polling will happen in the main event loop } else #endif #ifdef HAVE_INOTIFY diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index 8557e95831..3a689563e3 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -60,6 +60,7 @@ #define USB_VENDOR_VALVE 0x28de #define USB_VENDOR_ZEROPLUS 0x0c12 #define USB_VENDOR_RASPBERRYPI 0x2e8a // Commercial hardware from various companies are registered under this VID +#define USB_VENDOR_ZUIKI 0x33dd #define USB_PRODUCT_8BITDO_SF30_PRO 0x6000 // B + START #define USB_PRODUCT_8BITDO_SF30_PRO_BT 0x6100 // B + START @@ -170,7 +171,9 @@ #define USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC 0x10c6 #define USB_PRODUCT_HANDHELDLEGEND_PROGCC 0x10df #define USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE 0x10dd -#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0 +#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0 +#define USB_PRODUCT_ZUIKI_MASCON_PRO 0x0006 +#define USB_PRODUCT_VOIDGAMING_PS4FIREBIRD 0x10e5 // USB usage pages #define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001 diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c index 8600c0242e..b7a8de577f 100644 --- a/src/joystick/virtual/SDL_virtualjoystick.c +++ b/src/joystick/virtual/SDL_virtualjoystick.c @@ -138,11 +138,11 @@ SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *des SDL_AssertJoysticksLocked(); - if (!desc) { + CHECK_PARAM(!desc) { SDL_InvalidParamError("desc"); return 0; } - if (desc->version < sizeof(*desc)) { + CHECK_PARAM(desc->version < sizeof(*desc)) { // Update this to handle older versions of this interface SDL_SetError("Invalid desc, should be initialized with SDL_INIT_INTERFACE()"); return 0; diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c index dbc5658ef5..11ee2243b7 100644 --- a/src/joystick/windows/SDL_windows_gaming_input.c +++ b/src/joystick/windows/SDL_windows_gaming_input.c @@ -585,7 +585,7 @@ static bool WGI_JoystickInit(void) { HRESULT hr; - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, true)) { + if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, false)) { return true; } diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index e7fbfcb346..805f8cb6aa 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -416,11 +416,15 @@ void WINDOWS_JoystickDetect(void) while (pCurList) { JoyStick_DeviceData *pListNext = NULL; - if (!pCurList->bXInputDevice) { #ifdef SDL_HAPTIC_DINPUT +#ifdef SDL_JOYSTICK_XINPUT + if (!pCurList->bXInputDevice) { SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice); -#endif } +#else + SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice); +#endif +#endif SDL_PrivateJoystickRemoved(pCurList->nInstanceID); @@ -432,11 +436,15 @@ void WINDOWS_JoystickDetect(void) for (pCurList = SYS_Joystick; pCurList; pCurList = pCurList->pNext) { if (pCurList->send_add_event) { - if (!pCurList->bXInputDevice) { #ifdef SDL_HAPTIC_DINPUT +#ifdef SDL_JOYSTICK_XINPUT + if (!pCurList->bXInputDevice) { SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice); -#endif } +#else + SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice); +#endif +#endif SDL_PrivateJoystickAdded(pCurList->nInstanceID); @@ -489,16 +497,18 @@ static int WINDOWS_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) device = device->pNext; } +#ifdef SDL_JOYSTICK_XINPUT if (device->bXInputDevice) { // The slot for XInput devices can change as controllers are seated return SDL_XINPUT_GetSteamVirtualGamepadSlot(device->XInputUserId); - } else { - return device->steam_virtual_gamepad_slot; } +#endif + return device->steam_virtual_gamepad_slot; } static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index) { +#ifdef SDL_JOYSTICK_XINPUT JoyStick_DeviceData *device = SYS_Joystick; int index; @@ -507,6 +517,9 @@ static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index) } return device->bXInputDevice ? (int)device->XInputUserId : -1; +#else + return -1; +#endif } static void WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index) @@ -560,20 +573,22 @@ static bool WINDOWS_JoystickOpen(SDL_Joystick *joystick, int device_index) } joystick->hwdata->guid = device->guid; +#ifdef SDL_JOYSTICK_XINPUT if (device->bXInputDevice) { return SDL_XINPUT_JoystickOpen(joystick, device); - } else { - return SDL_DINPUT_JoystickOpen(joystick, device); } +#endif + return SDL_DINPUT_JoystickOpen(joystick, device); } static bool WINDOWS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { +#ifdef SDL_JOYSTICK_XINPUT if (joystick->hwdata->bXInputDevice) { return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); - } else { - return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); } +#endif + return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); } static bool WINDOWS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) @@ -602,21 +617,27 @@ static void WINDOWS_JoystickUpdate(SDL_Joystick *joystick) return; } +#ifdef SDL_JOYSTICK_XINPUT if (joystick->hwdata->bXInputDevice) { SDL_XINPUT_JoystickUpdate(joystick); - } else { - SDL_DINPUT_JoystickUpdate(joystick); + return; } +#endif + SDL_DINPUT_JoystickUpdate(joystick); } // Function to close a joystick after use static void WINDOWS_JoystickClose(SDL_Joystick *joystick) { +#ifdef SDL_JOYSTICK_XINPUT if (joystick->hwdata->bXInputDevice) { SDL_XINPUT_JoystickClose(joystick); } else { SDL_DINPUT_JoystickClose(joystick); } +#else + SDL_DINPUT_JoystickClose(joystick); +#endif SDL_free(joystick->hwdata); } diff --git a/src/joystick/windows/SDL_windowsjoystick_c.h b/src/joystick/windows/SDL_windowsjoystick_c.h index 16b91848db..963571a85b 100644 --- a/src/joystick/windows/SDL_windowsjoystick_c.h +++ b/src/joystick/windows/SDL_windowsjoystick_c.h @@ -37,9 +37,11 @@ typedef struct JoyStick_DeviceData char *joystickname; Uint8 send_add_event; SDL_JoystickID nInstanceID; +#ifdef SDL_JOYSTICK_XINPUT bool bXInputDevice; BYTE SubType; Uint8 XInputUserId; +#endif DIDEVICEINSTANCE dxdevice; char path[MAX_PATH]; int steam_virtual_gamepad_slot; @@ -85,10 +87,12 @@ struct joystick_hwdata LPDIRECTINPUTEFFECT ffeffect_ref; #endif +#ifdef SDL_JOYSTICK_XINPUT bool bXInputDevice; // true if this device supports using the xinput API rather than DirectInput bool bXInputHaptic; // Supports force feedback via XInput. Uint8 userid; // XInput userid index for this joystick DWORD dwPacketNumber; +#endif }; #ifdef SDL_JOYSTICK_DINPUT diff --git a/src/libm/e_exp.c b/src/libm/e_exp.c index 6519f58087..413e3609d0 100644 --- a/src/libm/e_exp.c +++ b/src/libm/e_exp.c @@ -76,10 +76,6 @@ #include "math_libm.h" #include "math_private.h" -#ifdef __WATCOMC__ /* Watcom defines huge=__huge */ -#undef huge -#endif - static const double one = 1.0, halF[2] = {0.5,-0.5,}, diff --git a/src/libm/e_pow.c b/src/libm/e_pow.c index d1a141ec4b..dc393e1f0c 100644 --- a/src/libm/e_pow.c +++ b/src/libm/e_pow.c @@ -64,10 +64,6 @@ #pragma warning ( disable : 4756 ) #endif -#ifdef __WATCOMC__ /* Watcom defines huge=__huge */ -#undef huge -#endif - static const double bp[] = {1.0, 1.5,}, dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ diff --git a/src/libm/s_atan.c b/src/libm/s_atan.c index ce429d2269..c8a0d01543 100644 --- a/src/libm/s_atan.c +++ b/src/libm/s_atan.c @@ -61,10 +61,6 @@ static const double aT[] = { 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ }; -#ifdef __WATCOMC__ /* Watcom defines huge=__huge */ -#undef huge -#endif - static const double one = 1.0, huge = 1.0e300; diff --git a/src/libm/s_floor.c b/src/libm/s_floor.c index 4809af1551..a3f4f2fa55 100644 --- a/src/libm/s_floor.c +++ b/src/libm/s_floor.c @@ -25,10 +25,6 @@ #include "math_libm.h" #include "math_private.h" -#ifdef __WATCOMC__ /* Watcom defines huge=__huge */ -#undef huge -#endif - static const double huge = 1.0e300; double floor(double x) diff --git a/src/libm/s_scalbn.c b/src/libm/s_scalbn.c index b3a06044ab..799e7fc578 100644 --- a/src/libm/s_scalbn.c +++ b/src/libm/s_scalbn.c @@ -21,10 +21,6 @@ #include "math_private.h" #include -#ifdef __WATCOMC__ /* Watcom defines huge=__huge */ -#undef huge -#endif - static const double two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ diff --git a/src/loadso/windows/SDL_sysloadso.c b/src/loadso/windows/SDL_sysloadso.c index 89e414560b..c5eba7aba8 100644 --- a/src/loadso/windows/SDL_sysloadso.c +++ b/src/loadso/windows/SDL_sysloadso.c @@ -29,7 +29,7 @@ SDL_SharedObject *SDL_LoadObject(const char *sofile) { - if (!sofile) { + CHECK_PARAM(!sofile) { SDL_InvalidParamError("sofile"); return NULL; } diff --git a/src/locale/windows/SDL_syslocale.c b/src/locale/windows/SDL_syslocale.c index 7f69c56974..452682d0c1 100644 --- a/src/locale/windows/SDL_syslocale.c +++ b/src/locale/windows/SDL_syslocale.c @@ -23,7 +23,7 @@ #include "../../core/windows/SDL_windows.h" #include "../SDL_syslocale.h" -typedef BOOL(WINAPI *pfnGetUserPreferredUILanguages)(DWORD, PULONG, WCHAR *, PULONG); +typedef BOOL (WINAPI *pfnGetUserPreferredUILanguages)(DWORD, PULONG, WCHAR *, PULONG); #ifndef MUI_LANGUAGE_NAME #define MUI_LANGUAGE_NAME 0x8 #endif diff --git a/src/main/emscripten/SDL_sysmain_runapp.c b/src/main/emscripten/SDL_sysmain_runapp.c index 8e2252eecd..3b9c0fda89 100644 --- a/src/main/emscripten/SDL_sysmain_runapp.c +++ b/src/main/emscripten/SDL_sysmain_runapp.c @@ -26,6 +26,11 @@ EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8"); +// even though we reference the C runtime's free() in other places, it appears +// to be inlined more aggressively in Emscripten 4, so we need a reference to +// it here, too, so the inlined Javascript doesn't fail to find it. +EMSCRIPTEN_KEEPALIVE void force_free(void *ptr) { free(ptr); } + int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { (void)reserved; @@ -44,8 +49,8 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv //console.log("Setting SDL env var '" + key + "' to '" + value + "' ..."); dynCall('iiii', $0, [ckey, cvalue, 1]); } - _free(ckey); // these must use free(), not SDL_free()! - _free(cvalue); + _force_free(ckey); // these must use free(), not SDL_free()! + _force_free(cvalue); } } }, SDL_setenv_unsafe); diff --git a/src/main/generic/SDL_sysmain_callbacks.c b/src/main/generic/SDL_sysmain_callbacks.c index a08d101908..7c6f4f8f80 100644 --- a/src/main/generic/SDL_sysmain_callbacks.c +++ b/src/main/generic/SDL_sysmain_callbacks.c @@ -54,7 +54,7 @@ static SDL_AppResult GenericIterateMainCallbacks(void) int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit) { SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit); - if (rc == 0) { + if (rc == SDL_APP_CONTINUE) { SDL_AddHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL); Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0; diff --git a/src/main/ios/SDL_sysmain_callbacks.m b/src/main/ios/SDL_sysmain_callbacks.m index 8ebaec6718..3c8388b662 100644 --- a/src/main/ios/SDL_sysmain_callbacks.m +++ b/src/main/ios/SDL_sysmain_callbacks.m @@ -43,6 +43,17 @@ static SDLIosMainCallbacksDisplayLink *globalDisplayLink; { if ((self = [super init])) { self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(appIteration:)]; + // Enable high refresh rates on iOS + // To enable this on phones, you should add the following line to Info.plist: + // CADisableMinimumFrameDurationOnPhone + // If main callbacks are used then this CADisplayLink will affect framerate, not one in SDL_uikitviewcontroller. + if (@available(iOS 15.0, tvOS 15.0, *)) { + const SDL_DisplayMode *mode = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay()); + if (mode && mode->refresh_rate > 60.0f) { + int frame_rate = (int)mode->refresh_rate; + self.displayLink.preferredFrameRateRange = CAFrameRateRangeMake((frame_rate * 2) / 3, frame_rate, frame_rate); + } + } [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } return self; diff --git a/src/misc/SDL_url.c b/src/misc/SDL_url.c index b3163ab118..85d0e43147 100644 --- a/src/misc/SDL_url.c +++ b/src/misc/SDL_url.c @@ -24,7 +24,7 @@ bool SDL_OpenURL(const char *url) { - if (!url) { + CHECK_PARAM(!url) { return SDL_InvalidParamError("url"); } return SDL_SYS_OpenURL(url); diff --git a/src/process/SDL_process.c b/src/process/SDL_process.c index 5db6db49b4..e7316bb281 100644 --- a/src/process/SDL_process.c +++ b/src/process/SDL_process.c @@ -25,7 +25,7 @@ SDL_Process *SDL_CreateProcess(const char * const *args, bool pipe_stdio) { - if (!args || !args[0] || !args[0][0]) { + CHECK_PARAM(!args || !args[0] || !args[0][0]) { SDL_InvalidParamError("args"); return NULL; } @@ -47,12 +47,12 @@ SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props) const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL); #if defined(SDL_PLATFORM_WINDOWS) const char *cmdline = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, NULL); - if ((!args || !args[0] || !args[0][0]) && (!cmdline || !cmdline[0])) { + CHECK_PARAM((!args || !args[0] || !args[0][0]) && (!cmdline || !cmdline[0])) { SDL_SetError("Either SDL_PROP_PROCESS_CREATE_ARGS_POINTER or SDL_PROP_PROCESS_CREATE_CMDLINE_STRING must be valid"); return NULL; } #else - if (!args || !args[0] || !args[0][0]) { + CHECK_PARAM(!args || !args[0] || !args[0][0]) { SDL_InvalidParamError("SDL_PROP_PROCESS_CREATE_ARGS_POINTER"); return NULL; } @@ -81,7 +81,7 @@ SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props) SDL_PropertiesID SDL_GetProcessProperties(SDL_Process *process) { - if (!process) { + CHECK_PARAM(!process) { return SDL_InvalidParamError("process"); } return process->props; @@ -98,7 +98,7 @@ void *SDL_ReadProcess(SDL_Process *process, size_t *datasize, int *exitcode) *exitcode = -1; } - if (!process) { + CHECK_PARAM(!process) { SDL_InvalidParamError("process"); return NULL; } @@ -118,7 +118,7 @@ void *SDL_ReadProcess(SDL_Process *process, size_t *datasize, int *exitcode) SDL_IOStream *SDL_GetProcessInput(SDL_Process *process) { - if (!process) { + CHECK_PARAM(!process) { SDL_InvalidParamError("process"); return NULL; } @@ -134,7 +134,7 @@ SDL_IOStream *SDL_GetProcessInput(SDL_Process *process) SDL_IOStream *SDL_GetProcessOutput(SDL_Process *process) { - if (!process) { + CHECK_PARAM(!process) { SDL_InvalidParamError("process"); return NULL; } @@ -150,7 +150,7 @@ SDL_IOStream *SDL_GetProcessOutput(SDL_Process *process) bool SDL_KillProcess(SDL_Process *process, bool force) { - if (!process) { + CHECK_PARAM(!process) { return SDL_InvalidParamError("process"); } @@ -163,7 +163,7 @@ bool SDL_KillProcess(SDL_Process *process, bool force) bool SDL_WaitProcess(SDL_Process *process, bool block, int *exitcode) { - if (!process) { + CHECK_PARAM(!process) { return SDL_InvalidParamError("process"); } diff --git a/src/process/posix/SDL_posixprocess.c b/src/process/posix/SDL_posixprocess.c index 2e05b01324..627f0de688 100644 --- a/src/process/posix/SDL_posixprocess.c +++ b/src/process/posix/SDL_posixprocess.c @@ -203,7 +203,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR #ifdef SDL_PLATFORM_APPLE if (__builtin_available(macOS 10.15, *)) { - if (posix_spawn_file_actions_addchdir(&fa, working_directory) != 0) { + if (posix_spawn_file_actions_addchdir_np(&fa, working_directory) != 0) { SDL_SetError("posix_spawn_file_actions_addchdir failed: %s", strerror(errno)); goto posix_spawn_fail_all; } diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 303d883b58..513076f1ae 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -50,22 +50,22 @@ this should probably be removed at some point in the future. --ryan. */ #define SDL_PROP_TEXTURE_PARENT_POINTER "SDL.internal.texture.parent" #define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result) \ - if (!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \ + CHECK_PARAM(!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \ SDL_InvalidParamError("renderer"); \ return result; \ } -#define CHECK_RENDERER_MAGIC(renderer, result) \ - CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result); \ - if ((renderer)->destroyed) { \ +#define CHECK_RENDERER_MAGIC(renderer, result) \ + CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result); \ + CHECK_PARAM(renderer->destroyed) { \ SDL_SetError("Renderer's window has been destroyed, can't use further"); \ - return result; \ + return result; \ } -#define CHECK_TEXTURE_MAGIC(texture, result) \ - if (!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \ - SDL_InvalidParamError("texture"); \ - return result; \ +#define CHECK_TEXTURE_MAGIC(texture, result) \ + CHECK_PARAM(!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \ + SDL_InvalidParamError("texture"); \ + return result; \ } // Predefined blend modes @@ -347,6 +347,15 @@ static bool FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture) return true; } +static bool FlushRenderCommandsIfPaletteNeeded(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + if (palette->last_command_generation == renderer->render_command_generation) { + // the current command queue depends on this palette, flush the queue now before it changes + return FlushRenderCommands(renderer); + } + return true; +} + static bool FlushRenderCommandsIfGPURenderStateNeeded(SDL_GPURenderState *state) { SDL_Renderer *renderer = state->renderer; @@ -697,6 +706,60 @@ static bool QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, co return result; } +static bool UpdateTexturePalette(SDL_Texture *texture) +{ + SDL_Renderer *renderer = texture->renderer; + SDL_Palette *public = texture->public_palette; + + if (!SDL_ISPIXELFORMAT_INDEXED(texture->format)) { + return true; + } + + if (!public) { + return SDL_SetError("Texture doesn't have a palette"); + } + + if (texture->native) { + // Keep the native texture in sync with palette updates + if (texture->palette_version == public->version) { + return true; + } + + if (!FlushRenderCommandsIfTextureNeeded(texture->native)) { + return false; + } + + SDL_Surface *surface; + bool result = SDL_LockTextureToSurface(texture->native, NULL, &surface); + if (result) { + result = SDL_BlitSurface(texture->palette_surface, NULL, surface, NULL); + SDL_UnlockTexture(texture->native); + } + if (!result) { + return false; + } + texture->palette_version = public->version; + return true; + } + + SDL_TexturePalette *palette = texture->palette; + if (palette->version != public->version) { + // Keep the native palette in sync with palette updates + if (!FlushRenderCommandsIfPaletteNeeded(renderer, palette)) { + return false; + } + + if (!renderer->UpdatePalette(renderer, palette, public->ncolors, public->colors)) { + return false; + } + + palette->version = public->version; + } + + palette->last_command_generation = renderer->render_command_generation; + return true; +} + static bool QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect) { SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY, texture); @@ -832,7 +895,7 @@ int SDL_GetNumRenderDrivers(void) const char *SDL_GetRenderDriver(int index) { #ifndef SDL_RENDER_DISABLED - if (index < 0 || index >= SDL_GetNumRenderDrivers()) { + CHECK_PARAM(index < 0 || index >= SDL_GetNumRenderDrivers()) { SDL_InvalidParamError("index"); return NULL; } @@ -885,17 +948,16 @@ static bool SDL_RendererEventWatch(void *userdata, SDL_Event *event) bool SDL_CreateWindowAndRenderer(const char *title, int width, int height, SDL_WindowFlags window_flags, SDL_Window **window, SDL_Renderer **renderer) { - bool hidden = (window_flags & SDL_WINDOW_HIDDEN) != 0; - - if (!window) { + CHECK_PARAM(!window) { return SDL_InvalidParamError("window"); } - if (!renderer) { + CHECK_PARAM(!renderer) { return SDL_InvalidParamError("renderer"); } // Hide the window so if the renderer recreates it, we don't get a visual flash on screen + bool hidden = (window_flags & SDL_WINDOW_HIDDEN) != 0; window_flags |= SDL_WINDOW_HIDDEN; *window = SDL_CreateWindow(title, width, height, window_flags); if (!*window) { @@ -985,6 +1047,27 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) const char *hint; SDL_PropertiesID new_props; + // The GPU renderer is the only one that can be created without a window or surface + CHECK_PARAM(!window && !surface && (!driver_name || SDL_strcmp(driver_name, SDL_GPU_RENDERER) != 0)) { + SDL_InvalidParamError("window"); + return NULL; + } + + CHECK_PARAM(window && surface) { + SDL_SetError("A renderer can't target both a window and surface"); + return NULL; + } + + CHECK_PARAM(window && SDL_WindowHasSurface(window)) { + SDL_SetError("Surface already associated with window"); + return NULL; + } + + CHECK_PARAM(window && SDL_GetRenderer(window)) { + SDL_SetError("Renderer already associated with window"); + return NULL; + } + #ifdef SDL_PLATFORM_ANDROID if (!Android_WaitActiveAndLockActivity()) { return NULL; @@ -998,21 +1081,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, true); - if ((!window && !surface) || (window && surface)) { - SDL_InvalidParamError("window"); - goto error; - } - - if (window && SDL_WindowHasSurface(window)) { - SDL_SetError("Surface already associated with window"); - goto error; - } - - if (window && SDL_GetRenderer(window)) { - SDL_SetError("Renderer already associated with window"); - goto error; - } - hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); if (hint && *hint) { SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, true)); @@ -1046,6 +1114,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) if (rc) { break; } + SDL_DestroyRendererWithoutFreeing(renderer); + SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct. } } @@ -1098,6 +1168,11 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) UpdatePixelClipRect(renderer, &renderer->main_view); UpdateMainViewDimensions(renderer); + renderer->palettes = SDL_CreateHashTable(0, false, SDL_HashPointer, SDL_KeyMatchPointer, SDL_DestroyHashValue, NULL); + if (!renderer->palettes) { + goto error; + } + // new textures start at zero, so we start at 1 so first render doesn't flush by accident. renderer->render_command_generation = 1; @@ -1147,8 +1222,16 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); } - int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); +#ifdef SDL_PLATFORM_EMSCRIPTEN // don't change vsync on Emscripten unless explicitly requested; we already set this with a mainloop, and a 0 default causes problems here. + if (SDL_HasProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER)) { + const int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); + SDL_SetRenderVSync(renderer, vsync); + } +#else // everything else defaults to no vsync if not requested. + const int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); SDL_SetRenderVSync(renderer, vsync); +#endif + SDL_CalculateSimulatedVSyncInterval(renderer, window); SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, @@ -1192,43 +1275,38 @@ SDL_Renderer *SDL_CreateRenderer(SDL_Window *window, const char *name) return renderer; } -SDL_Renderer *SDL_CreateGPURenderer(SDL_Window *window, SDL_GPUShaderFormat format_flags, SDL_GPUDevice **device) +SDL_Renderer *SDL_CreateGPURenderer(SDL_GPUDevice *device, SDL_Window *window) { - if (!device) { - SDL_InvalidParamError("device"); - return NULL; - } - - *device = NULL; SDL_Renderer *renderer; SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER, device); SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window); - if (format_flags & SDL_GPU_SHADERFORMAT_SPIRV) { - SDL_SetBooleanProperty(props, SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN, true); - } - if (format_flags & SDL_GPU_SHADERFORMAT_DXIL) { - SDL_SetBooleanProperty(props, SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN, true); - } - if (format_flags & SDL_GPU_SHADERFORMAT_MSL) { - SDL_SetBooleanProperty(props, SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN, true); - } - SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, "gpu"); + SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, SDL_GPU_RENDERER); renderer = SDL_CreateRendererWithProperties(props); - if (renderer) { - *device = (SDL_GPUDevice *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL); - } SDL_DestroyProperties(props); return renderer; } +SDL_GPUDevice *SDL_GetGPURendererDevice(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + + SDL_GPUDevice *device = SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL); + if (!device) { + SDL_SetError("Renderer isn't a GPU renderer"); + return NULL; + } + return device; +} + SDL_Renderer *SDL_CreateSoftwareRenderer(SDL_Surface *surface) { #ifdef SDL_VIDEO_RENDER_SW SDL_Renderer *renderer; - if (!surface) { + CHECK_PARAM(!surface) { SDL_InvalidParamError("surface"); return NULL; } @@ -1288,8 +1366,8 @@ bool SDL_GetRenderOutputSize(SDL_Renderer *renderer, int *w, int *h) } else if (renderer->window) { return SDL_GetWindowSizeInPixels(renderer->window, w, h); } else { - SDL_assert(!"This should never happen"); - return SDL_SetError("Renderer doesn't support querying output size"); + // We don't have any output size, this might be an offscreen-only renderer + return true; } } @@ -1401,6 +1479,7 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert SDL_TextureAccess access = (SDL_TextureAccess)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC); int w = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, 0); int h = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, 0); + SDL_Palette *palette = (SDL_Palette *)SDL_GetPointerProperty(props, SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER, NULL); SDL_Colorspace default_colorspace; bool texture_is_fourcc_and_target; @@ -1409,22 +1488,21 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert if (!format) { format = renderer->texture_formats[0]; } - if (SDL_BYTESPERPIXEL(format) == 0) { + + CHECK_PARAM(SDL_BYTESPERPIXEL(format) == 0) { SDL_SetError("Invalid texture format"); return NULL; } - if (SDL_ISPIXELFORMAT_INDEXED(format)) { - if (!IsSupportedFormat(renderer, format)) { - SDL_SetError("Palettized textures are not supported"); - return NULL; - } + CHECK_PARAM(SDL_ISPIXELFORMAT_INDEXED(format) && access == SDL_TEXTUREACCESS_TARGET) { + SDL_SetError("Palettized textures can't be render targets"); + return NULL; } - if (w <= 0 || h <= 0) { + CHECK_PARAM(w <= 0 || h <= 0) { SDL_SetError("Texture dimensions can't be 0"); return NULL; } int max_texture_size = (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 0); - if (max_texture_size && (w > max_texture_size || h > max_texture_size)) { + CHECK_PARAM(max_texture_size && (w > max_texture_size || h > max_texture_size)) { SDL_SetError("Texture dimensions are limited to %dx%d", max_texture_size, max_texture_size); return NULL; } @@ -1447,7 +1525,12 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert texture->color.b = 1.0f; texture->color.a = 1.0f; texture->blendMode = SDL_ISPIXELFORMAT_ALPHA(format) ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE; - texture->scaleMode = renderer->scale_mode; + if (renderer->scale_mode == SDL_SCALEMODE_LINEAR && + SDL_ISPIXELFORMAT_INDEXED(format)) { + texture->scaleMode = SDL_SCALEMODE_PIXELART; + } else { + texture->scaleMode = renderer->scale_mode; + } texture->view.pixel_w = w; texture->view.pixel_h = h; texture->view.viewport.w = -1; @@ -1500,7 +1583,12 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert } } SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, closest_format); - SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, texture->access); + if (SDL_ISPIXELFORMAT_INDEXED(texture->format)) { + // We're going to be uploading pixels frequently as the palette changes + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING); + } else { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, texture->access); + } SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, texture->w); SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, texture->h); @@ -1526,6 +1614,8 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert texture->next = texture->native; renderer->textures = texture; + SDL_SetTextureScaleMode(texture->native, texture->scaleMode); + if (texture->format == SDL_PIXELFORMAT_MJPG) { // We have a custom decode + upload path for this } else if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { @@ -1538,6 +1628,12 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert SDL_DestroyTexture(texture); return NULL; } + } else if (SDL_ISPIXELFORMAT_INDEXED(texture->format)) { + texture->palette_surface = SDL_CreateSurface(w, h, texture->format); + if (!texture->palette_surface) { + SDL_DestroyTexture(texture); + return NULL; + } } else if (access == SDL_TEXTUREACCESS_STREAMING) { // The pitch is 4 byte aligned texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); @@ -1549,6 +1645,10 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert } } + if (SDL_ISPIXELFORMAT_INDEXED(texture->format) && palette) { + SDL_SetTexturePalette(texture, palette); + } + // Now set the properties for the new texture props = SDL_GetTextureProperties(texture); SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_COLORSPACE_NUMBER, texture->colorspace); @@ -1578,50 +1678,11 @@ SDL_Texture *SDL_CreateTexture(SDL_Renderer *renderer, SDL_PixelFormat format, S static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, SDL_Surface *surface) { - SDL_TextureAccess access; bool direct_update; - SDL_PixelFormat tex_format; - SDL_PropertiesID surface_props; - SDL_PropertiesID tex_props; - SDL_Colorspace surface_colorspace = SDL_COLORSPACE_UNKNOWN; - SDL_Colorspace texture_colorspace = SDL_COLORSPACE_UNKNOWN; - if (texture == NULL || surface == NULL) { - return false; - } - - tex_props = SDL_GetTextureProperties(texture); - if (!tex_props) { - return false; - } - - surface_props = SDL_GetSurfaceProperties(surface); - if (!surface_props) { - return false; - } - - tex_format = (SDL_PixelFormat)SDL_GetNumberProperty(tex_props, SDL_PROP_TEXTURE_FORMAT_NUMBER, 0); - access = (SDL_TextureAccess)SDL_GetNumberProperty(tex_props, SDL_PROP_TEXTURE_ACCESS_NUMBER, 0); - - if (access != SDL_TEXTUREACCESS_STATIC && access != SDL_TEXTUREACCESS_STREAMING) { - return false; - } - - surface_colorspace = SDL_GetSurfaceColorspace(surface); - texture_colorspace = surface_colorspace; - - if (surface_colorspace == SDL_COLORSPACE_SRGB_LINEAR || - SDL_COLORSPACETRANSFER(surface_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) { - if (SDL_ISPIXELFORMAT_FLOAT(tex_format)) { - texture_colorspace = SDL_COLORSPACE_SRGB_LINEAR; - } else if (SDL_ISPIXELFORMAT_10BIT(tex_format)) { - texture_colorspace = SDL_COLORSPACE_HDR10; - } else { - texture_colorspace = SDL_COLORSPACE_SRGB; - } - } - - if (tex_format == surface->format && texture_colorspace == surface_colorspace) { + if (surface->format == texture->format && + surface->palette == texture->public_palette && + SDL_GetSurfaceColorspace(surface) == texture->colorspace) { if (SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) { /* Surface and Renderer formats are identical. * Intermediate conversion is needed to convert color key to alpha (SDL_ConvertColorkeyToAlpha()). */ @@ -1637,17 +1698,16 @@ static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, S if (direct_update) { if (SDL_MUSTLOCK(surface)) { - SDL_LockSurface(surface); - SDL_UpdateTexture(texture, rect, surface->pixels, surface->pitch); - SDL_UnlockSurface(surface); + if (SDL_LockSurface(surface)) { + SDL_UpdateTexture(texture, rect, surface->pixels, surface->pitch); + SDL_UnlockSurface(surface); + } } else { SDL_UpdateTexture(texture, rect, surface->pixels, surface->pitch); } } else { - SDL_Surface *temp = NULL; - // Set up a destination surface for the texture update - temp = SDL_ConvertSurfaceAndColorspace(surface, tex_format, NULL, texture_colorspace, surface_props); + SDL_Surface *temp = SDL_ConvertSurfaceAndColorspace(surface, texture->format, texture->public_palette, texture->colorspace, SDL_GetSurfaceProperties(surface)); if (temp) { SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); SDL_DestroySurface(temp); @@ -1691,7 +1751,7 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s CHECK_RENDERER_MAGIC(renderer, NULL); - if (!SDL_SurfaceValid(surface)) { + CHECK_PARAM(!SDL_SurfaceValid(surface)) { SDL_InvalidParamError("SDL_CreateTextureFromSurface(): surface"); return NULL; } @@ -1703,7 +1763,7 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s needAlpha = false; } - // If Palette contains alpha values, promotes to alpha format + // If palette contains alpha values, promotes to alpha format palette = SDL_GetSurfacePalette(surface); if (palette) { bool is_opaque, has_alpha_channel; @@ -1800,6 +1860,9 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC); SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, surface->w); SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, surface->h); + if (format == surface->format && palette) { + SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER, palette); + } texture = SDL_CreateTextureWithProperties(renderer, props); SDL_DestroyProperties(props); if (!texture) { @@ -1851,6 +1914,84 @@ bool SDL_GetTextureSize(SDL_Texture *texture, float *w, float *h) return true; } +bool SDL_SetTexturePalette(SDL_Texture *texture, SDL_Palette *palette) +{ + CHECK_TEXTURE_MAGIC(texture, false); + + CHECK_PARAM(!SDL_ISPIXELFORMAT_INDEXED(texture->format)) { + return SDL_SetError("Texture isn't palettized format"); + } + + CHECK_PARAM(palette && palette->ncolors > (1 << SDL_BITSPERPIXEL(texture->format))) { + return SDL_SetError("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format"); + } + + if (palette != texture->public_palette) { + SDL_Renderer *renderer = texture->renderer; + + if (texture->public_palette) { + SDL_DestroyPalette(texture->public_palette); + + if (!texture->native) { + // Clean up the texture palette + --texture->palette->refcount; + if (texture->palette->refcount == 0) { + renderer->DestroyPalette(renderer, texture->palette); + SDL_RemoveFromHashTable(renderer->palettes, texture->public_palette); + } + texture->palette = NULL; + } + } + + texture->public_palette = palette; + texture->palette_version = 0; + + if (texture->public_palette) { + ++texture->public_palette->refcount; + + if (!texture->native) { + if (SDL_FindInHashTable(renderer->palettes, palette, (const void **)&texture->palette)) { + ++texture->palette->refcount; + } else { + SDL_TexturePalette *texture_palette = (SDL_TexturePalette *)SDL_calloc(1, sizeof(*texture_palette)); + if (!texture_palette) { + SDL_SetTexturePalette(texture, NULL); + return false; + } + if (!renderer->CreatePalette(renderer, texture_palette)) { + renderer->DestroyPalette(renderer, texture_palette); + SDL_SetTexturePalette(texture, NULL); + return false; + } + texture->palette = texture_palette; + texture->palette->refcount = 1; + + if (!SDL_InsertIntoHashTable(renderer->palettes, palette, texture->palette, false)) { + SDL_SetTexturePalette(texture, NULL); + return false; + } + } + } + + if (!texture->native && renderer->ChangeTexturePalette) { + renderer->ChangeTexturePalette(renderer, texture); + } + } + + if (texture->palette_surface) { + SDL_SetSurfacePalette(texture->palette_surface, palette); + } + } + return true; +} + +SDL_Palette *SDL_GetTexturePalette(SDL_Texture *texture) +{ + CHECK_TEXTURE_MAGIC(texture, NULL); + + return texture->public_palette; +} + bool SDL_SetTextureColorMod(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b) { const float fR = (float)r / 255.0f; @@ -1987,7 +2128,7 @@ bool SDL_SetTextureBlendMode(SDL_Texture *texture, SDL_BlendMode blendMode) CHECK_TEXTURE_MAGIC(texture, false); - if (blendMode == SDL_BLENDMODE_INVALID) { + CHECK_PARAM(blendMode == SDL_BLENDMODE_INVALID) { return SDL_InvalidParamError("blendMode"); } @@ -2022,9 +2163,13 @@ bool SDL_SetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode scaleMode) switch (scaleMode) { case SDL_SCALEMODE_NEAREST: - case SDL_SCALEMODE_LINEAR: case SDL_SCALEMODE_PIXELART: break; + case SDL_SCALEMODE_LINEAR: + if (SDL_ISPIXELFORMAT_INDEXED(texture->format)) { + scaleMode = SDL_SCALEMODE_PIXELART; + } + break; default: return SDL_InvalidParamError("scaleMode"); } @@ -2040,7 +2185,7 @@ bool SDL_SetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode scaleMode) bool SDL_GetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode *scaleMode) { if (scaleMode) { - *scaleMode = SDL_SCALEMODE_LINEAR; + *scaleMode = SDL_SCALEMODE_INVALID; } CHECK_TEXTURE_MAGIC(texture, false); @@ -2057,6 +2202,7 @@ static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, { SDL_Texture *native = texture->native; SDL_Rect full_rect; + bool result = true; if (!SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch)) { return false; @@ -2076,8 +2222,7 @@ static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, native_pixels, native_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, native_pixels, native_pitch); SDL_UnlockTexture(native); } else { // Use a temporary buffer for updating @@ -2088,25 +2233,38 @@ static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, if (!temp_pixels) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, temp_pixels, temp_pitch); - SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, temp_pixels, temp_pitch); + if (result) { + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + } SDL_free(temp_pixels); } } - return true; + return result; } #endif // SDL_HAVE_YUV -static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, - const void *pixels, int pitch) +static bool SDL_UpdateTexturePaletteSurface(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) +{ + SDL_Surface *surface = texture->palette_surface; + + const Uint8 *src = (const Uint8 *)pixels; + Uint8 *dst = ((Uint8 *)surface->pixels) + rect->y * surface->pitch + (rect->x * SDL_BITSPERPIXEL(texture->format)) / 8; + int w = ((rect->w * SDL_BITSPERPIXEL(texture->format)) + 7) / 8; + int h = rect->h; + while (h--) { + SDL_memcpy(dst, src, w); + src += pitch; + dst += surface->pitch; + } + texture->palette_version = 0; + return true; +} + +static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) { SDL_Texture *native = texture->native; - if (!rect->w || !rect->h) { - return true; // nothing to do. - } - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { // We can lock the texture and copy to it void *native_pixels = NULL; @@ -2144,10 +2302,10 @@ bool SDL_UpdateTexture(SDL_Texture *texture, const SDL_Rect *rect, const void *p CHECK_TEXTURE_MAGIC(texture, false); - if (!pixels) { + CHECK_PARAM(!pixels) { return SDL_InvalidParamError("pixels"); } - if (!pitch) { + CHECK_PARAM(!pitch) { return SDL_InvalidParamError("pitch"); } @@ -2167,6 +2325,8 @@ bool SDL_UpdateTexture(SDL_Texture *texture, const SDL_Rect *rect, const void *p } else if (texture->yuv) { return SDL_UpdateTextureYUV(texture, &real_rect, pixels, pitch); #endif + } else if (texture->palette_surface) { + return SDL_UpdateTexturePaletteSurface(texture, &real_rect, pixels, pitch); } else if (texture->native) { return SDL_UpdateTextureNative(texture, &real_rect, pixels, pitch); } else { @@ -2186,6 +2346,7 @@ static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rec { SDL_Texture *native = texture->native; SDL_Rect full_rect; + bool result = true; if (!SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch)) { return false; @@ -2209,8 +2370,7 @@ static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rec if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, native_pixels, native_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, native_pixels, native_pitch); SDL_UnlockTexture(native); } else { // Use a temporary buffer for updating @@ -2221,13 +2381,14 @@ static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rec if (!temp_pixels) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, temp_pixels, temp_pitch); - SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, temp_pixels, temp_pitch); + if (result) { + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + } SDL_free(temp_pixels); } } - return true; + return result; } static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect, @@ -2236,6 +2397,7 @@ static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect { SDL_Texture *native = texture->native; SDL_Rect full_rect; + bool result = true; if (!SDL_SW_UpdateNVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, UVplane, UVpitch)) { return false; @@ -2259,8 +2421,7 @@ static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, native_pixels, native_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, native_pixels, native_pitch); SDL_UnlockTexture(native); } else { // Use a temporary buffer for updating @@ -2271,13 +2432,14 @@ static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect if (!temp_pixels) { return false; } - SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, - rect->w, rect->h, temp_pixels, temp_pitch); - SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + result = SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, rect->w, rect->h, temp_pixels, temp_pitch); + if (result) { + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + } SDL_free(temp_pixels); } } - return true; + return result; } #endif // SDL_HAVE_YUV @@ -2293,28 +2455,28 @@ bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect, CHECK_TEXTURE_MAGIC(texture, false); - if (!Yplane) { + CHECK_PARAM(!Yplane) { return SDL_InvalidParamError("Yplane"); } - if (!Ypitch) { + CHECK_PARAM(!Ypitch) { return SDL_InvalidParamError("Ypitch"); } - if (!Uplane) { + CHECK_PARAM(!Uplane) { return SDL_InvalidParamError("Uplane"); } - if (!Upitch) { + CHECK_PARAM(!Upitch) { return SDL_InvalidParamError("Upitch"); } - if (!Vplane) { + CHECK_PARAM(!Vplane) { return SDL_InvalidParamError("Vplane"); } - if (!Vpitch) { + CHECK_PARAM(!Vpitch) { return SDL_InvalidParamError("Vpitch"); } - if (texture->format != SDL_PIXELFORMAT_YV12 && - texture->format != SDL_PIXELFORMAT_IYUV) { - return SDL_SetError("Texture format must by YV12 or IYUV"); + CHECK_PARAM(texture->format != SDL_PIXELFORMAT_YV12 && + texture->format != SDL_PIXELFORMAT_IYUV) { + return SDL_SetError("Texture format must be YV12 or IYUV"); } real_rect.x = 0; @@ -2359,22 +2521,23 @@ bool SDL_UpdateNVTexture(SDL_Texture *texture, const SDL_Rect *rect, CHECK_TEXTURE_MAGIC(texture, false); - if (!Yplane) { + CHECK_PARAM(!Yplane) { return SDL_InvalidParamError("Yplane"); } - if (!Ypitch) { + CHECK_PARAM(!Ypitch) { return SDL_InvalidParamError("Ypitch"); } - if (!UVplane) { + CHECK_PARAM(!UVplane) { return SDL_InvalidParamError("UVplane"); } - if (!UVpitch) { + CHECK_PARAM(!UVpitch) { return SDL_InvalidParamError("UVpitch"); } - if (texture->format != SDL_PIXELFORMAT_NV12 && - texture->format != SDL_PIXELFORMAT_NV21) { - return SDL_SetError("Texture format must by NV12 or NV21"); + CHECK_PARAM(texture->format != SDL_PIXELFORMAT_NV12 && + texture->format != SDL_PIXELFORMAT_NV21 && + texture->format != SDL_PIXELFORMAT_P010) { + return SDL_SetError("Texture format must be NV12, NV21, or P010"); } real_rect.x = 0; @@ -2417,8 +2580,16 @@ static bool SDL_LockTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, } #endif // SDL_HAVE_YUV -static bool SDL_LockTextureNative(SDL_Texture *texture, const SDL_Rect *rect, - void **pixels, int *pitch) +static bool SDL_LockTexturePaletteSurface(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) +{ + SDL_Surface *surface = texture->palette_surface; + + *pixels = ((Uint8 *)surface->pixels) + rect->y * surface->pitch + (rect->x * SDL_BITSPERPIXEL(texture->format)) / 8; + *pitch = surface->pitch; + return true; +} + +static bool SDL_LockTextureNative(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) { texture->locked_rect = *rect; *pixels = (void *)((Uint8 *)texture->pixels + @@ -2434,7 +2605,7 @@ bool SDL_LockTexture(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, CHECK_TEXTURE_MAGIC(texture, false); - if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + CHECK_PARAM(texture->access != SDL_TEXTUREACCESS_STREAMING) { return SDL_SetError("SDL_LockTexture(): texture must be streaming"); } @@ -2454,7 +2625,9 @@ bool SDL_LockTexture(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, return SDL_LockTextureYUV(texture, rect, pixels, pitch); } else #endif - if (texture->native) { + if (texture->palette_surface) { + return SDL_LockTexturePaletteSurface(texture, rect, pixels, pitch); + } else if (texture->native) { // Calls a real SDL_LockTexture/SDL_UnlockTexture on unlock, flushing then. return SDL_LockTextureNative(texture, rect, pixels, pitch); } else { @@ -2472,8 +2645,10 @@ bool SDL_LockTextureToSurface(SDL_Texture *texture, const SDL_Rect *rect, SDL_Su void *pixels = NULL; int pitch = 0; // fix static analysis - if (!texture || !surface) { - return false; + CHECK_TEXTURE_MAGIC(texture, false); + + CHECK_PARAM(!surface) { + return SDL_InvalidParamError("surface"); } real_rect.x = 0; @@ -2493,6 +2668,9 @@ bool SDL_LockTextureToSurface(SDL_Texture *texture, const SDL_Rect *rect, SDL_Su SDL_UnlockTexture(texture); return false; } + if (texture->public_palette) { + SDL_SetSurfacePalette(texture->locked_surface, texture->public_palette); + } *surface = texture->locked_surface; return true; @@ -2520,6 +2698,11 @@ static void SDL_UnlockTextureYUV(SDL_Texture *texture) } #endif // SDL_HAVE_YUV +static void SDL_UnlockTexturePaletteSurface(SDL_Texture *texture) +{ + texture->palette_version = 0; +} + static void SDL_UnlockTextureNative(SDL_Texture *texture) { SDL_Texture *native = texture->native; @@ -2547,33 +2730,42 @@ void SDL_UnlockTexture(SDL_Texture *texture) if (texture->access != SDL_TEXTUREACCESS_STREAMING) { return; } + #ifdef SDL_HAVE_YUV if (texture->yuv) { SDL_UnlockTextureYUV(texture); } else #endif - if (texture->native) { + if (texture->palette_surface) { + SDL_UnlockTexturePaletteSurface(texture); + } else if (texture->native) { SDL_UnlockTextureNative(texture); } else { SDL_Renderer *renderer = texture->renderer; renderer->UnlockTexture(renderer, texture); } - SDL_DestroySurface(texture->locked_surface); - texture->locked_surface = NULL; + if (texture->locked_surface) { + SDL_DestroySurface(texture->locked_surface); + texture->locked_surface = NULL; + } } bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) { + CHECK_RENDERER_MAGIC(renderer, false); + // texture == NULL is valid and means reset the target to the window if (texture) { CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } - if (texture->access != SDL_TEXTUREACCESS_TARGET) { + CHECK_PARAM(texture->access != SDL_TEXTUREACCESS_TARGET) { return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET"); } + if (texture->native) { // Always render to the native texture texture = texture->native; @@ -2618,6 +2810,7 @@ bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer) { CHECK_RENDERER_MAGIC(renderer, NULL); + if (!renderer->target) { return NULL; } @@ -2754,9 +2947,14 @@ bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_ CHECK_RENDERER_MAGIC(renderer, false); SDL_RenderViewState *view = renderer->view; + if (mode == SDL_LOGICAL_PRESENTATION_DISABLED) { + view->logical_w = 0; + view->logical_h = 0; + } else { + view->logical_w = w; + view->logical_h = h; + } view->logical_presentation_mode = mode; - view->logical_w = w; - view->logical_h = h; UpdateLogicalPresentation(renderer); @@ -3274,7 +3472,7 @@ bool SDL_SetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) { CHECK_RENDERER_MAGIC(renderer, false); - if (blendMode == SDL_BLENDMODE_INVALID) { + CHECK_PARAM(blendMode == SDL_BLENDMODE_INVALID) { return SDL_InvalidParamError("blendMode"); } @@ -3354,9 +3552,10 @@ bool SDL_RenderPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int coun CHECK_RENDERER_MAGIC(renderer, false); - if (!points) { + CHECK_PARAM(!points) { return SDL_InvalidParamError("SDL_RenderPoints(): points"); } + if (count < 1) { return true; } @@ -3560,9 +3759,10 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count CHECK_RENDERER_MAGIC(renderer, false); - if (!points) { + CHECK_PARAM(!points) { return SDL_InvalidParamError("SDL_RenderLines(): points"); } + if (count < 2) { return true; } @@ -3739,9 +3939,10 @@ bool SDL_RenderRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count) CHECK_RENDERER_MAGIC(renderer, false); - if (!rects) { + CHECK_PARAM(!rects) { return SDL_InvalidParamError("SDL_RenderRects(): rects"); } + if (count < 1) { return true; } @@ -3784,9 +3985,10 @@ bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int cou CHECK_RENDERER_MAGIC(renderer, false); - if (!rects) { + CHECK_PARAM(!rects) { return SDL_InvalidParamError("SDL_RenderFillRects(): rects"); } + if (count < 1) { return true; } @@ -3884,7 +4086,7 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } @@ -3912,6 +4114,10 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F dstrect = &full_dstrect; } + if (!UpdateTexturePalette(texture)) { + return false; + } + if (texture->native) { texture = texture->native; } @@ -3931,7 +4137,7 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } if (!renderer->QueueCopyEx && !renderer->QueueGeometry) { @@ -3957,6 +4163,10 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, GetRenderViewportSize(renderer, &real_dstrect); + if (!UpdateTexturePalette(texture)) { + return false; + } + if (texture->native) { texture = texture->native; } @@ -4054,7 +4264,7 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } if (!renderer->QueueCopyEx && !renderer->QueueGeometry) { @@ -4085,6 +4295,10 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, dstrect = &full_dstrect; } + if (!UpdateTexturePalette(texture)) { + return false; + } + if (texture->native) { texture = texture->native; } @@ -4298,6 +4512,11 @@ static bool SDL_RenderTextureTiled_Iterate(SDL_Renderer *renderer, SDL_Texture * return true; } +static bool IsNPOT(int x) +{ + return (x <= 0) || ((x & (x - 1)) != 0); +} + bool SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) { SDL_FRect real_srcrect; @@ -4305,11 +4524,11 @@ bool SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } - if (scale <= 0.0f) { + CHECK_PARAM(scale <= 0.0f) { return SDL_InvalidParamError("scale"); } @@ -4336,17 +4555,28 @@ bool SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const dstrect = &full_dstrect; } + if (!UpdateTexturePalette(texture)) { + return false; + } + if (texture->native) { texture = texture->native; } texture->last_command_generation = renderer->render_command_generation; + bool do_wrapping = !renderer->software && + (!srcrect || + (real_srcrect.x == 0.0f && real_srcrect.y == 0.0f && + real_srcrect.w == (float)texture->w && real_srcrect.h == (float)texture->h)); + if (do_wrapping) { + if (renderer->npot_texture_wrap_unsupported && (IsNPOT((int) real_srcrect.w) || IsNPOT((int) real_srcrect.h))) { + do_wrapping = false; + } + } + // See if we can use geometry with repeating texture coordinates - if (!renderer->software && - (!srcrect || - (real_srcrect.x == 0.0f && real_srcrect.y == 0.0f && - real_srcrect.w == (float)texture->w && real_srcrect.h == (float)texture->h))) { + if (do_wrapping) { return SDL_RenderTextureTiled_Wrap(renderer, texture, &real_srcrect, scale, dstrect); } else { return SDL_RenderTextureTiled_Iterate(renderer, texture, &real_srcrect, scale, dstrect); @@ -4365,7 +4595,7 @@ bool SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } @@ -4502,7 +4732,7 @@ bool SDL_RenderTexture9GridTiled(SDL_Renderer *renderer, SDL_Texture *texture, c CHECK_RENDERER_MAGIC(renderer, false); CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } @@ -5049,42 +5279,45 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, CHECK_RENDERER_MAGIC(renderer, false); - if (!renderer->QueueGeometry) { - return SDL_Unsupported(); - } - if (texture) { CHECK_TEXTURE_MAGIC(texture, false); - if (renderer != texture->renderer) { + CHECK_PARAM(renderer != texture->renderer) { return SDL_SetError("Texture was not created with this renderer"); } } - if (!xy) { + CHECK_PARAM(!xy) { return SDL_InvalidParamError("xy"); } - if (!color) { + CHECK_PARAM(!color) { return SDL_InvalidParamError("color"); } - if (texture && !uv) { + CHECK_PARAM(texture && !uv) { return SDL_InvalidParamError("uv"); } - if (count % 3 != 0) { + (void)count; // In case parameter checking is disabled + CHECK_PARAM(count % 3 != 0) { return SDL_InvalidParamError(indices ? "num_indices" : "num_vertices"); } if (indices) { - if (size_indices != 1 && size_indices != 2 && size_indices != 4) { + CHECK_PARAM(size_indices != 1 && size_indices != 2 && size_indices != 4) { return SDL_InvalidParamError("size_indices"); } - } else { + } + + if (!indices) { size_indices = 0; } + if (!renderer->QueueGeometry) { + return SDL_Unsupported(); + } + #if DONT_DRAW_WHILE_HIDDEN // Don't draw while we're hidden if (renderer->hidden) { @@ -5096,8 +5329,14 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, return true; } - if (texture && texture->native) { - texture = texture->native; + if (texture) { + if (!UpdateTexturePalette(texture)) { + return false; + } + + if (texture->native) { + texture = texture->native; + } } texture_address_mode_u = renderer->texture_address_mode_u; @@ -5309,8 +5548,12 @@ bool SDL_RenderPresent(SDL_Renderer *renderer) CHECK_RENDERER_MAGIC(renderer, false); - if (renderer->target) { - return SDL_SetError("You can't present on a render target"); + CHECK_PARAM(renderer->target) { + if (!renderer->window && SDL_strcmp(renderer->name, SDL_GPU_RENDERER) == 0) { + // We're an offscreen renderer, we must submit the command queue + } else { + return SDL_SetError("You can't present on a render target"); + } } if (renderer->transparent_window) { @@ -5340,6 +5583,10 @@ static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) { SDL_Renderer *renderer; + if (texture->public_palette) { + SDL_SetTexturePalette(texture, NULL); + } + SDL_DestroyProperties(texture->props); renderer = texture->renderer; @@ -5376,8 +5623,14 @@ static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) renderer->DestroyTexture(renderer, texture); - SDL_DestroySurface(texture->locked_surface); - texture->locked_surface = NULL; + if (texture->palette_surface) { + SDL_DestroySurface(texture->palette_surface); + texture->palette_surface = NULL; + } + if (texture->locked_surface) { + SDL_DestroySurface(texture->locked_surface); + texture->locked_surface = NULL; + } SDL_free(texture); } @@ -5451,6 +5704,13 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) SDL_assert(tex != renderer->textures); // satisfy static analysis. } + // Free palette cache, which should be empty now + if (renderer->palettes) { + SDL_assert(SDL_HashTableEmpty(renderer->palettes)); + SDL_DestroyHashTable(renderer->palettes); + renderer->palettes = NULL; + } + // Clean up renderer-specific resources if (renderer->DestroyRenderer) { renderer->DestroyRenderer(renderer); @@ -5862,12 +6122,12 @@ SDL_GPURenderState *SDL_CreateGPURenderState(SDL_Renderer *renderer, SDL_GPURend { CHECK_RENDERER_MAGIC(renderer, NULL); - if (!createinfo) { + CHECK_PARAM(!createinfo) { SDL_InvalidParamError("createinfo"); return NULL; } - if (!createinfo->fragment_shader) { + CHECK_PARAM(!createinfo->fragment_shader) { SDL_SetError("A fragment_shader is required"); return NULL; } @@ -5963,7 +6223,7 @@ bool SDL_SetGPURenderStateFragmentUniforms(SDL_GPURenderState *state, Uint32 slo return true; } -bool SDL_SetRenderGPUState(SDL_Renderer *renderer, SDL_GPURenderState *state) +bool SDL_SetGPURenderState(SDL_Renderer *renderer, SDL_GPURenderState *state) { CHECK_RENDERER_MAGIC(renderer, false); diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index d42f536294..b4bb15ac88 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -70,6 +70,15 @@ typedef struct SDL_RenderViewState SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot. } SDL_RenderViewState; +// Define the SDL texture palette structure +typedef struct SDL_TexturePalette +{ + int refcount; + Uint32 version; + Uint32 last_command_generation; // last command queue generation this palette was in. + void *internal; // Driver specific palette representation +} SDL_TexturePalette; + // Define the SDL texture structure struct SDL_Texture { @@ -81,6 +90,7 @@ struct SDL_Texture int refcount; /**< Application reference count, used when freeing texture */ // Private API definition + SDL_Renderer *renderer; SDL_Colorspace colorspace; // The colorspace of the texture float SDR_white_point; // The SDR white point for this content float HDR_headroom; // The HDR headroom needed by this content @@ -89,8 +99,10 @@ struct SDL_Texture SDL_ScaleMode scaleMode; // The texture scale mode SDL_FColor color; // Texture modulation values SDL_RenderViewState view; // Target texture view state - - SDL_Renderer *renderer; + SDL_Palette *public_palette; + SDL_TexturePalette *palette; + Uint32 palette_version; + SDL_Surface *palette_surface; // Support for formats not supported directly by the renderer SDL_Texture *native; @@ -233,6 +245,10 @@ struct SDL_Renderer void (*InvalidateCachedState)(SDL_Renderer *renderer); bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize); + bool (*CreatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette); + bool (*UpdatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors); + void (*DestroyPalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette); + bool (*ChangeTexturePalette)(SDL_Renderer *renderer, SDL_Texture *texture); bool (*UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch); @@ -269,6 +285,7 @@ struct SDL_Renderer SDL_PixelFormat *texture_formats; int num_texture_formats; bool software; + bool npot_texture_wrap_unsupported; // The window associated with the renderer SDL_Window *window; @@ -297,6 +314,9 @@ struct SDL_Renderer SDL_Texture *target; SDL_Mutex *target_mutex; + // The list of palettes + SDL_HashTable *palettes; + SDL_Colorspace output_colorspace; float SDR_white_point; float HDR_headroom; diff --git a/src/render/direct3d/D3D9_PixelShader_Palette.h b/src/render/direct3d/D3D9_PixelShader_Palette.h new file mode 100755 index 0000000000..9bc727ee50 --- /dev/null +++ b/src/render/direct3d/D3D9_PixelShader_Palette.h @@ -0,0 +1,92 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// Parameters: +// +// sampler2D image; +// sampler1D palette; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// image s0 1 +// palette s1 1 +// + + ps_2_0 + def c0, 0.99609375, 0.001953125, 0, 0 + dcl t0.xy + dcl v0 + dcl_2d s0 + dcl_2d s1 + texld r0, t0, s0 + mad r0.xy, r0.x, c0.x, c0.y + texld r0, r0, s1 + mul r0, r0, v0 + mov oC0, r0 + +// approximately 5 instruction slots used (2 texture, 3 arithmetic) +#endif + +const BYTE g_ps20_main[] = +{ + 0, 2, 255, 255, 254, 255, + 42, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 123, 0, + 0, 0, 0, 2, 255, 255, + 2, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 116, 0, 0, 0, 68, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 76, 0, + 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 100, 0, 0, 0, 0, 0, + 0, 0, 105, 109, 97, 103, + 101, 0, 171, 171, 4, 0, + 12, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 112, 97, 108, 101, + 116, 116, 101, 0, 4, 0, + 11, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, + 114, 111, 115, 111, 102, 116, + 32, 40, 82, 41, 32, 72, + 76, 83, 76, 32, 83, 104, + 97, 100, 101, 114, 32, 67, + 111, 109, 112, 105, 108, 101, + 114, 32, 49, 48, 46, 49, + 0, 171, 81, 0, 0, 5, + 0, 0, 15, 160, 0, 0, + 127, 63, 0, 0, 0, 59, + 0, 0, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 2, + 0, 0, 0, 128, 0, 0, + 3, 176, 31, 0, 0, 2, + 0, 0, 0, 128, 0, 0, + 15, 144, 31, 0, 0, 2, + 0, 0, 0, 144, 0, 8, + 15, 160, 31, 0, 0, 2, + 0, 0, 0, 144, 1, 8, + 15, 160, 66, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 176, 0, 8, 228, 160, + 4, 0, 0, 4, 0, 0, + 3, 128, 0, 0, 0, 128, + 0, 0, 0, 160, 0, 0, + 85, 160, 66, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 1, 8, 228, 160, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 128, + 0, 0, 228, 144, 1, 0, + 0, 2, 0, 8, 15, 128, + 0, 0, 228, 128, 255, 255, + 0, 0 +}; diff --git a/src/render/direct3d/D3D9_PixelShader_Palette.hlsl b/src/render/direct3d/D3D9_PixelShader_Palette.hlsl new file mode 100644 index 0000000000..99dd4798d0 --- /dev/null +++ b/src/render/direct3d/D3D9_PixelShader_Palette.hlsl @@ -0,0 +1,19 @@ + +uniform sampler2D image; +uniform sampler1D palette; + +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; +}; + +float4 main(PixelShaderInput input) : SV_TARGET +{ + float4 Output; + float index; + index = tex2D(image, input.tex).r; + Output = tex1D(palette, index * (255. / 256) + (0.5 / 256)); + return Output * input.color; +} diff --git a/src/render/direct3d/D3D9_PixelShader_YUV.h b/src/render/direct3d/D3D9_PixelShader_YUV.h index e6d913009b..57a0a775e0 100644 --- a/src/render/direct3d/D3D9_PixelShader_YUV.h +++ b/src/render/direct3d/D3D9_PixelShader_YUV.h @@ -51,114 +51,114 @@ const BYTE g_ps20_main[] = { - 0, 2, 255, 255, 254, 255, - 97, 0, 67, 84, 65, 66, - 28, 0, 0, 0, 87, 1, - 0, 0, 0, 2, 255, 255, - 7, 0, 0, 0, 28, 0, - 0, 0, 0, 1, 0, 0, - 80, 1, 0, 0, 168, 0, - 0, 0, 2, 0, 3, 0, - 1, 0, 0, 0, 176, 0, - 0, 0, 0, 0, 0, 0, - 192, 0, 0, 0, 2, 0, - 2, 0, 1, 0, 0, 0, - 176, 0, 0, 0, 0, 0, - 0, 0, 199, 0, 0, 0, - 2, 0, 1, 0, 1, 0, - 0, 0, 176, 0, 0, 0, - 0, 0, 0, 0, 206, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 176, 0, - 0, 0, 0, 0, 0, 0, - 214, 0, 0, 0, 3, 0, - 1, 0, 1, 0, 0, 0, - 240, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 3, 0, 2, 0, 1, 0, - 0, 0, 24, 1, 0, 0, - 0, 0, 0, 0, 40, 1, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 64, 1, - 0, 0, 0, 0, 0, 0, - 66, 99, 111, 101, 102, 102, - 0, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 71, 99, 111, 101, 102, 102, - 0, 82, 99, 111, 101, 102, - 102, 0, 89, 111, 102, 102, - 115, 101, 116, 0, 116, 104, - 101, 83, 97, 109, 112, 108, - 101, 114, 43, 116, 104, 101, - 84, 101, 120, 116, 117, 114, - 101, 85, 0, 171, 171, 171, - 4, 0, 7, 0, 1, 0, - 4, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 116, 104, - 101, 83, 97, 109, 112, 108, - 101, 114, 43, 116, 104, 101, - 84, 101, 120, 116, 117, 114, - 101, 86, 0, 171, 4, 0, - 7, 0, 1, 0, 4, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 116, 104, 101, 83, - 97, 109, 112, 108, 101, 114, - 43, 116, 104, 101, 84, 101, - 120, 116, 117, 114, 101, 89, - 0, 171, 4, 0, 7, 0, - 1, 0, 4, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 112, 115, 95, 50, 95, 48, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 49, 48, 46, 49, 0, 171, - 81, 0, 0, 5, 4, 0, - 15, 160, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 15, 144, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 1, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 2, 8, 15, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 176, - 0, 8, 228, 160, 66, 0, - 0, 3, 1, 0, 15, 128, - 0, 0, 228, 176, 1, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 0, 0, - 228, 176, 2, 8, 228, 160, - 1, 0, 0, 2, 0, 0, - 2, 128, 1, 0, 0, 128, - 1, 0, 0, 2, 0, 0, - 4, 128, 2, 0, 0, 128, - 2, 0, 0, 3, 0, 0, - 7, 128, 0, 0, 228, 128, - 0, 0, 228, 160, 8, 0, - 0, 3, 1, 0, 1, 128, - 0, 0, 228, 128, 1, 0, - 228, 160, 8, 0, 0, 3, - 1, 0, 2, 128, 0, 0, - 228, 128, 2, 0, 228, 160, - 8, 0, 0, 3, 1, 0, - 4, 128, 0, 0, 228, 128, - 3, 0, 228, 160, 1, 0, - 0, 2, 1, 0, 8, 128, - 4, 0, 0, 160, 5, 0, - 0, 3, 0, 0, 15, 128, - 1, 0, 228, 128, 0, 0, - 228, 144, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, + 0, 2, 255, 255, 254, 255, + 97, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 87, 1, + 0, 0, 0, 2, 255, 255, + 7, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 80, 1, 0, 0, 168, 0, + 0, 0, 2, 0, 3, 0, + 1, 0, 0, 0, 176, 0, + 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 2, 0, + 2, 0, 1, 0, 0, 0, + 176, 0, 0, 0, 0, 0, + 0, 0, 199, 0, 0, 0, + 2, 0, 1, 0, 1, 0, + 0, 0, 176, 0, 0, 0, + 0, 0, 0, 0, 206, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 176, 0, + 0, 0, 0, 0, 0, 0, + 214, 0, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 240, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 3, 0, 2, 0, 1, 0, + 0, 0, 24, 1, 0, 0, + 0, 0, 0, 0, 40, 1, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 64, 1, + 0, 0, 0, 0, 0, 0, + 66, 99, 111, 101, 102, 102, + 0, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 71, 99, 111, 101, 102, 102, + 0, 82, 99, 111, 101, 102, + 102, 0, 89, 111, 102, 102, + 115, 101, 116, 0, 116, 104, + 101, 83, 97, 109, 112, 108, + 101, 114, 43, 116, 104, 101, + 84, 101, 120, 116, 117, 114, + 101, 85, 0, 171, 171, 171, + 4, 0, 7, 0, 1, 0, + 4, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 116, 104, + 101, 83, 97, 109, 112, 108, + 101, 114, 43, 116, 104, 101, + 84, 101, 120, 116, 117, 114, + 101, 86, 0, 171, 4, 0, + 7, 0, 1, 0, 4, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 116, 104, 101, 83, + 97, 109, 112, 108, 101, 114, + 43, 116, 104, 101, 84, 101, + 120, 116, 117, 114, 101, 89, + 0, 171, 4, 0, 7, 0, + 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 112, 115, 95, 50, 95, 48, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 49, 48, 46, 49, 0, 171, + 81, 0, 0, 5, 4, 0, + 15, 160, 0, 0, 128, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 3, 176, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 15, 144, + 31, 0, 0, 2, 0, 0, + 0, 144, 0, 8, 15, 160, + 31, 0, 0, 2, 0, 0, + 0, 144, 1, 8, 15, 160, + 31, 0, 0, 2, 0, 0, + 0, 144, 2, 8, 15, 160, + 66, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 176, + 0, 8, 228, 160, 66, 0, + 0, 3, 1, 0, 15, 128, + 0, 0, 228, 176, 1, 8, + 228, 160, 66, 0, 0, 3, + 2, 0, 15, 128, 0, 0, + 228, 176, 2, 8, 228, 160, + 1, 0, 0, 2, 0, 0, + 2, 128, 1, 0, 0, 128, + 1, 0, 0, 2, 0, 0, + 4, 128, 2, 0, 0, 128, + 2, 0, 0, 3, 0, 0, + 7, 128, 0, 0, 228, 128, + 0, 0, 228, 160, 8, 0, + 0, 3, 1, 0, 1, 128, + 0, 0, 228, 128, 1, 0, + 228, 160, 8, 0, 0, 3, + 1, 0, 2, 128, 0, 0, + 228, 128, 2, 0, 228, 160, + 8, 0, 0, 3, 1, 0, + 4, 128, 0, 0, 228, 128, + 3, 0, 228, 160, 1, 0, + 0, 2, 1, 0, 8, 128, + 4, 0, 0, 160, 5, 0, + 0, 3, 0, 0, 15, 128, + 1, 0, 228, 128, 0, 0, + 228, 144, 1, 0, 0, 2, + 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0 }; diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index 5132a23226..e72c49e34e 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -48,6 +48,26 @@ typedef struct const float *shader_params; } D3D_DrawStateCache; +typedef struct +{ + bool dirty; + int w, h; + DWORD usage; + Uint32 format; + D3DFORMAT d3dfmt; + IDirect3DTexture9 *texture; + IDirect3DTexture9 *staging; +} D3D_TextureRep; + +struct D3D_PaletteData +{ + D3D_TextureRep texture; + + struct D3D_PaletteData *prev; + struct D3D_PaletteData *next; +}; +typedef struct D3D_PaletteData D3D_PaletteData; + // Direct3D renderer implementation typedef struct @@ -74,19 +94,9 @@ typedef struct int currentVertexBuffer; bool reportedVboProblem; D3D_DrawStateCache drawstate; + D3D_PaletteData *palettes; } D3D_RenderData; -typedef struct -{ - bool dirty; - int w, h; - DWORD usage; - Uint32 format; - D3DFORMAT d3dfmt; - IDirect3DTexture9 *texture; - IDirect3DTexture9 *staging; -} D3D_TextureRep; - typedef struct { D3D_TextureRep texture; @@ -198,6 +208,7 @@ static D3DFORMAT PixelFormatToD3DFMT(Uint32 format) return D3DFMT_X8R8G8B8; case SDL_PIXELFORMAT_ARGB8888: return D3DFMT_A8R8G8B8; + case SDL_PIXELFORMAT_INDEX8: case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_NV12: @@ -530,6 +541,99 @@ static void D3D_DestroyTextureRep(D3D_TextureRep *texture) } } +static bool D3D_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_PaletteData *palettedata = (D3D_PaletteData *)SDL_calloc(1, sizeof(*palettedata)); + if (!palettedata) { + return false; + } + palette->internal = palettedata; + + if (!D3D_CreateTextureRep(data->device, &palettedata->texture, 0, SDL_PIXELFORMAT_ARGB8888, D3DFMT_A8R8G8B8, 256, 1)) { + SDL_free(palettedata); + return false; + } + + // Keep a reference to the palette so we can restore the texture if we lose the D3D device + if (data->palettes) { + palettedata->next = data->palettes; + data->palettes->prev = palettedata; + } + data->palettes = palettedata; + return true; +} + +static bool D3D_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal; + bool retval; + + Uint32 *entries = SDL_stack_alloc(Uint32, ncolors); + if (!entries) { + return false; + } + for (int i = 0; i < ncolors; ++i) { + entries[i] = (colors[i].a << 24) | (colors[i].r << 16) | (colors[i].g << 8) | colors[i].b; + } + retval = D3D_UpdateTextureRep(data->device, &palettedata->texture, 0, 0, ncolors, 1, entries, ncolors * sizeof(*entries)); + SDL_stack_free(entries); + return retval; +} + +static void D3D_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal; + + if (palettedata) { + D3D_DestroyTextureRep(&palettedata->texture); + + if (data->palettes == palettedata) { + data->palettes = palettedata->next; + } else if (palettedata->prev) { + palettedata->prev->next = palettedata->next; + } + if (palettedata->next) { + palettedata->next->prev = palettedata->prev; + } + SDL_free(palettedata); + } +} + +static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, const void *pixels, int pitch) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } + + if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) { + return false; + } +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + // Skip to the correct offset into the next texture + pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch); + + if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) { + return false; + } + + // Skip to the correct offset into the next texture + pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2)); + if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) { + return false; + } + } +#endif + return true; +} + static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) { D3D_RenderData *data = (D3D_RenderData *)renderer->internal; @@ -552,6 +656,9 @@ static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ if (!D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) { return false; } + if (texture->format == SDL_PIXELFORMAT_INDEX8) { + texturedata->shader = SHADER_PALETTE; + } #ifdef SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { @@ -601,38 +708,6 @@ static bool D3D_RecreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return true; } -static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_Rect *rect, const void *pixels, int pitch) -{ - D3D_RenderData *data = (D3D_RenderData *)renderer->internal; - D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; - - if (!texturedata) { - return SDL_SetError("Texture is not currently available"); - } - - if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) { - return false; - } -#ifdef SDL_HAVE_YUV - if (texturedata->yuv) { - // Skip to the correct offset into the next texture - pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch); - - if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) { - return false; - } - - // Skip to the correct offset into the next texture - pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2)); - if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) { - return false; - } - } -#endif - return true; -} - #ifdef SDL_HAVE_YUV static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, @@ -980,6 +1055,12 @@ static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_S if (!BindTextureRep(data->device, &texturedata->texture, 0)) { return false; } + if (texture->palette) { + D3D_PaletteData *palette = (D3D_PaletteData *)texture->palette->internal; + if (!BindTextureRep(data->device, &palette->texture, 1)) { + return false; + } + } #ifdef SDL_HAVE_YUV if (texturedata->yuv) { if (!BindTextureRep(data->device, &texturedata->utexture, 1)) { @@ -999,10 +1080,8 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) const SDL_BlendMode blend = cmd->data.draw.blend; if (texture != data->drawstate.texture) { -#ifdef SDL_HAVE_YUV D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *)data->drawstate.texture->internal : NULL; D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *)texture->internal : NULL; -#endif D3D9_Shader shader = SHADER_NONE; const float *shader_params = NULL; @@ -1010,6 +1089,10 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) if (!texture) { IDirect3DDevice9_SetTexture(data->device, 0, NULL); } + if ((!newtexturedata || !texture->palette) && + (oldtexturedata && (data->drawstate.texture->palette))) { + IDirect3DDevice9_SetTexture(data->device, 1, NULL); + } #ifdef SDL_HAVE_YUV if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) { IDirect3DDevice9_SetTexture(data->device, 1, NULL); @@ -1046,6 +1129,10 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; if (texturedata) { UpdateDirtyTexture(data->device, &texturedata->texture); + if (texture->palette) { + D3D_PaletteData *palettedata = (D3D_PaletteData *)texture->palette->internal; + UpdateDirtyTexture(data->device, &palettedata->texture); + } #ifdef SDL_HAVE_YUV if (texturedata->yuv) { UpdateDirtyTexture(data->device, &texturedata->utexture); @@ -1445,8 +1532,11 @@ static void D3D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) renderdata->drawstate.shader_params = NULL; IDirect3DDevice9_SetPixelShader(renderdata->device, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL); + if (texture->palette) { + IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL); + } #ifdef SDL_HAVE_YUV - if (data->yuv) { + if (data && data->yuv) { IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL); } @@ -1474,6 +1564,9 @@ static void D3D_DestroyRenderer(SDL_Renderer *renderer) if (data) { int i; + // Make sure the palettes have been freed + SDL_assert(!data->palettes); + // Release the render target if (data->defaultRenderTarget) { IDirect3DSurface9_Release(data->defaultRenderTarget); @@ -1483,14 +1576,12 @@ static void D3D_DestroyRenderer(SDL_Renderer *renderer) IDirect3DSurface9_Release(data->currentRenderTarget); data->currentRenderTarget = NULL; } -#ifdef SDL_HAVE_YUV for (i = 0; i < SDL_arraysize(data->shaders); ++i) { if (data->shaders[i]) { IDirect3DPixelShader9_Release(data->shaders[i]); data->shaders[i] = NULL; } } -#endif // Release all vertex buffers for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { if (data->vertexBuffers[i]) { @@ -1516,6 +1607,7 @@ static bool D3D_Reset(SDL_Renderer *renderer) const Float4X4 d3dmatrix = MatrixIdentity(); HRESULT result; SDL_Texture *texture; + D3D_PaletteData *palette; int i; // Cancel any scene that we've started @@ -1543,6 +1635,11 @@ static bool D3D_Reset(SDL_Renderer *renderer) } } + // Release all palettes + for (palette = data->palettes; palette; palette = palette->next) { + D3D_RecreateTextureRep(data->device, &palette->texture); + } + // Release all vertex buffers for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { if (data->vertexBuffers[i]) { @@ -1667,6 +1764,9 @@ static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P renderer->WindowEvent = D3D_WindowEvent; renderer->SupportsBlendMode = D3D_SupportsBlendMode; + renderer->CreatePalette = D3D_CreatePalette; + renderer->UpdatePalette = D3D_UpdatePalette; + renderer->DestroyPalette = D3D_DestroyPalette; renderer->CreateTexture = D3D_CreateTexture; renderer->UpdateTexture = D3D_UpdateTexture; #ifdef SDL_HAVE_YUV @@ -1771,19 +1871,19 @@ static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P // Set up parameters for rendering D3D_InitRenderState(data); + for (int i = SHADER_NONE + 1; i < SDL_arraysize(data->shaders); ++i) { + result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]); + if (FAILED(result)) { + D3D_SetError("CreatePixelShader()", result); + } + } + if (caps.MaxSimultaneousTextures >= 2 && data->shaders[SHADER_PALETTE]) { + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); + } #ifdef SDL_HAVE_YUV - if (caps.MaxSimultaneousTextures >= 3) { - int i; - for (i = SHADER_NONE + 1; i < SDL_arraysize(data->shaders); ++i) { - result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]); - if (FAILED(result)) { - D3D_SetError("CreatePixelShader()", result); - } - } - if (data->shaders[SHADER_YUV]) { - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); - SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); - } + if (caps.MaxSimultaneousTextures >= 3 && data->shaders[SHADER_YUV]) { + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); } #endif diff --git a/src/render/direct3d/SDL_shaders_d3d.c b/src/render/direct3d/SDL_shaders_d3d.c index 9b1b4b5124..ffbf4df915 100644 --- a/src/render/direct3d/SDL_shaders_d3d.c +++ b/src/render/direct3d/SDL_shaders_d3d.c @@ -30,12 +30,17 @@ // The shaders here were compiled with compile_shaders.bat +#define g_ps20_main D3D9_PixelShader_Palette +#include "D3D9_PixelShader_Palette.h" +#undef g_ps20_main + #define g_ps20_main D3D9_PixelShader_YUV #include "D3D9_PixelShader_YUV.h" #undef g_ps20_main static const BYTE *D3D9_shaders[] = { NULL, + D3D9_PixelShader_Palette, D3D9_PixelShader_YUV }; SDL_COMPILE_TIME_ASSERT(D3D9_shaders, SDL_arraysize(D3D9_shaders) == NUM_SHADERS); diff --git a/src/render/direct3d/SDL_shaders_d3d.h b/src/render/direct3d/SDL_shaders_d3d.h index 90ef7a9b10..491b24a5d1 100644 --- a/src/render/direct3d/SDL_shaders_d3d.h +++ b/src/render/direct3d/SDL_shaders_d3d.h @@ -25,6 +25,7 @@ typedef enum { SHADER_NONE, + SHADER_PALETTE, SHADER_YUV, NUM_SHADERS } D3D9_Shader; diff --git a/src/render/direct3d/compile_shaders.bat b/src/render/direct3d/compile_shaders.bat index 81d513e2cc..c8b8e183a3 100644 --- a/src/render/direct3d/compile_shaders.bat +++ b/src/render/direct3d/compile_shaders.bat @@ -1 +1,2 @@ +fxc /T ps_2_0 /Fh D3D9_PixelShader_Palette.h D3D9_PixelShader_Palette.hlsl fxc /T ps_2_0 /Fh D3D9_PixelShader_YUV.h D3D9_PixelShader_YUV.hlsl diff --git a/src/render/direct3d11/D3D11_PixelShader_Advanced.h b/src/render/direct3d11/D3D11_PixelShader_Advanced.h index 59c90ae6e5..c6e3bc7bb6 100644 --- a/src/render/direct3d11/D3D11_PixelShader_Advanced.h +++ b/src/render/direct3d11/D3D11_PixelShader_Advanced.h @@ -3,7 +3,7 @@ // Generated by Microsoft (R) HLSL Shader Compiler 10.1 // // -// Buffer Definitions: +// Buffer Definitions: // // cbuffer Constants // { @@ -29,11 +29,12 @@ // // Name Type Format Dim HLSL Bind Count // ------------------------------ ---------- ------- ----------- -------------- ------ -// sampler0 sampler NA NA s0 1 -// texture0 texture float4 2d t0 1 -// texture1 texture float4 2d t1 1 -// texture2 texture float4 2d t2 1 -// Constants cbuffer NA NA cb0 1 +// sampler0 sampler NA NA s0 1 +// sampler1 sampler NA NA s1 1 +// texture0 texture float4 2d t0 1 +// texture1 texture float4 2d t1 1 +// texture2 texture float4 2d t2 1 +// Constants cbuffer NA NA cb0 1 // // // @@ -41,8 +42,8 @@ // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ -// SV_POSITION 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // COLOR 0 xyzw 2 NONE float xyzw // // @@ -56,6 +57,7 @@ ps_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer CB0[7], immediateIndexed dcl_sampler s0, mode_default +dcl_sampler s1, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_resource_texture2d (float,float,float,float) t1 dcl_resource_texture2d (float,float,float,float) t2 @@ -66,11 +68,11 @@ dcl_temps 7 eq r0.xyzw, cb0[0].yzzz, l(0.000000, 3.000000, 2.000000, 1.000000) if_nz r0.x mov r1.xyzw, l(1.000000,1.000000,1.000000,1.000000) -else +else eq r0.x, cb0[0].y, l(1.000000) if_nz r0.x sample_indexable(texture2d)(float,float,float,float) r1.xyzw, v1.xyxx, t0.xyzw, s0 - else + else eq r0.x, cb0[0].y, l(2.000000) if_nz r0.x deriv_rtx_coarse r2.xy, v1.xyxx @@ -94,43 +96,81 @@ else add r3.xy, r3.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) mul r3.xy, r3.xyxx, cb0[1].xyxx sample_d_indexable(texture2d)(float,float,float,float) r1.xyzw, r3.xyxx, t0.xyzw, s0, r2.xyxx, r2.zwzz - else + else eq r0.x, cb0[0].y, l(3.000000) if_nz r0.x - sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 - sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zxyw, s0 - add r2.xyz, r2.xyzx, cb0[3].xyzx - dp3 r1.x, r2.xyzx, cb0[4].xyzx - dp3 r1.y, r2.xyzx, cb0[5].xyzx - dp3 r1.z, r2.xyzx, cb0[6].xyzx - else + sample_indexable(texture2d)(float,float,float,float) r0.x, v1.xyxx, t0.xyzw, s0 + mad r0.x, r0.x, l(255.000000), l(0.500000) + mul r2.x, r0.x, l(0.003906) + mov r2.y, l(0.500000) + sample_indexable(texture2d)(float,float,float,float) r1.xyzw, r2.xyxx, t1.xyzw, s1 + else eq r0.x, cb0[0].y, l(4.000000) if_nz r0.x - sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 - sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zyxw, s0 - add r2.xyz, r2.xyzx, cb0[3].xyzx - dp3 r1.x, r2.xyzx, cb0[4].xyzx - dp3 r1.y, r2.xyzx, cb0[5].xyzx - dp3 r1.z, r2.xyzx, cb0[6].xyzx - else + deriv_rtx_coarse r2.xy, v1.xyxx + deriv_rty_coarse r2.zw, v1.xxxy + add r3.xy, |r2.zwzz|, |r2.xyxx| + mul r3.xy, r3.xyxx, cb0[1].zwzz + max r3.xy, r3.xyxx, l(0.000010, 0.000010, 0.000000, 0.000000) + min r3.xy, r3.xyxx, l(1.000000, 1.000000, 0.000000, 0.000000) + mul r3.zw, r3.xxxy, l(0.000000, 0.000000, 0.500000, 0.500000) + mad r3.zw, v1.xxxy, cb0[1].zzzw, -r3.zzzw + add r3.xy, -r3.xyxx, l(1.000000, 1.000000, 0.000000, 0.000000) + frc r4.xy, r3.zwzz + add r4.zw, -r3.xxxy, l(0.000000, 0.000000, 1.000000, 1.000000) + add r3.xy, -r3.xyxx, r4.xyxx + div r4.xy, l(1.000000, 1.000000, 1.000000, 1.000000), r4.zwzz + mul_sat r3.xy, r3.xyxx, r4.xyxx + mad r4.xy, r3.xyxx, l(-2.000000, -2.000000, 0.000000, 0.000000), l(3.000000, 3.000000, 0.000000, 0.000000) + mul r3.xy, r3.xyxx, r3.xyxx + round_ni r3.zw, r3.zzzw + mad r3.xy, r4.xyxx, r3.xyxx, r3.zwzz + add r3.xy, r3.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) + mul r3.xy, r3.xyxx, cb0[1].xyxx + sample_d_indexable(texture2d)(float,float,float,float) r0.x, r3.xyxx, t0.xyzw, s0, r2.xyxx, r2.zwzz + mad r0.x, r0.x, l(255.000000), l(0.500000) + mul r2.x, r0.x, l(0.003906) + mov r2.y, l(0.500000) + sample_indexable(texture2d)(float,float,float,float) r1.xyzw, r2.xyxx, t1.xyzw, s1 + else eq r0.x, cb0[0].y, l(5.000000) if_nz r0.x sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 - sample_indexable(texture2d)(float,float,float,float) r2.y, v1.xyxx, t1.yxzw, s0 - sample_indexable(texture2d)(float,float,float,float) r2.z, v1.xyxx, t2.yzxw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zxyw, s0 add r2.xyz, r2.xyzx, cb0[3].xyzx dp3 r1.x, r2.xyzx, cb0[4].xyzx dp3 r1.y, r2.xyzx, cb0[5].xyzx dp3 r1.z, r2.xyzx, cb0[6].xyzx - else - mov r1.xyz, l(1.000000,0,0,0) - endif - endif - endif - mov r1.w, l(1.000000) - endif - endif -endif + else + eq r0.x, cb0[0].y, l(6.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zyxw, s0 + add r2.xyz, r2.xyzx, cb0[3].xyzx + dp3 r1.x, r2.xyzx, cb0[4].xyzx + dp3 r1.y, r2.xyzx, cb0[5].xyzx + dp3 r1.z, r2.xyzx, cb0[6].xyzx + else + eq r0.x, cb0[0].y, l(7.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.y, v1.xyxx, t1.yxzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.z, v1.xyxx, t2.yzxw, s0 + add r2.xyz, r2.xyzx, cb0[3].xyzx + dp3 r1.x, r2.xyzx, cb0[4].xyzx + dp3 r1.y, r2.xyzx, cb0[5].xyzx + dp3 r1.z, r2.xyzx, cb0[6].xyzx + else + mov r1.xyz, l(1.000000,0,0,0) + endif + endif + endif + mov r1.w, l(1.000000) + endif + endif + endif + endif +endif log r2.xyz, |r1.xyzx| mul r2.xyz, r2.xyzx, l(0.012683, 0.012683, 0.012683, 0.000000) exp r2.xyz, r2.xyzx @@ -176,9 +216,9 @@ if_nz r0.w mul r5.xyz, r5.xyzx, l(2.400000, 2.400000, 2.400000, 0.000000) exp r5.xyz, r5.xyzx movc r2.xyz, r3.xyzx, r4.xyzx, r5.xyzx - endif + endif mul r1.xyz, r2.xyzx, cb0[0].wwww -else +else if_nz r0.z mul r1.xyz, r2.xyzx, cb0[0].wwww ne r0.x, l(0.000000, 0.000000, 0.000000, 0.000000), cb0[0].x @@ -190,8 +230,8 @@ else exp r4.xyz, r4.xyzx mad r4.xyz, r4.xyzx, l(1.055000, 1.055000, 1.055000, 0.000000), l(-0.055000, -0.055000, -0.055000, 0.000000) movc_sat r1.xyz, r0.xzwx, r3.xyzx, r4.xyzx - endif - else + endif + else if_nz r0.y dp3 r0.x, l(1.660496, -0.587656, -0.072840, 0.000000), r2.xyzx dp3 r0.y, l(-0.124547, 1.132895, -0.008348, 0.000000), r2.xyzx @@ -206,1024 +246,1226 @@ else exp r4.xyz, r4.xyzx mad r4.xyz, r4.xyzx, l(1.055000, 1.055000, 1.055000, 0.000000), l(-0.055000, -0.055000, -0.055000, 0.000000) movc_sat r1.xyz, r0.xyzx, r3.xyzx, r4.xyzx - endif - else + endif + else mul r1.xyz, r2.xyzx, cb0[0].wwww - endif - endif -endif + endif + endif +endif mul o0.xyzw, r1.xyzw, v2.xyzw -ret -// Approximately 151 instruction slots used +ret +// Approximately 189 instruction slots used #endif const BYTE g_main[] = { - 68, 88, 66, 67, 211, 185, - 112, 94, 11, 90, 193, 206, - 105, 12, 109, 71, 22, 113, - 149, 88, 1, 0, 0, 0, - 152, 23, 0, 0, 5, 0, - 0, 0, 52, 0, 0, 0, - 128, 4, 0, 0, 244, 4, - 0, 0, 40, 5, 0, 0, - 252, 22, 0, 0, 82, 68, - 69, 70, 68, 4, 0, 0, - 1, 0, 0, 0, 12, 1, - 0, 0, 5, 0, 0, 0, - 60, 0, 0, 0, 0, 5, - 255, 255, 0, 1, 0, 0, - 28, 4, 0, 0, 82, 68, - 49, 49, 60, 0, 0, 0, - 24, 0, 0, 0, 32, 0, - 0, 0, 40, 0, 0, 0, - 36, 0, 0, 0, 12, 0, - 0, 0, 0, 0, 0, 0, - 220, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 229, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 13, 0, 0, 0, 238, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 1, 0, 0, 0, 1, 0, - 0, 0, 13, 0, 0, 0, - 247, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 2, 0, 0, 0, - 1, 0, 0, 0, 13, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 115, 97, - 109, 112, 108, 101, 114, 48, - 0, 116, 101, 120, 116, 117, - 114, 101, 48, 0, 116, 101, - 120, 116, 117, 114, 101, 49, - 0, 116, 101, 120, 116, 117, - 114, 101, 50, 0, 67, 111, - 110, 115, 116, 97, 110, 116, - 115, 0, 171, 171, 0, 1, - 0, 0, 13, 0, 0, 0, - 36, 1, 0, 0, 112, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 44, 3, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 64, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 100, 3, 0, 0, - 4, 0, 0, 0, 4, 0, - 0, 0, 2, 0, 0, 0, - 64, 3, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 113, 3, 0, 0, 8, 0, - 0, 0, 4, 0, 0, 0, - 2, 0, 0, 0, 64, 3, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 124, 3, - 0, 0, 12, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 64, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 136, 3, 0, 0, - 16, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 156, 3, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 192, 3, 0, 0, 32, 0, - 0, 0, 4, 0, 0, 0, - 2, 0, 0, 0, 64, 3, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 207, 3, - 0, 0, 36, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 64, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 223, 3, 0, 0, - 40, 0, 0, 0, 4, 0, - 0, 0, 2, 0, 0, 0, - 64, 3, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 239, 3, 0, 0, 44, 0, - 0, 0, 4, 0, 0, 0, - 2, 0, 0, 0, 64, 3, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 255, 3, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 156, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 7, 4, 0, 0, - 64, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 156, 3, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 14, 4, 0, 0, 80, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 156, 3, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 21, 4, - 0, 0, 96, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 156, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 115, 99, 82, 71, - 66, 95, 111, 117, 116, 112, - 117, 116, 0, 102, 108, 111, - 97, 116, 0, 171, 0, 0, - 3, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 57, 3, 0, 0, 116, 101, - 120, 116, 117, 114, 101, 95, - 116, 121, 112, 101, 0, 105, - 110, 112, 117, 116, 95, 116, - 121, 112, 101, 0, 99, 111, - 108, 111, 114, 95, 115, 99, - 97, 108, 101, 0, 116, 101, - 120, 101, 108, 95, 115, 105, - 122, 101, 0, 102, 108, 111, - 97, 116, 52, 0, 171, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 147, 3, 0, 0, - 116, 111, 110, 101, 109, 97, - 112, 95, 109, 101, 116, 104, - 111, 100, 0, 116, 111, 110, - 101, 109, 97, 112, 95, 102, - 97, 99, 116, 111, 114, 49, - 0, 116, 111, 110, 101, 109, - 97, 112, 95, 102, 97, 99, - 116, 111, 114, 50, 0, 115, - 100, 114, 95, 119, 104, 105, - 116, 101, 95, 112, 111, 105, - 110, 116, 0, 89, 111, 102, - 102, 115, 101, 116, 0, 82, - 99, 111, 101, 102, 102, 0, - 71, 99, 111, 101, 102, 102, - 0, 66, 99, 111, 101, 102, - 102, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 49, 48, 46, 49, 0, - 73, 83, 71, 78, 108, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 3, 0, 0, 101, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 0, 0, 0, - 15, 15, 0, 0, 83, 86, - 95, 80, 79, 83, 73, 84, - 73, 79, 78, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 67, 79, 76, 79, 82, - 0, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 65, 82, - 71, 69, 84, 0, 171, 171, - 83, 72, 69, 88, 204, 17, - 0, 0, 80, 0, 0, 0, - 115, 4, 0, 0, 106, 8, - 0, 1, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 88, 24, 0, 4, - 0, 112, 16, 0, 2, 0, - 0, 0, 85, 85, 0, 0, - 98, 16, 0, 3, 50, 16, - 16, 0, 1, 0, 0, 0, - 98, 16, 0, 3, 242, 16, - 16, 0, 2, 0, 0, 0, - 101, 0, 0, 3, 242, 32, - 16, 0, 0, 0, 0, 0, - 104, 0, 0, 2, 7, 0, - 0, 0, 24, 0, 0, 11, - 242, 0, 16, 0, 0, 0, - 0, 0, 150, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 64, 64, 0, 0, 0, 64, - 0, 0, 128, 63, 31, 0, - 4, 3, 10, 0, 16, 0, - 0, 0, 0, 0, 54, 0, - 0, 8, 242, 0, 16, 0, - 1, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 18, 0, 0, 1, 24, 0, - 0, 8, 18, 0, 16, 0, - 0, 0, 0, 0, 26, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 31, 0, 4, 3, 10, 0, - 16, 0, 0, 0, 0, 0, - 69, 0, 0, 139, 194, 0, - 0, 128, 67, 85, 21, 0, - 242, 0, 16, 0, 1, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 18, 0, 0, 1, - 24, 0, 0, 8, 18, 0, - 16, 0, 0, 0, 0, 0, - 26, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 64, 31, 0, 4, 3, - 10, 0, 16, 0, 0, 0, - 0, 0, 122, 0, 0, 5, - 50, 0, 16, 0, 2, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 124, 0, - 0, 5, 194, 0, 16, 0, - 2, 0, 0, 0, 6, 20, - 16, 0, 1, 0, 0, 0, - 0, 0, 0, 9, 50, 0, - 16, 0, 3, 0, 0, 0, - 230, 10, 16, 128, 129, 0, - 0, 0, 2, 0, 0, 0, - 70, 0, 16, 128, 129, 0, - 0, 0, 2, 0, 0, 0, - 56, 0, 0, 8, 50, 0, - 16, 0, 3, 0, 0, 0, - 70, 0, 16, 0, 3, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 52, 0, 0, 10, - 50, 0, 16, 0, 3, 0, - 0, 0, 70, 0, 16, 0, - 3, 0, 0, 0, 2, 64, - 0, 0, 172, 197, 39, 55, - 172, 197, 39, 55, 0, 0, - 0, 0, 0, 0, 0, 0, - 51, 0, 0, 10, 50, 0, - 16, 0, 3, 0, 0, 0, - 70, 0, 16, 0, 3, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 56, 0, - 0, 10, 194, 0, 16, 0, - 3, 0, 0, 0, 6, 4, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 63, 0, 0, - 0, 63, 50, 0, 0, 11, - 194, 0, 16, 0, 3, 0, - 0, 0, 6, 20, 16, 0, - 1, 0, 0, 0, 166, 142, - 32, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 166, 14, - 16, 128, 65, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 11, 50, 0, 16, 0, - 3, 0, 0, 0, 70, 0, - 16, 128, 65, 0, 0, 0, - 3, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 26, 0, 0, 5, 50, 0, - 16, 0, 4, 0, 0, 0, - 230, 10, 16, 0, 3, 0, - 0, 0, 0, 0, 0, 11, - 194, 0, 16, 0, 4, 0, - 0, 0, 6, 4, 16, 128, - 65, 0, 0, 0, 3, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 8, 50, 0, 16, 0, - 3, 0, 0, 0, 70, 0, - 16, 128, 65, 0, 0, 0, - 3, 0, 0, 0, 70, 0, - 16, 0, 4, 0, 0, 0, - 14, 0, 0, 10, 50, 0, - 16, 0, 4, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 128, 63, 230, 10, 16, 0, - 4, 0, 0, 0, 56, 32, - 0, 7, 50, 0, 16, 0, - 3, 0, 0, 0, 70, 0, - 16, 0, 3, 0, 0, 0, - 70, 0, 16, 0, 4, 0, - 0, 0, 50, 0, 0, 15, - 50, 0, 16, 0, 4, 0, - 0, 0, 70, 0, 16, 0, - 3, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 192, - 0, 0, 0, 192, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 64, 64, 0, 0, 64, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 56, 0, 0, 7, - 50, 0, 16, 0, 3, 0, - 0, 0, 70, 0, 16, 0, - 3, 0, 0, 0, 70, 0, - 16, 0, 3, 0, 0, 0, - 65, 0, 0, 5, 194, 0, - 16, 0, 3, 0, 0, 0, - 166, 14, 16, 0, 3, 0, - 0, 0, 50, 0, 0, 9, - 50, 0, 16, 0, 3, 0, - 0, 0, 70, 0, 16, 0, - 4, 0, 0, 0, 70, 0, - 16, 0, 3, 0, 0, 0, - 230, 10, 16, 0, 3, 0, - 0, 0, 0, 0, 0, 10, - 50, 0, 16, 0, 3, 0, - 0, 0, 70, 0, 16, 0, - 3, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 56, 0, 0, 8, 50, 0, - 16, 0, 3, 0, 0, 0, - 70, 0, 16, 0, 3, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 73, 0, 0, 143, - 194, 0, 0, 128, 67, 85, - 21, 0, 242, 0, 16, 0, - 1, 0, 0, 0, 70, 0, - 16, 0, 3, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 2, 0, 0, 0, - 230, 10, 16, 0, 2, 0, - 0, 0, 18, 0, 0, 1, - 24, 0, 0, 8, 18, 0, - 16, 0, 0, 0, 0, 0, - 26, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 64, 64, 31, 0, 4, 3, - 10, 0, 16, 0, 0, 0, - 0, 0, 69, 0, 0, 139, - 194, 0, 0, 128, 67, 85, - 21, 0, 18, 0, 16, 0, - 2, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 139, 194, 0, 0, 128, - 67, 85, 21, 0, 98, 0, - 16, 0, 2, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 38, 125, 16, 0, - 1, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 16, 0, 0, 8, - 18, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 16, 0, - 0, 8, 34, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 70, 130, 32, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 16, 0, 0, 8, 66, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 6, 0, - 0, 0, 18, 0, 0, 1, - 24, 0, 0, 8, 18, 0, - 16, 0, 0, 0, 0, 0, - 26, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 128, 64, 31, 0, 4, 3, - 10, 0, 16, 0, 0, 0, - 0, 0, 69, 0, 0, 139, - 194, 0, 0, 128, 67, 85, - 21, 0, 18, 0, 16, 0, - 2, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 139, 194, 0, 0, 128, - 67, 85, 21, 0, 98, 0, - 16, 0, 2, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 102, 124, 16, 0, - 1, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 16, 0, 0, 8, - 18, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 16, 0, - 0, 8, 34, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 70, 130, 32, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 16, 0, 0, 8, 66, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 6, 0, - 0, 0, 18, 0, 0, 1, - 24, 0, 0, 8, 18, 0, - 16, 0, 0, 0, 0, 0, - 26, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 160, 64, 31, 0, 4, 3, - 10, 0, 16, 0, 0, 0, - 0, 0, 69, 0, 0, 139, - 194, 0, 0, 128, 67, 85, - 21, 0, 18, 0, 16, 0, - 2, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 139, 194, 0, 0, 128, - 67, 85, 21, 0, 34, 0, - 16, 0, 2, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 22, 126, 16, 0, - 1, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 69, 0, 0, 139, 194, 0, - 0, 128, 67, 85, 21, 0, - 66, 0, 16, 0, 2, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 150, 124, - 16, 0, 2, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 8, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 16, 0, - 0, 8, 18, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 70, 130, 32, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 16, 0, 0, 8, 34, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 16, 0, 0, 8, - 66, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 18, 0, - 0, 1, 54, 0, 0, 8, - 114, 0, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 21, 0, - 0, 1, 21, 0, 0, 1, - 21, 0, 0, 1, 54, 0, - 0, 5, 130, 0, 16, 0, - 1, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 21, 0, 0, 1, 21, 0, - 0, 1, 21, 0, 0, 1, - 47, 0, 0, 6, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 128, 129, 0, - 0, 0, 1, 0, 0, 0, - 56, 0, 0, 10, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 2, 64, 0, 0, - 172, 205, 79, 60, 172, 205, - 79, 60, 172, 205, 79, 60, - 0, 0, 0, 0, 25, 0, - 0, 5, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 0, 0, 0, 10, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 86, 191, 0, 0, - 86, 191, 0, 0, 86, 191, - 0, 0, 0, 0, 52, 0, - 0, 10, 114, 0, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 50, 0, 0, 16, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 2, 0, - 0, 0, 2, 64, 0, 0, - 0, 128, 149, 65, 0, 128, - 149, 65, 0, 128, 149, 65, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 208, 150, 65, - 0, 208, 150, 65, 0, 208, - 150, 65, 0, 0, 0, 0, - 14, 0, 0, 7, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 47, 0, - 0, 6, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, - 16, 128, 129, 0, 0, 0, - 2, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 2, 64, 0, 0, 107, 224, - 200, 64, 107, 224, 200, 64, - 107, 224, 200, 64, 0, 0, - 0, 0, 25, 0, 0, 5, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 2, 64, 0, 0, 0, 64, - 28, 70, 0, 64, 28, 70, - 0, 64, 28, 70, 0, 0, - 0, 0, 14, 0, 0, 8, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 246, 143, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 2, 0, 0, 0, 86, 5, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 57, 0, - 0, 8, 18, 0, 16, 0, - 0, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 0, 0, - 56, 0, 0, 8, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 86, 133, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 24, 0, 0, 11, - 50, 0, 16, 0, 4, 0, - 0, 0, 6, 128, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 0, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 10, 18, 0, 16, 0, - 5, 0, 0, 0, 2, 64, - 0, 0, 140, 157, 32, 63, - 200, 151, 168, 62, 249, 104, - 49, 61, 0, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 16, 0, 0, 10, - 34, 0, 16, 0, 5, 0, - 0, 0, 2, 64, 0, 0, - 186, 130, 141, 61, 10, 103, - 107, 63, 175, 39, 58, 60, - 0, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 16, 0, 0, 10, 66, 0, - 16, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 107, 70, - 134, 60, 41, 64, 180, 61, - 183, 69, 101, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 5, 0, 0, 0, 166, 10, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 52, 0, - 0, 7, 130, 0, 16, 0, - 2, 0, 0, 0, 42, 0, - 16, 0, 5, 0, 0, 0, - 26, 0, 16, 0, 5, 0, - 0, 0, 52, 0, 0, 7, - 130, 0, 16, 0, 2, 0, - 0, 0, 58, 0, 16, 0, - 2, 0, 0, 0, 10, 0, - 16, 0, 5, 0, 0, 0, - 49, 0, 0, 7, 130, 0, - 16, 0, 3, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 0, 58, 0, 16, 0, - 2, 0, 0, 0, 50, 0, - 0, 13, 194, 0, 16, 0, - 4, 0, 0, 0, 86, 137, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 246, 15, - 16, 0, 2, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 14, 0, 0, 7, - 130, 0, 16, 0, 2, 0, - 0, 0, 42, 0, 16, 0, - 4, 0, 0, 0, 58, 0, - 16, 0, 4, 0, 0, 0, - 56, 0, 0, 7, 114, 0, - 16, 0, 6, 0, 0, 0, - 246, 15, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 5, 0, 0, 0, 246, 15, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 6, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 16, 0, - 0, 10, 18, 0, 16, 0, - 6, 0, 0, 0, 2, 64, - 0, 0, 34, 139, 212, 63, - 160, 112, 22, 191, 35, 45, - 149, 189, 0, 0, 0, 0, - 70, 2, 16, 0, 5, 0, - 0, 0, 16, 0, 0, 10, - 34, 0, 16, 0, 6, 0, - 0, 0, 2, 64, 0, 0, - 127, 18, 255, 189, 180, 2, - 145, 63, 13, 198, 8, 188, - 0, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 16, 0, 0, 10, 66, 0, - 16, 0, 6, 0, 0, 0, - 2, 64, 0, 0, 179, 183, - 148, 188, 205, 5, 206, 189, - 60, 51, 143, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 5, 0, 0, 0, 166, 10, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 6, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 55, 0, - 0, 9, 226, 0, 16, 0, - 4, 0, 0, 0, 86, 5, - 16, 0, 4, 0, 0, 0, - 6, 9, 16, 0, 5, 0, - 0, 0, 6, 9, 16, 0, - 2, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 3, 0, 0, 0, 6, 0, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 150, 7, 16, 0, - 4, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 2, 0, 0, 0, 6, 0, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 31, 0, - 4, 3, 58, 0, 16, 0, - 0, 0, 0, 0, 57, 0, - 0, 11, 18, 0, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 4, 3, 10, 0, - 16, 0, 0, 0, 0, 0, - 29, 0, 0, 10, 114, 0, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 230, 174, - 37, 61, 230, 174, 37, 61, - 230, 174, 37, 61, 0, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 2, 64, 0, 0, 145, 131, - 158, 61, 145, 131, 158, 61, - 145, 131, 158, 61, 0, 0, - 0, 0, 0, 0, 0, 10, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 2, 64, - 0, 0, 174, 71, 97, 61, - 174, 71, 97, 61, 174, 71, - 97, 61, 0, 0, 0, 0, - 56, 0, 0, 11, 114, 0, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 128, 129, 0, - 0, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 111, 167, - 114, 63, 111, 167, 114, 63, - 111, 167, 114, 63, 0, 0, - 0, 0, 47, 0, 0, 5, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 154, 153, - 25, 64, 154, 153, 25, 64, - 154, 153, 25, 64, 0, 0, - 0, 0, 25, 0, 0, 5, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 21, 0, - 0, 1, 56, 0, 0, 8, - 114, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 246, 143, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 18, 0, - 0, 1, 31, 0, 4, 3, - 42, 0, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 8, - 114, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 246, 143, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 57, 0, - 0, 11, 18, 0, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 3, 10, 0, - 16, 0, 0, 0, 0, 0, - 29, 0, 0, 10, 210, 0, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 28, 46, - 77, 59, 0, 0, 0, 0, - 28, 46, 77, 59, 28, 46, - 77, 59, 6, 9, 16, 0, - 1, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 2, 64, 0, 0, 82, 184, - 78, 65, 82, 184, 78, 65, - 82, 184, 78, 65, 0, 0, - 0, 0, 47, 0, 0, 6, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 128, - 129, 0, 0, 0, 1, 0, - 0, 0, 56, 0, 0, 10, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 2, 64, - 0, 0, 85, 85, 213, 62, - 85, 85, 213, 62, 85, 85, - 213, 62, 0, 0, 0, 0, - 25, 0, 0, 5, 114, 0, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 4, 0, - 0, 0, 50, 0, 0, 15, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 2, 64, - 0, 0, 61, 10, 135, 63, - 61, 10, 135, 63, 61, 10, - 135, 63, 0, 0, 0, 0, - 2, 64, 0, 0, 174, 71, - 97, 189, 174, 71, 97, 189, - 174, 71, 97, 189, 0, 0, - 0, 0, 55, 32, 0, 9, - 114, 0, 16, 0, 1, 0, - 0, 0, 134, 3, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 4, 0, - 0, 0, 21, 0, 0, 1, - 18, 0, 0, 1, 31, 0, - 4, 3, 26, 0, 16, 0, - 0, 0, 0, 0, 16, 0, - 0, 10, 18, 0, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 34, 139, 212, 63, - 160, 112, 22, 191, 35, 45, - 149, 189, 0, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 16, 0, 0, 10, - 34, 0, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 127, 18, 255, 189, 180, 2, - 145, 63, 13, 198, 8, 188, - 0, 0, 0, 0, 70, 2, - 16, 0, 2, 0, 0, 0, - 16, 0, 0, 10, 66, 0, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 179, 183, - 148, 188, 205, 5, 206, 189, - 60, 51, 143, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 2, 0, 0, 0, 56, 0, - 0, 8, 114, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 246, 143, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 57, 0, 0, 11, 18, 0, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 10, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 3, - 10, 0, 16, 0, 0, 0, - 0, 0, 29, 0, 0, 10, - 114, 0, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 28, 46, 77, 59, 28, 46, - 77, 59, 28, 46, 77, 59, - 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 56, 0, 0, 10, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 82, 184, 78, 65, 82, 184, - 78, 65, 82, 184, 78, 65, - 0, 0, 0, 0, 47, 0, - 0, 6, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 128, 129, 0, 0, 0, - 1, 0, 0, 0, 56, 0, - 0, 10, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 2, 64, 0, 0, 85, 85, - 213, 62, 85, 85, 213, 62, - 85, 85, 213, 62, 0, 0, - 0, 0, 25, 0, 0, 5, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 50, 0, - 0, 15, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 2, 64, 0, 0, 61, 10, - 135, 63, 61, 10, 135, 63, - 61, 10, 135, 63, 0, 0, - 0, 0, 2, 64, 0, 0, - 174, 71, 97, 189, 174, 71, - 97, 189, 174, 71, 97, 189, - 0, 0, 0, 0, 55, 32, - 0, 9, 114, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 21, 0, - 0, 1, 18, 0, 0, 1, - 56, 0, 0, 8, 114, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 246, 143, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 21, 0, 0, 1, - 21, 0, 0, 1, 21, 0, - 0, 1, 56, 0, 0, 7, - 242, 32, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 1, 0, 0, 0, 70, 30, - 16, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 148, 0, 0, 0, - 151, 0, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 10, 0, - 0, 0, 12, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 10, 0, 0, 0, - 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, + 68, 88, 66, 67, 21, 212, + 190, 204, 0, 233, 124, 222, + 179, 192, 161, 234, 41, 79, + 56, 168, 1, 0, 0, 0, + 84, 28, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 168, 4, 0, 0, 28, 5, + 0, 0, 80, 5, 0, 0, + 184, 27, 0, 0, 82, 68, + 69, 70, 108, 4, 0, 0, + 1, 0, 0, 0, 52, 1, + 0, 0, 6, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 68, 4, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 252, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 5, 1, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 14, 1, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 23, 1, 0, 0, 2, 0, + 0, 0, 5, 0, 0, 0, + 4, 0, 0, 0, 255, 255, + 255, 255, 1, 0, 0, 0, + 1, 0, 0, 0, 13, 0, + 0, 0, 32, 1, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 4, 0, 0, 0, + 255, 255, 255, 255, 2, 0, + 0, 0, 1, 0, 0, 0, + 13, 0, 0, 0, 41, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 115, 97, 109, 112, 108, 101, + 114, 48, 0, 115, 97, 109, + 112, 108, 101, 114, 49, 0, + 116, 101, 120, 116, 117, 114, + 101, 48, 0, 116, 101, 120, + 116, 117, 114, 101, 49, 0, + 116, 101, 120, 116, 117, 114, + 101, 50, 0, 67, 111, 110, + 115, 116, 97, 110, 116, 115, + 0, 171, 41, 1, 0, 0, + 13, 0, 0, 0, 76, 1, + 0, 0, 112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 84, 3, 0, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 104, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 140, 3, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 104, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 153, 3, + 0, 0, 8, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 104, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 164, 3, 0, 0, + 12, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 104, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 176, 3, 0, 0, 16, 0, + 0, 0, 16, 0, 0, 0, + 2, 0, 0, 0, 196, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 232, 3, + 0, 0, 32, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 104, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 247, 3, 0, 0, + 36, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 104, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 7, 4, 0, 0, 40, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 104, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 23, 4, + 0, 0, 44, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 104, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 39, 4, 0, 0, + 48, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 196, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 47, 4, 0, 0, 64, 0, + 0, 0, 16, 0, 0, 0, + 2, 0, 0, 0, 196, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 54, 4, + 0, 0, 80, 0, 0, 0, + 16, 0, 0, 0, 2, 0, + 0, 0, 196, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 61, 4, 0, 0, + 96, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 196, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 115, 99, 82, 71, 66, 95, + 111, 117, 116, 112, 117, 116, + 0, 102, 108, 111, 97, 116, + 0, 171, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 97, 3, + 0, 0, 116, 101, 120, 116, + 117, 114, 101, 95, 116, 121, + 112, 101, 0, 105, 110, 112, + 117, 116, 95, 116, 121, 112, + 101, 0, 99, 111, 108, 111, + 114, 95, 115, 99, 97, 108, + 101, 0, 116, 101, 120, 101, + 108, 95, 115, 105, 122, 101, + 0, 102, 108, 111, 97, 116, + 52, 0, 171, 171, 1, 0, + 3, 0, 1, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 187, 3, 0, 0, 116, 111, + 110, 101, 109, 97, 112, 95, + 109, 101, 116, 104, 111, 100, + 0, 116, 111, 110, 101, 109, + 97, 112, 95, 102, 97, 99, + 116, 111, 114, 49, 0, 116, + 111, 110, 101, 109, 97, 112, + 95, 102, 97, 99, 116, 111, + 114, 50, 0, 115, 100, 114, + 95, 119, 104, 105, 116, 101, + 95, 112, 111, 105, 110, 116, + 0, 89, 111, 102, 102, 115, + 101, 116, 0, 82, 99, 111, + 101, 102, 102, 0, 71, 99, + 111, 101, 102, 102, 0, 66, + 99, 111, 101, 102, 102, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 108, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 101, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 2, 0, 0, 0, 15, 15, + 0, 0, 83, 86, 95, 80, + 79, 83, 73, 84, 73, 79, + 78, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 67, + 79, 76, 79, 82, 0, 171, + 79, 83, 71, 78, 44, 0, + 0, 0, 1, 0, 0, 0, + 8, 0, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 83, 86, + 95, 84, 65, 82, 71, 69, + 84, 0, 171, 171, 83, 72, + 69, 88, 96, 22, 0, 0, + 80, 0, 0, 0, 152, 5, + 0, 0, 106, 8, 0, 1, + 89, 0, 0, 4, 70, 142, + 32, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 90, 0, + 0, 3, 0, 96, 16, 0, + 0, 0, 0, 0, 90, 0, + 0, 3, 0, 96, 16, 0, + 1, 0, 0, 0, 88, 24, + 0, 4, 0, 112, 16, 0, + 0, 0, 0, 0, 85, 85, + 0, 0, 88, 24, 0, 4, + 0, 112, 16, 0, 1, 0, + 0, 0, 85, 85, 0, 0, + 88, 24, 0, 4, 0, 112, + 16, 0, 2, 0, 0, 0, + 85, 85, 0, 0, 98, 16, + 0, 3, 50, 16, 16, 0, + 1, 0, 0, 0, 98, 16, + 0, 3, 242, 16, 16, 0, + 2, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 104, 0, + 0, 2, 7, 0, 0, 0, + 24, 0, 0, 11, 242, 0, + 16, 0, 0, 0, 0, 0, + 150, 138, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 64, 64, + 0, 0, 0, 64, 0, 0, + 128, 63, 31, 0, 4, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 54, 0, 0, 8, + 242, 0, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 18, 0, + 0, 1, 24, 0, 0, 8, + 18, 0, 16, 0, 0, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 31, 0, + 4, 3, 10, 0, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 242, 0, + 16, 0, 1, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 64, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 122, 0, 0, 5, 50, 0, + 16, 0, 2, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 124, 0, 0, 5, + 194, 0, 16, 0, 2, 0, + 0, 0, 6, 20, 16, 0, + 1, 0, 0, 0, 0, 0, + 0, 9, 50, 0, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 70, 0, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 56, 0, + 0, 8, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 230, 138, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 52, 0, 0, 10, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 172, 197, 39, 55, 172, 197, + 39, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 51, 0, + 0, 10, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 10, + 194, 0, 16, 0, 3, 0, + 0, 0, 6, 4, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 63, + 50, 0, 0, 11, 194, 0, + 16, 0, 3, 0, 0, 0, + 6, 20, 16, 0, 1, 0, + 0, 0, 166, 142, 32, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 166, 14, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 11, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 26, 0, + 0, 5, 50, 0, 16, 0, + 4, 0, 0, 0, 230, 10, + 16, 0, 3, 0, 0, 0, + 0, 0, 0, 11, 194, 0, + 16, 0, 4, 0, 0, 0, + 6, 4, 16, 128, 65, 0, + 0, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 0, 8, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 4, 0, 0, 0, 14, 0, + 0, 10, 50, 0, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 230, 10, 16, 0, 4, 0, + 0, 0, 56, 32, 0, 7, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 15, 50, 0, + 16, 0, 4, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 192, 0, 0, + 0, 192, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 64, 64, + 0, 0, 64, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 65, 0, + 0, 5, 194, 0, 16, 0, + 3, 0, 0, 0, 166, 14, + 16, 0, 3, 0, 0, 0, + 50, 0, 0, 9, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 4, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 0, 3, 0, 0, 0, + 0, 0, 0, 10, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 63, 0, 0, + 0, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 56, 0, + 0, 8, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 70, 128, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 73, 0, 0, 143, 194, 0, + 0, 128, 67, 85, 21, 0, + 242, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 70, 0, 16, 0, + 2, 0, 0, 0, 230, 10, + 16, 0, 2, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 64, 64, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 18, 0, 16, 0, 0, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 50, 0, 0, 9, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 127, 67, + 1, 64, 0, 0, 0, 0, + 0, 63, 56, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 59, + 54, 0, 0, 5, 34, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 63, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 242, 0, 16, 0, + 1, 0, 0, 0, 70, 0, + 16, 0, 2, 0, 0, 0, + 70, 126, 16, 0, 1, 0, + 0, 0, 0, 96, 16, 0, + 1, 0, 0, 0, 18, 0, + 0, 1, 24, 0, 0, 8, + 18, 0, 16, 0, 0, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 64, 31, 0, + 4, 3, 10, 0, 16, 0, + 0, 0, 0, 0, 122, 0, + 0, 5, 50, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 124, 0, 0, 5, 194, 0, + 16, 0, 2, 0, 0, 0, + 6, 20, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 9, + 50, 0, 16, 0, 3, 0, + 0, 0, 230, 10, 16, 128, + 129, 0, 0, 0, 2, 0, + 0, 0, 70, 0, 16, 128, + 129, 0, 0, 0, 2, 0, + 0, 0, 56, 0, 0, 8, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 230, 138, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 52, 0, + 0, 10, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 172, 197, + 39, 55, 172, 197, 39, 55, + 0, 0, 0, 0, 0, 0, + 0, 0, 51, 0, 0, 10, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 0, 0, 0, 0, 0, 0, + 56, 0, 0, 10, 194, 0, + 16, 0, 3, 0, 0, 0, + 6, 4, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 63, + 0, 0, 0, 63, 50, 0, + 0, 11, 194, 0, 16, 0, + 3, 0, 0, 0, 6, 20, + 16, 0, 1, 0, 0, 0, + 166, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 166, 14, 16, 128, 65, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 11, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 128, 65, 0, + 0, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 26, 0, 0, 5, + 50, 0, 16, 0, 4, 0, + 0, 0, 230, 10, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 11, 194, 0, 16, 0, + 4, 0, 0, 0, 6, 4, + 16, 128, 65, 0, 0, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 0, 8, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 128, 65, 0, + 0, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 4, 0, + 0, 0, 14, 0, 0, 10, + 50, 0, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 230, 10, + 16, 0, 4, 0, 0, 0, + 56, 32, 0, 7, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 4, 0, 0, 0, 50, 0, + 0, 15, 50, 0, 16, 0, + 4, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 192, 0, 0, 0, 192, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 64, 64, 0, 0, + 64, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 65, 0, 0, 5, + 194, 0, 16, 0, 3, 0, + 0, 0, 166, 14, 16, 0, + 3, 0, 0, 0, 50, 0, + 0, 9, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 4, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 230, 10, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 10, 50, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 8, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 70, 128, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 73, 0, + 0, 143, 194, 0, 0, 128, + 67, 85, 21, 0, 18, 0, + 16, 0, 0, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 70, 0, 16, 0, 2, 0, + 0, 0, 230, 10, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 127, 67, 1, 64, 0, 0, + 0, 0, 0, 63, 56, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 59, 54, 0, 0, 5, + 34, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 63, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 242, 0, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 2, 0, + 0, 0, 70, 126, 16, 0, + 1, 0, 0, 0, 0, 96, + 16, 0, 1, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 160, 64, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 18, 0, 16, 0, 2, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 98, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 38, 125, 16, 0, 1, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 16, 0, 0, 8, 18, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 16, 0, 0, 8, + 34, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 16, 0, + 0, 8, 66, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 192, 64, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 18, 0, 16, 0, 2, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 98, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 102, 124, 16, 0, 1, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 16, 0, 0, 8, 18, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 16, 0, 0, 8, + 34, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 16, 0, + 0, 8, 66, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 224, 64, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 18, 0, 16, 0, 2, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 34, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 22, 126, 16, 0, 1, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 66, 0, + 16, 0, 2, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 150, 124, 16, 0, + 2, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 16, 0, 0, 8, + 18, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 16, 0, + 0, 8, 34, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 5, 0, 0, 0, + 16, 0, 0, 8, 66, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 6, 0, + 0, 0, 18, 0, 0, 1, + 54, 0, 0, 8, 114, 0, + 16, 0, 1, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 21, 0, 0, 1, + 21, 0, 0, 1, 21, 0, + 0, 1, 54, 0, 0, 5, + 130, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 21, 0, + 0, 1, 21, 0, 0, 1, + 21, 0, 0, 1, 21, 0, + 0, 1, 21, 0, 0, 1, + 47, 0, 0, 6, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 128, 129, 0, + 0, 0, 1, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 172, 205, 79, 60, 172, 205, + 79, 60, 172, 205, 79, 60, + 0, 0, 0, 0, 25, 0, + 0, 5, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 0, 0, 0, 10, 114, 0, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 86, 191, 0, 0, + 86, 191, 0, 0, 86, 191, + 0, 0, 0, 0, 52, 0, + 0, 10, 114, 0, 16, 0, + 3, 0, 0, 0, 70, 2, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 50, 0, 0, 16, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 0, 128, 149, 65, 0, 128, + 149, 65, 0, 128, 149, 65, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 208, 150, 65, + 0, 208, 150, 65, 0, 208, + 150, 65, 0, 0, 0, 0, + 14, 0, 0, 7, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 47, 0, + 0, 6, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 107, 224, + 200, 64, 107, 224, 200, 64, + 107, 224, 200, 64, 0, 0, + 0, 0, 25, 0, 0, 5, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 0, 64, + 28, 70, 0, 64, 28, 70, + 0, 64, 28, 70, 0, 0, + 0, 0, 14, 0, 0, 8, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 2, 0, 0, 0, 86, 5, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 1, 0, 0, 0, 57, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 128, + 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 56, 0, 0, 8, 114, 0, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 86, 133, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 24, 0, 0, 11, + 50, 0, 16, 0, 4, 0, + 0, 0, 6, 128, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 0, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 10, 18, 0, 16, 0, + 5, 0, 0, 0, 2, 64, + 0, 0, 140, 157, 32, 63, + 200, 151, 168, 62, 249, 104, + 49, 61, 0, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 16, 0, 0, 10, + 34, 0, 16, 0, 5, 0, + 0, 0, 2, 64, 0, 0, + 186, 130, 141, 61, 10, 103, + 107, 63, 175, 39, 58, 60, + 0, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 16, 0, 0, 10, 66, 0, + 16, 0, 5, 0, 0, 0, + 2, 64, 0, 0, 107, 70, + 134, 60, 41, 64, 180, 61, + 183, 69, 101, 63, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 5, 0, 0, 0, 166, 10, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 5, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 52, 0, + 0, 7, 130, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 52, 0, 0, 7, + 130, 0, 16, 0, 2, 0, + 0, 0, 58, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 49, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 13, 194, 0, 16, 0, + 4, 0, 0, 0, 86, 137, + 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 14, 0, 0, 7, + 130, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 56, 0, 0, 7, 114, 0, + 16, 0, 6, 0, 0, 0, + 246, 15, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 5, 0, 0, 0, 246, 15, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 6, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 16, 0, + 0, 10, 18, 0, 16, 0, + 6, 0, 0, 0, 2, 64, + 0, 0, 34, 139, 212, 63, + 160, 112, 22, 191, 35, 45, + 149, 189, 0, 0, 0, 0, + 70, 2, 16, 0, 5, 0, + 0, 0, 16, 0, 0, 10, + 34, 0, 16, 0, 6, 0, + 0, 0, 2, 64, 0, 0, + 127, 18, 255, 189, 180, 2, + 145, 63, 13, 198, 8, 188, + 0, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 16, 0, 0, 10, 66, 0, + 16, 0, 6, 0, 0, 0, + 2, 64, 0, 0, 179, 183, + 148, 188, 205, 5, 206, 189, + 60, 51, 143, 63, 0, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 5, 0, 0, 0, 166, 10, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 6, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 55, 0, + 0, 9, 226, 0, 16, 0, + 4, 0, 0, 0, 86, 5, + 16, 0, 4, 0, 0, 0, + 6, 9, 16, 0, 5, 0, + 0, 0, 6, 9, 16, 0, + 2, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 3, 0, 0, 0, 6, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 150, 7, 16, 0, + 4, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 2, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 31, 0, + 4, 3, 58, 0, 16, 0, + 0, 0, 0, 0, 57, 0, + 0, 11, 18, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 29, 0, 0, 10, 114, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 230, 174, + 37, 61, 230, 174, 37, 61, + 230, 174, 37, 61, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 145, 131, + 158, 61, 145, 131, 158, 61, + 145, 131, 158, 61, 0, 0, + 0, 0, 0, 0, 0, 10, + 114, 0, 16, 0, 5, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 174, 71, 97, 61, + 174, 71, 97, 61, 174, 71, + 97, 61, 0, 0, 0, 0, + 56, 0, 0, 11, 114, 0, + 16, 0, 5, 0, 0, 0, + 70, 2, 16, 128, 129, 0, + 0, 0, 5, 0, 0, 0, + 2, 64, 0, 0, 111, 167, + 114, 63, 111, 167, 114, 63, + 111, 167, 114, 63, 0, 0, + 0, 0, 47, 0, 0, 5, + 114, 0, 16, 0, 5, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 5, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 2, 64, 0, 0, 154, 153, + 25, 64, 154, 153, 25, 64, + 154, 153, 25, 64, 0, 0, + 0, 0, 25, 0, 0, 5, + 114, 0, 16, 0, 5, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 55, 0, + 0, 9, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 21, 0, + 0, 1, 56, 0, 0, 8, + 114, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 0, + 0, 1, 31, 0, 4, 3, + 42, 0, 16, 0, 0, 0, + 0, 0, 56, 0, 0, 8, + 114, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, + 0, 11, 18, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 0, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 29, 0, 0, 10, 210, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 28, 46, + 77, 59, 0, 0, 0, 0, + 28, 46, 77, 59, 28, 46, + 77, 59, 6, 9, 16, 0, + 1, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 3, 0, 0, 0, 70, 2, + 16, 0, 1, 0, 0, 0, + 2, 64, 0, 0, 82, 184, + 78, 65, 82, 184, 78, 65, + 82, 184, 78, 65, 0, 0, + 0, 0, 47, 0, 0, 6, + 114, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 128, + 129, 0, 0, 0, 1, 0, + 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 85, 85, 213, 62, + 85, 85, 213, 62, 85, 85, + 213, 62, 0, 0, 0, 0, + 25, 0, 0, 5, 114, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 0, 4, 0, + 0, 0, 50, 0, 0, 15, + 114, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 61, 10, 135, 63, + 61, 10, 135, 63, 61, 10, + 135, 63, 0, 0, 0, 0, + 2, 64, 0, 0, 174, 71, + 97, 189, 174, 71, 97, 189, + 174, 71, 97, 189, 0, 0, + 0, 0, 55, 32, 0, 9, + 114, 0, 16, 0, 1, 0, + 0, 0, 134, 3, 16, 0, + 0, 0, 0, 0, 70, 2, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 4, 0, + 0, 0, 21, 0, 0, 1, + 18, 0, 0, 1, 31, 0, + 4, 3, 26, 0, 16, 0, + 0, 0, 0, 0, 16, 0, + 0, 10, 18, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 34, 139, 212, 63, + 160, 112, 22, 191, 35, 45, + 149, 189, 0, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 16, 0, 0, 10, + 34, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 127, 18, 255, 189, 180, 2, + 145, 63, 13, 198, 8, 188, + 0, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 16, 0, 0, 10, 66, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 179, 183, + 148, 188, 205, 5, 206, 189, + 60, 51, 143, 63, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 56, 0, + 0, 8, 114, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, + 246, 143, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 57, 0, 0, 11, 18, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 29, 0, 0, 10, + 114, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 28, 46, 77, 59, 28, 46, + 77, 59, 28, 46, 77, 59, + 0, 0, 0, 0, 70, 2, + 16, 0, 1, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 82, 184, 78, 65, 82, 184, + 78, 65, 82, 184, 78, 65, + 0, 0, 0, 0, 47, 0, + 0, 6, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 128, 129, 0, 0, 0, + 1, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 2, 64, 0, 0, 85, 85, + 213, 62, 85, 85, 213, 62, + 85, 85, 213, 62, 0, 0, + 0, 0, 25, 0, 0, 5, + 114, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 50, 0, + 0, 15, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 2, 64, 0, 0, 61, 10, + 135, 63, 61, 10, 135, 63, + 61, 10, 135, 63, 0, 0, + 0, 0, 2, 64, 0, 0, + 174, 71, 97, 189, 174, 71, + 97, 189, 174, 71, 97, 189, + 0, 0, 0, 0, 55, 32, + 0, 9, 114, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 21, 0, + 0, 1, 18, 0, 0, 1, + 56, 0, 0, 8, 114, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 246, 143, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 21, 0, 0, 1, + 21, 0, 0, 1, 21, 0, + 0, 1, 56, 0, 0, 7, + 242, 32, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 1, 0, 0, 0, 70, 30, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 148, 0, 0, 0, + 189, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 118, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 0, + 0, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 10, 0, 0, 0, + 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/src/render/direct3d11/D3D11_PixelShader_Colors.h b/src/render/direct3d11/D3D11_PixelShader_Colors.h index b2e30cea01..a0a4126c80 100644 --- a/src/render/direct3d11/D3D11_PixelShader_Colors.h +++ b/src/render/direct3d11/D3D11_PixelShader_Colors.h @@ -3,7 +3,7 @@ // Generated by Microsoft (R) HLSL Shader Compiler 10.1 // // -// Buffer Definitions: +// Buffer Definitions: // // cbuffer Constants // { @@ -29,7 +29,7 @@ // // Name Type Format Dim HLSL Bind Count // ------------------------------ ---------- ------- ----------- -------------- ------ -// Constants cbuffer NA NA cb0 1 +// Constants cbuffer NA NA cb0 1 // // // @@ -37,8 +37,8 @@ // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ -// SV_POSITION 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float // COLOR 0 xyzw 2 NONE float xyzw // // @@ -73,218 +73,218 @@ dcl_temps 1 mov r0.x, cb0[0].w mov r0.w, l(1.000000) mul o0.xyzw, r0.xxxw, v2.xyzw -ret +ret // Approximately 4 instruction slots used #endif const BYTE g_main[] = { - 68, 88, 66, 67, 131, 2, - 46, 215, 253, 13, 129, 98, - 132, 106, 250, 166, 217, 206, - 9, 154, 1, 0, 0, 0, - 224, 4, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 172, 0, 0, 0, 56, 1, - 0, 0, 180, 1, 0, 0, - 56, 4, 0, 0, 172, 4, - 0, 0, 65, 111, 110, 57, - 108, 0, 0, 0, 108, 0, - 0, 0, 0, 2, 255, 255, - 60, 0, 0, 0, 48, 0, - 0, 0, 1, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 48, 0, 0, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 2, - 255, 255, 31, 0, 0, 2, - 0, 0, 0, 128, 1, 0, - 15, 176, 5, 0, 0, 3, - 0, 0, 7, 128, 1, 0, - 228, 176, 0, 0, 255, 160, - 1, 0, 0, 2, 0, 0, - 8, 128, 1, 0, 255, 176, - 1, 0, 0, 2, 0, 8, - 15, 128, 0, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 132, 0, 0, 0, - 64, 0, 0, 0, 33, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 98, 16, 0, 3, 242, 16, - 16, 0, 2, 0, 0, 0, - 101, 0, 0, 3, 242, 32, - 16, 0, 0, 0, 0, 0, - 104, 0, 0, 2, 1, 0, - 0, 0, 54, 0, 0, 6, - 18, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 130, 0, 16, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 56, 0, - 0, 7, 242, 32, 16, 0, - 0, 0, 0, 0, 6, 12, - 16, 0, 0, 0, 0, 0, - 70, 30, 16, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 4, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 124, 2, 0, 0, - 1, 0, 0, 0, 72, 0, - 0, 0, 1, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 255, 255, 0, 1, 0, 0, - 84, 2, 0, 0, 60, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, - 67, 111, 110, 115, 116, 97, - 110, 116, 115, 0, 171, 171, - 60, 0, 0, 0, 13, 0, - 0, 0, 96, 0, 0, 0, - 112, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 152, 1, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 184, 1, 0, 0, 4, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 197, 1, 0, 0, 8, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 208, 1, 0, 0, 12, 0, - 0, 0, 4, 0, 0, 0, - 2, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 220, 1, 0, 0, 16, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 232, 1, - 0, 0, 0, 0, 0, 0, - 248, 1, 0, 0, 32, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 7, 2, 0, 0, 36, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 23, 2, 0, 0, 40, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 39, 2, 0, 0, 44, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 55, 2, 0, 0, 48, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 232, 1, - 0, 0, 0, 0, 0, 0, - 63, 2, 0, 0, 64, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 232, 1, - 0, 0, 0, 0, 0, 0, - 70, 2, 0, 0, 80, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 232, 1, - 0, 0, 0, 0, 0, 0, - 77, 2, 0, 0, 96, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 232, 1, - 0, 0, 0, 0, 0, 0, - 115, 99, 82, 71, 66, 95, - 111, 117, 116, 112, 117, 116, - 0, 171, 171, 171, 0, 0, - 3, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 116, 101, 120, 116, - 117, 114, 101, 95, 116, 121, - 112, 101, 0, 105, 110, 112, - 117, 116, 95, 116, 121, 112, - 101, 0, 99, 111, 108, 111, - 114, 95, 115, 99, 97, 108, - 101, 0, 116, 101, 120, 101, - 108, 95, 115, 105, 122, 101, - 0, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 116, 111, 110, 101, 109, 97, - 112, 95, 109, 101, 116, 104, - 111, 100, 0, 116, 111, 110, - 101, 109, 97, 112, 95, 102, - 97, 99, 116, 111, 114, 49, - 0, 116, 111, 110, 101, 109, - 97, 112, 95, 102, 97, 99, - 116, 111, 114, 50, 0, 115, - 100, 114, 95, 119, 104, 105, - 116, 101, 95, 112, 111, 105, - 110, 116, 0, 89, 111, 102, - 102, 115, 101, 116, 0, 82, - 99, 111, 101, 102, 102, 0, - 71, 99, 111, 101, 102, 102, - 0, 66, 99, 111, 101, 102, - 102, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 49, 48, 46, 49, 0, - 73, 83, 71, 78, 108, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 101, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 0, 0, 0, - 15, 15, 0, 0, 83, 86, - 95, 80, 79, 83, 73, 84, - 73, 79, 78, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 67, 79, 76, 79, 82, - 0, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 65, 82, + 68, 88, 66, 67, 131, 2, + 46, 215, 253, 13, 129, 98, + 132, 106, 250, 166, 217, 206, + 9, 154, 1, 0, 0, 0, + 224, 4, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 172, 0, 0, 0, 56, 1, + 0, 0, 180, 1, 0, 0, + 56, 4, 0, 0, 172, 4, + 0, 0, 65, 111, 110, 57, + 108, 0, 0, 0, 108, 0, + 0, 0, 0, 2, 255, 255, + 60, 0, 0, 0, 48, 0, + 0, 0, 1, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 48, 0, 0, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 2, + 255, 255, 31, 0, 0, 2, + 0, 0, 0, 128, 1, 0, + 15, 176, 5, 0, 0, 3, + 0, 0, 7, 128, 1, 0, + 228, 176, 0, 0, 255, 160, + 1, 0, 0, 2, 0, 0, + 8, 128, 1, 0, 255, 176, + 1, 0, 0, 2, 0, 8, + 15, 128, 0, 0, 228, 128, + 255, 255, 0, 0, 83, 72, + 68, 82, 132, 0, 0, 0, + 64, 0, 0, 0, 33, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 98, 16, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 101, 0, 0, 3, 242, 32, + 16, 0, 0, 0, 0, 0, + 104, 0, 0, 2, 1, 0, + 0, 0, 54, 0, 0, 6, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 56, 0, + 0, 7, 242, 32, 16, 0, + 0, 0, 0, 0, 6, 12, + 16, 0, 0, 0, 0, 0, + 70, 30, 16, 0, 2, 0, + 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 116, 0, + 0, 0, 4, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 82, 68, + 69, 70, 124, 2, 0, 0, + 1, 0, 0, 0, 72, 0, + 0, 0, 1, 0, 0, 0, + 28, 0, 0, 0, 0, 4, + 255, 255, 0, 1, 0, 0, + 84, 2, 0, 0, 60, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 67, 111, 110, 115, 116, 97, + 110, 116, 115, 0, 171, 171, + 60, 0, 0, 0, 13, 0, + 0, 0, 96, 0, 0, 0, + 112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 152, 1, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 184, 1, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 197, 1, 0, 0, 8, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 208, 1, 0, 0, 12, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 220, 1, 0, 0, 16, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 232, 1, + 0, 0, 0, 0, 0, 0, + 248, 1, 0, 0, 32, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 7, 2, 0, 0, 36, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 23, 2, 0, 0, 40, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 39, 2, 0, 0, 44, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 168, 1, + 0, 0, 0, 0, 0, 0, + 55, 2, 0, 0, 48, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 232, 1, + 0, 0, 0, 0, 0, 0, + 63, 2, 0, 0, 64, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 232, 1, + 0, 0, 0, 0, 0, 0, + 70, 2, 0, 0, 80, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 232, 1, + 0, 0, 0, 0, 0, 0, + 77, 2, 0, 0, 96, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 232, 1, + 0, 0, 0, 0, 0, 0, + 115, 99, 82, 71, 66, 95, + 111, 117, 116, 112, 117, 116, + 0, 171, 171, 171, 0, 0, + 3, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 116, 101, 120, 116, + 117, 114, 101, 95, 116, 121, + 112, 101, 0, 105, 110, 112, + 117, 116, 95, 116, 121, 112, + 101, 0, 99, 111, 108, 111, + 114, 95, 115, 99, 97, 108, + 101, 0, 116, 101, 120, 101, + 108, 95, 115, 105, 122, 101, + 0, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 116, 111, 110, 101, 109, 97, + 112, 95, 109, 101, 116, 104, + 111, 100, 0, 116, 111, 110, + 101, 109, 97, 112, 95, 102, + 97, 99, 116, 111, 114, 49, + 0, 116, 111, 110, 101, 109, + 97, 112, 95, 102, 97, 99, + 116, 111, 114, 50, 0, 115, + 100, 114, 95, 119, 104, 105, + 116, 101, 95, 112, 111, 105, + 110, 116, 0, 89, 111, 102, + 102, 115, 101, 116, 0, 82, + 99, 111, 101, 102, 102, 0, + 71, 99, 111, 101, 102, 102, + 0, 66, 99, 111, 101, 102, + 102, 0, 77, 105, 99, 114, + 111, 115, 111, 102, 116, 32, + 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, + 100, 101, 114, 32, 67, 111, + 109, 112, 105, 108, 101, 114, + 32, 49, 48, 46, 49, 0, + 73, 83, 71, 78, 108, 0, + 0, 0, 3, 0, 0, 0, + 8, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 92, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 101, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 2, 0, 0, 0, + 15, 15, 0, 0, 83, 86, + 95, 80, 79, 83, 73, 84, + 73, 79, 78, 0, 84, 69, + 88, 67, 79, 79, 82, 68, + 0, 67, 79, 76, 79, 82, + 0, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 65, 82, 71, 69, 84, 0, 171, 171 }; diff --git a/src/render/direct3d11/D3D11_PixelShader_Common.hlsli b/src/render/direct3d11/D3D11_PixelShader_Common.hlsli index b47a5e12bd..c2c49e01e8 100644 --- a/src/render/direct3d11/D3D11_PixelShader_Common.hlsli +++ b/src/render/direct3d11/D3D11_PixelShader_Common.hlsli @@ -3,6 +3,7 @@ Texture2D texture0 : register(t0); Texture2D texture1 : register(t1); Texture2D texture2 : register(t2); SamplerState sampler0 : register(s0); +SamplerState sampler1 : register(s1); struct PixelShaderInput { @@ -19,9 +20,11 @@ static const float TONEMAP_CHROME = 2; static const float TEXTURETYPE_NONE = 0; static const float TEXTURETYPE_RGB = 1; static const float TEXTURETYPE_RGB_PIXELART = 2; -static const float TEXTURETYPE_NV12 = 3; -static const float TEXTURETYPE_NV21 = 4; -static const float TEXTURETYPE_YUV = 5; +static const float TEXTURETYPE_PALETTE = 3; +static const float TEXTURETYPE_PALETTE_PIXELART = 4; +static const float TEXTURETYPE_NV12 = 5; +static const float TEXTURETYPE_NV21 = 6; +static const float TEXTURETYPE_YUV = 7; static const float INPUTTYPE_UNSPECIFIED = 0; static const float INPUTTYPE_SRGB = 1; @@ -116,6 +119,23 @@ float3 ApplyTonemap(float3 v) return v; } +float2 GetPixelArtUV(PixelShaderInput input) +{ + // box filter size in texel units + float2 boxSize = clamp(fwidth(input.tex) * texel_size.zw, 1e-5, 1); + + // scale uv by texture size to get texel coordinate + float2 tx = input.tex * texel_size.zw - 0.5 * boxSize; + + // compute offset for pixel-sized box filter + float2 txOffset = smoothstep(1 - boxSize, 1, frac(tx)); + + // compute bilinear sample uv coordinates + float2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy; + + return uv; +} + float4 GetInputColor(PixelShaderInput input) { float4 rgba; @@ -125,20 +145,15 @@ float4 GetInputColor(PixelShaderInput input) } else if (texture_type == TEXTURETYPE_RGB) { rgba = texture0.Sample(sampler0, input.tex); } else if (texture_type == TEXTURETYPE_RGB_PIXELART) { - // box filter size in texel units - float2 boxSize = clamp(fwidth(input.tex) * texel_size.zw, 1e-5, 1); - - // scale uv by texture size to get texel coordinate - float2 tx = input.tex * texel_size.zw - 0.5 * boxSize; - - // compute offset for pixel-sized box filter - float2 txOffset = smoothstep(1 - boxSize, 1, frac(tx)); - - // compute bilinear sample uv coordinates - float2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy; - - // sample the texture + float2 uv = GetPixelArtUV(input); rgba = texture0.SampleGrad(sampler0, uv, ddx(input.tex), ddy(input.tex)); + } else if (texture_type == TEXTURETYPE_PALETTE) { + float index = texture0.Sample(sampler0, input.tex).r * 255; + rgba = texture1.Sample(sampler1, float2((index + 0.5) / 256, 0.5)); + } else if (texture_type == TEXTURETYPE_PALETTE_PIXELART) { + float2 uv = GetPixelArtUV(input); + float index = texture0.SampleGrad(sampler0, uv, ddx(input.tex), ddy(input.tex)).r * 255; + rgba = texture1.Sample(sampler1, float2((index + 0.5) / 256, 0.5)); } else if (texture_type == TEXTURETYPE_NV12) { float3 yuv; yuv.x = texture0.Sample(sampler0, input.tex).r; diff --git a/src/render/direct3d11/D3D11_PixelShader_Textures.h b/src/render/direct3d11/D3D11_PixelShader_Textures.h index 4b06c09c92..1048b8e1b4 100644 --- a/src/render/direct3d11/D3D11_PixelShader_Textures.h +++ b/src/render/direct3d11/D3D11_PixelShader_Textures.h @@ -3,7 +3,7 @@ // Generated by Microsoft (R) HLSL Shader Compiler 10.1 // // -// Buffer Definitions: +// Buffer Definitions: // // cbuffer Constants // { @@ -29,9 +29,9 @@ // // Name Type Format Dim HLSL Bind Count // ------------------------------ ---------- ------- ----------- -------------- ------ -// theSampler sampler NA NA s0 1 -// theTexture texture float4 2d t0 1 -// Constants cbuffer NA NA cb0 1 +// sampler0 sampler NA NA s0 1 +// texture0 texture float4 2d t0 1 +// Constants cbuffer NA NA cb0 1 // // // @@ -39,8 +39,8 @@ // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ -// SV_POSITION 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // COLOR 0 xyzw 2 NONE float xyzw // // @@ -62,7 +62,7 @@ // // Target Sampler Source Sampler Source Resource // -------------- --------------- ---------------- -// s0 s0 t0 +// s0 s0 t0 // // // Level9 shader bytecode: @@ -88,251 +88,250 @@ dcl_temps 1 sample r0.xyzw, v1.xyxx, t0.xyzw, s0 mul r0.xyz, r0.xyzx, cb0[0].wwww mul o0.xyzw, r0.xyzw, v2.xyzw -ret +ret // Approximately 4 instruction slots used #endif const BYTE g_main[] = { - 68, 88, 66, 67, 59, 235, - 166, 93, 21, 32, 225, 129, - 78, 220, 127, 97, 218, 34, - 222, 113, 1, 0, 0, 0, - 164, 5, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 220, 0, 0, 0, 168, 1, - 0, 0, 36, 2, 0, 0, - 252, 4, 0, 0, 112, 5, - 0, 0, 65, 111, 110, 57, - 156, 0, 0, 0, 156, 0, - 0, 0, 0, 2, 255, 255, - 104, 0, 0, 0, 52, 0, - 0, 0, 1, 0, 40, 0, - 0, 0, 52, 0, 0, 0, - 52, 0, 1, 0, 36, 0, - 0, 0, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 255, 255, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 128, 1, 0, 15, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 176, - 0, 8, 228, 160, 5, 0, - 0, 3, 0, 0, 7, 128, - 0, 0, 228, 128, 0, 0, - 255, 160, 5, 0, 0, 3, - 0, 0, 15, 128, 0, 0, - 228, 128, 1, 0, 228, 176, - 1, 0, 0, 2, 0, 8, - 15, 128, 0, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 196, 0, 0, 0, - 64, 0, 0, 0, 49, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 98, 16, - 0, 3, 50, 16, 16, 0, - 1, 0, 0, 0, 98, 16, - 0, 3, 242, 16, 16, 0, - 2, 0, 0, 0, 101, 0, - 0, 3, 242, 32, 16, 0, - 0, 0, 0, 0, 104, 0, - 0, 2, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 56, 0, 0, 8, 114, 0, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 246, 143, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 56, 0, 0, 7, - 242, 32, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 70, 30, - 16, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 4, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 208, 2, 0, 0, 1, 0, - 0, 0, 156, 0, 0, 0, - 3, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 255, 255, - 0, 1, 0, 0, 168, 2, - 0, 0, 124, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 135, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 1, 0, - 0, 0, 13, 0, 0, 0, - 146, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 116, 104, 101, 83, - 97, 109, 112, 108, 101, 114, - 0, 116, 104, 101, 84, 101, - 120, 116, 117, 114, 101, 0, - 67, 111, 110, 115, 116, 97, - 110, 116, 115, 0, 146, 0, - 0, 0, 13, 0, 0, 0, - 180, 0, 0, 0, 112, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 236, 1, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 12, 2, - 0, 0, 4, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 25, 2, - 0, 0, 8, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 36, 2, - 0, 0, 12, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 48, 2, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 60, 2, 0, 0, - 0, 0, 0, 0, 76, 2, - 0, 0, 32, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 91, 2, - 0, 0, 36, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 107, 2, - 0, 0, 40, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 123, 2, - 0, 0, 44, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 252, 1, 0, 0, - 0, 0, 0, 0, 139, 2, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 60, 2, 0, 0, - 0, 0, 0, 0, 147, 2, - 0, 0, 64, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 60, 2, 0, 0, - 0, 0, 0, 0, 154, 2, - 0, 0, 80, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 60, 2, 0, 0, - 0, 0, 0, 0, 161, 2, - 0, 0, 96, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 60, 2, 0, 0, - 0, 0, 0, 0, 115, 99, - 82, 71, 66, 95, 111, 117, - 116, 112, 117, 116, 0, 171, - 171, 171, 0, 0, 3, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 116, 101, 120, 116, 117, 114, - 101, 95, 116, 121, 112, 101, - 0, 105, 110, 112, 117, 116, - 95, 116, 121, 112, 101, 0, - 99, 111, 108, 111, 114, 95, - 115, 99, 97, 108, 101, 0, - 116, 101, 120, 101, 108, 95, - 115, 105, 122, 101, 0, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 116, 111, - 110, 101, 109, 97, 112, 95, - 109, 101, 116, 104, 111, 100, - 0, 116, 111, 110, 101, 109, - 97, 112, 95, 102, 97, 99, - 116, 111, 114, 49, 0, 116, - 111, 110, 101, 109, 97, 112, - 95, 102, 97, 99, 116, 111, - 114, 50, 0, 115, 100, 114, - 95, 119, 104, 105, 116, 101, - 95, 112, 111, 105, 110, 116, - 0, 89, 111, 102, 102, 115, - 101, 116, 0, 82, 99, 111, - 101, 102, 102, 0, 71, 99, - 111, 101, 102, 102, 0, 66, - 99, 111, 101, 102, 102, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 49, - 48, 46, 49, 0, 73, 83, - 71, 78, 108, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 3, - 0, 0, 101, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 2, 0, 0, 0, 15, 15, - 0, 0, 83, 86, 95, 80, - 79, 83, 73, 84, 73, 79, - 78, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 67, - 79, 76, 79, 82, 0, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 65, 82, 71, 69, - 84, 0, 171, 171 + 68, 88, 66, 67, 98, 171, + 127, 123, 23, 170, 245, 47, + 35, 199, 24, 186, 200, 109, + 190, 201, 1, 0, 0, 0, + 160, 5, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 220, 0, 0, 0, 168, 1, + 0, 0, 36, 2, 0, 0, + 248, 4, 0, 0, 108, 5, + 0, 0, 65, 111, 110, 57, + 156, 0, 0, 0, 156, 0, + 0, 0, 0, 2, 255, 255, + 104, 0, 0, 0, 52, 0, + 0, 0, 1, 0, 40, 0, + 0, 0, 52, 0, 0, 0, + 52, 0, 1, 0, 36, 0, + 0, 0, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 255, 255, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 3, 176, + 31, 0, 0, 2, 0, 0, + 0, 128, 1, 0, 15, 176, + 31, 0, 0, 2, 0, 0, + 0, 144, 0, 8, 15, 160, + 66, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 176, + 0, 8, 228, 160, 5, 0, + 0, 3, 0, 0, 7, 128, + 0, 0, 228, 128, 0, 0, + 255, 160, 5, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 1, 0, 228, 176, + 1, 0, 0, 2, 0, 8, + 15, 128, 0, 0, 228, 128, + 255, 255, 0, 0, 83, 72, + 68, 82, 196, 0, 0, 0, + 64, 0, 0, 0, 49, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 90, 0, 0, 3, 0, 96, + 16, 0, 0, 0, 0, 0, + 88, 24, 0, 4, 0, 112, + 16, 0, 0, 0, 0, 0, + 85, 85, 0, 0, 98, 16, + 0, 3, 50, 16, 16, 0, + 1, 0, 0, 0, 98, 16, + 0, 3, 242, 16, 16, 0, + 2, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 104, 0, + 0, 2, 1, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 8, 114, 0, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 0, 0, + 0, 0, 246, 143, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 7, + 242, 32, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 70, 30, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 116, 0, 0, 0, + 4, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 82, 68, 69, 70, + 204, 2, 0, 0, 1, 0, + 0, 0, 152, 0, 0, 0, + 3, 0, 0, 0, 28, 0, + 0, 0, 0, 4, 255, 255, + 0, 1, 0, 0, 164, 2, + 0, 0, 124, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 133, 0, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 142, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 115, 97, 109, 112, + 108, 101, 114, 48, 0, 116, + 101, 120, 116, 117, 114, 101, + 48, 0, 67, 111, 110, 115, + 116, 97, 110, 116, 115, 0, + 142, 0, 0, 0, 13, 0, + 0, 0, 176, 0, 0, 0, + 112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 232, 1, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 8, 2, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 21, 2, 0, 0, 8, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 32, 2, 0, 0, 12, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 44, 2, 0, 0, 16, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 56, 2, + 0, 0, 0, 0, 0, 0, + 72, 2, 0, 0, 32, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 87, 2, 0, 0, 36, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 103, 2, 0, 0, 40, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 119, 2, 0, 0, 44, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 248, 1, + 0, 0, 0, 0, 0, 0, + 135, 2, 0, 0, 48, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 56, 2, + 0, 0, 0, 0, 0, 0, + 143, 2, 0, 0, 64, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 56, 2, + 0, 0, 0, 0, 0, 0, + 150, 2, 0, 0, 80, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 56, 2, + 0, 0, 0, 0, 0, 0, + 157, 2, 0, 0, 96, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 56, 2, + 0, 0, 0, 0, 0, 0, + 115, 99, 82, 71, 66, 95, + 111, 117, 116, 112, 117, 116, + 0, 171, 171, 171, 0, 0, + 3, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 116, 101, 120, 116, + 117, 114, 101, 95, 116, 121, + 112, 101, 0, 105, 110, 112, + 117, 116, 95, 116, 121, 112, + 101, 0, 99, 111, 108, 111, + 114, 95, 115, 99, 97, 108, + 101, 0, 116, 101, 120, 101, + 108, 95, 115, 105, 122, 101, + 0, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 116, 111, 110, 101, 109, 97, + 112, 95, 109, 101, 116, 104, + 111, 100, 0, 116, 111, 110, + 101, 109, 97, 112, 95, 102, + 97, 99, 116, 111, 114, 49, + 0, 116, 111, 110, 101, 109, + 97, 112, 95, 102, 97, 99, + 116, 111, 114, 50, 0, 115, + 100, 114, 95, 119, 104, 105, + 116, 101, 95, 112, 111, 105, + 110, 116, 0, 89, 111, 102, + 102, 115, 101, 116, 0, 82, + 99, 111, 101, 102, 102, 0, + 71, 99, 111, 101, 102, 102, + 0, 66, 99, 111, 101, 102, + 102, 0, 77, 105, 99, 114, + 111, 115, 111, 102, 116, 32, + 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, + 100, 101, 114, 32, 67, 111, + 109, 112, 105, 108, 101, 114, + 32, 49, 48, 46, 49, 0, + 73, 83, 71, 78, 108, 0, + 0, 0, 3, 0, 0, 0, + 8, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 92, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 3, 3, 0, 0, 101, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 2, 0, 0, 0, + 15, 15, 0, 0, 83, 86, + 95, 80, 79, 83, 73, 84, + 73, 79, 78, 0, 84, 69, + 88, 67, 79, 79, 82, 68, + 0, 67, 79, 76, 79, 82, + 0, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 65, 82, + 71, 69, 84, 0, 171, 171 }; diff --git a/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl b/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl index f2ecf18a8a..9031e0fa33 100644 --- a/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl +++ b/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl @@ -1,9 +1,7 @@ -Texture2D theTexture : register(t0); -SamplerState theSampler : register(s0); #include "D3D11_PixelShader_Common.hlsli" float4 main(PixelShaderInput input) : SV_TARGET { - return GetOutputColor(theTexture.Sample(theSampler, input.tex)) * input.color; + return GetOutputColor(texture0.Sample(sampler0, input.tex)) * input.color; } diff --git a/src/render/direct3d11/D3D11_VertexShader.h b/src/render/direct3d11/D3D11_VertexShader.h index e6aac573e6..97beaa39e6 100644 --- a/src/render/direct3d11/D3D11_VertexShader.h +++ b/src/render/direct3d11/D3D11_VertexShader.h @@ -3,7 +3,7 @@ // Generated by Microsoft (R) HLSL Shader Compiler 10.1 // // -// Buffer Definitions: +// Buffer Definitions: // // cbuffer VertexShaderConstants // { @@ -18,7 +18,7 @@ // // Name Type Format Dim HLSL Bind Count // ------------------------------ ---------- ------- ----------- -------------- ------ -// VertexShaderConstants cbuffer NA NA cb0 1 +// VertexShaderConstants cbuffer NA NA cb0 1 // // // @@ -26,8 +26,8 @@ // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xyz 0 NONE float xyz -// TEXCOORD 0 xy 1 NONE float xy +// POSITION 0 xyz 0 NONE float xyz +// TEXCOORD 0 xy 1 NONE float xy // COLOR 0 xyzw 2 NONE float xyzw // // @@ -36,7 +36,7 @@ // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_POSITION 0 xyzw 0 POS float xyzw -// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 0 xy 1 NONE float xy // COLOR 0 xyzw 2 NONE float xyzw // // @@ -93,247 +93,247 @@ mad r1.xyzw, r0.zzzz, cb0[6].xyzw, r1.xyzw mad o0.xyzw, r0.wwww, cb0[7].xyzw, r1.xyzw mov o1.xy, v1.xyxx mov o2.xyzw, v2.xyzw -ret +ret // Approximately 11 instruction slots used #endif const BYTE g_main[] = { - 68, 88, 66, 67, 152, 172, - 81, 45, 198, 200, 12, 38, - 143, 4, 178, 228, 158, 175, - 169, 64, 1, 0, 0, 0, - 140, 5, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 108, 1, 0, 0, 52, 3, - 0, 0, 176, 3, 0, 0, - 168, 4, 0, 0, 24, 5, - 0, 0, 65, 111, 110, 57, - 44, 1, 0, 0, 44, 1, - 0, 0, 0, 2, 254, 255, - 248, 0, 0, 0, 52, 0, - 0, 0, 1, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 48, 0, 0, 0, 36, 0, - 1, 0, 48, 0, 0, 0, - 0, 0, 8, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 254, 255, - 31, 0, 0, 2, 5, 0, - 0, 128, 0, 0, 15, 144, - 31, 0, 0, 2, 5, 0, - 1, 128, 1, 0, 15, 144, - 31, 0, 0, 2, 5, 0, - 2, 128, 2, 0, 15, 144, - 5, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 85, 144, - 2, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 15, 128, - 0, 0, 0, 144, 1, 0, - 228, 160, 0, 0, 228, 128, - 4, 0, 0, 4, 0, 0, - 15, 128, 0, 0, 170, 144, - 3, 0, 228, 160, 0, 0, - 228, 128, 2, 0, 0, 3, - 0, 0, 15, 128, 0, 0, - 228, 128, 4, 0, 228, 160, - 5, 0, 0, 3, 1, 0, - 15, 128, 0, 0, 85, 128, - 6, 0, 228, 160, 4, 0, - 0, 4, 1, 0, 15, 128, - 0, 0, 0, 128, 5, 0, - 228, 160, 1, 0, 228, 128, - 4, 0, 0, 4, 1, 0, - 15, 128, 0, 0, 170, 128, - 7, 0, 228, 160, 1, 0, - 228, 128, 4, 0, 0, 4, - 0, 0, 15, 128, 0, 0, - 255, 128, 8, 0, 228, 160, - 1, 0, 228, 128, 4, 0, - 0, 4, 0, 0, 3, 192, - 0, 0, 255, 128, 0, 0, - 228, 160, 0, 0, 228, 128, - 1, 0, 0, 2, 0, 0, - 12, 192, 0, 0, 228, 128, - 1, 0, 0, 2, 0, 0, - 3, 224, 1, 0, 228, 144, - 1, 0, 0, 2, 1, 0, - 15, 224, 2, 0, 228, 144, - 255, 255, 0, 0, 83, 72, - 68, 82, 192, 1, 0, 0, - 64, 0, 1, 0, 112, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 8, 0, 0, 0, - 95, 0, 0, 3, 114, 16, - 16, 0, 0, 0, 0, 0, - 95, 0, 0, 3, 50, 16, - 16, 0, 1, 0, 0, 0, - 95, 0, 0, 3, 242, 16, - 16, 0, 2, 0, 0, 0, - 103, 0, 0, 4, 242, 32, - 16, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 50, 32, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 242, 32, 16, 0, - 2, 0, 0, 0, 104, 0, - 0, 2, 2, 0, 0, 0, - 56, 0, 0, 8, 242, 0, - 16, 0, 0, 0, 0, 0, - 86, 21, 16, 0, 0, 0, - 0, 0, 70, 142, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 50, 0, 0, 10, - 242, 0, 16, 0, 0, 0, - 0, 0, 6, 16, 16, 0, - 0, 0, 0, 0, 70, 142, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 166, 26, 16, 0, 0, 0, - 0, 0, 70, 142, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 8, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 70, 142, 32, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 56, 0, 0, 8, 242, 0, - 16, 0, 1, 0, 0, 0, - 86, 5, 16, 0, 0, 0, - 0, 0, 70, 142, 32, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 50, 0, 0, 10, - 242, 0, 16, 0, 1, 0, - 0, 0, 6, 0, 16, 0, - 0, 0, 0, 0, 70, 142, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 70, 14, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 1, 0, 0, 0, - 166, 10, 16, 0, 0, 0, - 0, 0, 70, 142, 32, 0, - 0, 0, 0, 0, 6, 0, - 0, 0, 70, 14, 16, 0, - 1, 0, 0, 0, 50, 0, - 0, 10, 242, 32, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 0, 0, 0, 0, - 70, 142, 32, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 70, 14, 16, 0, 1, 0, - 0, 0, 54, 0, 0, 5, - 50, 32, 16, 0, 1, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 54, 0, - 0, 5, 242, 32, 16, 0, - 2, 0, 0, 0, 70, 30, - 16, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 11, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 240, 0, 0, 0, 1, 0, - 0, 0, 84, 0, 0, 0, - 1, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 254, 255, - 0, 1, 0, 0, 198, 0, - 0, 0, 60, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 86, 101, - 114, 116, 101, 120, 83, 104, - 97, 100, 101, 114, 67, 111, - 110, 115, 116, 97, 110, 116, - 115, 0, 171, 171, 60, 0, - 0, 0, 2, 0, 0, 0, - 108, 0, 0, 0, 128, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 156, 0, - 0, 0, 0, 0, 0, 0, - 64, 0, 0, 0, 2, 0, - 0, 0, 164, 0, 0, 0, - 0, 0, 0, 0, 180, 0, - 0, 0, 64, 0, 0, 0, - 64, 0, 0, 0, 2, 0, - 0, 0, 164, 0, 0, 0, - 0, 0, 0, 0, 109, 111, - 100, 101, 108, 0, 171, 171, - 2, 0, 3, 0, 4, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 112, 114, - 111, 106, 101, 99, 116, 105, - 111, 110, 65, 110, 100, 86, - 105, 101, 119, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 49, 48, 46, - 49, 0, 171, 171, 73, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 7, 7, - 0, 0, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 3, - 0, 0, 98, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 2, 0, 0, 0, 15, 15, - 0, 0, 80, 79, 83, 73, - 84, 73, 79, 78, 0, 84, - 69, 88, 67, 79, 79, 82, - 68, 0, 67, 79, 76, 79, - 82, 0, 79, 83, 71, 78, - 108, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 12, 0, 0, - 101, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 2, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 80, 79, 83, - 73, 84, 73, 79, 78, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 67, 79, 76, + 68, 88, 66, 67, 152, 172, + 81, 45, 198, 200, 12, 38, + 143, 4, 178, 228, 158, 175, + 169, 64, 1, 0, 0, 0, + 140, 5, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 108, 1, 0, 0, 52, 3, + 0, 0, 176, 3, 0, 0, + 168, 4, 0, 0, 24, 5, + 0, 0, 65, 111, 110, 57, + 44, 1, 0, 0, 44, 1, + 0, 0, 0, 2, 254, 255, + 248, 0, 0, 0, 52, 0, + 0, 0, 1, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 48, 0, 0, 0, 36, 0, + 1, 0, 48, 0, 0, 0, + 0, 0, 8, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 254, 255, + 31, 0, 0, 2, 5, 0, + 0, 128, 0, 0, 15, 144, + 31, 0, 0, 2, 5, 0, + 1, 128, 1, 0, 15, 144, + 31, 0, 0, 2, 5, 0, + 2, 128, 2, 0, 15, 144, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 85, 144, + 2, 0, 228, 160, 4, 0, + 0, 4, 0, 0, 15, 128, + 0, 0, 0, 144, 1, 0, + 228, 160, 0, 0, 228, 128, + 4, 0, 0, 4, 0, 0, + 15, 128, 0, 0, 170, 144, + 3, 0, 228, 160, 0, 0, + 228, 128, 2, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 4, 0, 228, 160, + 5, 0, 0, 3, 1, 0, + 15, 128, 0, 0, 85, 128, + 6, 0, 228, 160, 4, 0, + 0, 4, 1, 0, 15, 128, + 0, 0, 0, 128, 5, 0, + 228, 160, 1, 0, 228, 128, + 4, 0, 0, 4, 1, 0, + 15, 128, 0, 0, 170, 128, + 7, 0, 228, 160, 1, 0, + 228, 128, 4, 0, 0, 4, + 0, 0, 15, 128, 0, 0, + 255, 128, 8, 0, 228, 160, + 1, 0, 228, 128, 4, 0, + 0, 4, 0, 0, 3, 192, + 0, 0, 255, 128, 0, 0, + 228, 160, 0, 0, 228, 128, + 1, 0, 0, 2, 0, 0, + 12, 192, 0, 0, 228, 128, + 1, 0, 0, 2, 0, 0, + 3, 224, 1, 0, 228, 144, + 1, 0, 0, 2, 1, 0, + 15, 224, 2, 0, 228, 144, + 255, 255, 0, 0, 83, 72, + 68, 82, 192, 1, 0, 0, + 64, 0, 1, 0, 112, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 8, 0, 0, 0, + 95, 0, 0, 3, 114, 16, + 16, 0, 0, 0, 0, 0, + 95, 0, 0, 3, 50, 16, + 16, 0, 1, 0, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 103, 0, 0, 4, 242, 32, + 16, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 101, 0, + 0, 3, 50, 32, 16, 0, + 1, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 2, 0, 0, 0, 104, 0, + 0, 2, 2, 0, 0, 0, + 56, 0, 0, 8, 242, 0, + 16, 0, 0, 0, 0, 0, + 86, 21, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 0, 0, + 0, 0, 6, 16, 16, 0, + 0, 0, 0, 0, 70, 142, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 166, 26, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 242, 0, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 70, 142, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 56, 0, 0, 8, 242, 0, + 16, 0, 1, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 5, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 1, 0, + 0, 0, 6, 0, 16, 0, + 0, 0, 0, 0, 70, 142, + 32, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 1, 0, 0, 0, + 166, 10, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 6, 0, + 0, 0, 70, 14, 16, 0, + 1, 0, 0, 0, 50, 0, + 0, 10, 242, 32, 16, 0, + 0, 0, 0, 0, 246, 15, + 16, 0, 0, 0, 0, 0, + 70, 142, 32, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 5, + 50, 32, 16, 0, 1, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 54, 0, + 0, 5, 242, 32, 16, 0, + 2, 0, 0, 0, 70, 30, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 116, 0, 0, 0, + 11, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 82, 68, 69, 70, + 240, 0, 0, 0, 1, 0, + 0, 0, 84, 0, 0, 0, + 1, 0, 0, 0, 28, 0, + 0, 0, 0, 4, 254, 255, + 0, 1, 0, 0, 198, 0, + 0, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 86, 101, + 114, 116, 101, 120, 83, 104, + 97, 100, 101, 114, 67, 111, + 110, 115, 116, 97, 110, 116, + 115, 0, 171, 171, 60, 0, + 0, 0, 2, 0, 0, 0, + 108, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 156, 0, + 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 2, 0, + 0, 0, 164, 0, 0, 0, + 0, 0, 0, 0, 180, 0, + 0, 0, 64, 0, 0, 0, + 64, 0, 0, 0, 2, 0, + 0, 0, 164, 0, 0, 0, + 0, 0, 0, 0, 109, 111, + 100, 101, 108, 0, 171, 171, + 2, 0, 3, 0, 4, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 112, 114, + 111, 106, 101, 99, 116, 105, + 111, 110, 65, 110, 100, 86, + 105, 101, 119, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 49, 48, 46, + 49, 0, 171, 171, 73, 83, + 71, 78, 104, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 7, 7, + 0, 0, 89, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 2, 0, 0, 0, 15, 15, + 0, 0, 80, 79, 83, 73, + 84, 73, 79, 78, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 67, 79, 76, 79, + 82, 0, 79, 83, 71, 78, + 108, 0, 0, 0, 3, 0, + 0, 0, 8, 0, 0, 0, + 80, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 92, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 3, 12, 0, 0, + 101, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 80, 79, 83, + 73, 84, 73, 79, 78, 0, + 84, 69, 88, 67, 79, 79, + 82, 68, 0, 67, 79, 76, 79, 82, 0, 171 }; diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 39fc94dbe8..6fa296b046 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -62,16 +62,18 @@ typedef struct } D3D11_VertexShaderConstants; // These should mirror the definitions in D3D11_PixelShader_Common.hlsli -//static const float TONEMAP_NONE = 0; +static const float TONEMAP_NONE = 0; //static const float TONEMAP_LINEAR = 1; static const float TONEMAP_CHROME = 2; //static const float TEXTURETYPE_NONE = 0; static const float TEXTURETYPE_RGB = 1; static const float TEXTURETYPE_RGB_PIXELART = 2; -static const float TEXTURETYPE_NV12 = 3; -static const float TEXTURETYPE_NV21 = 4; -static const float TEXTURETYPE_YUV = 5; +static const float TEXTURETYPE_PALETTE = 3; +static const float TEXTURETYPE_PALETTE_PIXELART = 4; +static const float TEXTURETYPE_NV12 = 5; +static const float TEXTURETYPE_NV21 = 6; +static const float TEXTURETYPE_YUV = 7; static const float INPUTTYPE_UNSPECIFIED = 0; static const float INPUTTYPE_SRGB = 1; @@ -112,6 +114,13 @@ typedef struct SDL_FColor color; } D3D11_VertexPositionColor; +// Per-palette data +typedef struct +{ + ID3D11Texture2D *texture; + ID3D11ShaderResourceView *resourceView; +} D3D11_PaletteData; + // Per-texture data typedef struct { @@ -122,7 +131,6 @@ typedef struct ID3D11Texture2D *stagingTexture; int lockedTexturePositionX; int lockedTexturePositionY; - D3D11_Shader shader; const float *YCbCr_matrix; #ifdef SDL_HAVE_YUV // YV12 texture support @@ -155,7 +163,6 @@ typedef struct SDL_SharedObject *hDXGIMod; SDL_SharedObject *hD3D11Mod; IDXGIFactory2 *dxgiFactory; - IDXGIAdapter *dxgiAdapter; IDXGIDebug *dxgiDebug; ID3D11Device1 *d3dDevice; ID3D11DeviceContext1 *d3dContext; @@ -192,8 +199,10 @@ typedef struct ID3D11BlendState *currentBlendState; D3D11_Shader currentShader; D3D11_PixelShaderState currentShaderState[NUM_SHADERS]; + int numCurrentShaderResources; ID3D11ShaderResourceView *currentShaderResource; - ID3D11SamplerState *currentSampler; + int numCurrentShaderSamplers; + ID3D11SamplerState *currentShaderSampler; bool cliprectDirty; bool currentCliprectEnabled; SDL_Rect currentCliprect; @@ -228,6 +237,8 @@ static const GUID SDL_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe #pragma GCC diagnostic pop #endif +static bool D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch); + SDL_PixelFormat D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) { switch (dxgiFormat) { @@ -271,6 +282,7 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8X8_UNORM; + case SDL_PIXELFORMAT_INDEX8: case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: return DXGI_FORMAT_R8_UNORM; @@ -370,7 +382,6 @@ static void D3D11_ReleaseAll(SDL_Renderer *renderer) SAFE_RELEASE(data->d3dContext); SAFE_RELEASE(data->d3dDevice); - SAFE_RELEASE(data->dxgiAdapter); SAFE_RELEASE(data->dxgiFactory); data->swapEffect = (DXGI_SWAP_EFFECT)0; @@ -381,8 +392,10 @@ static void D3D11_ReleaseAll(SDL_Renderer *renderer) data->currentBlendState = NULL; data->currentShader = SHADER_NONE; SDL_zero(data->currentShaderState); + data->numCurrentShaderResources = 0; data->currentShaderResource = NULL; - data->currentSampler = NULL; + data->numCurrentShaderSamplers = 0; + data->currentShaderSampler = NULL; // Check for any leaks if in debug mode if (data->dxgiDebug) { @@ -507,16 +520,18 @@ static ID3D11BlendState *D3D11_CreateBlendState(SDL_Renderer *renderer, SDL_Blen // Create resources that depend on the device. static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) { - typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); - typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY2)(UINT flags, REFIID riid, void **ppFactory); - PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc = NULL; - PFN_CREATE_DXGI_FACTORY2 CreateDXGIFactory2Func = NULL; + typedef HRESULT (WINAPI *pfnCreateDXGIFactory)(REFIID riid, void **ppFactory); + typedef HRESULT (WINAPI *pfnCreateDXGIFactory2)(UINT flags, REFIID riid, void **ppFactory); + pfnCreateDXGIFactory pCreateDXGIFactory = NULL; + pfnCreateDXGIFactory2 pCreateDXGIFactory2 = NULL; D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; - PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc; + PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice; + IDXGIAdapter *dxgiAdapter = NULL; ID3D11Device *d3dDevice = NULL; ID3D11DeviceContext *d3dContext = NULL; IDXGIDevice1 *dxgiDevice = NULL; HRESULT result = S_OK; + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN; UINT creationFlags = 0; bool createDebug; #ifdef HAVE_DXGI1_5_H @@ -550,10 +565,10 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) goto done; } - CreateDXGIFactory2Func = (PFN_CREATE_DXGI_FACTORY2)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory2"); - if (!CreateDXGIFactory2Func) { - CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory"); - if (!CreateDXGIFactoryFunc) { + pCreateDXGIFactory2 = (pfnCreateDXGIFactory2)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory2"); + if (!pCreateDXGIFactory2) { + pCreateDXGIFactory = (pfnCreateDXGIFactory)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory"); + if (!pCreateDXGIFactory) { result = E_FAIL; goto done; } @@ -565,8 +580,8 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) goto done; } - D3D11CreateDeviceFunc = (PFN_D3D11_CREATE_DEVICE)SDL_LoadFunction(data->hD3D11Mod, "D3D11CreateDevice"); - if (!D3D11CreateDeviceFunc) { + pD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)SDL_LoadFunction(data->hD3D11Mod, "D3D11CreateDevice"); + if (!pD3D11CreateDevice) { result = E_FAIL; goto done; } @@ -574,22 +589,22 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) if (createDebug) { #ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__ IDXGIInfoQueue *dxgiInfoQueue = NULL; - PFN_CREATE_DXGI_FACTORY2 DXGIGetDebugInterfaceFunc; + pfnCreateDXGIFactory2 pDXGIGetDebugInterface1; // If the debug hint is set, also create the DXGI factory in debug mode - DXGIGetDebugInterfaceFunc = (PFN_CREATE_DXGI_FACTORY2)SDL_LoadFunction(data->hDXGIMod, "DXGIGetDebugInterface1"); - if (!DXGIGetDebugInterfaceFunc) { + pDXGIGetDebugInterface1 = (pfnCreateDXGIFactory2)SDL_LoadFunction(data->hDXGIMod, "DXGIGetDebugInterface1"); + if (!pDXGIGetDebugInterface1) { result = E_FAIL; goto done; } - result = DXGIGetDebugInterfaceFunc(0, &SDL_IID_IDXGIDebug1, (void **)&data->dxgiDebug); + result = pDXGIGetDebugInterface1(0, &SDL_IID_IDXGIDebug1, (void **)&data->dxgiDebug); if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("DXGIGetDebugInterface1"), result); goto done; } - result = DXGIGetDebugInterfaceFunc(0, &SDL_IID_IDXGIInfoQueue, (void **)&dxgiInfoQueue); + result = pDXGIGetDebugInterface1(0, &SDL_IID_IDXGIInfoQueue, (void **)&dxgiInfoQueue); if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("DXGIGetDebugInterface1"), result); goto done; @@ -602,10 +617,10 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) creationFlags = DXGI_CREATE_FACTORY_DEBUG; } - if (CreateDXGIFactory2Func) { - result = CreateDXGIFactory2Func(creationFlags, &SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); + if (pCreateDXGIFactory2) { + result = pCreateDXGIFactory2(creationFlags, &SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); } else { - result = CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); + result = pCreateDXGIFactory(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); } if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("CreateDXGIFactory"), result); @@ -615,22 +630,31 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) #ifdef HAVE_DXGI1_5_H // Check for tearing support, which requires the IDXGIFactory5 interface. data->swapChainFlags = 0; - result = IDXGIFactory2_QueryInterface(data->dxgiFactory, &SDL_IID_IDXGIFactory5, (void **)&dxgiFactory5); - if (SUCCEEDED(result)) { - BOOL allowTearing = FALSE; - result = IDXGIFactory5_CheckFeatureSupport(dxgiFactory5, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); - if (SUCCEEDED(result) && allowTearing) { - data->swapChainFlags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + if (!(SDL_GetWindowFlags(renderer->window) & SDL_WINDOW_TRANSPARENT)) { + result = IDXGIFactory2_QueryInterface(data->dxgiFactory, &SDL_IID_IDXGIFactory5, (void **)&dxgiFactory5); + if (SUCCEEDED(result)) { + BOOL allowTearing = FALSE; + result = IDXGIFactory5_CheckFeatureSupport(dxgiFactory5, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); + if (SUCCEEDED(result) && allowTearing) { + data->swapChainFlags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + IDXGIFactory5_Release(dxgiFactory5); } - IDXGIFactory5_Release(dxgiFactory5); } #endif // HAVE_DXGI1_5_H - // FIXME: Should we use the default adapter? - result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &data->dxgiAdapter); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result); - goto done; + if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D11_WARP, false)) { + driverType = D3D_DRIVER_TYPE_WARP; + dxgiAdapter = NULL; + } else { + driverType = D3D_DRIVER_TYPE_UNKNOWN; + + // FIXME: Should we use the default adapter? + result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &dxgiAdapter); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("EnumAdapters"), result); + goto done; + } } /* This flag adds support for surfaces with a different color channel ordering @@ -649,9 +673,9 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) } // Create the Direct3D 11 API device object and a corresponding context. - result = D3D11CreateDeviceFunc( - data->dxgiAdapter, - D3D_DRIVER_TYPE_UNKNOWN, + result = pD3D11CreateDevice( + dxgiAdapter, + driverType, NULL, creationFlags, // Set set debug and Direct2D compatibility flags. featureLevels, // List of feature levels this app can support. @@ -780,6 +804,7 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D11_DEVICE_POINTER, data->d3dDevice); done: + SAFE_RELEASE(dxgiAdapter); SAFE_RELEASE(d3dDevice); SAFE_RELEASE(d3dContext); SAFE_RELEASE(dxgiDevice); @@ -1161,6 +1186,73 @@ static bool GetTextureProperty(SDL_PropertiesID props, const char *name, ID3D11T return true; } +static bool D3D11_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + D3D11_PaletteData *palettedata = (D3D11_PaletteData *)SDL_calloc(1, sizeof(*palettedata)); + if (!palettedata) { + return false; + } + palette->internal = palettedata; + + if (!data->d3dDevice) { + return SDL_SetError("Device lost and couldn't be recovered"); + } + + D3D11_TEXTURE2D_DESC textureDesc; + SDL_zero(textureDesc); + textureDesc.Width = 256; + textureDesc.Height = 1; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = SDLPixelFormatToDXGITextureFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace); + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.MiscFlags = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.CPUAccessFlags = 0; + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + HRESULT result = ID3D11Device_CreateTexture2D(data->d3dDevice, &textureDesc, NULL, &palettedata->texture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); + } + + D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; + SDL_zero(resourceViewDesc); + resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace); + resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceViewDesc.Texture2D.MostDetailedMip = 0; + resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; + result = ID3D11Device_CreateShaderResourceView(data->d3dDevice, + (ID3D11Resource *)palettedata->texture, + &resourceViewDesc, + &palettedata->resourceView); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); + } + return true; +} + +static bool D3D11_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + D3D11_PaletteData *palettedata = (D3D11_PaletteData *)palette->internal; + + return D3D11_UpdateTextureInternal(data, palettedata->texture, 4, 0, 0, ncolors, 1, colors, ncolors * sizeof(*colors)); +} + +static void D3D11_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + D3D11_PaletteData *palettedata = (D3D11_PaletteData *)palette->internal; + + if (palettedata) { + SAFE_RELEASE(palettedata->texture); + SAFE_RELEASE(palettedata->resourceView); + SDL_free(palettedata); + } +} + static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) { D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; @@ -1205,11 +1297,6 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD } textureData->w = (int)textureDesc.Width; textureData->h = (int)textureDesc.Height; - if (SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) { - textureData->shader = SHADER_RGB; - } else { - textureData->shader = SHADER_ADVANCED; - } if (texture->access == SDL_TEXTUREACCESS_STREAMING) { textureDesc.Usage = D3D11_USAGE_DYNAMIC; @@ -1238,6 +1325,7 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD } } SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER, textureData->mainTexture); + #ifdef SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { @@ -1312,6 +1400,7 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD if (FAILED(result)) { return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); } + #ifdef SDL_HAVE_YUV if (textureData->yuv) { result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, @@ -2100,6 +2189,14 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; switch (texture->format) { + case SDL_PIXELFORMAT_INDEX8: + if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) { + constants->texture_type = TEXTURETYPE_PALETTE_PIXELART; + } else { + constants->texture_type = TEXTURETYPE_PALETTE; + } + constants->input_type = INPUTTYPE_UNSPECIFIED; + break; case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: constants->texture_type = TEXTURETYPE_YUV; @@ -2120,10 +2217,6 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC default: if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) { constants->texture_type = TEXTURETYPE_RGB_PIXELART; - constants->texture_width = texture->w; - constants->texture_height = texture->h; - constants->texel_width = 1.0f / constants->texture_width; - constants->texel_height = 1.0f / constants->texture_height; } else { constants->texture_type = TEXTURETYPE_RGB; } @@ -2138,6 +2231,13 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC break; } + if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) { + constants->texture_width = texture->w; + constants->texture_height = texture->h; + constants->texel_width = 1.0f / constants->texture_width; + constants->texel_height = 1.0f / constants->texture_height; + } + constants->sdr_white_point = texture->SDR_white_point; if (renderer->target) { @@ -2158,34 +2258,54 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC } } +static D3D11_Shader SelectShader(const D3D11_PixelShaderConstants *shader_constants) +{ + if (!shader_constants) { + return SHADER_SOLID; + } + + if (shader_constants->texture_type == TEXTURETYPE_RGB && + shader_constants->input_type == INPUTTYPE_UNSPECIFIED && + shader_constants->tonemap_method == TONEMAP_NONE) { + return SHADER_RGB; + } + + return SHADER_ADVANCED; +} + static bool D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, - D3D11_Shader shader, const D3D11_PixelShaderConstants *shader_constants, - const int numShaderResources, ID3D11ShaderResourceView **shaderResources, - ID3D11SamplerState *sampler, const Float4X4 *matrix) + const D3D11_PixelShaderConstants *shader_constants, + int numShaderResources, ID3D11ShaderResourceView **shaderResources, + int numShaderSamplers, ID3D11SamplerState **shaderSamplers, const Float4X4 *matrix) { D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity; ID3D11RasterizerState *rasterizerState; ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer); - ID3D11ShaderResourceView *shaderResource; const SDL_BlendMode blendMode = cmd->data.draw.blend; ID3D11BlendState *blendState = NULL; bool updateSubresource = false; + D3D11_Shader shader = SelectShader(shader_constants); D3D11_PixelShaderState *shader_state = &rendererData->currentShaderState[shader]; D3D11_PixelShaderConstants solid_constants; - if (numShaderResources > 0) { - shaderResource = shaderResources[0]; - } else { - shaderResource = NULL; + bool shaderResourcesChanged = false; + if (numShaderResources != rendererData->numCurrentShaderResources || + (numShaderResources > 0 && shaderResources[0] != rendererData->currentShaderResource)) { + shaderResourcesChanged = true; + } + + bool shaderSamplersChanged = false; + if (numShaderSamplers != rendererData->numCurrentShaderSamplers || + (numShaderSamplers > 0 && shaderSamplers[0] != rendererData->currentShaderSampler)) { + shaderSamplersChanged = true; } // Make sure the render target isn't bound to a shader - if (shaderResource != rendererData->currentShaderResource) { + if (shaderResourcesChanged) { ID3D11ShaderResourceView *pNullResource = NULL; ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, 1, &pNullResource); - rendererData->currentShaderResource = NULL; } if (renderTargetView != rendererData->currentRenderTargetView) { @@ -2288,13 +2408,19 @@ static bool D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand * } rendererData->currentShader = shader; } - if (shaderResource != rendererData->currentShaderResource) { + if (shaderResourcesChanged) { ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, numShaderResources, shaderResources); - rendererData->currentShaderResource = shaderResource; + rendererData->numCurrentShaderResources = numShaderResources; + if (numShaderResources > 0) { + rendererData->currentShaderResource = shaderResources[0]; + } } - if (sampler != rendererData->currentSampler) { - ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler); - rendererData->currentSampler = sampler; + if (shaderSamplersChanged) { + ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, numShaderSamplers, shaderSamplers); + rendererData->numCurrentShaderSamplers = numShaderSamplers; + if (numShaderSamplers) { + rendererData->currentShaderSampler = shaderSamplers[0]; + } } if (updateSubresource == true || SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)) != 0) { @@ -2374,7 +2500,10 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * SDL_Texture *texture = cmd->data.draw.texture; D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; - ID3D11SamplerState *textureSampler; + int numShaderResources = 0; + ID3D11ShaderResourceView *shaderResources[3]; + int numShaderSamplers = 0; + ID3D11SamplerState *shaderSamplers[2]; D3D11_PixelShaderConstants constants; if (!textureData) { @@ -2383,34 +2512,35 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * D3D11_SetupShaderConstants(renderer, cmd, texture, &constants); - textureSampler = D3D11_GetSamplerState(rendererData, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); - if (!textureSampler) { + shaderResources[numShaderResources++] = textureData->mainTextureResourceView; + + shaderSamplers[numShaderSamplers] = D3D11_GetSamplerState(rendererData, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); + if (!shaderSamplers[numShaderSamplers]) { return false; } + ++numShaderSamplers; + + if (texture->palette) { + D3D11_PaletteData *palette = (D3D11_PaletteData *)texture->palette->internal; + + shaderResources[numShaderResources++] = palette->resourceView; + + shaderSamplers[numShaderSamplers] = D3D11_GetSamplerState(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); + if (!shaderSamplers[numShaderSamplers]) { + return false; + } + ++numShaderSamplers; + } #ifdef SDL_HAVE_YUV if (textureData->yuv) { - ID3D11ShaderResourceView *shaderResources[3]; - - shaderResources[0] = textureData->mainTextureResourceView; - shaderResources[1] = textureData->mainTextureResourceViewU; - shaderResources[2] = textureData->mainTextureResourceViewV; - - return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, - SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix); - + shaderResources[numShaderResources++] = textureData->mainTextureResourceViewU; + shaderResources[numShaderResources++] = textureData->mainTextureResourceViewV; } else if (textureData->nv12) { - ID3D11ShaderResourceView *shaderResources[2]; - - shaderResources[0] = textureData->mainTextureResourceView; - shaderResources[1] = textureData->mainTextureResourceViewNV; - - return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, - SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix); + shaderResources[numShaderResources++] = textureData->mainTextureResourceViewNV; } #endif // SDL_HAVE_YUV - return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, - 1, &textureData->mainTextureResourceView, textureSampler, matrix); + return D3D11_SetDrawState(renderer, cmd, &constants, numShaderResources, shaderResources, numShaderSamplers, shaderSamplers, matrix); } static void D3D11_DrawPrimitives(SDL_Renderer *renderer, D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, const size_t vertexStart, const size_t vertexCount) @@ -2427,8 +2557,10 @@ static void D3D11_InvalidateCachedState(SDL_Renderer *renderer) data->currentRasterizerState = NULL; data->currentBlendState = NULL; data->currentShader = SHADER_NONE; + data->numCurrentShaderResources = 0; data->currentShaderResource = NULL; - data->currentSampler = NULL; + data->numCurrentShaderSamplers = 0; + data->currentShaderSampler = NULL; data->cliprectDirty = true; data->viewportDirty = true; } @@ -2507,7 +2639,7 @@ static bool D3D11_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd const size_t count = cmd->data.draw.count; const size_t first = cmd->data.draw.first; const size_t start = first / sizeof(D3D11_VertexPositionColor); - D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + D3D11_SetDrawState(renderer, cmd, NULL, 0, NULL, 0, NULL, NULL); D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start, count); break; } @@ -2518,7 +2650,7 @@ static bool D3D11_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd const size_t first = cmd->data.draw.first; const size_t start = first / sizeof(D3D11_VertexPositionColor); const D3D11_VertexPositionColor *verts = (D3D11_VertexPositionColor *)(((Uint8 *)vertices) + first); - D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + D3D11_SetDrawState(renderer, cmd, NULL, 0, NULL, 0, NULL, NULL); D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count); if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) { D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count - 1), 1); @@ -2545,7 +2677,7 @@ static bool D3D11_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd if (texture) { D3D11_SetCopyState(renderer, cmd, NULL); } else { - D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + D3D11_SetDrawState(renderer, cmd, NULL, 0, NULL, 0, NULL, NULL); } D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, start, count); @@ -2745,6 +2877,9 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL renderer->WindowEvent = D3D11_WindowEvent; renderer->SupportsBlendMode = D3D11_SupportsBlendMode; + renderer->CreatePalette = D3D11_CreatePalette; + renderer->UpdatePalette = D3D11_UpdatePalette; + renderer->DestroyPalette = D3D11_DestroyPalette; renderer->CreateTexture = D3D11_CreateTexture; renderer->UpdateTexture = D3D11_UpdateTexture; #ifdef SDL_HAVE_YUV @@ -2775,6 +2910,7 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); diff --git a/src/render/direct3d12/D3D12_PixelShader_Advanced.h b/src/render/direct3d12/D3D12_PixelShader_Advanced.h index 8c03218a26..c8a4a3f969 100644 --- a/src/render/direct3d12/D3D12_PixelShader_Advanced.h +++ b/src/render/direct3d12/D3D12_PixelShader_Advanced.h @@ -15,7 +15,7 @@ ; -------------------- ----- ------ -------- -------- ------- ------ ; SV_Target 0 xyzw 0 TARGET float xyzw ; -; shader hash: d37677952ab198af41892c76b2b3f57f +; shader hash: 4d23473de2445ea68fe5dad543ff9936 ; ; Pipeline Runtime Information: ; @@ -71,6 +71,7 @@ ; ------------------------------ ---------- ------- ----------- ------- -------------- ------ ; Constants cbuffer NA NA CB0 cb1 1 ; sampler0 sampler NA NA S0 s0 1 +; sampler1 sampler NA NA S1 s1 1 ; texture0 texture f32 2d T0 t0 1 ; texture1 texture f32 2d T1 t1 1 ; texture2 texture f32 2d T2 t2 1 @@ -101,584 +102,670 @@ define void @main() { %1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 2, i32 2, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) %2 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) %3 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) - %4 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 3, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) - %5 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) - %6 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %7 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %8 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %9 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 3, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %10 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %11 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) - %12 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %5, i32 0) ; CBufferLoadLegacy(handle,regIndex) - %13 = extractvalue %dx.types.CBufRet.f32 %12, 1 - %14 = fcmp fast oeq float %13, 0.000000e+00 - br i1 %14, label %175, label %15 + %4 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 3, i32 1, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %5 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 3, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %6 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %7 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %8 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %9 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %10 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 3, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %11 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %12 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %13 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %6, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %14 = extractvalue %dx.types.CBufRet.f32 %13, 1 + %15 = fcmp fast oeq float %14, 0.000000e+00 + br i1 %15, label %253, label %16 -;