diff --git a/Engine/lib/sdl/CMakeLists.txt b/Engine/lib/sdl/CMakeLists.txt index 59bacf0f5..644715aae 100644 --- a/Engine/lib/sdl/CMakeLists.txt +++ b/Engine/lib/sdl/CMakeLists.txt @@ -66,12 +66,12 @@ include(${SDL2_SOURCE_DIR}/cmake/sdlchecks.cmake) # set SDL_BINARY_AGE and SDL_INTERFACE_AGE to 0. set(SDL_MAJOR_VERSION 2) set(SDL_MINOR_VERSION 0) -set(SDL_MICRO_VERSION 21) -set(SDL_INTERFACE_AGE 3) -set(SDL_BINARY_AGE 21) +set(SDL_MICRO_VERSION 22) +set(SDL_INTERFACE_AGE 0) +set(SDL_BINARY_AGE 22) set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}") # the following should match the versions in Xcode project file: -set(DYLIB_CURRENT_VERSION 19.3.0) +set(DYLIB_CURRENT_VERSION 23.0.0) set(DYLIB_COMPATIBILITY_VERSION 1.0.0) # Set defaults preventing destination file conflicts @@ -372,6 +372,7 @@ endforeach() # Allow some projects to be built conditionally. set_option(SDL2_DISABLE_SDL2MAIN "Disable building/installation of SDL2main" OFF) +set_option(SDL2_DISABLE_INSTALL "Disable installation of SDL2" OFF) set_option(SDL2_DISABLE_UNINSTALL "Disable uninstallation of SDL2" OFF) option_string(SDL_ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto") @@ -1600,6 +1601,7 @@ elseif(WINDOWS) # headers needed elsewhere check_include_file(tpcshrd.h HAVE_TPCSHRD_H) + check_include_file(roapi.h HAVE_ROAPI_H) check_include_file(mmdeviceapi.h HAVE_MMDEVICEAPI_H) check_include_file(audioclient.h HAVE_AUDIOCLIENT_H) check_include_file(sensorsapi.h HAVE_SENSORSAPI_H) @@ -2279,6 +2281,11 @@ elseif(VITA) ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c) set(HAVE_SDL_THREADS TRUE) endif() + if(SDL_LOCALE) + file(GLOB LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/vita/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${LOCALE_SOURCES}) + set(HAVE_SDL_LOCALE TRUE) + endif() if(SDL_TIMERS) set(SDL_TIMER_VITA 1) file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/vita/*.c) @@ -2305,10 +2312,10 @@ elseif(VITA) list(APPEND EXTRA_LIBS pib ) - set(HAVE_VITA_PIB ON) + set(HAVE_VIDEO_VITA_PIB ON) set(SDL_VIDEO_VITA_PIB 1) else() - set(HAVE_VITA_PIB OFF) + set(HAVE_VIDEO_VITA_PIB OFF) endif() endif() @@ -2316,6 +2323,7 @@ elseif(VITA) check_include_file(gpu_es4/psp2_pvr_hint.h HAVE_PVR_H) if(HAVE_PVR_H) target_compile_definitions(sdl-build-options INTERFACE "-D__psp2__") + check_include_file(gl4esinit.h HAVE_GL4ES_H) set(SDL_VIDEO_OPENGL_EGL 1) set(HAVE_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES 1) @@ -2327,10 +2335,20 @@ elseif(VITA) libgpu_es4_ext_stub_weak libIMGEGL_stub_weak ) - set(HAVE_VITA_PVR ON) + + set(HAVE_VIDEO_VITA_PVR ON) set(SDL_VIDEO_VITA_PVR 1) + + if(HAVE_GL4ES_H) + set(HAVE_OPENGL TRUE) + set(SDL_VIDEO_OPENGL 1) + set(SDL_VIDEO_RENDER_OGL 1) + list(APPEND EXTRA_LIBS libGL_stub) + set(SDL_VIDEO_VITA_PVR_OGL 1) + endif() + else() - set(HAVE_VITA_PVR OFF) + set(HAVE_VIDEO_VITA_PVR OFF) endif() endif() @@ -2342,6 +2360,7 @@ elseif(VITA) SceCtrl_stub SceAppMgr_stub SceAudio_stub + SceAudioIn_stub SceSysmodule_stub SceDisplay_stub SceCtrl_stub @@ -2950,122 +2969,125 @@ if(SDL_TEST) endif() ##### Installation targets ##### -if(SDL_SHARED) - install(TARGETS SDL2 EXPORT SDL2Targets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() - -if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) - install(TARGETS SDL2main EXPORT SDL2mainTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() - -if(SDL_STATIC) - install(TARGETS SDL2-static EXPORT SDL2staticTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() - -##### Export files ##### -if (WINDOWS AND NOT MINGW) - set(PKG_PREFIX "cmake") -else () - set(PKG_PREFIX "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2") -endif () - -include(CMakePackageConfigHelpers) -write_basic_package_version_file("${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake" - VERSION ${SDL_VERSION} - COMPATIBILITY AnyNewerVersion -) - -if(SDL_SHARED) - install(EXPORT SDL2Targets - FILE SDL2Targets.cmake - NAMESPACE SDL2:: - DESTINATION ${PKG_PREFIX} - ) -endif() - -if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) - install(EXPORT SDL2mainTargets - FILE SDL2mainTargets.cmake - NAMESPACE SDL2:: - DESTINATION ${PKG_PREFIX} - ) -endif() - -if(SDL_STATIC) - install(EXPORT SDL2staticTargets - FILE SDL2staticTargets.cmake - NAMESPACE SDL2:: - DESTINATION ${PKG_PREFIX} - ) -endif() - -install( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake - ${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake - DESTINATION ${PKG_PREFIX} - COMPONENT Devel -) - -file(GLOB INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/*.h) -file(GLOB BIN_INCLUDE_FILES ${SDL2_BINARY_DIR}/include/*.h) -foreach(_FNAME ${BIN_INCLUDE_FILES}) - get_filename_component(_INCNAME ${_FNAME} NAME) - list(REMOVE_ITEM INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/${_INCNAME}) -endforeach() -list(APPEND INCLUDE_FILES ${BIN_INCLUDE_FILES}) -install(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SDL2) - -string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) -if (UPPER_BUILD_TYPE MATCHES DEBUG) - set(SOPOSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}") -else() - set(SOPOSTFIX "") -endif() - -if(NOT (WINDOWS OR CYGWIN) OR MINGW) +if(NOT SDL2_DISABLE_INSTALL) if(SDL_SHARED) - set(SOEXT ${CMAKE_SHARED_LIBRARY_SUFFIX}) # ".so", ".dylib", etc. - get_target_property(SONAME SDL2 OUTPUT_NAME) - if(NOT ANDROID AND NOT MINGW AND NOT OS2) - install(CODE " - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink - \"lib${SONAME}${SOPOSTFIX}${SOEXT}\" \"libSDL2${SOPOSTFIX}${SOEXT}\" - WORKING_DIRECTORY \"${SDL2_BINARY_DIR}\")") - install(FILES ${SDL2_BINARY_DIR}/libSDL2${SOPOSTFIX}${SOEXT} DESTINATION "${CMAKE_INSTALL_LIBDIR}") - endif() + install(TARGETS SDL2 EXPORT SDL2Targets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") endif() - if(FREEBSD) - # FreeBSD uses ${PREFIX}/libdata/pkgconfig - install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "libdata/pkgconfig") + + if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) + install(TARGETS SDL2main EXPORT SDL2mainTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() + + if(SDL_STATIC) + install(TARGETS SDL2-static EXPORT SDL2staticTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() + + ##### Export files ##### + if (WINDOWS AND NOT MINGW) + set(PKG_PREFIX "cmake") + else () + set(PKG_PREFIX "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2") + endif () + + include(CMakePackageConfigHelpers) + write_basic_package_version_file("${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake" + VERSION ${SDL_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + if(SDL_SHARED) + install(EXPORT SDL2Targets + FILE SDL2Targets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() + + if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) + install(EXPORT SDL2mainTargets + FILE SDL2mainTargets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() + + if(SDL_STATIC) + install(EXPORT SDL2staticTargets + FILE SDL2staticTargets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() + + install( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake + ${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake + DESTINATION ${PKG_PREFIX} + COMPONENT Devel + ) + + file(GLOB INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/*.h) + file(GLOB BIN_INCLUDE_FILES ${SDL2_BINARY_DIR}/include/*.h) + foreach(_FNAME ${BIN_INCLUDE_FILES}) + get_filename_component(_INCNAME ${_FNAME} NAME) + list(REMOVE_ITEM INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/${_INCNAME}) + endforeach() + list(APPEND INCLUDE_FILES ${BIN_INCLUDE_FILES}) + install(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SDL2) + + string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) + if (UPPER_BUILD_TYPE MATCHES DEBUG) + set(SOPOSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}") else() - install(FILES ${SDL2_BINARY_DIR}/sdl2.pc - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + set(SOPOSTFIX "") + endif() + + if(NOT (WINDOWS OR CYGWIN) OR MINGW) + if(SDL_SHARED) + set(SOEXT ${CMAKE_SHARED_LIBRARY_SUFFIX}) # ".so", ".dylib", etc. + get_target_property(SONAME SDL2 OUTPUT_NAME) + if(NOT ANDROID AND NOT MINGW AND NOT OS2) + install(CODE " + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink + \"lib${SONAME}${SOPOSTFIX}${SOEXT}\" \"libSDL2${SOPOSTFIX}${SOEXT}\" + WORKING_DIRECTORY \"${SDL2_BINARY_DIR}\")") + install(FILES ${SDL2_BINARY_DIR}/libSDL2${SOPOSTFIX}${SOEXT} DESTINATION "${CMAKE_INSTALL_LIBDIR}") + endif() + endif() + if(FREEBSD) + # FreeBSD uses ${PREFIX}/libdata/pkgconfig + install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "libdata/pkgconfig") + else() + install(FILES ${SDL2_BINARY_DIR}/sdl2.pc + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() + install(PROGRAMS ${SDL2_BINARY_DIR}/sdl2-config DESTINATION "${CMAKE_INSTALL_BINDIR}") + # TODO: what about the .spec file? Is it only needed for RPM creation? + install(FILES "${SDL2_SOURCE_DIR}/sdl2.m4" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/aclocal") endif() - install(PROGRAMS ${SDL2_BINARY_DIR}/sdl2-config DESTINATION "${CMAKE_INSTALL_BINDIR}") - # TODO: what about the .spec file? Is it only needed for RPM creation? - install(FILES "${SDL2_SOURCE_DIR}/sdl2.m4" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/aclocal") endif() ##### Uninstall target ##### if(NOT SDL2_DISABLE_UNINSTALL) -if(NOT TARGET uninstall) - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) + if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) - add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + endif() endif() -endif(NOT SDL2_DISABLE_UNINSTALL) + diff --git a/Engine/lib/sdl/Makefile.in b/Engine/lib/sdl/Makefile.in index 81c56fd3a..69f5cb1e2 100644 --- a/Engine/lib/sdl/Makefile.in +++ b/Engine/lib/sdl/Makefile.in @@ -19,6 +19,7 @@ distfile = $(distdir).tar.gz @SET_MAKE@ SHELL = @SHELL@ CC = @CC@ +CXX = @CXX@ INCLUDE = @INCLUDE@ CFLAGS = @BUILD_CFLAGS@ EXTRA_CFLAGS = @EXTRA_CFLAGS@ diff --git a/Engine/lib/sdl/Makefile.os2 b/Engine/lib/sdl/Makefile.os2 index eb34494c5..cfd0d6562 100644 --- a/Engine/lib/sdl/Makefile.os2 +++ b/Engine/lib/sdl/Makefile.os2 @@ -11,7 +11,7 @@ # wmake -f Makefile.os2 HIDAPI=1 LIBNAME = SDL2 -VERSION = 2.0.21 +VERSION = 2.0.22 DESCRIPTION = Simple DirectMedia Layer 2 LIBICONV=0 @@ -60,7 +60,7 @@ CFLAGS_DLL+= -DHAVE_LIBUSB_H=1 # building SDL itself (for DECLSPEC): CFLAGS_DLL+= -DBUILD_SDL -SRCS = SDL.c SDL_assert.c SDL_error.c SDL_log.c SDL_dataqueue.c SDL_hints.c +SRCS = SDL.c SDL_assert.c SDL_error.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c SRCS+= SDL_getenv.c SDL_iconv.c SDL_malloc.c SDL_qsort.c SDL_stdlib.c SDL_string.c SDL_strtokr.c SDL_crc32.c SRCS+= SDL_cpuinfo.c SDL_atomic.c SDL_spinlock.c SDL_thread.c SDL_timer.c SRCS+= SDL_rwops.c SDL_power.c @@ -140,9 +140,11 @@ SDL_blendpoint.obj: SDL_blendpoint.c wcc386 $(CFLAGS_DLL) -wcd=200 -fo=$^@ $< SDL_RLEaccel.obj: SDL_RLEaccel.c wcc386 $(CFLAGS_DLL) -wcd=201 -fo=$^@ $< +!ifeq HIDAPI 1 # c99 mode needed because of structs with flexible array members in libusb.h SDL_hidapi.obj: SDL_hidapi.c wcc386 $(CFLAGS_DLL) -za99 -fo=$^@ $< +!endif $(LIBICONV_LIB): "src/core/os2/iconv2.lbc" @echo * Creating: $@ diff --git a/Engine/lib/sdl/WhatsNew.txt b/Engine/lib/sdl/WhatsNew.txt index 33382ecea..fa6cbe11a 100644 --- a/Engine/lib/sdl/WhatsNew.txt +++ b/Engine/lib/sdl/WhatsNew.txt @@ -6,8 +6,38 @@ This is a list of major changes in SDL's version history. --------------------------------------------------------------------------- General: +* Added SDL_RenderGetWindow() to get the window associated with a renderer +* Added floating point rectangle functions: + * SDL_PointInFRect() + * SDL_FRectEmpty() + * SDL_FRectEquals() + * SDL_FRectEqualsEpsilon() + * SDL_HasIntersectionF() + * SDL_IntersectFRect() + * SDL_UnionFRect() + * SDL_EncloseFPoints() + * SDL_IntersectFRectAndLine() +* Added SDL_IsTextInputShown() which returns whether the IME window is currently shown +* Added SDL_ClearComposition() to dismiss the composition window without disabling IME input +* Added SDL_TEXTEDITING_EXT event for handling long composition text, and a hint SDL_HINT_IME_SUPPORT_EXTENDED_TEXT to enable it +* Added the hint SDL_HINT_MOUSE_RELATIVE_MODE_CENTER to control whether the mouse should be constrained to the whole window or the center of the window when relative mode is enabled +* The mouse is now automatically captured when mouse buttons are pressed, and the hint SDL_HINT_MOUSE_AUTO_CAPTURE allows you to control this behavior +* Added the hint SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL to let SDL know that a foreign window will be used with OpenGL +* Added the hint SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN to let SDL know that a foreign window will be used with Vulkan +* Added the hint SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE to specify whether an SDL_QUIT event will be delivered when the last application window is closed * Added the hint SDL_HINT_JOYSTICK_ROG_CHAKRAM to control whether ROG Chakram mice show up as joysticks +Windows: +* Added support for SDL_BLENDOPERATION_MINIMUM and SDL_BLENDOPERATION_MAXIMUM to the D3D9 renderer + +Linux: +* Compiling with Wayland support requires libwayland-client version 1.18.0 or later +* Added the hint SDL_HINT_X11_WINDOW_TYPE to specify the _NET_WM_WINDOW_TYPE of SDL windows +* Added the hint SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR to allow using libdecor with compositors that support xdg-decoration + +Android: +* Added SDL_AndroidSendMessage() to send a custom command to the SDL java activity + --------------------------------------------------------------------------- 2.0.20: diff --git a/Engine/lib/sdl/Xcode/SDL/Info-Framework.plist b/Engine/lib/sdl/Xcode/SDL/Info-Framework.plist index 19049bd46..49a711322 100644 --- a/Engine/lib/sdl/Xcode/SDL/Info-Framework.plist +++ b/Engine/lib/sdl/Xcode/SDL/Info-Framework.plist @@ -19,10 +19,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.21 + 2.0.22 CFBundleSignature SDLX CFBundleVersion - 2.0.21 + 2.0.22 diff --git a/Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj index cd8affb60..8858cfdd9 100644 --- a/Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -111,6 +111,24 @@ A1626A582617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; A1626A592617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; A1626A5A2617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; + A1BB8B6327F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6427F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6527F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6627F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6727F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6827F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6927F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6A27F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6B27F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6C27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6D27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6E27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6F27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7027F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7127F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7227F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7327F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7427F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; A7381E961D8B69D600B177DD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E951D8B69D600B177DD /* CoreAudio.framework */; }; A7381E971D8B6A0300B177DD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E931D8B69C300B177DD /* AudioToolbox.framework */; }; A75FCCFD23E25AB700529352 /* SDL_shaders_metal_tvos.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D8A8E323E2514000DCD162 /* SDL_shaders_metal_tvos.h */; }; @@ -3574,6 +3592,8 @@ 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = ""; }; A1626A3D2617006A003F1973 /* SDL_triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_triangle.c; sourceTree = ""; }; A1626A512617008C003F1973 /* SDL_triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_triangle.h; sourceTree = ""; }; + A1BB8B6127F6CF320057CFA8 /* SDL_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_list.c; sourceTree = ""; }; + A1BB8B6227F6CF330057CFA8 /* SDL_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_list.h; sourceTree = ""; }; A7381E931D8B69C300B177DD /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; A7381E951D8B69D600B177DD /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; A75FCEB323E25AB700529352 /* libSDL2.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libSDL2.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -4304,6 +4324,8 @@ A7D8A5AB23E2513D00DCD162 /* SDL_hints.c */, A7D8A58323E2513D00DCD162 /* SDL_internal.h */, A7D8A5DD23E2513D00DCD162 /* SDL_log.c */, + A1BB8B6127F6CF320057CFA8 /* SDL_list.c */, + A1BB8B6227F6CF330057CFA8 /* SDL_list.h */, A7D8A57123E2513D00DCD162 /* SDL.c */, ); name = "Library Source"; @@ -5284,6 +5306,7 @@ A75FCD4523E25AB700529352 /* SDL_gesture_c.h in Headers */, A75FCD4623E25AB700529352 /* SDL_shaders_gl.h in Headers */, A75FCD4723E25AB700529352 /* SDL_systhread_c.h in Headers */, + A1BB8B7327F6CF330057CFA8 /* SDL_list.h in Headers */, A75FCD4823E25AB700529352 /* SDL_keycode.h in Headers */, 5616CA63252BB35F005D5928 /* SDL_sysurl.h in Headers */, A75FCD4A23E25AB700529352 /* SDL_cocoakeyboard.h in Headers */, @@ -5509,6 +5532,7 @@ A75FCEFE23E25AC700529352 /* SDL_gesture_c.h in Headers */, A75FCEFF23E25AC700529352 /* SDL_shaders_gl.h in Headers */, A75FCF0023E25AC700529352 /* SDL_systhread_c.h in Headers */, + A1BB8B7427F6CF330057CFA8 /* SDL_list.h in Headers */, A75FCF0123E25AC700529352 /* SDL_keycode.h in Headers */, 5616CA66252BB361005D5928 /* SDL_sysurl.h in Headers */, A75FCF0323E25AC700529352 /* SDL_cocoakeyboard.h in Headers */, @@ -5707,6 +5731,7 @@ A769B0C623E259AE00872273 /* SDL_windowevents_c.h in Headers */, A769B0C823E259AE00872273 /* SDL_cocoavideo.h in Headers */, 5605721C2473688D00B46B66 /* SDL_syslocale.h in Headers */, + A1BB8B7127F6CF330057CFA8 /* SDL_list.h in Headers */, A769B0CA23E259AE00872273 /* SDL_uikitevents.h in Headers */, A769B0CB23E259AE00872273 /* SDL_gesture_c.h in Headers */, A769B0CC23E259AE00872273 /* SDL_shaders_gl.h in Headers */, @@ -5955,6 +5980,7 @@ A7D8A98E23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7423E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA5023E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6D27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98D23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99C23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A223E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6185,6 +6211,7 @@ A7D8A98F23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7523E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA5123E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6E27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98E23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99D23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A323E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6332,6 +6359,7 @@ A7D8BBAF23E2514500DCD162 /* SDL_windowevents_c.h in Headers */, A7D8AF0423E2514100DCD162 /* SDL_cocoavideo.h in Headers */, 5605721A2473688C00B46B66 /* SDL_syslocale.h in Headers */, + A1BB8B7027F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8ACC123E2514100DCD162 /* SDL_uikitevents.h in Headers */, A7D8BB3D23E2514500DCD162 /* SDL_gesture_c.h in Headers */, A7D8BA7723E2514400DCD162 /* SDL_shaders_gl.h in Headers */, @@ -6580,6 +6608,7 @@ A7D8A98D23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7323E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA4F23E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6C27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98C23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99B23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A123E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6796,6 +6825,7 @@ A7D8B29F23E2514200DCD162 /* vulkan_xlib.h in Headers */, A7D8B25D23E2514200DCD162 /* vulkan_vi.h in Headers */, A7D8B29923E2514200DCD162 /* vulkan_mir.h in Headers */, + A1BB8B6F27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8BB4E23E2514500DCD162 /* default_cursor.h in Headers */, A7D8B9FE23E2514400DCD162 /* SDL_render_sw_c.h in Headers */, A7D8BBED23E2574800DCD162 /* SDL_uikitappdelegate.h in Headers */, @@ -6918,6 +6948,7 @@ A7D8BB3E23E2514500DCD162 /* SDL_gesture_c.h in Headers */, A7D8BA7823E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8B42D23E2514300DCD162 /* SDL_systhread_c.h in Headers */, + A1BB8B7227F6CF330057CFA8 /* SDL_list.h in Headers */, DB313FDB17554B71006C0E22 /* SDL_keycode.h in Headers */, A7D8AE9323E2514100DCD162 /* SDL_cocoakeyboard.h in Headers */, A7D8ACE623E2514100DCD162 /* SDL_uikitvulkan.h in Headers */, @@ -7554,6 +7585,7 @@ A75FCE8423E25AB700529352 /* e_exp.c in Sources */, A75FCE8523E25AB700529352 /* SDL_quit.c in Sources */, A75FCE8623E25AB700529352 /* SDL_cocoawindow.m in Sources */, + A1BB8B6A27F6CF330057CFA8 /* SDL_list.c in Sources */, A75FCE8723E25AB700529352 /* SDL_sysmutex.c in Sources */, A75FCE8823E25AB700529352 /* SDL_syshaptic.c in Sources */, F3F07D61269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -7741,6 +7773,7 @@ A75FD03D23E25AC700529352 /* e_exp.c in Sources */, A75FD03E23E25AC700529352 /* SDL_quit.c in Sources */, A75FD03F23E25AC700529352 /* SDL_cocoawindow.m in Sources */, + A1BB8B6B27F6CF330057CFA8 /* SDL_list.c in Sources */, A75FD04023E25AC700529352 /* SDL_sysmutex.c in Sources */, A75FD04123E25AC700529352 /* SDL_syshaptic.c in Sources */, F3F07D62269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -7927,6 +7960,7 @@ A769B20F23E259AE00872273 /* SDL_syshaptic.c in Sources */, A769B21023E259AE00872273 /* e_exp.c in Sources */, F395C1A12569C68F00942BFF /* SDL_iokitjoystick.c in Sources */, + A1BB8B6827F6CF330057CFA8 /* SDL_list.c in Sources */, A769B21123E259AE00872273 /* SDL_quit.c in Sources */, A769B21223E259AE00872273 /* SDL_cocoawindow.m in Sources */, A769B21323E259AE00872273 /* SDL_sysmutex.c in Sources */, @@ -8116,6 +8150,7 @@ A7D8B43B23E2514300DCD162 /* SDL_sysmutex.c in Sources */, A7D8AAB123E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8B5CA23E2514300DCD162 /* SDL_rwopsbundlesupport.m in Sources */, + A1BB8B6427F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8AC1023E2514100DCD162 /* SDL_video.c in Sources */, 560572062473687700B46B66 /* SDL_syslocale.m in Sources */, F3F07D5B269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -8303,6 +8338,7 @@ A7D8B43C23E2514300DCD162 /* SDL_sysmutex.c in Sources */, A7D8AAB223E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8B5CB23E2514300DCD162 /* SDL_rwopsbundlesupport.m in Sources */, + A1BB8B6527F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8AC1123E2514100DCD162 /* SDL_video.c in Sources */, 560572072473687800B46B66 /* SDL_syslocale.m in Sources */, F3F07D5C269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -8489,6 +8525,7 @@ A7D8AADE23E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8BAE923E2514500DCD162 /* e_exp.c in Sources */, F395C1A02569C68F00942BFF /* SDL_iokitjoystick.c in Sources */, + A1BB8B6727F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8BB8523E2514500DCD162 /* SDL_quit.c in Sources */, A7D8AEAA23E2514100DCD162 /* SDL_cocoawindow.m in Sources */, A7D8B43E23E2514300DCD162 /* SDL_sysmutex.c in Sources */, @@ -8665,6 +8702,7 @@ A7D8B55123E2514300DCD162 /* SDL_hidapi_switch.c in Sources */, A7D8B96223E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7523E2514500DCD162 /* SDL_clipboardevents.c in Sources */, + A1BB8B6327F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8BAB523E2514400DCD162 /* k_cos.c in Sources */, A7D8B54523E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97423E2514400DCD162 /* SDL_malloc.c in Sources */, @@ -8850,6 +8888,7 @@ A7D8B96523E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7823E2514500DCD162 /* SDL_clipboardevents.c in Sources */, A7D8BAB823E2514400DCD162 /* k_cos.c in Sources */, + A1BB8B6627F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8B54823E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97723E2514400DCD162 /* SDL_malloc.c in Sources */, A7D8BBF023E2574800DCD162 /* SDL_uikitclipboard.m in Sources */, @@ -9035,6 +9074,7 @@ A7D8B96723E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7A23E2514500DCD162 /* SDL_clipboardevents.c in Sources */, A7D8BABA23E2514400DCD162 /* k_cos.c in Sources */, + A1BB8B6927F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8B54A23E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97923E2514400DCD162 /* SDL_malloc.c in Sources */, A7D8B8CB23E2514400DCD162 /* SDL_audio.c in Sources */, @@ -9111,7 +9151,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1.0.0; - DYLIB_CURRENT_VERSION = 19.3.0; + DYLIB_CURRENT_VERSION = 23.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_ALTIVEC_EXTENSIONS = YES; @@ -9195,7 +9235,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 1.0.0; - DYLIB_CURRENT_VERSION = 19.3.0; + DYLIB_CURRENT_VERSION = 23.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -9387,6 +9427,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_LINK_OBJC_RUNTIME = NO; + GCC_PREPROCESSOR_DEFINITIONS = GLES_SILENCE_DEPRECATION; GCC_SYMBOLS_PRIVATE_EXTERN = YES; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; @@ -9398,6 +9439,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_LINK_OBJC_RUNTIME = NO; + GCC_PREPROCESSOR_DEFINITIONS = GLES_SILENCE_DEPRECATION; GCC_SYMBOLS_PRIVATE_EXTERN = YES; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; diff --git a/Engine/lib/sdl/build-scripts/os2-buildbot.sh b/Engine/lib/sdl/build-scripts/os2-buildbot.sh deleted file mode 100644 index abe0350d0..000000000 --- a/Engine/lib/sdl/build-scripts/os2-buildbot.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# This is the script buildbot.libsdl.org uses to cross-compile SDL2 from -# x86 Linux to OS/2, using OpenWatcom. - -# The final zipfile can be unpacked on any machine that supports OpenWatcom -# (Windows, Linux, OS/2, etc). Point the compiler at the include directory -# and link against the SDL2.lib file. Ship the SDL2.dll with your app. - -if [ -z "$WATCOM" ]; then - echo "This script expects \$WATCOM to be set to the OpenWatcom install dir." 1>&2 - echo "This is often something like '/usr/local/share/watcom'" 1>&2 - exit 1 -fi -export PATH="$WATCOM/binl64:$PATH" - -ZIPFILE="$1" -if [ -z $1 ]; then - ZIPFILE=sdl-os2.zip -fi -ZIPDIR=buildbot/SDL - -set -e -set -x - -cd `dirname "$0"` -cd .. - -rm -f $ZIPFILE -wmake -f Makefile.os2 -rm -rf $ZIPDIR -mkdir -p $ZIPDIR -chmod 644 SDL2.dll SDL2.lib SDL2test.lib -mv SDL2.dll SDL2.lib SDL2test.lib $ZIPDIR/ -cp -R include $ZIPDIR/ -zip -9r "buildbot/$ZIPFILE" $ZIPDIR - -wmake -f Makefile.os2 distclean - -set +x -echo "All done. Final installable is in $ZIPFILE ..."; diff --git a/Engine/lib/sdl/build-scripts/winrtbuild.ps1 b/Engine/lib/sdl/build-scripts/winrtbuild.ps1 index 1da76abb1..892658014 100644 --- a/Engine/lib/sdl/build-scripts/winrtbuild.ps1 +++ b/Engine/lib/sdl/build-scripts/winrtbuild.ps1 @@ -39,7 +39,7 @@ # # Base version of SDL, used for packaging purposes -$SDLVersion = "2.0.21" +$SDLVersion = "2.0.22" # Gets the .bat file that sets up an MSBuild environment, given one of # Visual Studio's, "PlatformToolset"s. diff --git a/Engine/lib/sdl/cmake/sdlchecks.cmake b/Engine/lib/sdl/cmake/sdlchecks.cmake index c9feffb69..8dcb39265 100644 --- a/Engine/lib/sdl/cmake/sdlchecks.cmake +++ b/Engine/lib/sdl/cmake/sdlchecks.cmake @@ -632,7 +632,7 @@ endmacro() # - HAVE_SDL_LOADSO opt macro(CheckWayland) if(SDL_WAYLAND) - pkg_check_modules(WAYLAND wayland-client wayland-egl wayland-cursor egl "xkbcommon>=0.5.0") + pkg_check_modules(WAYLAND "wayland-client>=1.18" wayland-egl wayland-cursor egl "xkbcommon>=0.5.0") if(WAYLAND_FOUND) find_program(WAYLAND_SCANNER NAMES wayland-scanner REQUIRED) @@ -792,7 +792,9 @@ macro(CheckVivante) set(SDL_VIDEO_DRIVER_VIVANTE 1) if(HAVE_VIVANTE_VDK) set(SDL_VIDEO_DRIVER_VIVANTE_VDK 1) - list(APPEND EXTRA_LIBS VDK VIVANTE) + find_library(VIVANTE_LIBRARY REQUIRED NAMES VIVANTE vivante drm_vivante) + find_library(VIVANTE_VDK_LIBRARY VDK REQUIRED) + list(APPEND EXTRA_LIBS ${VIVANTE_LIBRARY} ${VIVANTE_VDK_LIBRARY}) else() set(SDL_CFLAGS "${SDL_CFLAGS} -DLINUX -DEGL_API_FB") list(APPEND EXTRA_LIBS EGL) diff --git a/Engine/lib/sdl/configure b/Engine/lib/sdl/configure index df73ab0cb..f3ea813eb 100755 --- a/Engine/lib/sdl/configure +++ b/Engine/lib/sdl/configure @@ -673,6 +673,8 @@ X_CFLAGS XMKMF RPI_LIBS RPI_CFLAGS +DECOR_LIBS +DECOR_CFLAGS FUSIONSOUND_LIBS FUSIONSOUND_CFLAGS ARTSCONFIG @@ -944,6 +946,8 @@ PULSEAUDIO_CFLAGS PULSEAUDIO_LIBS FUSIONSOUND_CFLAGS FUSIONSOUND_LIBS +DECOR_CFLAGS +DECOR_LIBS RPI_CFLAGS RPI_LIBS XMKMF @@ -1779,6 +1783,9 @@ Some influential environment variables: C compiler flags for FUSIONSOUND, overriding pkg-config FUSIONSOUND_LIBS linker flags for FUSIONSOUND, overriding pkg-config + DECOR_CFLAGS + C compiler flags for DECOR, overriding pkg-config + DECOR_LIBS linker flags for DECOR, overriding pkg-config RPI_CFLAGS C compiler flags for RPI, overriding pkg-config RPI_LIBS linker flags for RPI, overriding pkg-config XMKMF Path to xmkmf, Makefile generator for X Window System @@ -2859,9 +2866,9 @@ orig_CFLAGS="$CFLAGS" # SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=0 -SDL_MICRO_VERSION=21 -SDL_INTERFACE_AGE=3 -SDL_BINARY_AGE=21 +SDL_MICRO_VERSION=22 +SDL_INTERFACE_AGE=0 +SDL_BINARY_AGE=22 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION @@ -20572,7 +20579,7 @@ $as_echo_n "checking for Wayland support... " >&6; } video_wayland=no if test x$video_opengl_egl = xyes && \ test x$video_opengles_v2 = xyes; then - if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then + if $PKG_CONFIG --exists 'wayland-client >= 1.18' wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` @@ -20676,17 +20683,79 @@ else fi if test x$enable_libdecor = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdecor support" >&5 -$as_echo_n "checking for libdecor support... " >&6; } - if $PKG_CONFIG --exists libdecor-0; then : - video_libdecor=yes + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdecor-0" >&5 +$as_echo_n "checking for libdecor-0... " >&6; } + +if test -n "$DECOR_CFLAGS"; then + pkg_cv_DECOR_CFLAGS="$DECOR_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdecor-0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libdecor-0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DECOR_CFLAGS=`$PKG_CONFIG --cflags "libdecor-0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else - video_libdecor=no + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$DECOR_LIBS"; then + pkg_cv_DECOR_LIBS="$DECOR_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdecor-0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libdecor-0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DECOR_LIBS=`$PKG_CONFIG --libs "libdecor-0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + DECOR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdecor-0" 2>&1` + else + DECOR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdecor-0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$DECOR_PKG_ERRORS" >&5 + + video_libdecor=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + video_libdecor=no +else + DECOR_CFLAGS=$pkg_cv_DECOR_CFLAGS + DECOR_LIBS=$pkg_cv_DECOR_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + video_libdecor=yes fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $video_libdecor" >&5 -$as_echo "$video_libdecor" >&6; } if test x$video_libdecor = xyes; then - EXTRA_CFLAGS="$EXTRA_CFLAGS `$PKG_CONFIG --cflags libdecor-0`" + EXTRA_CFLAGS="$EXTRA_CFLAGS $DECOR_CFLAGS" $as_echo "#define HAVE_LIBDECOR_H 1" >>confdefs.h @@ -20699,18 +20768,16 @@ else fi + decor_lib=`find_lib "libdecor-0.so.*" "$DECOR_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` + if test x$enable_wayland_shared != xyes; then enable_libdecor_shared=no fi - - decor_lib=`find_lib "libdecor-0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'` - if test x$have_loadso != xyes && \ test x$enable_libdecor_shared = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You must have SDL_LoadObject() support for dynamic libdecor loading" >&5 $as_echo "$as_me: WARNING: You must have SDL_LoadObject() support for dynamic libdecor loading" >&2;} fi - if test x$have_loadso = xyes && \ test x$enable_libdecor_shared = xyes && test x$decor_lib != x; then echo "-- dynamic libdecor -> $decor_lib" @@ -20720,7 +20787,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF else - EXTRA_LDFLAGS="$EXTRA_LDFLAGS `$PKG_CONFIG --libs libdecor-0`" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS $DECOR_LIBS" fi fi fi @@ -24712,6 +24779,30 @@ $as_echo "$have_wince" >&6; } # This fixes Windows stack alignment with newer GCC CheckStackBoundary + + # headers needed elsewhere + ac_fn_c_check_header_mongrel "$LINENO" "tpcshrd.h" "ac_cv_header_tpcshrd_h" "$ac_includes_default" +if test "x$ac_cv_header_tpcshrd_h" = xyes; then : + have_tpcshrd_h=yes +fi + + + if test x$have_tpcshrd_h = xyes; then + +$as_echo "#define HAVE_TPCSHRD_H 1" >>confdefs.h + + fi + ac_fn_c_check_header_mongrel "$LINENO" "roapi.h" "ac_cv_header_roapi_h" "$ac_includes_default" +if test "x$ac_cv_header_roapi_h" = xyes; then : + have_roapi_h=yes +fi + + + if test x$have_roapi_h = xyes; then + +$as_echo "#define HAVE_ROAPI_H 1" >>confdefs.h + + fi } CheckOS2() @@ -26188,17 +26279,6 @@ $as_echo "#define SDL_HAPTIC_DINPUT 1" >>confdefs.h have_haptic=yes fi fi - ac_fn_c_check_header_mongrel "$LINENO" "tpcshrd.h" "ac_cv_header_tpcshrd_h" "$ac_includes_default" -if test "x$ac_cv_header_tpcshrd_h" = xyes; then : - have_tpcshrd_h=yes -fi - - - if test x$have_tpcshrd_h = xyes; then - -$as_echo "#define HAVE_TPCSHRD_H 1" >>confdefs.h - - fi # Set up files for the sensor library ac_fn_c_check_header_mongrel "$LINENO" "sensorsapi.h" "ac_cv_header_sensorsapi_h" "$ac_includes_default" if test "x$ac_cv_header_sensorsapi_h" = xyes; then : diff --git a/Engine/lib/sdl/configure.ac b/Engine/lib/sdl/configure.ac index 28d620d94..2209c04d7 100644 --- a/Engine/lib/sdl/configure.ac +++ b/Engine/lib/sdl/configure.ac @@ -22,9 +22,9 @@ dnl Set various version strings - taken gratefully from the GTk sources # SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=0 -SDL_MICRO_VERSION=21 -SDL_INTERFACE_AGE=3 -SDL_BINARY_AGE=21 +SDL_MICRO_VERSION=22 +SDL_INTERFACE_AGE=0 +SDL_BINARY_AGE=22 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION AC_SUBST(SDL_MAJOR_VERSION) @@ -1555,7 +1555,7 @@ CheckWayland() video_wayland=no if test x$video_opengl_egl = xyes && \ test x$video_opengles_v2 = xyes; then - if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then + if $PKG_CONFIG --exists 'wayland-client >= 1.18' wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` @@ -1626,39 +1626,31 @@ dnl FIXME: Do BSD and OS X need special cases? dnl See if libdecor is available AC_ARG_ENABLE(libdecor, -[AS_HELP_STRING([--enable-libdecor], [use libdecor for Wayland client-side decorations [default=yes]])], - , enable_libdecor=yes) +[AS_HELP_STRING([--enable-libdecor], [use libdecor for Wayland client-side decorations [default=yes]])],, enable_libdecor=yes) if test x$enable_libdecor = xyes; then - AC_MSG_CHECKING(for libdecor support) - AS_IF([$PKG_CONFIG --exists libdecor-0], - [video_libdecor=yes], - [video_libdecor=no]) - AC_MSG_RESULT($video_libdecor) + PKG_CHECK_MODULES([DECOR], [libdecor-0], video_libdecor=yes, video_libdecor=no) if test x$video_libdecor = xyes; then - EXTRA_CFLAGS="$EXTRA_CFLAGS `$PKG_CONFIG --cflags libdecor-0`" + EXTRA_CFLAGS="$EXTRA_CFLAGS $DECOR_CFLAGS" AC_DEFINE(HAVE_LIBDECOR_H, 1, [ ]) AC_ARG_ENABLE(libdecor-shared, -[AS_HELP_STRING([--enable-libdecor-shared], [dynamically load libdecor [default=yes]])], - , enable_libdecor_shared=yes) +[AS_HELP_STRING([--enable-libdecor-shared], [dynamically load libdecor [default=yes]])],, enable_libdecor_shared=yes) + + decor_lib=[`find_lib "libdecor-0.so.*" "$DECOR_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] if test x$enable_wayland_shared != xyes; then enable_libdecor_shared=no fi - - decor_lib=[`find_lib "libdecor-0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'`] - if test x$have_loadso != xyes && \ test x$enable_libdecor_shared = xyes; then AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic libdecor loading]) fi - if test x$have_loadso = xyes && \ test x$enable_libdecor_shared = xyes && test x$decor_lib != x; then echo "-- dynamic libdecor -> $decor_lib" AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR, "$decor_lib", [ ]) else - EXTRA_LDFLAGS="$EXTRA_LDFLAGS `$PKG_CONFIG --libs libdecor-0`" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS $DECOR_LIBS" fi fi fi @@ -3206,6 +3198,16 @@ CheckWINDOWS() # This fixes Windows stack alignment with newer GCC CheckStackBoundary + + # headers needed elsewhere + AC_CHECK_HEADER(tpcshrd.h,have_tpcshrd_h=yes) + if test x$have_tpcshrd_h = xyes; then + AC_DEFINE(HAVE_TPCSHRD_H, 1, [ ]) + fi + AC_CHECK_HEADER(roapi.h,have_roapi_h=yes) + if test x$have_roapi_h = xyes; then + AC_DEFINE(HAVE_ROAPI_H, 1, [ ]) + fi } dnl Determine whether the compiler can produce OS/2 executables @@ -4007,10 +4009,6 @@ case "$host" in have_haptic=yes fi fi - AC_CHECK_HEADER(tpcshrd.h,have_tpcshrd_h=yes) - if test x$have_tpcshrd_h = xyes; then - AC_DEFINE(HAVE_TPCSHRD_H, 1, [ ]) - fi # Set up files for the sensor library AC_CHECK_HEADER(sensorsapi.h,have_winsensors=yes,have_winsensors=no) if test x$have_winsensors = xyes; then diff --git a/Engine/lib/sdl/docs/README-directfb.md b/Engine/lib/sdl/docs/README-directfb.md index 67b64fb61..6672fa40e 100644 --- a/Engine/lib/sdl/docs/README-directfb.md +++ b/Engine/lib/sdl/docs/README-directfb.md @@ -15,29 +15,34 @@ What you need: * Kernel-Framebuffer support: required: vesafb, radeonfb .... * Mesa 7.0.x - optional for OpenGL -/etc/directfbrc - -This file should contain the following lines to make +The `/etc/directfbrc` file should contain the following lines to make your joystick work and avoid crashes: ------------------------- + +``` disable-module=joystick disable-module=cle266 disable-module=cyber5k no-linux-input-grab ------------------------- +``` To disable to use x11 backend when DISPLAY variable is found use +``` export SDL_DIRECTFB_X11_CHECK=0 +``` To disable the use of linux input devices, i.e. multimice/multikeyboard support, use +``` export SDL_DIRECTFB_LINUX_INPUT=0 +``` To use hardware accelerated YUV-overlays for YUV-textures, use: +``` export SDL_DIRECTFB_YUV_DIRECT=1 +``` This is disabled by default. It will only support one YUV texture, namely the first. Every other YUV texture will be @@ -45,7 +50,9 @@ rendered in software. In addition, you may use (directfb-1.2.x) +``` export SDL_DIRECTFB_YUV_UNDERLAY=1 +``` to make the YUV texture an underlay. This will make the cursor to be shown. @@ -54,14 +61,18 @@ Simple Window Manager ===================== The driver has support for a very, very basic window manager you may -want to use when running with "wm=default". Use +want to use when running with `wm=default`. Use +``` export SDL_DIRECTFB_WM=1 +``` to enable basic window borders. In order to have the window title rendered, you need to have the following font installed: +``` /usr/share/fonts/truetype/freefont/FreeSans.ttf +``` OpenGL Support ============== @@ -71,21 +82,25 @@ works at least on all directfb supported platforms. As of this writing 20100802 you need to pull Mesa from git and do the following: ------------------------- +``` git clone git://anongit.freedesktop.org/git/mesa/mesa cd mesa git checkout 2c9fdaf7292423c157fc79b5ce43f0f199dd753a ------------------------- +``` -Edit configs/linux-directfb so that the Directories-section looks like ------------------------- +Edit `configs/linux-directfb` so that the Directories-section looks like this: + +``` # Directories SRC_DIRS = mesa glu GLU_DIRS = sgi DRIVER_DIRS = directfb PROGRAM_DIRS = ------------------------- +``` +Then do the following: + +``` make linux-directfb make @@ -95,13 +110,14 @@ sudo make install INSTALL_DIR=/usr/local/dfb_GL cd src/mesa/drivers/directfb make sudo make install INSTALL_DIR=/usr/local/dfb_GL ------------------------- +``` To run the SDL - testprograms: +``` export SDL_VIDEODRIVER=directfb export LD_LIBRARY_PATH=/usr/local/dfb_GL/lib export LD_PRELOAD=/usr/local/dfb_GL/libGL.so.7 ./testgl - +``` diff --git a/Engine/lib/sdl/docs/README-visualc.md b/Engine/lib/sdl/docs/README-visualc.md index ea2bc1852..759752a56 100644 --- a/Engine/lib/sdl/docs/README-visualc.md +++ b/Engine/lib/sdl/docs/README-visualc.md @@ -1,7 +1,7 @@ Using SDL with Microsoft Visual C++ =================================== -### by [Lion Kimbro](mailto:snowlion@sprynet.com) with additions by [James Turk](mailto:james@conceptofzero.net) +### by Lion Kimbro with additions by James Turk You can either use the precompiled libraries from the [SDL](https://www.libsdl.org/download.php) web site, or you can build SDL yourself. diff --git a/Engine/lib/sdl/docs/README-vita.md b/Engine/lib/sdl/docs/README-vita.md index 535b4034c..503fef7d5 100644 --- a/Engine/lib/sdl/docs/README-vita.md +++ b/Engine/lib/sdl/docs/README-vita.md @@ -22,6 +22,9 @@ Notes * gles1/gles2 support and renderers are disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PVR=ON` These renderers support 720p and 1080i resolutions. These can be specified with: `SDL_setenv("VITA_RESOLUTION", "720", 1);` and `SDL_setenv("VITA_RESOLUTION", "1080", 1);` +* Desktop GL 1.X and 2.X support and renderers are also disabled by default and also can be enabled with `-DVIDEO_VITA_PVR=ON` as long as gl4es4vita is present in your SDK. + They support the same resolutions as the gles1/gles2 backends and require specifying `SDL_setenv("VITA_PVR_OGL", "1", 1);` + anytime before video subsystem initialization. * gles2 support via PIB is disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PIB=ON` * By default SDL emits mouse events for touch events on every touchscreen. Vita has two touchscreens, so it's recommended to use `SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");` and handle touch events instead. diff --git a/Engine/lib/sdl/docs/README-windows.md b/Engine/lib/sdl/docs/README-windows.md index 71f968eeb..ed0c93e2c 100644 --- a/Engine/lib/sdl/docs/README-windows.md +++ b/Engine/lib/sdl/docs/README-windows.md @@ -1,45 +1,58 @@ -Windows -================================================================================ +# Windows -================================================================================ -OpenGL ES 2.x support -================================================================================ +## LLVM and Intel C++ compiler support -SDL has support for OpenGL ES 2.x under Windows via two alternative -implementations. -The most straightforward method consists in running your app in a system with -a graphic card paired with a relatively recent (as of November of 2013) driver -which supports the WGL_EXT_create_context_es2_profile extension. Vendors known +SDL will build with the Visual Studio project files with LLVM-based compilers, such as the Intel oneAPI C++ +compiler, but you'll have to manually add the "-msse3" command line option +to at least the SDL_audiocvt.c source file, and possibly others. This may +not be necessary if you build SDL with CMake instead of the included Visual +Studio solution. + +Details are here: https://github.com/libsdl-org/SDL/issues/5186 + + +## OpenGL ES 2.x support + +SDL has support for OpenGL ES 2.x under Windows via two alternative +implementations. + +The most straightforward method consists in running your app in a system with +a graphic card paired with a relatively recent (as of November of 2013) driver +which supports the WGL_EXT_create_context_es2_profile extension. Vendors known to ship said extension on Windows currently include nVidia and Intel. -The other method involves using the ANGLE library (https://code.google.com/p/angleproject/) -If an OpenGL ES 2.x context is requested and no WGL_EXT_create_context_es2_profile -extension is found, SDL will try to load the libEGL.dll library provided by -ANGLE. +The other method involves using the +[ANGLE library](https://code.google.com/p/angleproject/). If an OpenGL ES 2.x +context is requested and no WGL_EXT_create_context_es2_profile extension is +found, SDL will try to load the libEGL.dll library provided by ANGLE. + To obtain the ANGLE binaries, you can either compile from source from -https://chromium.googlesource.com/angle/angle or copy the relevant binaries from -a recent Chrome/Chromium install for Windows. The files you need are: - - * libEGL.dll - * libGLESv2.dll - * d3dcompiler_46.dll (supports Windows Vista or later, better shader compiler) - or... - * d3dcompiler_43.dll (supports Windows XP or later) +https://chromium.googlesource.com/angle/angle or copy the relevant binaries +from a recent Chrome/Chromium install for Windows. The files you need are: + +- libEGL.dll +- libGLESv2.dll +- d3dcompiler_46.dll (supports Windows Vista or later, better shader + compiler) *or* d3dcompiler_43.dll (supports Windows XP or later) If you compile ANGLE from source, you can configure it so it does not need the -d3dcompiler_* DLL at all (for details on this, see their documentation). +d3dcompiler_* DLL at all (for details on this, see their documentation). However, by default SDL will try to preload the d3dcompiler_46.dll to -comply with ANGLE's requirements. If you wish SDL to preload d3dcompiler_43.dll (to -support Windows XP) or to skip this step at all, you can use the -SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more details). +comply with ANGLE's requirements. If you wish SDL to preload +d3dcompiler_43.dll (to support Windows XP) or to skip this step at all, you +can use the SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more +details). Known Bugs: - - * SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears - that there's a bug in the library which prevents the window contents from - refreshing if this is set to anything other than the default value. - -Vulkan Surface Support -============== -Support for creating Vulkan surfaces is configured on by default. To disable it change the value of `SDL_VIDEO_VULKAN` to 0 in `SDL_config_windows.h`. You must install the [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) in order to use Vulkan graphics in your application. +- SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears + that there's a bug in the library which prevents the window contents from + refreshing if this is set to anything other than the default value. + +## Vulkan Surface Support + +Support for creating Vulkan surfaces is configured on by default. To disable +it change the value of `SDL_VIDEO_VULKAN` to 0 in `SDL_config_windows.h`. You +must install the [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) in order to +use Vulkan graphics in your application. + diff --git a/Engine/lib/sdl/include/SDL_blendmode.h b/Engine/lib/sdl/include/SDL_blendmode.h index b6d140dbb..08c9f9dd6 100644 --- a/Engine/lib/sdl/include/SDL_blendmode.h +++ b/Engine/lib/sdl/include/SDL_blendmode.h @@ -67,9 +67,8 @@ typedef enum SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */ SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */ SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */ - SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D11 */ - SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D11 */ - + SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D9, D3D11 */ + SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D9, D3D11 */ } SDL_BlendOperation; /** @@ -87,7 +86,6 @@ typedef enum SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */ SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */ SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */ - } SDL_BlendFactor; /** @@ -135,10 +133,10 @@ typedef enum * SDL 2.0.6. All renderers support the four blend modes listed in the * SDL_BlendMode enumeration. * - * - **direct3d**: Supports `SDL_BLENDOPERATION_ADD` with all factors. - * - **direct3d11**: Supports all operations with all factors. However, some + * - **direct3d**: Supports all operations with all factors. However, some * factors produce unexpected results with `SDL_BLENDOPERATION_MINIMUM` and * `SDL_BLENDOPERATION_MAXIMUM`. + * - **direct3d11**: Same as Direct3D 9. * - **opengl**: Supports the `SDL_BLENDOPERATION_ADD` operation with all * factors. OpenGL versions 1.1, 1.2, and 1.3 do not work correctly with SDL * 2.0.6. diff --git a/Engine/lib/sdl/include/SDL_config.h.cmake b/Engine/lib/sdl/include/SDL_config.h.cmake index 9a1bf6758..fcd18e57d 100644 --- a/Engine/lib/sdl/include/SDL_config.h.cmake +++ b/Engine/lib/sdl/include/SDL_config.h.cmake @@ -253,6 +253,7 @@ #cmakedefine HAVE_AUDIOCLIENT_H @HAVE_AUDIOCLIENT_H@ #cmakedefine HAVE_TPCSHRD_H @HAVE_TPCSHRD_H@ #cmakedefine HAVE_SENSORSAPI_H @HAVE_SENSORSAPI_H@ +#cmakedefine HAVE_ROAPI_H @HAVE_ROAPI_H@ #cmakedefine HAVE_XINPUT_GAMEPAD_EX @HAVE_XINPUT_GAMEPAD_EX@ #cmakedefine HAVE_XINPUT_STATE_EX @HAVE_XINPUT_STATE_EX@ @@ -520,6 +521,7 @@ #cmakedefine SDL_VIDEO_VITA_PIB @SDL_VIDEO_VITA_PIB@ #cmakedefine SDL_VIDEO_VITA_PVR @SDL_VIDEO_VITA_PVR@ +#cmakedefine SDL_VIDEO_VITA_PVR_OGL @SDL_VIDEO_VITA_PVR_OGL@ #if !defined(__WIN32__) && !defined(__WINRT__) # if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H) diff --git a/Engine/lib/sdl/include/SDL_config.h.in b/Engine/lib/sdl/include/SDL_config.h.in index 195b9887e..f912e4112 100644 --- a/Engine/lib/sdl/include/SDL_config.h.in +++ b/Engine/lib/sdl/include/SDL_config.h.in @@ -242,6 +242,7 @@ #undef HAVE_AUDIOCLIENT_H #undef HAVE_TPCSHRD_H #undef HAVE_SENSORSAPI_H +#undef HAVE_ROAPI_H /* SDL internal assertion support */ #undef SDL_DEFAULT_ASSERT_LEVEL diff --git a/Engine/lib/sdl/include/SDL_config_emscripten.h b/Engine/lib/sdl/include/SDL_config_emscripten.h index 7efe32373..028777df1 100644 --- a/Engine/lib/sdl/include/SDL_config_emscripten.h +++ b/Engine/lib/sdl/include/SDL_config_emscripten.h @@ -185,6 +185,7 @@ /* Enable various threading systems */ #ifdef __EMSCRIPTEN_PTHREADS__ #define SDL_THREAD_PTHREAD 1 +#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1 #endif /* Enable various timer systems */ diff --git a/Engine/lib/sdl/include/SDL_config_windows.h b/Engine/lib/sdl/include/SDL_config_windows.h index efb246da9..770b19039 100644 --- a/Engine/lib/sdl/include/SDL_config_windows.h +++ b/Engine/lib/sdl/include/SDL_config_windows.h @@ -104,6 +104,7 @@ typedef unsigned int uintptr_t; #endif #if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0602 /* Windows 8 SDK */ #define HAVE_D3D11_H 1 +#define HAVE_ROAPI_H 1 #endif #define HAVE_MMDEVICEAPI_H 1 #define HAVE_AUDIOCLIENT_H 1 diff --git a/Engine/lib/sdl/include/SDL_config_winrt.h b/Engine/lib/sdl/include/SDL_config_winrt.h index c548fd695..f3901a597 100644 --- a/Engine/lib/sdl/include/SDL_config_winrt.h +++ b/Engine/lib/sdl/include/SDL_config_winrt.h @@ -195,6 +195,8 @@ typedef unsigned int uintptr_t; #define HAVE_TRUNCF 1 #define HAVE__FSEEKI64 1 +#define HAVE_ROAPI_H 1 + /* Enable various audio drivers */ #define SDL_AUDIO_DRIVER_WASAPI 1 #define SDL_AUDIO_DRIVER_DISK 1 diff --git a/Engine/lib/sdl/include/SDL_hints.h b/Engine/lib/sdl/include/SDL_hints.h index 133f68769..ea819c85d 100644 --- a/Engine/lib/sdl/include/SDL_hints.h +++ b/Engine/lib/sdl/include/SDL_hints.h @@ -1354,6 +1354,18 @@ extern "C" { */ #define SDL_HINT_TOUCH_MOUSE_EVENTS "SDL_TOUCH_MOUSE_EVENTS" +/** + * \brief A variable controlling which touchpad should generate synthetic mouse events + * + * This variable can be set to the following values: + * "0" - Only front touchpad should generate mouse events. Default + * "1" - Only back touchpad should generate mouse events. + * "2" - Both touchpads should generate mouse events. + * + * By default SDL will generate mouse events for all touch devices + */ +#define SDL_HINT_VITA_TOUCH_MOUSE_DEVICE "SDL_HINT_VITA_TOUCH_MOUSE_DEVICE" + /** * \brief A variable controlling whether the Android / tvOS remotes * should be listed as joystick devices, instead of sending keyboard events. @@ -1463,6 +1475,20 @@ extern "C" { */ #define SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR "SDL_VIDEO_WAYLAND_ALLOW_LIBDECOR" +/** + * \brief A variable controlling whether the libdecor Wayland backend is preferred over native decrations. + * + * When this hint is set, libdecor will be used to provide window decorations, even if xdg-decoration is + * available. (Note that, by default, libdecor will use xdg-decoration itself if available). + * + * This variable can be set to the following values: + * "0" - libdecor is enabled only if server-side decorations are unavailable. + * "1" - libdecor is always enabled if available. + * + * libdecor is used over xdg-shell when xdg-decoration protocol is unavailable. + */ +#define SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR "SDL_VIDEO_WAYLAND_PREFER_LIBDECOR" + /** * \brief A variable that is the address of another SDL_Window* (as a hex string formatted with "%p"). * @@ -1938,8 +1964,7 @@ extern "C" { * If not set or set to "", this hint is ignored. This hint must be set * before the SDL_CreateWindow() call that it is intended to affect. * - * This hint is available since SDL 2.0.22. Before then, virtual devices are - * always ignored. + * This hint is available since SDL 2.0.22. */ #define SDL_HINT_X11_WINDOW_TYPE "SDL_X11_WINDOW_TYPE" @@ -1968,6 +1993,53 @@ extern "C" { #define SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE "SDL_QUIT_ON_LAST_WINDOW_CLOSE" +/** + * \brief A variable that decides what video backend to use. + * + * By default, SDL will try all available video backends in a reasonable + * order until it finds one that can work, but this hint allows the app + * or user to force a specific target, such as "x11" if, say, you are + * on Wayland but want to try talking to the X server instead. + * + * This functionality has existed since SDL 2.0.0 (indeed, before that) + * but before 2.0.22 this was an environment variable only. In 2.0.22, + * it was upgraded to a full SDL hint, so you can set the environment + * variable as usual or programatically set the hint with SDL_SetHint, + * which won't propagate to child processes. + * + * The default value is unset, in which case SDL will try to figure out + * the best video backend on your behalf. This hint needs to be set + * before SDL_Init() is called to be useful. + * + * This hint is available since SDL 2.0.22. Before then, you could set + * the environment variable to get the same effect. + */ +#define SDL_HINT_VIDEODRIVER "SDL_VIDEODRIVER" + +/** + * \brief A variable that decides what audio backend to use. + * + * By default, SDL will try all available audio backends in a reasonable + * order until it finds one that can work, but this hint allows the app + * or user to force a specific target, such as "alsa" if, say, you are + * on PulseAudio but want to try talking to the lower level instead. + * + * This functionality has existed since SDL 2.0.0 (indeed, before that) + * but before 2.0.22 this was an environment variable only. In 2.0.22, + * it was upgraded to a full SDL hint, so you can set the environment + * variable as usual or programatically set the hint with SDL_SetHint, + * which won't propagate to child processes. + * + * The default value is unset, in which case SDL will try to figure out + * the best audio backend on your behalf. This hint needs to be set + * before SDL_Init() is called to be useful. + * + * This hint is available since SDL 2.0.22. Before then, you could set + * the environment variable to get the same effect. + */ +#define SDL_HINT_AUDIODRIVER "SDL_AUDIODRIVER" + + /** * \brief An enumeration of hint priorities */ diff --git a/Engine/lib/sdl/include/SDL_metal.h b/Engine/lib/sdl/include/SDL_metal.h index 9ecaa8151..eb3082879 100644 --- a/Engine/lib/sdl/include/SDL_metal.h +++ b/Engine/lib/sdl/include/SDL_metal.h @@ -92,6 +92,7 @@ extern DECLSPEC void *SDLCALL SDL_Metal_GetLayer(SDL_MetalView view); * * \param window SDL_Window from which the drawable size should be queried * \param w Pointer to variable for storing the width in pixels, may be NULL + * \param h Pointer to variable for storing the height in pixels, may be NULL * * \since This function is available since SDL 2.0.14. * diff --git a/Engine/lib/sdl/include/SDL_rect.h b/Engine/lib/sdl/include/SDL_rect.h index 55a6473f2..b678c7a34 100644 --- a/Engine/lib/sdl/include/SDL_rect.h +++ b/Engine/lib/sdl/include/SDL_rect.h @@ -54,11 +54,6 @@ typedef struct SDL_Point /** * The structure that defines a point (floating point) * - * \sa SDL_FRectEmpty - * \sa SDL_FRectEquals - * \sa SDL_HasIntersectionF - * \sa SDL_IntersectFRect - * \sa SDL_UnionFRect * \sa SDL_EncloseFPoints * \sa SDL_PointInFRect */ @@ -76,6 +71,7 @@ typedef struct SDL_FPoint * \sa SDL_RectEquals * \sa SDL_HasIntersection * \sa SDL_IntersectRect + * \sa SDL_IntersectRectAndLine * \sa SDL_UnionRect * \sa SDL_EnclosePoints */ @@ -88,6 +84,16 @@ typedef struct SDL_Rect /** * A rectangle, with the origin at the upper left (floating point). + * + * \sa SDL_FRectEmpty + * \sa SDL_FRectEquals + * \sa SDL_FRectEqualsEpsilon + * \sa SDL_HasIntersectionF + * \sa SDL_IntersectFRect + * \sa SDL_IntersectFRectAndLine + * \sa SDL_UnionFRect + * \sa SDL_EncloseFPoints + * \sa SDL_PointInFRect */ typedef struct SDL_FRect { @@ -239,12 +245,28 @@ SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r) } /** - * Returns true if the two rectangles are equal. + * Returns true if the two rectangles are equal, within some given epsilon. + * + * \since This function is available since SDL 2.0.22. + */ +SDL_FORCE_INLINE SDL_bool SDL_FRectEqualsEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon) +{ + return (a && b && ((a == b) || + ((SDL_fabs(a->x - b->x) <= epsilon) && + (SDL_fabs(a->y - b->y) <= epsilon) && + (SDL_fabs(a->w - b->w) <= epsilon) && + (SDL_fabs(a->h - b->h) <= epsilon)))) + ? SDL_TRUE : SDL_FALSE; +} + +/** + * Returns true if the two rectangles are equal, using a default epsilon. + * + * \since This function is available since SDL 2.0.22. */ SDL_FORCE_INLINE SDL_bool SDL_FRectEquals(const SDL_FRect *a, const SDL_FRect *b) { - return (a && b && (a->x == b->x) && (a->y == b->y) && - (a->w == b->w) && (a->h == b->h)) ? SDL_TRUE : SDL_FALSE; + return SDL_FRectEqualsEpsilon(a, b, SDL_FLT_EPSILON); } /** diff --git a/Engine/lib/sdl/include/SDL_render.h b/Engine/lib/sdl/include/SDL_render.h index 88620336b..d859e3fd6 100644 --- a/Engine/lib/sdl/include/SDL_render.h +++ b/Engine/lib/sdl/include/SDL_render.h @@ -261,6 +261,17 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateSoftwareRenderer(SDL_Surface * */ extern DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window * window); +/** + * Get the window associated with a renderer. + * + * \param renderer the renderer to query + * \returns the window on success or NULL on failure; call SDL_GetError() for + * more information. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC SDL_Window * SDLCALL SDL_RenderGetWindow(SDL_Renderer *renderer); + /** * Get information about a rendering context. * @@ -1607,6 +1618,7 @@ extern DECLSPEC int SDLCALL SDL_RenderCopyExF(SDL_Renderer * renderer, * vertex array Color and alpha modulation is done per vertex * (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored). * + * \param renderer The rendering context. * \param texture (optional) The SDL texture to use. * \param vertices Vertices. * \param num_vertices Number of vertices. @@ -1631,6 +1643,7 @@ extern DECLSPEC int SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, * vertex arrays Color and alpha modulation is done per vertex * (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored). * + * \param renderer The rendering context. * \param texture (optional) The SDL texture to use. * \param xy Vertex positions * \param xy_stride Byte size to move from one element to the next element diff --git a/Engine/lib/sdl/include/SDL_stdinc.h b/Engine/lib/sdl/include/SDL_stdinc.h index 4554f9e71..449e6445c 100644 --- a/Engine/lib/sdl/include/SDL_stdinc.h +++ b/Engine/lib/sdl/include/SDL_stdinc.h @@ -234,6 +234,19 @@ typedef uint64_t Uint64; /* @} *//* Basic data types */ +/** + * \name Floating-point constants + */ +/* @{ */ + +#ifdef FLT_EPSILON +#define SDL_FLT_EPSILON FLT_EPSILON +#else +#define SDL_FLT_EPSILON 1.1920928955078125e-07F /* 0x0.000002p0 */ +#endif + +/* @} *//* Floating-point constants */ + /* Make sure we have macros for printing width-based integers. * should define these but this is not true all platforms. * (for example win32) */ @@ -355,9 +368,9 @@ typedef uint64_t Uint64; #endif /* SDL_DISABLE_ANALYZE_MACROS */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x); +#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x) #elif defined(__cplusplus) && (__cplusplus >= 201103L) -#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x); +#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) #else /* universal, but may trigger -Wunused-local-typedefs */ #define SDL_COMPILE_TIME_ASSERT(name, x) \ typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1] diff --git a/Engine/lib/sdl/include/SDL_syswm.h b/Engine/lib/sdl/include/SDL_syswm.h index f7cd670cd..45f8e7540 100644 --- a/Engine/lib/sdl/include/SDL_syswm.h +++ b/Engine/lib/sdl/include/SDL_syswm.h @@ -298,6 +298,8 @@ struct SDL_SysWMinfo struct wl_egl_window *egl_window; /**< Wayland EGL window (native window) */ struct xdg_surface *xdg_surface; /**< Wayland xdg surface (window manager handle) */ struct xdg_toplevel *xdg_toplevel; /**< Wayland xdg toplevel role */ + struct xdg_popup *xdg_popup; /**< Wayland xdg popup role */ + struct xdg_positioner *xdg_positioner; /**< Wayland xdg positioner, for popup */ } wl; #endif #if defined(SDL_VIDEO_DRIVER_MIR) /* no longer available, left for API/ABI compatibility. Remove in 2.1! */ diff --git a/Engine/lib/sdl/include/SDL_version.h b/Engine/lib/sdl/include/SDL_version.h index a925dc432..3df4e041a 100644 --- a/Engine/lib/sdl/include/SDL_version.h +++ b/Engine/lib/sdl/include/SDL_version.h @@ -59,7 +59,7 @@ typedef struct SDL_version */ #define SDL_MAJOR_VERSION 2 #define SDL_MINOR_VERSION 0 -#define SDL_PATCHLEVEL 21 +#define SDL_PATCHLEVEL 22 /** * Macro to determine SDL version program was compiled against. diff --git a/Engine/lib/sdl/include/SDL_video.h b/Engine/lib/sdl/include/SDL_video.h index e43cb27ec..c62e0891a 100644 --- a/Engine/lib/sdl/include/SDL_video.h +++ b/Engine/lib/sdl/include/SDL_video.h @@ -1337,6 +1337,7 @@ extern DECLSPEC void SDLCALL SDL_SetWindowKeyboardGrab(SDL_Window * window, * Mouse grab confines the mouse cursor to the window. * * \param window The window for which the mouse grab mode should be set. + * \param grabbed This is SDL_TRUE to grab mouse, and SDL_FALSE to release. * * \since This function is available since SDL 2.0.16. * diff --git a/Engine/lib/sdl/include/begin_code.h b/Engine/lib/sdl/include/begin_code.h index 63f064b6f..b1b1a3a9b 100644 --- a/Engine/lib/sdl/include/begin_code.h +++ b/Engine/lib/sdl/include/begin_code.h @@ -107,7 +107,7 @@ #ifdef __BORLANDC__ #pragma nopackwarning #endif -#ifdef _M_X64 +#ifdef _WIN64 /* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */ #pragma pack(push,8) #else diff --git a/Engine/lib/sdl/src/SDL.c b/Engine/lib/sdl/src/SDL.c index dfc4572f4..68a4f5da2 100644 --- a/Engine/lib/sdl/src/SDL.c +++ b/Engine/lib/sdl/src/SDL.c @@ -316,6 +316,8 @@ SDL_InitSubSystem(Uint32 flags) #endif } + (void) flags_initialized; /* make static analysis happy, since this only gets used in error cases. */ + return (0); quit_and_error: diff --git a/Engine/lib/sdl/src/SDL_hints.c b/Engine/lib/sdl/src/SDL_hints.c index 2eea5501e..d3fc8ab46 100644 --- a/Engine/lib/sdl/src/SDL_hints.c +++ b/Engine/lib/sdl/src/SDL_hints.c @@ -178,6 +178,11 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) return; } hint->name = SDL_strdup(name); + if (!hint->name) { + SDL_free(hint); + SDL_OutOfMemory(); + return; + } hint->value = NULL; hint->priority = SDL_HINT_DEFAULT; hint->callbacks = NULL; diff --git a/Engine/lib/sdl/src/SDL_list.c b/Engine/lib/sdl/src/SDL_list.c new file mode 100644 index 000000000..af9f8bf81 --- /dev/null +++ b/Engine/lib/sdl/src/SDL_list.c @@ -0,0 +1,93 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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.h" +#include "./SDL_list.h" + +/* Push */ +int +SDL_ListAdd(SDL_ListNode **head, void *ent) +{ + SDL_ListNode *node = SDL_malloc(sizeof (*node)); + + if (node == NULL) { + return SDL_OutOfMemory(); + } + + node->entry = ent; + node->next = *head; + *head = node; + return 0; +} + +/* Pop from end as a FIFO (if add with SDL_ListAdd) */ +void +SDL_ListPop(SDL_ListNode **head, void **ent) +{ + SDL_ListNode **ptr = head; + + /* Invalid or empty */ + if (head == NULL || *head == NULL) { + return; + } + + while ((*ptr)->next) { + ptr = &(*ptr)->next; + } + + if (ent) { + *ent = (*ptr)->entry; + } + + SDL_free(*ptr); + *ptr = NULL; +} + +void +SDL_ListRemove(SDL_ListNode **head, void *ent) +{ + SDL_ListNode **ptr = head; + + while (*ptr) { + if ((*ptr)->entry == ent) { + SDL_ListNode *tmp = *ptr; + *ptr = (*ptr)->next; + SDL_free(tmp); + return; + } + ptr = &(*ptr)->next; + } +} + +void +SDL_ListClear(SDL_ListNode **head) +{ + SDL_ListNode *l = *head; + *head = NULL; + while (l) { + SDL_ListNode *tmp = l; + l = l->next; + SDL_free(tmp); + } +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/SDL_list.h b/Engine/lib/sdl/src/SDL_list.h new file mode 100644 index 000000000..a7ead1dcd --- /dev/null +++ b/Engine/lib/sdl/src/SDL_list.h @@ -0,0 +1,39 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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_list_h_ +#define SDL_list_h_ + +typedef struct SDL_ListNode +{ + void *entry; + struct SDL_ListNode *next; +} SDL_ListNode; + + +int SDL_ListAdd(SDL_ListNode **head, void *ent); +void SDL_ListPop(SDL_ListNode **head, void **ent); +void SDL_ListRemove(SDL_ListNode **head, void *ent); +void SDL_ListClear(SDL_ListNode **head); + +#endif /* SDL_list_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/audio/SDL_audio.c b/Engine/lib/sdl/src/audio/SDL_audio.c index 3a841450c..fb363f771 100644 --- a/Engine/lib/sdl/src/audio/SDL_audio.c +++ b/Engine/lib/sdl/src/audio/SDL_audio.c @@ -936,7 +936,7 @@ SDL_AudioInit(const char *driver_name) /* Select the proper audio driver */ if (driver_name == NULL) { - driver_name = SDL_getenv("SDL_AUDIODRIVER"); + driver_name = SDL_GetHint(SDL_HINT_AUDIODRIVER); } if (driver_name != NULL && *driver_name != 0) { diff --git a/Engine/lib/sdl/src/audio/SDL_audiocvt.c b/Engine/lib/sdl/src/audio/SDL_audiocvt.c index bd49ab008..539900d84 100644 --- a/Engine/lib/sdl/src/audio/SDL_audiocvt.c +++ b/Engine/lib/sdl/src/audio/SDL_audiocvt.c @@ -80,7 +80,7 @@ SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format) Just use unaligned load/stores, if the memory at runtime is aligned it'll be just as fast on modern processors */ while (i >= 4) { /* 4 * float32 */ - _mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_loadu_ps(src+4)), divby2)); + _mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_loadu_ps(src), _mm_loadu_ps(src+4)), divby2)); i -= 4; src += 8; dst += 4; } diff --git a/Engine/lib/sdl/src/audio/SDL_wave.c b/Engine/lib/sdl/src/audio/SDL_wave.c index 07eb10147..e49b55068 100644 --- a/Engine/lib/sdl/src/audio/SDL_wave.c +++ b/Engine/lib/sdl/src/audio/SDL_wave.c @@ -685,7 +685,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len) state.output.pos = 0; state.output.size = outputsize / sizeof(Sint16); - state.output.data = (Sint16 *)SDL_malloc(outputsize); + state.output.data = (Sint16 *)SDL_calloc(1, outputsize); if (state.output.data == NULL) { return SDL_OutOfMemory(); } diff --git a/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c b/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c index bc2a0e10d..722f5d0fa 100644 --- a/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c @@ -32,7 +32,7 @@ static void FeedAudioDevice(_THIS, const void *buf, const int buflen) { const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels; - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels']; for (var c = 0; c < numChannels; ++c) { @@ -101,7 +101,7 @@ HandleCaptureProcess(_THIS) return; } - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels; for (var c = 0; c < numChannels; ++c) { @@ -147,7 +147,7 @@ HandleCaptureProcess(_THIS) static void EMSCRIPTENAUDIO_CloseDevice(_THIS) { - EM_ASM_({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; if ($0) { if (SDL2.capture.silenceTimer !== undefined) { @@ -201,7 +201,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname) /* based on parts of library_sdl.js */ /* create context */ - result = EM_ASM_INT({ + result = MAIN_THREAD_EM_ASM_INT({ if(typeof(Module['SDL2']) === 'undefined') { Module['SDL2'] = {}; } @@ -280,7 +280,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname) feels like it's a pretty inefficient tapdance in similar ways, to be honest. */ - EM_ASM_({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var have_microphone = function(stream) { //console.log('SDL audio capture: we have a microphone! Replacing silence callback.'); @@ -323,7 +323,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname) }, this->spec.channels, this->spec.samples, HandleCaptureProcess, this); } else { /* setup a ScriptProcessorNode */ - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { @@ -359,7 +359,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl) impl->ProvidesOwnCallbackThread = SDL_TRUE; /* check availability */ - available = EM_ASM_INT_V({ + available = MAIN_THREAD_EM_ASM_INT({ if (typeof(AudioContext) !== 'undefined') { return true; } else if (typeof(webkitAudioContext) !== 'undefined') { @@ -372,7 +372,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl) SDL_SetError("No audio context available"); } - capture_available = available && EM_ASM_INT_V({ + capture_available = available && MAIN_THREAD_EM_ASM_INT({ if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) { return true; } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') { diff --git a/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.c b/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.c index 524124e80..88f4a3285 100644 --- a/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.c +++ b/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.c @@ -37,18 +37,35 @@ #include #include +#include #define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63) #define SCE_AUDIO_MAX_VOLUME 0x8000 -/* The tag name used by VITA audio */ -#define VITAAUD_DRIVER_NAME "vita" +static int +VITAAUD_OpenCaptureDevice(_THIS) +{ + this->spec.freq = 16000; + this->spec.samples = 512; + this->spec.channels = 1; + + SDL_CalculateAudioSpec(&this->spec); + + this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE , 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO); + + if (this->hidden->port < 0) { + return SDL_SetError("Couldn't open audio in port: %x", this->hidden->port); + } + + return 0; +} static int VITAAUD_OpenDevice(_THIS, const char *devname) { int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN; int vols[2] = {SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME}; + SDL_AudioFormat test_format; this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); @@ -56,13 +73,20 @@ VITAAUD_OpenDevice(_THIS, const char *devname) return SDL_OutOfMemory(); } SDL_memset(this->hidden, 0, sizeof(*this->hidden)); - switch (this->spec.format & 0xff) { - case 8: - case 16: - this->spec.format = AUDIO_S16LSB; + + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + if (test_format == AUDIO_S16LSB) { + this->spec.format = test_format; break; - default: - return SDL_SetError("Unsupported audio format"); + } + } + + if(!test_format) { + return SDL_SetError("Unsupported audio format"); + } + + if (this->iscapture) { + return VITAAUD_OpenCaptureDevice(this); } /* The sample count must be a multiple of 64. */ @@ -91,14 +115,14 @@ VITAAUD_OpenDevice(_THIS, const char *devname) port = SCE_AUDIO_OUT_PORT_TYPE_BGM; } - this->hidden->channel = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format); - if (this->hidden->channel < 0) { + this->hidden->port = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format); + if (this->hidden->port < 0) { free(this->hidden->rawbuf); this->hidden->rawbuf = NULL; - return SDL_SetError("Couldn't reserve hardware channel"); + return SDL_SetError("Couldn't open audio out port: %x", this->hidden->port); } - sceAudioOutSetVolume(this->hidden->channel, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols); + sceAudioOutSetVolume(this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols); SDL_memset(this->hidden->rawbuf, 0, mixlen); for (i = 0; i < NUM_BUFFERS; i++) { @@ -113,7 +137,7 @@ static void VITAAUD_PlayDevice(_THIS) { Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer]; - sceAudioOutOutput(this->hidden->channel, mixbuf); + sceAudioOutOutput(this->hidden->port, mixbuf); this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; } @@ -123,6 +147,7 @@ static void VITAAUD_WaitDevice(_THIS) { /* Because we block when sending audio, there's no need for this function to do anything. */ } + static Uint8 *VITAAUD_GetDeviceBuf(_THIS) { return this->hidden->mixbufs[this->hidden->next_buffer]; @@ -130,17 +155,32 @@ static Uint8 *VITAAUD_GetDeviceBuf(_THIS) static void VITAAUD_CloseDevice(_THIS) { - if (this->hidden->channel >= 0) { - sceAudioOutReleasePort(this->hidden->channel); - this->hidden->channel = -1; + if (this->hidden->port >= 0) { + if (this->iscapture) { + sceAudioInReleasePort(this->hidden->port); + } else { + sceAudioOutReleasePort(this->hidden->port); + } + this->hidden->port = -1; } - if (this->hidden->rawbuf != NULL) { + if (!this->iscapture && this->hidden->rawbuf != NULL) { free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */ this->hidden->rawbuf = NULL; } } +static int VITAAUD_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + int ret; + SDL_assert(buflen == this->spec.size); + ret = sceAudioInInput(this->hidden->port, buffer); + if (ret < 0) { + return SDL_SetError("Failed to capture from device: %x", ret); + } + return this->spec.size; +} + static void VITAAUD_ThreadInit(_THIS) { /* Increase the priority of this audio thread by 1 to put it @@ -165,12 +205,13 @@ VITAAUD_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = VITAAUD_CloseDevice; impl->ThreadInit = VITAAUD_ThreadInit; - /* VITA audio device */ - impl->OnlyHasDefaultOutputDevice = SDL_TRUE; - /* + impl->CaptureFromDevice = VITAAUD_CaptureFromDevice; + + /* and the capabilities */ impl->HasCaptureSupport = SDL_TRUE; - impl->OnlyHasDefaultInputDevice = SDL_TRUE; - */ + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; + return SDL_TRUE; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.h b/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.h index 73870759b..a5601b28c 100644 --- a/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.h +++ b/Engine/lib/sdl/src/audio/vita/SDL_vitaaudio.h @@ -30,8 +30,8 @@ #define NUM_BUFFERS 2 struct SDL_PrivateAudioData { - /* The hardware output channel. */ - int channel; + /* The hardware input/output port. */ + int port; /* The raw allocated mixing buffer. */ Uint8 *rawbuf; /* Individual mixing buffers. */ diff --git a/Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c b/Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c index e7d640c12..862ed9f5e 100644 --- a/Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c +++ b/Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c @@ -558,12 +558,16 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret); } +#if 1 /* we're getting reports that WASAPI's resampler introduces distortions, so it's disabled for now. --ryan. */ + this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */ +#else /* favor WASAPI's resampler over our own */ if (this->spec.freq != waveformat->nSamplesPerSec) { streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY); waveformat->nSamplesPerSec = this->spec.freq; waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8); } +#endif streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL); diff --git a/Engine/lib/sdl/src/core/linux/SDL_fcitx.c b/Engine/lib/sdl/src/core/linux/SDL_fcitx.c index 3f0794736..bab5e88f3 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_fcitx.c +++ b/Engine/lib/sdl/src/core/linux/SDL_fcitx.c @@ -339,11 +339,11 @@ SDL_Fcitx_Reset(void) } SDL_bool -SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { - Uint32 state = Fcitx_ModState(); + Uint32 mod_state = Fcitx_ModState(); Uint32 handled = SDL_FALSE; - Uint32 is_release = SDL_FALSE; + Uint32 is_release = (state == SDL_RELEASED); Uint32 event_time = 0; if (!fcitx_client.ic_path) { @@ -351,7 +351,7 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) } if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mod_state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) { if (handled) { SDL_Fcitx_UpdateTextRect(NULL); diff --git a/Engine/lib/sdl/src/core/linux/SDL_fcitx.h b/Engine/lib/sdl/src/core/linux/SDL_fcitx.h index f7884ea43..c3cea523d 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_fcitx.h +++ b/Engine/lib/sdl/src/core/linux/SDL_fcitx.h @@ -31,7 +31,7 @@ extern SDL_bool SDL_Fcitx_Init(void); extern void SDL_Fcitx_Quit(void); extern void SDL_Fcitx_SetFocus(SDL_bool focused); extern void SDL_Fcitx_Reset(void); -extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect); extern void SDL_Fcitx_PumpEvents(void); diff --git a/Engine/lib/sdl/src/core/linux/SDL_ibus.c b/Engine/lib/sdl/src/core/linux/SDL_ibus.c index a7bafda35..60af0ba29 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_ibus.c +++ b/Engine/lib/sdl/src/core/linux/SDL_ibus.c @@ -503,15 +503,20 @@ SDL_IBus_Reset(void) } SDL_bool -SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { Uint32 result = 0; SDL_DBusContext *dbus = SDL_DBus_GetContext(); - + + if (IBus_CheckConnection(dbus)) { Uint32 mods = IBus_ModState(); + Uint32 ibus_keycode = keycode - 8; + if (state == SDL_RELEASED) { + mods |= (1 << 30); // IBUS_RELEASE_MASK + } if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &ibus_keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) { result = 0; } diff --git a/Engine/lib/sdl/src/core/linux/SDL_ibus.h b/Engine/lib/sdl/src/core/linux/SDL_ibus.h index 73a9f1b8b..71d1f2d30 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_ibus.h +++ b/Engine/lib/sdl/src/core/linux/SDL_ibus.h @@ -41,7 +41,7 @@ extern void SDL_IBus_Reset(void); /* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to update its candidate list or change input methods. PumpEvents should be called some time after this, to recieve the TextInput / TextEditing event back. */ -extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); /* Update the position of IBus' candidate list. If rect is NULL then this will just reposition it relative to the focused window's new position. */ diff --git a/Engine/lib/sdl/src/core/linux/SDL_ime.c b/Engine/lib/sdl/src/core/linux/SDL_ime.c index 84c461f8b..9c0cb80f0 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_ime.c +++ b/Engine/lib/sdl/src/core/linux/SDL_ime.c @@ -27,7 +27,7 @@ typedef SDL_bool (*_SDL_IME_Init)(void); typedef void (*_SDL_IME_Quit)(void); typedef void (*_SDL_IME_SetFocus)(SDL_bool); typedef void (*_SDL_IME_Reset)(void); -typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32); +typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32, Uint8 state); typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *); typedef void (*_SDL_IME_PumpEvents)(void); @@ -127,10 +127,10 @@ SDL_IME_Reset(void) } SDL_bool -SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { if (SDL_IME_ProcessKeyEvent_Real) - return SDL_IME_ProcessKeyEvent_Real(keysym, keycode); + return SDL_IME_ProcessKeyEvent_Real(keysym, keycode, state); return SDL_FALSE; } diff --git a/Engine/lib/sdl/src/core/linux/SDL_ime.h b/Engine/lib/sdl/src/core/linux/SDL_ime.h index a28a4b430..cc5b105f0 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_ime.h +++ b/Engine/lib/sdl/src/core/linux/SDL_ime.h @@ -31,7 +31,7 @@ extern SDL_bool SDL_IME_Init(void); extern void SDL_IME_Quit(void); extern void SDL_IME_SetFocus(SDL_bool focused); extern void SDL_IME_Reset(void); -extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_IME_UpdateTextRect(SDL_Rect *rect); extern void SDL_IME_PumpEvents(void); diff --git a/Engine/lib/sdl/src/core/windows/SDL_windows.c b/Engine/lib/sdl/src/core/windows/SDL_windows.c index fcbf8e847..50e128fcc 100644 --- a/Engine/lib/sdl/src/core/windows/SDL_windows.c +++ b/Engine/lib/sdl/src/core/windows/SDL_windows.c @@ -25,7 +25,15 @@ #include "SDL_windows.h" #include "SDL_error.h" -#include /* for CoInitialize/CoUninitialize (Win32 only) */ +#include /* for CoInitialize/CoUninitialize (Win32 only) */ +#if defined(HAVE_ROAPI_H) +#include /* For RoInitialize/RoUninitialize (Win32 only) */ +#else +typedef enum RO_INIT_TYPE { + RO_INIT_SINGLETHREADED = 0, + RO_INIT_MULTITHREADED = 1 +} RO_INIT_TYPE; +#endif #ifndef _WIN32_WINNT_VISTA #define _WIN32_WINNT_VISTA 0x0600 @@ -37,6 +45,10 @@ #define _WIN32_WINNT_WIN8 0x0602 #endif +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + /* Sets an error message based on an HRESULT */ int @@ -104,51 +116,66 @@ void WIN_CoUninitialize(void) { #ifndef __WINRT__ - /* Don't uninitialize COM because of what appears to be a bug in Microsoft WGI reference counting. - * - * If you plug in a non-Xbox controller and let the application run for 30 seconds, then it crashes in CoUninitialize() - * with this stack trace: + CoUninitialize(); +#endif +} - Windows.Gaming.Input.dll!GameController::~GameController(void) Unknown - Windows.Gaming.Input.dll!GameController::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl,1,1,0,struct Windows::Gaming::Input::IGameController,struct Windows::Gaming::Input::IGameControllerBatteryInfo,struct Microsoft::WRL::CloakedIid,class Microsoft::WRL::FtmBase>::Release(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::AggregableRuntimeClass,struct Microsoft::WRL::CloakedIid,struct Microsoft::WRL::CloakedIid,struct Microsoft::WRL::CloakedIid,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>() Unknown - Windows.Gaming.Input.dll!`eh vector destructor iterator'(void *,unsigned int,int,void (*)(void *)) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection::~GameControllerCollection(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl,1,1,0,struct Windows::Foundation::Collections::IIterable,struct Windows::Foundation::Collections::IVectorView,class Microsoft::WRL::FtmBase>::Release(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase::~CustomGameControllerFactoryBase(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory >,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil,0>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>() Unknown - Windows.Gaming.Input.dll!NtList::~NtList(void) Unknown - Windows.Gaming.Input.dll!FactoryManager::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory,struct Windows::Gaming::Input::Custom::IGameControllerFactoryManagerStatics2,struct Microsoft::WRL::CloakedIid,0>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::TerminateMap(class Microsoft::WRL::Details::ModuleBase *,unsigned short const *,bool) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Module<1,class Microsoft::WRL::Details::DefaultModule<1> >::~Module<1,class Microsoft::WRL::Details::DefaultModule<1> >(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::DefaultModule<1>::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!`dynamic atexit destructor for 'Microsoft::WRL::Details::StaticStorage,0,int>::instance_''() Unknown - Windows.Gaming.Input.dll!__CRT_INIT@12() Unknown - Windows.Gaming.Input.dll!__DllMainCRTStartup() Unknown - ntdll.dll!_LdrxCallInitRoutine@16() Unknown - ntdll.dll!LdrpCallInitRoutine() Unknown - ntdll.dll!LdrpProcessDetachNode() Unknown - ntdll.dll!LdrpUnloadNode() Unknown - ntdll.dll!LdrpDecrementModuleLoadCountEx() Unknown - ntdll.dll!LdrUnloadDll() Unknown - KernelBase.dll!FreeLibrary() Unknown - combase.dll!FreeLibraryWithLogging(LoadOrFreeWhy why, HINSTANCE__ * hMod, const wchar_t * pswzOptionalFileName) Line 193 C++ - combase.dll!CClassCache::CDllPathEntry::CFinishObject::Finish() Line 3311 C++ - combase.dll!CClassCache::CFinishComposite::Finish() Line 3421 C++ - combase.dll!CClassCache::CleanUpDllsForProcess() Line 7009 C++ - [Inline Frame] combase.dll!CCCleanUpDllsForProcess() Line 8773 C++ - combase.dll!ProcessUninitialize() Line 2243 C++ - combase.dll!DecrementProcessInitializeCount() Line 993 C++ - combase.dll!wCoUninitialize(COleTls & Tls, int fHostThread) Line 4126 C++ - combase.dll!CoUninitialize() Line 3945 C++ - */ - /*CoUninitialize();*/ +#ifndef __WINRT__ +void * +WIN_LoadComBaseFunction(const char *name) +{ + static SDL_bool s_bLoaded; + static HMODULE s_hComBase; + + if (!s_bLoaded) { + s_hComBase = LoadLibraryEx(TEXT("combase.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + s_bLoaded = SDL_TRUE; + } + if (s_hComBase) { + return GetProcAddress(s_hComBase, name); + } else { + return NULL; + } +} +#endif + +HRESULT +WIN_RoInitialize(void) +{ +#ifdef __WINRT__ + return S_OK; +#else + typedef HRESULT (WINAPI *RoInitialize_t)(RO_INIT_TYPE initType); + RoInitialize_t RoInitializeFunc = (RoInitialize_t)WIN_LoadComBaseFunction("RoInitialize"); + if (RoInitializeFunc) { + /* RO_INIT_SINGLETHREADED is equivalent to COINIT_APARTMENTTHREADED */ + HRESULT hr = RoInitializeFunc(RO_INIT_SINGLETHREADED); + if (hr == RPC_E_CHANGED_MODE) { + hr = RoInitializeFunc(RO_INIT_MULTITHREADED); + } + + /* S_FALSE means success, but someone else already initialized. */ + /* You still need to call RoUninitialize in this case! */ + if (hr == S_FALSE) { + return S_OK; + } + + return hr; + } else { + return E_NOINTERFACE; + } +#endif +} + +void +WIN_RoUninitialize(void) +{ +#ifndef __WINRT__ + typedef void (WINAPI *RoUninitialize_t)(void); + RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize"); + if (RoUninitializeFunc) { + RoUninitializeFunc(); + } #endif } diff --git a/Engine/lib/sdl/src/core/windows/SDL_windows.h b/Engine/lib/sdl/src/core/windows/SDL_windows.h index 221c3bd87..917a8256f 100644 --- a/Engine/lib/sdl/src/core/windows/SDL_windows.h +++ b/Engine/lib/sdl/src/core/windows/SDL_windows.h @@ -63,10 +63,19 @@ extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr); /* Sets an error message based on GetLastError(). Always return -1. */ extern int WIN_SetError(const char *prefix); +#if !defined(__WINRT__) +/* Load a function from combase.dll */ +void *WIN_LoadComBaseFunction(const char *name); +#endif + /* Wrap up the oddities of CoInitialize() into a common function. */ extern HRESULT WIN_CoInitialize(void); extern void WIN_CoUninitialize(void); +/* Wrap up the oddities of RoInitialize() into a common function. */ +extern HRESULT WIN_RoInitialize(void); +extern void WIN_RoUninitialize(void); + /* Returns SDL_TRUE if we're running on Windows Vista and newer */ extern BOOL WIN_IsWindowsVistaOrGreater(void); diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h b/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h index 299dde303..526513ad5 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h @@ -864,3 +864,4 @@ #define SDL_UnionFRect SDL_UnionFRect_REAL #define SDL_EncloseFPoints SDL_EncloseFPoints_REAL #define SDL_IntersectFRectAndLine SDL_IntersectFRectAndLine_REAL +#define SDL_RenderGetWindow SDL_RenderGetWindow_REAL diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h b/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h index 2c0d5b03e..22bf870d9 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h @@ -935,3 +935,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRect,(const SDL_FRect *a, const SDL_FRect SDL_DYNAPI_PROC(void,SDL_UnionFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),) SDL_DYNAPI_PROC(SDL_bool,SDL_EncloseFPoints,(const SDL_FPoint *a, int b, const SDL_FRect *c, SDL_FRect *d),(a,b,c,d),return) SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRectAndLine,(const SDL_FRect *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(SDL_Window*,SDL_RenderGetWindow,(SDL_Renderer *a),(a),return) diff --git a/Engine/lib/sdl/src/events/SDL_keyboard.c b/Engine/lib/sdl/src/events/SDL_keyboard.c index cd150fab6..14e79ca49 100644 --- a/Engine/lib/sdl/src/events/SDL_keyboard.c +++ b/Engine/lib/sdl/src/events/SDL_keyboard.c @@ -638,6 +638,7 @@ SDL_SetKeyboardFocus(SDL_Window * window) /* old window must lose an existing mouse capture. */ if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) { SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */ + SDL_UpdateMouseCapture(SDL_TRUE); SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE)); } diff --git a/Engine/lib/sdl/src/events/SDL_mouse.c b/Engine/lib/sdl/src/events/SDL_mouse.c index 2e88ee714..254182cc5 100644 --- a/Engine/lib/sdl/src/events/SDL_mouse.c +++ b/Engine/lib/sdl/src/events/SDL_mouse.c @@ -109,6 +109,28 @@ SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldVal mouse->touch_mouse_events = SDL_GetStringBoolean(hint, SDL_TRUE); } +#if defined(__vita__) +static void SDLCALL +SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + if (hint) { + switch(*hint) { + default: + case '0': + mouse->vita_touch_mouse_device = 0; + break; + case '1': + mouse->vita_touch_mouse_device = 1; + break; + case '2': + mouse->vita_touch_mouse_device = 2; + break; + } + } +} +#endif + static void SDLCALL SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) { @@ -134,12 +156,8 @@ SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldVal SDL_bool auto_capture = SDL_GetStringBoolean(hint, SDL_TRUE); if (auto_capture != mouse->auto_capture) { - /* Turn off mouse capture if it's currently active because of button presses */ - if (!auto_capture && SDL_GetMouseState(NULL, NULL) != 0) { - SDL_CaptureMouse(SDL_FALSE); - } - mouse->auto_capture = auto_capture; + SDL_UpdateMouseCapture(SDL_FALSE); } } @@ -166,6 +184,11 @@ SDL_MouseInit(void) SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, SDL_TouchMouseEventsChanged, mouse); +#if defined(__vita__) + SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE, + SDL_VitaTouchMouseDeviceChanged, mouse); +#endif + SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, SDL_MouseTouchEventsChanged, mouse); @@ -384,12 +407,9 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ /* Ignore relative motion when first positioning the mouse */ if (!mouse->has_position) { - xrel = 0; - yrel = 0; mouse->x = x; mouse->y = y; mouse->has_position = SDL_TRUE; - return 0; } else if (!xrel && !yrel) { /* Drop events that don't change state */ #ifdef DEBUG_MOUSE SDL_Log("Mouse event didn't change state - dropped!\n"); @@ -540,7 +560,6 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state Uint32 type; Uint32 buttonstate; SDL_MouseInputSource *source; - SDL_bool had_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE); source = GetMouseInputSource(mouse, mouseID); if (!source) { @@ -643,10 +662,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state /* Automatically capture the mouse while buttons are pressed */ if (mouse->auto_capture) { - SDL_bool has_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE); - if (has_buttons_pressed != had_buttons_pressed) { - SDL_CaptureMouse(has_buttons_pressed); - } + SDL_UpdateMouseCapture(SDL_FALSE); } return posted; @@ -743,6 +759,7 @@ SDL_MouseQuit(void) if (mouse->CaptureMouse) { SDL_CaptureMouse(SDL_FALSE); + SDL_UpdateMouseCapture(SDL_TRUE); } SDL_SetRelativeMouseMode(SDL_FALSE); SDL_ShowCursor(1); @@ -947,6 +964,8 @@ SDL_SetRelativeMouseMode(SDL_bool enabled) if (!enabled) { SDL_WarpMouseInWindow(focusWindow, mouse->x, mouse->y); } + + SDL_UpdateMouseCapture(SDL_FALSE); } if (!enabled) { @@ -968,39 +987,59 @@ SDL_GetRelativeMouseMode() return mouse->relative_mode; } +int +SDL_UpdateMouseCapture(SDL_bool force_release) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *capture_window = NULL; + + if (!mouse->CaptureMouse) { + return 0; + } + + if (!force_release) { + if (mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseState(NULL, NULL) != 0)) { + if (!mouse->relative_mode) { + capture_window = SDL_GetKeyboardFocus(); + } + } + } + + if (capture_window != mouse->capture_window) { + if (mouse->capture_window) { + mouse->CaptureMouse(NULL); + mouse->capture_window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + mouse->capture_window = NULL; + } + + if (capture_window) { + if (mouse->CaptureMouse(capture_window) < 0) { + /* CaptureMouse() will have set an error */ + return -1; + } + capture_window->flags |= SDL_WINDOW_MOUSE_CAPTURE; + } + + mouse->capture_window = capture_window; + } + return 0; +} + int SDL_CaptureMouse(SDL_bool enabled) { SDL_Mouse *mouse = SDL_GetMouse(); - SDL_Window *focusWindow; - SDL_bool isCaptured; if (!mouse->CaptureMouse) { return SDL_Unsupported(); } - focusWindow = SDL_GetKeyboardFocus(); - - isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE); - if (isCaptured == enabled) { - return 0; /* already done! */ + if (enabled && SDL_GetKeyboardFocus() == NULL) { + return SDL_SetError("No window has focus"); } + mouse->capture_desired = enabled; - if (enabled) { - if (!focusWindow) { - return SDL_SetError("No window has focus"); - } else if (mouse->CaptureMouse(focusWindow) == -1) { - return -1; /* CaptureMouse() should call SetError */ - } - focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; - } else { - if (mouse->CaptureMouse(NULL) == -1) { - return -1; /* CaptureMouse() should call SetError */ - } - focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; - } - - return 0; + return SDL_UpdateMouseCapture(SDL_FALSE); } SDL_Cursor * diff --git a/Engine/lib/sdl/src/events/SDL_mouse_c.h b/Engine/lib/sdl/src/events/SDL_mouse_c.h index 7b020447a..f06934b6f 100644 --- a/Engine/lib/sdl/src/events/SDL_mouse_c.h +++ b/Engine/lib/sdl/src/events/SDL_mouse_c.h @@ -100,7 +100,12 @@ typedef struct SDL_bool touch_mouse_events; SDL_bool mouse_touch_events; SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */ +#if defined(__vita__) + Uint8 vita_touch_mouse_device; +#endif SDL_bool auto_capture; + SDL_bool capture_desired; + SDL_Window *capture_window; /* Data for input source state */ int num_sources; @@ -132,6 +137,9 @@ extern void SDL_SetDefaultCursor(SDL_Cursor * cursor); /* Set the mouse focus window */ extern void SDL_SetMouseFocus(SDL_Window * window); +/* Update the mouse capture window */ +extern int SDL_UpdateMouseCapture(SDL_bool force_release); + /* Send a mouse motion event */ extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y); diff --git a/Engine/lib/sdl/src/events/SDL_touch.c b/Engine/lib/sdl/src/events/SDL_touch.c index c3534f00e..ebf26e091 100644 --- a/Engine/lib/sdl/src/events/SDL_touch.c +++ b/Engine/lib/sdl/src/events/SDL_touch.c @@ -265,8 +265,13 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window, #if SYNTHESIZE_TOUCH_TO_MOUSE /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */ + /* SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only */ { +#if defined(__vita__) + if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 2)) ) { +#else if (mouse->touch_mouse_events) { +#endif /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */ if (id != SDL_MOUSE_TOUCHID) { if (window) { diff --git a/Engine/lib/sdl/src/filesystem/windows/SDL_sysfilesystem.c b/Engine/lib/sdl/src/filesystem/windows/SDL_sysfilesystem.c index d50fb511b..b57546c67 100644 --- a/Engine/lib/sdl/src/filesystem/windows/SDL_sysfilesystem.c +++ b/Engine/lib/sdl/src/filesystem/windows/SDL_sysfilesystem.c @@ -35,39 +35,23 @@ char * SDL_GetBasePath(void) { - typedef DWORD (WINAPI *GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD); - GetModuleFileNameExW_t pGetModuleFileNameExW; DWORD buflen = 128; WCHAR *path = NULL; - HANDLE psapi = LoadLibrary(TEXT("psapi.dll")); char *retval = NULL; DWORD len = 0; int i; - if (!psapi) { - WIN_SetError("Couldn't load psapi.dll"); - return NULL; - } - - pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW"); - if (!pGetModuleFileNameExW) { - WIN_SetError("Couldn't find GetModuleFileNameExW"); - FreeLibrary(psapi); - return NULL; - } - while (SDL_TRUE) { void *ptr = SDL_realloc(path, buflen * sizeof (WCHAR)); if (!ptr) { SDL_free(path); - FreeLibrary(psapi); SDL_OutOfMemory(); return NULL; } path = (WCHAR *) ptr; - len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen); + len = GetModuleFileNameW(NULL, path, buflen); /* if it truncated, then len >= buflen - 1 */ /* if there was enough room (or failure), len < buflen - 1 */ if (len < buflen - 1) { @@ -78,8 +62,6 @@ SDL_GetBasePath(void) buflen *= 2; } - FreeLibrary(psapi); - if (len == 0) { SDL_free(path); WIN_SetError("Couldn't locate our .exe"); diff --git a/Engine/lib/sdl/src/hidapi/SDL_hidapi.c b/Engine/lib/sdl/src/hidapi/SDL_hidapi.c index aacff63bf..369b616f5 100644 --- a/Engine/lib/sdl/src/hidapi/SDL_hidapi.c +++ b/Engine/lib/sdl/src/hidapi/SDL_hidapi.c @@ -951,6 +951,7 @@ DeleteHIDDeviceWrapper(SDL_hid_device *device) } #if !SDL_HIDAPI_DISABLED +#if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC) #define COPY_IF_EXISTS(var) \ if (pSrc->var != NULL) { \ @@ -987,6 +988,7 @@ CopyHIDDeviceInfo(struct SDL_hid_device_info *pSrc, struct SDL_hid_device_info * #undef COPY_IF_EXISTS #undef WCOPY_IF_EXISTS +#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */ #endif /* !SDL_HIDAPI_DISABLED */ static int SDL_hidapi_refcount = 0; @@ -1185,9 +1187,9 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned #ifdef SDL_LIBUSB_DYNAMIC if (libusb_ctx.libhandle) { usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id); - #ifdef DEBUG_HIDAPI +#ifdef DEBUG_HIDAPI SDL_Log("libusb devices found:"); - #endif +#endif for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) { new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info)); if (!new_dev) { @@ -1197,11 +1199,11 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned return NULL; } CopyHIDDeviceInfo(usb_dev, new_dev); - #ifdef DEBUG_HIDAPI +#ifdef DEBUG_HIDAPI SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx", usb_dev->manufacturer_string, usb_dev->product_string, usb_dev->vendor_id, usb_dev->product_id); - #endif +#endif if (last != NULL) { last->next = new_dev; diff --git a/Engine/lib/sdl/src/hidapi/libusb/hid.c b/Engine/lib/sdl/src/hidapi/libusb/hid.c index c54746e4d..9cb597fa8 100644 --- a/Engine/lib/sdl/src/hidapi/libusb/hid.c +++ b/Engine/lib/sdl/src/hidapi/libusb/hid.c @@ -1497,6 +1497,7 @@ void HID_API_EXPORT hid_close(hid_device *dev) /* Clean up the Transfer objects allocated in read_thread(). */ free(dev->transfer->buffer); + dev->transfer->buffer = NULL; libusb_free_transfer(dev->transfer); /* release the interface */ diff --git a/Engine/lib/sdl/src/hidapi/mac/hid.c b/Engine/lib/sdl/src/hidapi/mac/hid.c index a9a85b1f7..ec7ffaf16 100644 --- a/Engine/lib/sdl/src/hidapi/mac/hid.c +++ b/Engine/lib/sdl/src/hidapi/mac/hid.c @@ -572,8 +572,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, if ((vendor_id == 0x0 && product_id == 0x0) || (vendor_id == dev_vid && product_id == dev_pid)) { struct hid_device_info *tmp; - size_t len; - + /* VID/PID match. Create the record. */ tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info)); if (cur_dev) { @@ -590,7 +589,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, /* Fill out the record */ cur_dev->next = NULL; - len = make_path(dev, cbuf, sizeof(cbuf)); + make_path(dev, cbuf, sizeof(cbuf)); cur_dev->path = strdup(cbuf); /* Serial Number */ @@ -817,10 +816,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) CFSetGetValues(device_set, (const void **) device_array); for (i = 0; i < num_devices; i++) { char cbuf[BUF_LEN]; - size_t len; IOHIDDeviceRef os_dev = device_array[i]; - len = make_path(os_dev, cbuf, sizeof(cbuf)); + make_path(os_dev, cbuf, sizeof(cbuf)); if (!strcmp(cbuf, path)) { // Matched Paths. Open this Device. IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone); @@ -833,6 +831,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) /* Create the buffers for receiving data */ dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev); + SDL_assert(dev->max_input_report_len > 0); dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t)); /* Create the Run Loop Mode for this device. @@ -936,11 +935,14 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length) /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; - size_t len = (length < rpt->len)? length: rpt->len; - memcpy(data, rpt->data, len); - dev->input_reports = rpt->next; - free(rpt->data); - free(rpt); + size_t len = 0; + if (rpt != NULL) { + len = (length < rpt->len)? length: rpt->len; + memcpy(data, rpt->data, len); + dev->input_reports = rpt->next; + free(rpt->data); + free(rpt); + } return (int)len; } diff --git a/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h b/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h index 2aa9ca6e8..9dab7cbba 100644 --- a/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h +++ b/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h @@ -501,7 +501,7 @@ static const char *s_ControllerMappings [] = "03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,", #endif -#if defined(__LINUX__) +#ifdef SDL_JOYSTICK_LINUX "xinput,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -762,6 +762,7 @@ static const char *s_ControllerMappings [] = "0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,", "030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", + "030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,", diff --git a/Engine/lib/sdl/src/joystick/SDL_joystick.c b/Engine/lib/sdl/src/joystick/SDL_joystick.c index 3f3482b7d..ae4591223 100644 --- a/Engine/lib/sdl/src/joystick/SDL_joystick.c +++ b/Engine/lib/sdl/src/joystick/SDL_joystick.c @@ -1590,11 +1590,13 @@ SDL_JoystickUpdate(void) for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { if (joystick->attached) { - /* This should always be true, but seeing a crash in the wild...? */ - if (joystick->driver) { - joystick->driver->Update(joystick); + /* This driver should always be != NULL, but seeing a crash in the wild...? */ + if (!joystick->driver) { + continue; /* nothing we can do, and other things use joystick->driver below here. */ } + joystick->driver->Update(joystick); + if (joystick->delayed_guide_button) { SDL_GameControllerHandleDelayedGuideButton(joystick); } @@ -2158,7 +2160,10 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid) MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */ - MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS */ + MAKE_VIDPID(0x044f, 0xb696), /* Thrustmaster T248 */ + MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS (normal mode) */ + MAKE_VIDPID(0x044f, 0xb66f), /* Thrustmaster T300RS (advanced mode) */ + MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster T300RS (PS4 mode) */ MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */ MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ diff --git a/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c b/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c index 6d7f87d59..2549c2afd 100644 --- a/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -747,7 +747,11 @@ HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joy } } - return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size); + if (SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size) != report_size) { + return -1; + } + + return 0; } static int @@ -957,7 +961,10 @@ HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, axis = ((int)packet->ucRightJoystickY * 257) - 32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); - if (packet->ucBatteryLevel & 0x10) { + /* A check of packet->ucBatteryLevel & 0x10 should work as a check for BT vs USB but doesn't + * seem to always work. Possibly related to being 100% charged? + */ + if (!ctx->is_bluetooth) { /* 0x20 set means fully charged */ SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED); } else { diff --git a/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapijoystick.c b/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapijoystick.c index 55d9a1353..f54b3c3f2 100644 --- a/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/Engine/lib/sdl/src/joystick/hidapi/SDL_hidapijoystick.c @@ -227,7 +227,7 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device) } /* Disconnect any joysticks */ - while (device->num_joysticks) { + while (device->num_joysticks && device->joysticks) { HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } diff --git a/Engine/lib/sdl/src/joystick/iphoneos/SDL_mfijoystick.m b/Engine/lib/sdl/src/joystick/iphoneos/SDL_mfijoystick.m index c75fbbae2..38ab3fe60 100644 --- a/Engine/lib/sdl/src/joystick/iphoneos/SDL_mfijoystick.m +++ b/Engine/lib/sdl/src/joystick/iphoneos/SDL_mfijoystick.m @@ -330,6 +330,19 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle subtype = 1; } + if (SDL_strcmp(name, "Backbone One") == 0) { + /* The Backbone app uses the guide and share buttons */ + if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) != 0) { + device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_GUIDE); + --nbuttons; + } + if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_MISC1)) != 0) { + device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_MISC1); + --nbuttons; + device->has_xbox_share_button = SDL_FALSE; + } + } + device->naxes = 6; /* 2 thumbsticks and 2 triggers */ device->nhats = 1; /* d-pad */ device->nbuttons = nbuttons; diff --git a/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c index 851448acd..a268c0d9b 100644 --- a/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c @@ -109,6 +109,7 @@ typedef struct SDL_joylist_item /* Steam Controller support */ SDL_bool m_bSteamController; + SDL_bool checked_mapping; SDL_GamepadMapping *mapping; } SDL_joylist_item; @@ -605,6 +606,26 @@ LINUX_InotifyJoystickDetect(void) } #endif /* HAVE_INOTIFY */ +static int get_event_joystick_index(int event) +{ + int joystick_index = -1; + int i, count; + struct dirent **entries = NULL; + char path[PATH_MAX]; + + SDL_snprintf(path, SDL_arraysize(path), "/sys/class/input/event%d/device", event); + count = scandir(path, &entries, NULL, alphasort); + for (i = 0; i < count; ++i) { + if (SDL_strncmp(entries[i]->d_name, "js", 2) == 0) { + joystick_index = SDL_atoi(entries[i]->d_name+2); + } + free(entries[i]); /* This should NOT be SDL_free() */ + } + free(entries); /* This should NOT be SDL_free() */ + + return joystick_index; +} + /* Detect devices by reading /dev/input. In the inotify code path we * have to do this the first time, to detect devices that already existed * before we started; in the non-inotify code path we do this repeatedly @@ -615,12 +636,39 @@ filter_entries(const struct dirent *entry) return IsJoystickDeviceNode(entry->d_name); } static int -sort_entries(const struct dirent **a, const struct dirent **b) +sort_entries(const void *_a, const void *_b) { - int numA = SDL_atoi((*a)->d_name+5); - int numB = SDL_atoi((*b)->d_name+5); + const struct dirent **a = (const struct dirent **)_a; + const struct dirent **b = (const struct dirent **)_b; + int numA, numB; + int offset; + + if (SDL_classic_joysticks) { + offset = 2; /* strlen("js") */ + numA = SDL_atoi((*a)->d_name+offset); + numB = SDL_atoi((*b)->d_name+offset); + } else { + offset = 5; /* strlen("event") */ + numA = SDL_atoi((*a)->d_name+offset); + numB = SDL_atoi((*b)->d_name+offset); + + /* See if we can get the joystick ordering */ + { + int jsA = get_event_joystick_index(numA); + int jsB = get_event_joystick_index(numB); + if (jsA >= 0 && jsB >= 0) { + numA = jsA; + numB = jsB; + } else if (jsA >= 0) { + return -1; + } else if (jsB >= 0) { + return 1; + } + } + } return (numA - numB); } + static void LINUX_FallbackJoystickDetect(void) { @@ -633,10 +681,13 @@ LINUX_FallbackJoystickDetect(void) /* Opening input devices can generate synchronous device I/O, so avoid it if we can */ if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) { int i, count; - struct dirent **entries; + struct dirent **entries = NULL; char path[PATH_MAX]; - count = scandir("/dev/input", &entries, filter_entries, sort_entries); + count = scandir("/dev/input", &entries, filter_entries, NULL); + if (count > 1) { + qsort(entries, count, sizeof(*entries), sort_entries); + } for (i = 0; i < count; ++i) { SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name); MaybeAddDevice(path); @@ -683,29 +734,7 @@ LINUX_JoystickInit(void) SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_CLASSIC, SDL_FALSE); -#if SDL_USE_LIBUDEV - if (enumeration_method == ENUMERATION_UNSET) { - if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "udev disabled by SDL_JOYSTICK_DISABLE_UDEV"); - enumeration_method = ENUMERATION_FALLBACK; - - } else if (access("/.flatpak-info", F_OK) == 0 - || access("/run/host/container-manager", F_OK) == 0) { - /* Explicitly check `/.flatpak-info` because, for old versions of - * Flatpak, this was the only available way to tell if we were in - * a Flatpak container. */ - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Container detected, disabling udev integration"); - enumeration_method = ENUMERATION_FALLBACK; - - } else { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Using udev for joystick device discovery"); - enumeration_method = ENUMERATION_LIBUDEV; - } - } -#endif + enumeration_method = ENUMERATION_UNSET; /* First see if the user specified one or more joysticks to use */ if (devices != NULL) { @@ -734,6 +763,28 @@ LINUX_JoystickInit(void) LINUX_JoystickDetect(); #if SDL_USE_LIBUDEV + if (enumeration_method == ENUMERATION_UNSET) { + if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "udev disabled by SDL_JOYSTICK_DISABLE_UDEV"); + enumeration_method = ENUMERATION_FALLBACK; + + } else if (access("/.flatpak-info", F_OK) == 0 + || access("/run/host/container-manager", F_OK) == 0) { + /* Explicitly check `/.flatpak-info` because, for old versions of + * Flatpak, this was the only available way to tell if we were in + * a Flatpak container. */ + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Container detected, disabling udev integration"); + enumeration_method = ENUMERATION_FALLBACK; + + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Using udev for joystick device discovery"); + enumeration_method = ENUMERATION_LIBUDEV; + } + } + if (enumeration_method == ENUMERATION_LIBUDEV) { if (SDL_UDEV_Init() < 0) { return SDL_SetError("Could not initialize UDEV"); @@ -1573,9 +1624,13 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) SDL_Joystick *joystick; SDL_joylist_item *item = JoystickByDevIndex(device_index); - if (item->mapping) { - SDL_memcpy(out, item->mapping, sizeof(*out)); - return SDL_TRUE; + if (item->checked_mapping) { + if (item->mapping) { + SDL_memcpy(out, item->mapping, sizeof(*out)); + return SDL_TRUE; + } else { + return SDL_FALSE; + } } /* We temporarily open the device to check how it's configured. Make @@ -1595,6 +1650,8 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) return SDL_FALSE; } + item->checked_mapping = SDL_TRUE; + if (PrepareJoystickHwdata(joystick, item) == -1) { SDL_free(joystick->hwdata); SDL_free(joystick); diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c b/Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c index 32b637827..df40232df 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c +++ b/Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c @@ -62,6 +62,7 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState; #define GamepadButtons_GUIDE 0x40000000 #define COBJMACROS #include "windows.gaming.input.h" +#include #endif #if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_WGI) @@ -565,22 +566,24 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) if (!wgi_state.initialized) { static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } }; HRESULT hr; - HMODULE hModule; - /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */ - if (FAILED(WIN_CoInitialize())) { + if (FAILED(WIN_RoInitialize())) { return; } wgi_state.initialized = SDL_TRUE; wgi_state.dirty = SDL_TRUE; - hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { + { typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string); typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory); - WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference"); - RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory"); +#ifdef __WINRT__ + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = WindowsCreateStringReference; + RoGetActivationFactory_t RoGetActivationFactoryFunc = RoGetActivationFactory; +#else + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); +#endif if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { PCWSTR pNamespace = L"Windows.Gaming.Input.Gamepad"; HSTRING_HEADER hNamespaceStringHeader; @@ -591,7 +594,6 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics); } } - FreeLibrary(hModule); } } } @@ -657,7 +659,7 @@ RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics); wgi_state.gamepad_statics = NULL; } - WIN_CoUninitialize(); + WIN_RoUninitialize(); wgi_state.initialized = SDL_FALSE; } } @@ -1320,8 +1322,10 @@ RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint if (!SUCCEEDED(hr)) { return SDL_SetError("Setting vibration failed: 0x%lx\n", hr); } + return 0; + } else { + return SDL_SetError("Controller isn't correlated yet, try hitting a button first"); } - return 0; #else return SDL_Unsupported(); #endif diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c b/Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c index a731dad63..6c5ec5528 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c +++ b/Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c @@ -68,6 +68,7 @@ static struct { EventRegistrationToken controller_added_token; EventRegistrationToken controller_removed_token; int controller_count; + SDL_bool ro_initialized; WindowsGamingInputControllerState *controllers; } wgi; @@ -260,10 +261,9 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde WindowsGetStringRawBufferFunc = WindowsGetStringRawBuffer; WindowsDeleteStringFunc = WindowsDeleteString; #else - HMODULE hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { - WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer"); - WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString"); + { + WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)WIN_LoadComBaseFunction("WindowsGetStringRawBuffer"); + WindowsDeleteStringFunc = (WindowsDeleteString_t)WIN_LoadComBaseFunction("WindowsDeleteString"); } #endif /* __WINRT__ */ if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) { @@ -277,11 +277,6 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde WindowsDeleteStringFunc(hString); } } -#ifndef __WINRT__ - if (hModule != NULL) { - FreeLibrary(hModule); - } -#endif __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2); } if (!name) { @@ -444,23 +439,43 @@ WGI_JoystickInit(void) WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL; RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL; -#ifndef __WINRT__ - HMODULE hModule; -#endif HRESULT hr; - if (FAILED(WIN_CoInitialize())) { - return SDL_SetError("CoInitialize() failed"); + if (FAILED(WIN_RoInitialize())) { + return SDL_SetError("RoInitialize() failed"); } + wgi.ro_initialized = SDL_TRUE; + +#ifndef __WINRT__ + { + /* There seems to be a bug in Windows where a dependency of WGI can be unloaded from memory prior to WGI itself. + * This results in Windows_Gaming_Input!GameController::~GameController() invoking an unloaded DLL and crashing. + * As a workaround, we will keep a reference to the MTA to prevent COM from unloading DLLs later. + * See https://github.com/libsdl-org/SDL/issues/5552 for more details. + */ + static PVOID cookie = NULL; + if (!cookie) { + typedef HRESULT (WINAPI *CoIncrementMTAUsage_t)(PVOID* pCookie); + CoIncrementMTAUsage_t CoIncrementMTAUsageFunc = (CoIncrementMTAUsage_t)WIN_LoadComBaseFunction("CoIncrementMTAUsage"); + if (CoIncrementMTAUsageFunc) { + if (FAILED(CoIncrementMTAUsageFunc(&cookie))) { + return SDL_SetError("CoIncrementMTAUsage() failed"); + } + } else { + /* CoIncrementMTAUsage() is present since Win8, so we should never make it here. */ + return SDL_SetError("CoIncrementMTAUsage() not found"); + } + } + } +#endif #ifdef __WINRT__ WindowsCreateStringReferenceFunc = WindowsCreateStringReference; RoGetActivationFactoryFunc = RoGetActivationFactory; #else - hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { - WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference"); - RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory"); + { + WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); } #endif /* __WINRT__ */ if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { @@ -519,11 +534,6 @@ WGI_JoystickInit(void) } } } -#ifndef __WINRT__ - if (hModule != NULL) { - FreeLibrary(hModule); - } -#endif if (wgi.statics) { __FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers; @@ -863,9 +873,12 @@ WGI_JoystickQuit(void) __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerRemoved(wgi.statics, wgi.controller_removed_token); __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.statics); } - SDL_zero(wgi); - WIN_CoUninitialize(); + if (wgi.ro_initialized) { + WIN_RoUninitialize(); + } + + SDL_zero(wgi); } static SDL_bool diff --git a/Engine/lib/sdl/src/locale/vita/SDL_syslocale.c b/Engine/lib/sdl/src/locale/vita/SDL_syslocale.c new file mode 100644 index 000000000..0a057cbfa --- /dev/null +++ b/Engine/lib/sdl/src/locale/vita/SDL_syslocale.c @@ -0,0 +1,71 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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_syslocale.h" + +#include +#include + +void +SDL_SYS_GetPreferredLocales(char *buf, size_t buflen) +{ + const char *vita_locales[] = { + "ja_JP", + "en_US", + "fr_FR", + "es_ES", + "de_DE", + "it_IT", + "nl_NL", + "pt_PT", + "ru_RU", + "ko_KR", + "zh_TW", + "zh_CN", + "fi_FI", + "sv_SE", + "da_DK", + "no_NO", + "pl_PL", + "pt_BR", + "en_GB", + "tr_TR", + }; + + Sint32 language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US; + SceAppUtilInitParam initParam; + SceAppUtilBootParam bootParam; + SDL_zero(initParam); + SDL_zero(bootParam); + sceAppUtilInit(&initParam, &bootParam); + sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_LANG, &language); + + if (language < 0 || language > SCE_SYSTEM_PARAM_LANG_TURKISH) + language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US; // default to english + + SDL_strlcpy(buf, vita_locales[language], buflen); + + sceAppUtilShutdown(); +} + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/Engine/lib/sdl/src/main/windows/version.rc b/Engine/lib/sdl/src/main/windows/version.rc index 36ff39f12..11e1394f8 100644 --- a/Engine/lib/sdl/src/main/windows/version.rc +++ b/Engine/lib/sdl/src/main/windows/version.rc @@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,21,0 - PRODUCTVERSION 2,0,21,0 + FILEVERSION 2,0,22,0 + PRODUCTVERSION 2,0,22,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L @@ -23,12 +23,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "SDL\0" - VALUE "FileVersion", "2, 0, 21, 0\0" + VALUE "FileVersion", "2, 0, 22, 0\0" VALUE "InternalName", "SDL\0" VALUE "LegalCopyright", "Copyright (C) 2022 Sam Lantinga\0" VALUE "OriginalFilename", "SDL2.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" - VALUE "ProductVersion", "2, 0, 21, 0\0" + VALUE "ProductVersion", "2, 0, 22, 0\0" END END BLOCK "VarFileInfo" diff --git a/Engine/lib/sdl/src/render/SDL_render.c b/Engine/lib/sdl/src/render/SDL_render.c index 441badbc6..58cda3d60 100644 --- a/Engine/lib/sdl/src/render/SDL_render.c +++ b/Engine/lib/sdl/src/render/SDL_render.c @@ -356,7 +356,7 @@ QueueCmdSetViewport(SDL_Renderer *renderer) if (cmd != NULL) { cmd->command = SDL_RENDERCMD_SETVIEWPORT; cmd->data.viewport.first = 0; /* render backend will fill this in. */ - /* Convert SDL_FRect to SDL_Rect */ + /* Convert SDL_DRect to SDL_Rect */ cmd->data.viewport.rect.x = (int)SDL_floor(renderer->viewport.x); cmd->data.viewport.rect.y = (int)SDL_floor(renderer->viewport.y); cmd->data.viewport.rect.w = (int)SDL_floor(renderer->viewport.w); @@ -386,7 +386,7 @@ QueueCmdSetClipRect(SDL_Renderer *renderer) } else { cmd->command = SDL_RENDERCMD_SETCLIPRECT; cmd->data.cliprect.enabled = renderer->clipping_enabled; - /* Convert SDL_FRect to SDL_Rect */ + /* Convert SDL_DRect to SDL_Rect */ cmd->data.cliprect.rect.x = (int)SDL_floor(renderer->clip_rect.x); cmd->data.cliprect.rect.y = (int)SDL_floor(renderer->clip_rect.y); cmd->data.cliprect.rect.w = (int)SDL_floor(renderer->clip_rect.w); @@ -580,10 +580,10 @@ QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int cou if (retval < 0) { cmd->command = SDL_RENDERCMD_NO_OP; } - - SDL_small_free(xy, isstack1); - SDL_small_free(indices, isstack2); } + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + } else { retval = renderer->QueueFillRects(renderer, cmd, rects, count); if (retval < 0) { @@ -676,7 +676,7 @@ SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info) #endif } -static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_FRect *viewport, SDL_FPoint *scale) +static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_DRect *viewport, SDL_FPoint *scale) { SDL_LockMutex(renderer->target_mutex); *logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w; @@ -698,7 +698,17 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) renderer->WindowEvent(renderer, &event->window); } - if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + /* In addition to size changes, we also want to do this block for + * moves as well, for two reasons: + * + * 1. The window could be moved to a new display, which has a new + * DPI and therefore a new window/drawable ratio + * 2. For whatever reason, the viewport can get messed up during + * window movement (this has been observed on macOS), so this is + * also a good opportunity to force viewport updates + */ + if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || + event->window.event == SDL_WINDOWEVENT_MOVED) { /* Make sure we're operating on the default render target */ SDL_Texture *saved_target = SDL_GetRenderTarget(renderer); if (saved_target) { @@ -728,10 +738,10 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_GetWindowSize(renderer->window, &w, &h); } - renderer->viewport.x = 0; - renderer->viewport.y = 0; - renderer->viewport.w = (float) w; - renderer->viewport.h = (float) h; + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)w; + renderer->viewport.h = (double)h; QueueCmdSetViewport(renderer); FlushRenderCommandsIfNotBatching(renderer); } @@ -758,7 +768,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); if (window == renderer->window) { int logical_w, logical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); if (logical_w) { @@ -785,7 +795,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); if (window == renderer->window) { int logical_w, logical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); if (logical_w) { @@ -800,7 +810,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) event->type == SDL_FINGERMOTION) { int logical_w, logical_h; float physical_w, physical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); @@ -1095,6 +1105,13 @@ SDL_GetRenderer(SDL_Window * window) return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA); } +SDL_Window * +SDL_RenderGetWindow(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + return renderer->window; +} + int SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) { @@ -1585,10 +1602,11 @@ SDL_SetTextureScaleMode(SDL_Texture * texture, SDL_ScaleMode scaleMode) CHECK_TEXTURE_MAGIC(texture, -1); renderer = texture->renderer; - renderer->SetTextureScaleMode(renderer, texture, scaleMode); texture->scaleMode = scaleMode; if (texture->native) { return SDL_SetTextureScaleMode(texture->native, scaleMode); + } else { + renderer->SetTextureScaleMode(renderer, texture, scaleMode); } return 0; } @@ -2210,10 +2228,10 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) } if (texture) { - renderer->viewport.x = 0.0f; - renderer->viewport.y = 0.0f; - renderer->viewport.w = (float) texture->w; - renderer->viewport.h = (float) texture->h; + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)texture->w; + renderer->viewport.h = (double)texture->h; SDL_zero(renderer->clip_rect); renderer->clipping_enabled = SDL_FALSE; renderer->scale.x = 1.0f; @@ -2245,6 +2263,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) SDL_Texture * SDL_GetRenderTarget(SDL_Renderer *renderer) { + CHECK_RENDERER_MAGIC(renderer, NULL); + return renderer->target; } @@ -2420,19 +2440,19 @@ SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) CHECK_RENDERER_MAGIC(renderer, -1); if (rect) { - renderer->viewport.x = rect->x * renderer->scale.x; - renderer->viewport.y = rect->y * renderer->scale.y; - renderer->viewport.w = rect->w * renderer->scale.x; - renderer->viewport.h = rect->h * renderer->scale.y; + renderer->viewport.x = (double)rect->x * renderer->scale.x; + renderer->viewport.y = (double)rect->y * renderer->scale.y; + renderer->viewport.w = (double)rect->w * renderer->scale.x; + renderer->viewport.h = (double)rect->h * renderer->scale.y; } else { int w, h; if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { return -1; } - renderer->viewport.x = 0.0f; - renderer->viewport.y = 0.0f; - renderer->viewport.w = (float) w; - renderer->viewport.h = (float) h; + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)w; + renderer->viewport.h = (double)h; } retval = QueueCmdSetViewport(renderer); return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer); @@ -2456,8 +2476,8 @@ RenderGetViewportSize(SDL_Renderer * renderer, SDL_FRect * rect) { rect->x = 0.0f; rect->y = 0.0f; - rect->w = renderer->viewport.w / renderer->scale.x; - rect->h = renderer->viewport.h / renderer->scale.y; + rect->w = (float)(renderer->viewport.w / renderer->scale.x); + rect->h = (float)(renderer->viewport.h / renderer->scale.y); } int @@ -2468,10 +2488,10 @@ SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect) if (rect) { renderer->clipping_enabled = SDL_TRUE; - renderer->clip_rect.x = rect->x * renderer->scale.x; - renderer->clip_rect.y = rect->y * renderer->scale.y; - renderer->clip_rect.w = rect->w * renderer->scale.x; - renderer->clip_rect.h = rect->h * renderer->scale.y; + renderer->clip_rect.x = (double)rect->x * renderer->scale.x; + renderer->clip_rect.y = (double)rect->y * renderer->scale.y; + renderer->clip_rect.w = (double)rect->w * renderer->scale.x; + renderer->clip_rect.h = (double)rect->h * renderer->scale.y; } else { renderer->clipping_enabled = SDL_FALSE; SDL_zero(renderer->clip_rect); @@ -2535,10 +2555,10 @@ SDL_RenderWindowToLogical(SDL_Renderer * renderer, int windowX, int windowY, flo window_physical_y = ((float) windowY) / renderer->dpi_scale.y; if (logicalX) { - *logicalX = (window_physical_x - renderer->viewport.x) / renderer->scale.x; + *logicalX = (float)((window_physical_x - renderer->viewport.x) / renderer->scale.x); } if (logicalY) { - *logicalY = (window_physical_y - renderer->viewport.y) / renderer->scale.y; + *logicalY = (float)((window_physical_y - renderer->viewport.y) / renderer->scale.y); } } @@ -2549,8 +2569,8 @@ SDL_RenderLogicalToWindow(SDL_Renderer * renderer, float logicalX, float logical CHECK_RENDERER_MAGIC(renderer, ); - window_physical_x = (logicalX * renderer->scale.x) + renderer->viewport.x; - window_physical_y = (logicalY * renderer->scale.y) + renderer->viewport.y; + window_physical_x = (float)((logicalX * renderer->scale.x) + renderer->viewport.x); + window_physical_y = (float)((logicalY * renderer->scale.y) + renderer->viewport.y); if (windowX) { *windowX = (int)(window_physical_x * renderer->dpi_scale.x); @@ -3138,10 +3158,11 @@ SDL_RenderDrawLinesF(SDL_Renderer * renderer, num_vertices, indices, num_indices, size_indices, 1.0f, 1.0f); - SDL_small_free(xy, isstack1); - SDL_small_free(indices, isstack2); } + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + } else if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { retval = RenderDrawLinesWithRectsF(renderer, points, count); } else { diff --git a/Engine/lib/sdl/src/render/SDL_sysrender.h b/Engine/lib/sdl/src/render/SDL_sysrender.h index 5d92f6a26..7aeb46710 100644 --- a/Engine/lib/sdl/src/render/SDL_sysrender.h +++ b/Engine/lib/sdl/src/render/SDL_sysrender.h @@ -28,6 +28,19 @@ #include "SDL_mutex.h" #include "SDL_yuv_sw_c.h" + +/** + * A rectangle, with the origin at the upper left (double precision). + */ +typedef struct SDL_DRect +{ + double x; + double y; + double w; + double h; +} SDL_DRect; + + /* The SDL 2D rendering system */ typedef struct SDL_RenderDriver SDL_RenderDriver; @@ -201,12 +214,12 @@ struct SDL_Renderer SDL_bool integer_scale; /* The drawable area within the window */ - SDL_FRect viewport; - SDL_FRect viewport_backup; + SDL_DRect viewport; + SDL_DRect viewport_backup; /* The clip rectangle within the window */ - SDL_FRect clip_rect; - SDL_FRect clip_rect_backup; + SDL_DRect clip_rect; + SDL_DRect clip_rect_backup; /* Wether or not the clipping rectangle is used. */ SDL_bool clipping_enabled; @@ -244,8 +257,8 @@ struct SDL_Renderer SDL_RenderCommand *render_commands_pool; Uint32 render_command_generation; Uint32 last_queued_color; - SDL_FRect last_queued_viewport; - SDL_FRect last_queued_cliprect; + SDL_DRect last_queued_viewport; + SDL_DRect last_queued_cliprect; SDL_bool last_queued_cliprect_enabled; SDL_bool color_queued; SDL_bool viewport_queued; diff --git a/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c b/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c index b267fb23e..477f4e975 100644 --- a/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c +++ b/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c @@ -347,7 +347,8 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } -static D3DBLEND GetBlendFunc(SDL_BlendFactor factor) +static D3DBLEND +GetBlendFunc(SDL_BlendFactor factor) { switch (factor) { case SDL_BLENDFACTOR_ZERO: @@ -370,9 +371,28 @@ static D3DBLEND GetBlendFunc(SDL_BlendFactor factor) return D3DBLEND_DESTALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3DBLEND_INVDESTALPHA; - default: - return (D3DBLEND)0; + default: break; } + return (D3DBLEND) 0; +} + +static D3DBLENDOP +GetBlendEquation(SDL_BlendOperation operation) +{ + switch (operation) { + case SDL_BLENDOPERATION_ADD: + return D3DBLENDOP_ADD; + case SDL_BLENDOPERATION_SUBTRACT: + return D3DBLENDOP_SUBTRACT; + case SDL_BLENDOPERATION_REV_SUBTRACT: + return D3DBLENDOP_REVSUBTRACT; + case SDL_BLENDOPERATION_MINIMUM: + return D3DBLENDOP_MIN; + case SDL_BLENDOPERATION_MAXIMUM: + return D3DBLENDOP_MAX; + default: break; + } + return (D3DBLENDOP) 0; } static SDL_bool @@ -387,14 +407,16 @@ D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) || - !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) { + !GetBlendEquation(colorOperation) || + !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) || + !GetBlendEquation(alphaOperation)) { return SDL_FALSE; } - if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) { - return SDL_FALSE; - } - if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) { - return SDL_FALSE; + + if (!data->enableSeparateAlphaBlend) { + if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) { + return SDL_FALSE; + } } return SDL_TRUE; } @@ -1040,11 +1062,15 @@ SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend))); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP, + GetBlendEquation(SDL_GetBlendModeColorOperation(blend))); if (data->enableSeparateAlphaBlend) { IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend))); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA, + GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend))); } } diff --git a/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c b/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c index 89e2ee544..714ca2e77 100644 --- a/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c +++ b/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c @@ -998,6 +998,16 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) goto done; } + /* Set the swap chain target immediately, so that a target is always set + * even before we get to SetDrawState. Without this it's possible to hit + * null references in places like ReadPixels! + */ + ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, + 1, + &data->mainRenderTargetView, + NULL + ); + data->viewportDirty = SDL_TRUE; done: diff --git a/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c b/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c index b5df73ace..b5af52af3 100644 --- a/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c +++ b/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c @@ -30,6 +30,11 @@ #include #endif +#ifdef SDL_VIDEO_VITA_PVR_OGL +#include +#include +#endif + /* To prevent unnecessary window recreation, * these should match the defaults selected in SDL_GL_ResetAttributes */ @@ -319,6 +324,20 @@ GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h) return result; } +static void +GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + /* If the window x/y/w/h changed at all, assume the viewport has been + * changed behind our backs. x/y changes might seem weird but viewport + * resets have been observed on macOS at minimum! + */ + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED || + event->event == SDL_WINDOWEVENT_MOVED) { + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + data->drawstate.viewport_dirty = SDL_TRUE; + } +} + static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) { @@ -1212,9 +1231,9 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic } #ifdef __MACOSX__ - // On macOS, moving the window seems to invalidate the OpenGL viewport state, - // so don't bother trying to persist it across frames; always reset it. - // Workaround for: https://github.com/libsdl-org/SDL/issues/1504 + // On macOS on older systems, the OpenGL view change and resize events aren't + // necessarily synchronized, so just always reset it. + // Workaround for: https://discourse.libsdl.org/t/sdl-2-0-22-prerelease/35306/6 data->drawstate.viewport_dirty = SDL_TRUE; #endif @@ -1733,6 +1752,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); +#ifndef SDL_VIDEO_VITA_PVR_OGL window_flags = SDL_GetWindowFlags(window); if (!(window_flags & SDL_WINDOW_OPENGL) || profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) { @@ -1746,6 +1766,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) goto error; } } +#endif renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { @@ -1760,6 +1781,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) goto error; } + renderer->WindowEvent = GL_WindowEvent; renderer->GetOutputSize = GL_GetOutputSize; renderer->SupportsBlendMode = GL_SupportsBlendMode; renderer->CreateTexture = GL_CreateTexture; diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm.c b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm.c index 8a8877849..98b03e629 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm.c @@ -61,6 +61,11 @@ static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * text const Uint8 *Uplane, int Upitch, const Uint8 *Vplane, int Vpitch); +static int VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); + static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch); @@ -105,12 +110,16 @@ SDL_RenderDriver VITA_GXM_RenderDriver = { .info = { .name = "VITA gxm", .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, - .num_texture_formats = 4, + .num_texture_formats = 8, .texture_formats = { [0] = SDL_PIXELFORMAT_ABGR8888, [1] = SDL_PIXELFORMAT_ARGB8888, [2] = SDL_PIXELFORMAT_RGB565, - [3] = SDL_PIXELFORMAT_BGR565 + [3] = SDL_PIXELFORMAT_BGR565, + [4] = SDL_PIXELFORMAT_YV12, + [5] = SDL_PIXELFORMAT_IYUV, + [6] = SDL_PIXELFORMAT_NV12, + [7] = SDL_PIXELFORMAT_NV21, }, .max_texture_width = 4096, .max_texture_height = 4096, @@ -133,6 +142,15 @@ PixelFormatToVITAFMT(Uint32 format) return SCE_GXM_TEXTURE_FORMAT_U5U6U5_RGB; case SDL_PIXELFORMAT_BGR565: return SCE_GXM_TEXTURE_FORMAT_U5U6U5_BGR; + case SDL_PIXELFORMAT_YV12: + return SCE_GXM_TEXTURE_FORMAT_YVU420P3_CSC0; + case SDL_PIXELFORMAT_IYUV: + return SCE_GXM_TEXTURE_FORMAT_YUV420P3_CSC0; + // should be the other way around. looks like SCE bug. + case SDL_PIXELFORMAT_NV12: + return SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC0; + case SDL_PIXELFORMAT_NV21: + return SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC0; default: return SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR; } @@ -228,6 +246,7 @@ VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->UpdateTexture = VITA_GXM_UpdateTexture; #if SDL_HAVE_YUV renderer->UpdateTextureYUV = VITA_GXM_UpdateTextureYUV; + renderer->UpdateTextureNV = VITA_GXM_UpdateTextureNV; #endif renderer->LockTexture = VITA_GXM_LockTexture; renderer->UnlockTexture = VITA_GXM_UnlockTexture; @@ -295,7 +314,17 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_OutOfMemory(); } - vita_texture->tex = create_gxm_texture(data, texture->w, texture->h, PixelFormatToVITAFMT(texture->format), (texture->access == SDL_TEXTUREACCESS_TARGET)); + vita_texture->tex = create_gxm_texture( + data, + texture->w, + texture->h, + PixelFormatToVITAFMT(texture->format), + (texture->access == SDL_TEXTUREACCESS_TARGET), + &(vita_texture->w), + &(vita_texture->h), + &(vita_texture->pitch), + &(vita_texture->wscale) + ); if (!vita_texture->tex) { SDL_free(vita_texture); @@ -306,38 +335,129 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) VITA_GXM_SetTextureScaleMode(renderer, texture, texture->scaleMode); - vita_texture->w = gxm_texture_get_width(vita_texture->tex); - vita_texture->h = gxm_texture_get_height(vita_texture->tex); - vita_texture->pitch = gxm_texture_get_stride(vita_texture->tex); +#if SDL_HAVE_YUV + vita_texture->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12)); + vita_texture->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21)); +#endif return 0; } +static void VITA_GXM_SetYUVProfile(SDL_Renderer * renderer, SDL_Texture *texture) +{ + VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata; + int ret = 0; + switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { + case SDL_YUV_CONVERSION_BT601: + ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD); + break; + case SDL_YUV_CONVERSION_BT709: + ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD); + break; + case SDL_YUV_CONVERSION_JPEG: + default: + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV profile: %d\n", SDL_GetYUVConversionModeForResolution(texture->w, texture->h)); + break; + } + + if (ret < 0) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Setting YUV profile failed: %x\n", ret); + } +} static int VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) { - const Uint8 *src; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; Uint8 *dst; - int row, length,dpitch; - src = pixels; + int row, length, dpitch; + +#if SDL_HAVE_YUV + if (vita_texture->yuv || vita_texture->nv12) { + VITA_GXM_SetYUVProfile(renderer, texture); + } +#endif VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); length = rect->w * SDL_BYTESPERPIXEL(texture->format); if (length == pitch && length == dpitch) { - SDL_memcpy(dst, src, length*rect->h); + SDL_memcpy(dst, pixels, length*rect->h); } else { for (row = 0; row < rect->h; ++row) { - SDL_memcpy(dst, src, length); - src += pitch; + SDL_memcpy(dst, pixels, length); + pixels += pitch; dst += dpitch; } } +#if SDL_HAVE_YUV + if (vita_texture->yuv) { + void *Udst; + void *Vdst; + int uv_pitch = (dpitch+1) / 2; + int uv_src_pitch = (pitch+1) / 2; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + // skip Y plane + Uint8 *Dpixels = gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h); + + Udst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x; + Vdst = Dpixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w; + + // U plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(Udst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Udst, pixels, length); + pixels += uv_src_pitch; + Udst += uv_pitch; + } + } + + // V plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(Vdst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Vdst, pixels, length); + pixels += uv_src_pitch; + Vdst += uv_pitch; + } + } + + } else if (vita_texture->nv12) { + void *UVdst; + int uv_pitch = 2 * ((dpitch+1) / 2); + int uv_src_pitch = 2 * ((pitch+1) / 2); + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2 , (rect->h + 1) / 2}; + + // skip Y plane + void *Dpixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + UVdst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w*2; + + // UV plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(UVdst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(UVdst, pixels, length); + pixels += uv_src_pitch; + UVdst += uv_pitch; + } + } + } +#endif + return 0; } +#if SDL_HAVE_YUV static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, @@ -345,9 +465,133 @@ VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, const Uint8 *Uplane, int Upitch, const Uint8 *Vplane, int Vpitch) { + Uint8 *dst; + int row, length, dpitch; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + VITA_GXM_SetYUVProfile(renderer, texture); + + // copy Y plane + // obtain pixels via locking so that texture is flushed + VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); + + length = rect->w; + + if (length == Ypitch && length == dpitch) { + SDL_memcpy(dst, Yplane, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, Yplane, length); + Yplane += Ypitch; + dst += dpitch; + } + } + + // U/V planes + { + void *Udst; + void *Vdst; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; + int uv_pitch = (dpitch+1) / 2; + + // skip Y plane + void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + + if (texture->format == SDL_PIXELFORMAT_YV12) { // YVU + Vdst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + Udst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + } else { // YUV + Udst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + Vdst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + } + + length = UVrect.w; + + // U plane + if (length == Upitch && length == uv_pitch) { + SDL_memcpy(Udst, Uplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Udst, Uplane, length); + Uplane += Upitch; + Udst += uv_pitch; + } + } + + // V plane + if (length == Vpitch && length == uv_pitch) { + SDL_memcpy(Vdst, Vplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Vdst, Vplane, length); + Vplane += Vpitch; + Vdst += uv_pitch; + } + } + + } + return 0; } +static int +VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ + + Uint8 *dst; + int row, length, dpitch; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + VITA_GXM_SetYUVProfile(renderer, texture); + + // copy Y plane + VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); + + length = rect->w * SDL_BYTESPERPIXEL(texture->format); + + if (length == Ypitch && length == dpitch) { + SDL_memcpy(dst, Yplane, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, Yplane, length); + Yplane += Ypitch; + dst += dpitch; + } + } + + // UV plane + { + void *UVdst; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; + int uv_pitch = 2 * ((dpitch+1) / 2); + + // skip Y plane + void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + + UVdst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w * 2; + + // UV plane + if (length == UVpitch && length == uv_pitch) { + SDL_memcpy(UVdst, UVplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(UVdst, UVplane, length); + UVplane += UVpitch; + UVdst += uv_pitch; + } + } + } + + return 0; +} + +#endif + static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) @@ -519,6 +763,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu size_indices = indices ? size_indices : 0; if (texture) { + VITA_GXM_TextureData* vita_texture = (VITA_GXM_TextureData*) texture->driverdata; texture_vertex *vertices; vertices = (texture_vertex *)pool_malloc( @@ -551,7 +796,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu vertices[i].x = xy_[0] * scale_x; vertices[i].y = xy_[1] * scale_y; - vertices[i].u = uv_[0]; + vertices[i].u = uv_[0] * vita_texture->wscale; vertices[i].v = uv_[1]; vertices[i].color = col_; } @@ -730,14 +975,6 @@ SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd) return 0; } -static int -SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) -{ - VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata; - - return SetDrawState(data, cmd); -} - static int VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { @@ -824,11 +1061,7 @@ VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void * nextcmd = nextcmd->next; } - if (thistexture) { - ret = SetCopyState(renderer, cmd); - } else { - ret = SetDrawState(data, cmd); - } + ret = SetDrawState(data, cmd); if (ret == 0) { int op = SCE_GXM_PRIMITIVE_TRIANGLES; @@ -1013,7 +1246,7 @@ VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) sceGxmFinish(data->gxm_context); - free_gxm_texture(vita_texture->tex); + free_gxm_texture(data, vita_texture->tex); SDL_free(vita_texture); diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.c b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.c index d3322730a..85d682ad7 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.c +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.c @@ -26,7 +26,7 @@ #include "SDL_render_vita_gxm_memory.h" void * -mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) +vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) { void *mem; @@ -51,7 +51,7 @@ mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignm } void -mem_gpu_free(SceUID uid) +vita_mem_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -61,7 +61,71 @@ mem_gpu_free(SceUID uid) } void * -mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size) +{ + void *mem; + + if (data->texturePool == NULL) { + int poolsize; + int ret; + SceKernelFreeMemorySizeInfo info; + info.size = sizeof(SceKernelFreeMemorySizeInfo); + sceKernelGetFreeMemorySize(&info); + + poolsize = ALIGN(info.size_cdram, 256*1024); + if (poolsize > info.size_cdram) { + poolsize = ALIGN(info.size_cdram - 256*1024, 256*1024); + } + data->texturePoolUID = sceKernelAllocMemBlock("gpu_texture_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL); + if (data->texturePoolUID < 0) { + return NULL; + } + + ret = sceKernelGetMemBlockBase(data->texturePoolUID, &mem); + if ( ret < 0) + { + return NULL; + } + data->texturePool = sceClibMspaceCreate(mem, poolsize); + + if (data->texturePool == NULL) { + return NULL; + } + ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); + if (ret < 0) + { + return NULL; + } + } + return sceClibMspaceMemalign(data->texturePool, SCE_GXM_TEXTURE_ALIGNMENT, size); +} + +void +vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr) +{ + if (data->texturePool != NULL) + { + sceClibMspaceFree(data->texturePool, ptr); + } +} + +void +vita_gpu_mem_destroy(VITA_GXM_RenderData *data) +{ + void *mem = NULL; + if (data->texturePool != NULL) + { + sceClibMspaceDestroy(data->texturePool); + data->texturePool = NULL; + if (sceKernelGetMemBlockBase(data->texturePoolUID, &mem) < 0) + return; + sceGxmUnmapMemory(mem); + sceKernelFreeMemBlock(data->texturePoolUID); + } +} + +void * +vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -77,7 +141,7 @@ mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) } void -mem_vertex_usse_free(SceUID uid) +vita_mem_vertex_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -87,7 +151,7 @@ mem_vertex_usse_free(SceUID uid) } void * -mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -103,7 +167,7 @@ mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offse } void -mem_fragment_usse_free(SceUID uid) +vita_mem_fragment_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.h b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.h index 51bc8a80a..93b9f3498 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.h +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_memory.h @@ -25,15 +25,19 @@ #include #include #include +#include "SDL_render_vita_gxm_types.h" #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -void *mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); -void mem_gpu_free(SceUID uid); -void *mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_vertex_usse_free(SceUID uid); -void *mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_fragment_usse_free(SceUID uid); +void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); +void vita_mem_free(SceUID uid); +void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size); +void vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr); +void vita_gpu_mem_destroy(VITA_GXM_RenderData *data); +void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_vertex_usse_free(SceUID uid); +void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_fragment_usse_free(SceUID uid); #endif /* SDL_RENDER_VITA_GXM_MEMORY_H */ diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.c b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.c index e043b55ab..035e8a63c 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.c +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.c @@ -117,6 +117,8 @@ tex_format_to_bytespp(SceGxmTextureFormat format) case SCE_GXM_TEXTURE_BASE_FORMAT_U8: case SCE_GXM_TEXTURE_BASE_FORMAT_S8: case SCE_GXM_TEXTURE_BASE_FORMAT_P8: + case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2: // YUV actually uses 12 bits per pixel. UV planes bits/mem are handled elsewhere + case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3: return 1; case SCE_GXM_TEXTURE_BASE_FORMAT_U4U4U4U4: case SCE_GXM_TEXTURE_BASE_FORMAT_U8U3U3U2: @@ -414,28 +416,28 @@ gxm_init(SDL_Renderer *renderer) } // allocate ring buffer memory using default sizes - vdmRingBuffer = mem_gpu_alloc( + vdmRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vdmRingBufferUid); - vertexRingBuffer = mem_gpu_alloc( + vertexRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vertexRingBufferUid); - fragmentRingBuffer = mem_gpu_alloc( + fragmentRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->fragmentRingBufferUid); - fragmentUsseRingBuffer = mem_fragment_usse_alloc( + fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc( SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, &data->fragmentUsseRingBufferUid, &fragmentUsseRingBufferOffset); @@ -480,7 +482,7 @@ gxm_init(SDL_Renderer *renderer) for (i = 0; i < VITA_GXM_BUFFERS; i++) { // allocate memory for display - data->displayBufferData[i] = mem_gpu_alloc( + data->displayBufferData[i] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -525,7 +527,7 @@ gxm_init(SDL_Renderer *renderer) // allocate the depth buffer - data->depthBufferData = mem_gpu_alloc( + data->depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -533,7 +535,7 @@ gxm_init(SDL_Renderer *renderer) &data->depthBufferUid); // allocate the stencil buffer - data->stencilBufferData = mem_gpu_alloc( + data->stencilBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -565,19 +567,19 @@ gxm_init(SDL_Renderer *renderer) // allocate memory for buffers and USSE code - patcherBuffer = mem_gpu_alloc( + patcherBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, patcherBufferSize, 4, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &data->patcherBufferUid); - patcherVertexUsse = mem_vertex_usse_alloc( + patcherVertexUsse = vita_mem_vertex_usse_alloc( patcherVertexUsseSize, &data->patcherVertexUsseUid, &patcherVertexUsseOffset); - patcherFragmentUsse = mem_fragment_usse_alloc( + patcherFragmentUsse = vita_mem_fragment_usse_alloc( patcherFragmentUsseSize, &data->patcherFragmentUsseUid, &patcherFragmentUsseOffset); @@ -728,7 +730,7 @@ gxm_init(SDL_Renderer *renderer) } // create the clear triangle vertex/index data - data->clearVertices = (clear_vertex *)mem_gpu_alloc( + data->clearVertices = (clear_vertex *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 3*sizeof(clear_vertex), 4, @@ -740,7 +742,7 @@ gxm_init(SDL_Renderer *renderer) // Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible // 16-bit indices in linear ascending order, so we can use this for // all drawing operations where we don't want to use indexing. - data->linearIndices = (uint16_t *)mem_gpu_alloc( + data->linearIndices = (uint16_t *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, UINT16_MAX*sizeof(uint16_t), sizeof(uint16_t), @@ -871,7 +873,7 @@ gxm_init(SDL_Renderer *renderer) data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp"); // Allocate memory for the memory pool - data->pool_addr[0] = mem_gpu_alloc( + data->pool_addr[0] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -879,7 +881,7 @@ gxm_init(SDL_Renderer *renderer) &data->poolUid[0] ); - data->pool_addr[1] = mem_gpu_alloc( + data->pool_addr[1] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -918,28 +920,28 @@ void gxm_finish(SDL_Renderer *renderer) free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod); free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul); - mem_gpu_free(data->linearIndicesUid); - mem_gpu_free(data->clearVerticesUid); + vita_mem_free(data->linearIndicesUid); + vita_mem_free(data->clearVerticesUid); // wait until display queue is finished before deallocating display buffers sceGxmDisplayQueueFinish(); // clean up display queue - mem_gpu_free(data->depthBufferUid); + vita_mem_free(data->depthBufferUid); for (size_t i = 0; i < VITA_GXM_BUFFERS; i++) { // clear the buffer then deallocate SDL_memset(data->displayBufferData[i], 0, VITA_GXM_SCREEN_HEIGHT * VITA_GXM_SCREEN_STRIDE * 4); - mem_gpu_free(data->displayBufferUid[i]); + vita_mem_free(data->displayBufferUid[i]); // destroy the sync object sceGxmSyncObjectDestroy(data->displayBufferSync[i]); } // Free the depth and stencil buffer - mem_gpu_free(data->depthBufferUid); - mem_gpu_free(data->stencilBufferUid); + vita_mem_free(data->depthBufferUid); + vita_mem_free(data->stencilBufferUid); // unregister programs and destroy shader patcher sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId); @@ -950,23 +952,24 @@ void gxm_finish(SDL_Renderer *renderer) sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId); sceGxmShaderPatcherDestroy(data->shaderPatcher); - mem_fragment_usse_free(data->patcherFragmentUsseUid); - mem_vertex_usse_free(data->patcherVertexUsseUid); - mem_gpu_free(data->patcherBufferUid); + vita_mem_fragment_usse_free(data->patcherFragmentUsseUid); + vita_mem_vertex_usse_free(data->patcherVertexUsseUid); + vita_mem_free(data->patcherBufferUid); // destroy the render target sceGxmDestroyRenderTarget(data->renderTarget); // destroy the gxm context sceGxmDestroyContext(data->gxm_context); - mem_fragment_usse_free(data->fragmentUsseRingBufferUid); - mem_gpu_free(data->fragmentRingBufferUid); - mem_gpu_free(data->vertexRingBufferUid); - mem_gpu_free(data->vdmRingBufferUid); + vita_mem_fragment_usse_free(data->fragmentUsseRingBufferUid); + vita_mem_free(data->fragmentRingBufferUid); + vita_mem_free(data->vertexRingBufferUid); + vita_mem_free(data->vdmRingBufferUid); SDL_free(data->contextParams.hostMem); - mem_gpu_free(data->poolUid[0]); - mem_gpu_free(data->poolUid[1]); + vita_mem_free(data->poolUid[0]); + vita_mem_free(data->poolUid[1]); + vita_gpu_mem_destroy(data); // terminate libgxm sceGxmTerminate(); @@ -975,16 +978,20 @@ void gxm_finish(SDL_Renderer *renderer) // textures void -free_gxm_texture(gxm_texture *texture) +free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture) { if (texture) { if (texture->gxm_rendertarget) { sceGxmDestroyRenderTarget(texture->gxm_rendertarget); } if (texture->depth_UID) { - mem_gpu_free(texture->depth_UID); + vita_mem_free(texture->depth_UID); + } + if (texture->cdram) { + vita_gpu_mem_free(data, sceGxmTextureGetData(&texture->gxm_tex)); + } else { + vita_mem_free(texture->data_UID); } - mem_gpu_free(texture->data_UID); SDL_free(texture); } } @@ -995,25 +1002,6 @@ gxm_texture_get_format(const gxm_texture *texture) return sceGxmTextureGetFormat(&texture->gxm_tex); } -unsigned int -gxm_texture_get_width(const gxm_texture *texture) -{ - return sceGxmTextureGetWidth(&texture->gxm_tex); -} - -unsigned int -gxm_texture_get_height(const gxm_texture *texture) -{ - return sceGxmTextureGetHeight(&texture->gxm_tex); -} - -unsigned int -gxm_texture_get_stride(const gxm_texture *texture) -{ - return ((gxm_texture_get_width(texture) + 7) & ~7) - * tex_format_to_bytespp(gxm_texture_get_format(texture)); -} - void * gxm_texture_get_datap(const gxm_texture *texture) { @@ -1021,34 +1009,53 @@ gxm_texture_get_datap(const gxm_texture *texture) } gxm_texture * -create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget) +create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale) { gxm_texture *texture = SDL_calloc(1, sizeof(gxm_texture)); - const int tex_size = ((w + 7) & ~ 7) * h * tex_format_to_bytespp(format); + int aligned_w = ALIGN(w, 8); + int texture_w = w; + int tex_size = aligned_w * h * tex_format_to_bytespp(format); void *texture_data; + int ret; + + *return_wscale = 1.0f; + + // SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3/P2 based formats require width aligned to 16 + if ( (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3 || (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2) { + aligned_w = ALIGN(w, 16); + texture_w = aligned_w; + tex_size = aligned_w * h * tex_format_to_bytespp(format); + *return_wscale = (float) (w) / texture_w; + // add storage for UV planes + tex_size += (((aligned_w + 1) / 2) * ((h + 1) / 2)) * 2; + } if (!texture) return NULL; + *return_w = w; + *return_h = h; + *return_pitch = aligned_w * tex_format_to_bytespp(format); + /* Allocate a GPU buffer for the texture */ - texture_data = mem_gpu_alloc( - SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, - tex_size, - SCE_GXM_TEXTURE_ALIGNMENT, - SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, - &texture->data_UID + texture_data = vita_gpu_mem_alloc( + data, + tex_size ); /* Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM */ if (!texture_data) { SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n"); - texture_data = mem_gpu_alloc( + texture_data = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, tex_size, SCE_GXM_TEXTURE_ALIGNMENT, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &texture->data_UID ); + texture->cdram = 0; + } else { + texture->cdram = 1; } if (!texture_data) { @@ -1060,7 +1067,12 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc SDL_memset(texture_data, 0, tex_size); /* Create the gxm texture */ - sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, w, h, 0); + ret = sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, texture_w, h, 0); + if (ret < 0) { + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret); + return NULL; + } if (isRenderTarget) { void *depthBufferData; @@ -1083,13 +1095,13 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc ); if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err); return NULL; } // allocate it - depthBufferData = mem_gpu_alloc( + depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4*sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -1106,8 +1118,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc NULL); if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err); return NULL; } @@ -1131,8 +1143,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc texture->gxm_rendertarget = tgt; if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err); return NULL; } } @@ -1181,7 +1193,7 @@ void gxm_init_for_common_dialog(void) for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { buffer_for_common_dialog[i].displayData.wait_vblank = SDL_TRUE; - buffer_for_common_dialog[i].displayData.address = mem_gpu_alloc( + buffer_for_common_dialog[i].displayData.address = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -1229,7 +1241,7 @@ void gxm_term_for_common_dialog(void) sceGxmDisplayQueueFinish(); for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { - mem_gpu_free(buffer_for_common_dialog[i].uid); + vita_mem_free(buffer_for_common_dialog[i].uid); sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync); } } diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.h b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.h index 351bdc2e6..67659889d 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.h +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_tools.h @@ -48,15 +48,12 @@ void unset_clip_rectangle(VITA_GXM_RenderData *data); int gxm_init(SDL_Renderer *renderer); void gxm_finish(SDL_Renderer *renderer); -gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget); -void free_gxm_texture(gxm_texture *texture); +gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale); +void free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture); void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter); SceGxmTextureFormat gxm_texture_get_format(const gxm_texture *texture); -unsigned int gxm_texture_get_width(const gxm_texture *texture); -unsigned int gxm_texture_get_height(const gxm_texture *texture); -unsigned int gxm_texture_get_stride(const gxm_texture *texture); void *gxm_texture_get_datap(const gxm_texture *texture); void gxm_minimal_init_for_common_dialog(void); diff --git a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_types.h b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_types.h index 898a92d9c..c5cbf5898 100644 --- a/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_types.h +++ b/Engine/lib/sdl/src/render/vitagxm/SDL_render_vita_gxm_types.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -79,6 +80,7 @@ typedef struct gxm_texture { SceGxmColorSurface gxm_colorsurface; SceGxmDepthStencilSurface gxm_depthstencil; SceUID depth_UID; + SDL_bool cdram; } gxm_texture; typedef struct fragment_programs { @@ -186,14 +188,19 @@ typedef struct blend_fragment_programs blendFragmentPrograms; gxm_drawstate_cache drawstate; + SceClibMspace texturePool; + SceUID texturePoolUID; } VITA_GXM_RenderData; typedef struct { gxm_texture *tex; - unsigned int pitch; - unsigned int w; - unsigned int h; + unsigned int pitch; + unsigned int w; + unsigned int h; + float wscale; + SDL_bool yuv; + SDL_bool nv12; } VITA_GXM_TextureData; #endif /* SDL_RENDER_VITA_GXM_TYPES_H */ diff --git a/Engine/lib/sdl/src/test/SDL_test_common.c b/Engine/lib/sdl/src/test/SDL_test_common.c index 48c6c72f0..93a0e7c74 100644 --- a/Engine/lib/sdl/src/test/SDL_test_common.c +++ b/Engine/lib/sdl/src/test/SDL_test_common.c @@ -1464,10 +1464,12 @@ default: return "???"; static void SDLTest_PrintEvent(SDL_Event * event) { +#ifndef VERBOSE_MOTION_EVENTS if ((event->type == SDL_MOUSEMOTION) || (event->type == SDL_FINGERMOTION)) { /* Mouse and finger motion are really spammy */ return; } +#endif switch (event->type) { case SDL_DISPLAYEVENT: diff --git a/Engine/lib/sdl/src/thread/os2/SDL_sysmutex.c b/Engine/lib/sdl/src/thread/os2/SDL_sysmutex.c index 984ae10fe..d3fc7a3bd 100644 --- a/Engine/lib/sdl/src/thread/os2/SDL_sysmutex.c +++ b/Engine/lib/sdl/src/thread/os2/SDL_sysmutex.c @@ -56,12 +56,12 @@ SDL_CreateMutex(void) void SDL_DestroyMutex(SDL_mutex * mutex) { - ULONG ulRC; HMTX hMtx = (HMTX)mutex; - - ulRC = DosCloseMutexSem(hMtx); - if (ulRC != NO_ERROR) { - debug_os2("DosCloseMutexSem(), rc = %u", ulRC); + if (hMtx != NULLHANDLE) { + const ULONG ulRC = DosCloseMutexSem(hMtx); + if (ulRC != NO_ERROR) { + debug_os2("DosCloseMutexSem(), rc = %u", ulRC); + } } } diff --git a/Engine/lib/sdl/src/timer/os2/SDL_systimer.c b/Engine/lib/sdl/src/timer/os2/SDL_systimer.c index c5bcf64b7..8a8425d29 100644 --- a/Engine/lib/sdl/src/timer/os2/SDL_systimer.c +++ b/Engine/lib/sdl/src/timer/os2/SDL_systimer.c @@ -39,6 +39,7 @@ typedef unsigned long long ULLONG; +static SDL_bool ticks_started = SDL_FALSE; static ULONG ulTmrFreq = 0; static ULLONG ullTmrStart = 0; @@ -46,7 +47,14 @@ void SDL_TicksInit(void) { ULONG ulTmrStart; /* for 32-bit fallback. */ - ULONG ulRC = DosTmrQueryFreq(&ulTmrFreq); + ULONG ulRC; + + if (ticks_started) { + return; + } + ticks_started = SDL_TRUE; + + ulRC = DosTmrQueryFreq(&ulTmrFreq); if (ulRC != NO_ERROR) { debug_os2("DosTmrQueryFreq() failed, rc = %u", ulRC); } else { @@ -65,6 +73,7 @@ SDL_TicksInit(void) void SDL_TicksQuit(void) { + ticks_started = SDL_FALSE; } Uint64 @@ -73,7 +82,7 @@ SDL_GetTicks64(void) Uint64 ui64Result; ULLONG ullTmrNow; - if (ulTmrFreq == 0) { /* Was not initialized. */ + if (!ticks_started) { SDL_TicksInit(); } diff --git a/Engine/lib/sdl/src/video/SDL_bmp.c b/Engine/lib/sdl/src/video/SDL_bmp.c index 0987f5435..cb220440a 100644 --- a/Engine/lib/sdl/src/video/SDL_bmp.c +++ b/Engine/lib/sdl/src/video/SDL_bmp.c @@ -412,6 +412,12 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) goto done; } + if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */ + SDL_SetError("Unsupported or incorrect biBitCount field"); + was_error = SDL_TRUE; + goto done; + } + if (biClrUsed == 0) { biClrUsed = 1 << biBitCount; } diff --git a/Engine/lib/sdl/src/video/SDL_egl.c b/Engine/lib/sdl/src/video/SDL_egl.c index c9fb476b0..e62fe9931 100644 --- a/Engine/lib/sdl/src/video/SDL_egl.c +++ b/Engine/lib/sdl/src/video/SDL_egl.c @@ -27,7 +27,6 @@ #endif #if SDL_VIDEO_DRIVER_ANDROID #include -#include "../core/android/SDL_android.h" #include "../video/android/SDL_androidvideo.h" #endif #if SDL_VIDEO_DRIVER_RPI @@ -99,7 +98,7 @@ #define DEFAULT_OGL_ES "libGLESv1_CM.so.1" #endif /* SDL_VIDEO_DRIVER_RPI */ -#if SDL_VIDEO_OPENGL +#if SDL_VIDEO_OPENGL && !SDL_VIDEO_VITA_PVR_OGL #include "SDL_opengl.h" #endif @@ -530,7 +529,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa } #endif /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */ - if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { + if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) && (_this->egl_data->eglGetDisplay != NULL)) { _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display); } if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { @@ -1062,7 +1061,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) { _this->gl_allow_no_surface = SDL_TRUE; } -#if SDL_VIDEO_OPENGL +#if SDL_VIDEO_OPENGL && !defined(SDL_VIDEO_DRIVER_VITA) } else { /* Desktop OpenGL supports it by default from version 3.0 on. */ void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); diff --git a/Engine/lib/sdl/src/video/SDL_pixels.c b/Engine/lib/sdl/src/video/SDL_pixels.c index b76161d03..858ccba7b 100644 --- a/Engine/lib/sdl/src/video/SDL_pixels.c +++ b/Engine/lib/sdl/src/video/SDL_pixels.c @@ -28,6 +28,7 @@ #include "SDL_blit.h" #include "SDL_pixels_c.h" #include "SDL_RLEaccel_c.h" +#include "../SDL_list.h" /* Lookup tables to expand partial bytes to the full 0..255 range */ @@ -1024,12 +1025,6 @@ SDL_AllocBlitMap(void) } -typedef struct SDL_ListNode -{ - void *entry; - struct SDL_ListNode *next; -} SDL_ListNode; - void SDL_InvalidateAllBlitMap(SDL_Surface *surface) { @@ -1045,40 +1040,6 @@ SDL_InvalidateAllBlitMap(SDL_Surface *surface) } } -static void SDL_ListAdd(SDL_ListNode **head, void *ent); -static void SDL_ListRemove(SDL_ListNode **head, void *ent); - -void -SDL_ListAdd(SDL_ListNode **head, void *ent) -{ - SDL_ListNode *node = SDL_malloc(sizeof (*node)); - - if (node == NULL) { - SDL_OutOfMemory(); - return; - } - - node->entry = ent; - node->next = *head; - *head = node; -} - -void -SDL_ListRemove(SDL_ListNode **head, void *ent) -{ - SDL_ListNode **ptr = head; - - while (*ptr) { - if ((*ptr)->entry == ent) { - SDL_ListNode *tmp = *ptr; - *ptr = (*ptr)->next; - SDL_free(tmp); - return; - } - ptr = &(*ptr)->next; - } -} - void SDL_InvalidateMap(SDL_BlitMap * map) { diff --git a/Engine/lib/sdl/src/video/SDL_sysvideo.h b/Engine/lib/sdl/src/video/SDL_sysvideo.h index e2a65045b..2384a64ac 100644 --- a/Engine/lib/sdl/src/video/SDL_sysvideo.h +++ b/Engine/lib/sdl/src/video/SDL_sysvideo.h @@ -345,6 +345,7 @@ struct SDL_VideoDevice Uint32 next_object_id; char *clipboard_text; SDL_bool setting_display_mode; + SDL_bool disable_display_mode_switching; /* * * */ /* Data used by the GL drivers */ diff --git a/Engine/lib/sdl/src/video/SDL_video.c b/Engine/lib/sdl/src/video/SDL_video.c index 3be98806d..93c803e70 100644 --- a/Engine/lib/sdl/src/video/SDL_video.c +++ b/Engine/lib/sdl/src/video/SDL_video.c @@ -61,12 +61,12 @@ static VideoBootStrap *bootstrap[] = { #if SDL_VIDEO_DRIVER_COCOA &COCOA_bootstrap, #endif -#if SDL_VIDEO_DRIVER_WAYLAND - &Wayland_bootstrap, -#endif #if SDL_VIDEO_DRIVER_X11 &X11_bootstrap, #endif +#if SDL_VIDEO_DRIVER_WAYLAND + &Wayland_bootstrap, +#endif #if SDL_VIDEO_DRIVER_VIVANTE &VIVANTE_bootstrap, #endif @@ -261,6 +261,7 @@ SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window * window, Uint32 * fo SDL_TEXTUREACCESS_STREAMING, window->w, window->h); if (!data->texture) { + /* codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_WINDOWTEXTUREDATA and not leaked here. */ return -1; } @@ -424,7 +425,7 @@ SDL_VideoInit(const char *driver_name) i = index = 0; video = NULL; if (driver_name == NULL) { - driver_name = SDL_getenv("SDL_VIDEODRIVER"); + driver_name = SDL_GetHint(SDL_HINT_VIDEODRIVER); } if (driver_name != NULL && *driver_name != 0) { const char *driver_attempt = driver_name; @@ -1184,6 +1185,7 @@ SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode) } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode, &fullscreen_mode)) { + SDL_zerop(mode); return SDL_SetError("Couldn't find display mode match"); } @@ -1337,14 +1339,17 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) resized = SDL_FALSE; } - /* only do the mode change if we want exclusive fullscreen */ - if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { - if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { - return -1; - } - } else { - if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { - return -1; + /* Don't try to change the display mode if the driver doesn't want it. */ + if (_this->disable_display_mode_switching == SDL_FALSE) { + /* only do the mode change if we want exclusive fullscreen */ + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { + if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { + return -1; + } + } else { + if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { + return -1; + } } } @@ -3055,7 +3060,8 @@ ShouldMinimizeOnFocusLoss(SDL_Window * window) /* Real fullscreen windows should minimize on focus loss so the desktop video mode is restored */ hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); if (!hint || !*hint || SDL_strcasecmp(hint, "auto") == 0) { - if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP || + _this->disable_display_mode_switching == SDL_TRUE) { return SDL_FALSE; } else { return SDL_TRUE; @@ -3919,6 +3925,10 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) { int retval; + if (!_this) { + return SDL_UninitializedVideo(); + } + if (window == SDL_GL_GetCurrentWindow() && ctx == SDL_GL_GetCurrentContext()) { /* We're already current. */ @@ -4262,12 +4272,12 @@ SDL_IsScreenKeyboardShown(SDL_Window *window) #if SDL_VIDEO_DRIVER_UIKIT #include "uikit/SDL_uikitmessagebox.h" #endif -#if SDL_VIDEO_DRIVER_WAYLAND -#include "wayland/SDL_waylandmessagebox.h" -#endif #if SDL_VIDEO_DRIVER_X11 #include "x11/SDL_x11messagebox.h" #endif +#if SDL_VIDEO_DRIVER_WAYLAND +#include "wayland/SDL_waylandmessagebox.h" +#endif #if SDL_VIDEO_DRIVER_HAIKU #include "haiku/SDL_bmessagebox.h" #endif @@ -4375,13 +4385,6 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) retval = 0; } #endif -#if SDL_VIDEO_DRIVER_WAYLAND - if (retval == -1 && - SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) && - Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) { - retval = 0; - } -#endif #if SDL_VIDEO_DRIVER_X11 if (retval == -1 && SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) && @@ -4389,6 +4392,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) retval = 0; } #endif +#if SDL_VIDEO_DRIVER_WAYLAND + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) && + Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif #if SDL_VIDEO_DRIVER_HAIKU if (retval == -1 && SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) && diff --git a/Engine/lib/sdl/src/video/android/SDL_androidvideo.c b/Engine/lib/sdl/src/video/android/SDL_androidvideo.c index 61b9a87e9..9555ea078 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidvideo.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidvideo.c @@ -122,6 +122,7 @@ Android_CreateDevice(int devindex) device->SetWindowTitle = Android_SetWindowTitle; device->SetWindowFullscreen = Android_SetWindowFullscreen; device->MinimizeWindow = Android_MinimizeWindow; + device->SetWindowResizable = Android_SetWindowResizable; device->DestroyWindow = Android_DestroyWindow; device->GetWindowWMInfo = Android_GetWindowWMInfo; diff --git a/Engine/lib/sdl/src/video/android/SDL_androidwindow.c b/Engine/lib/sdl/src/video/android/SDL_androidwindow.c index c5f8919ea..f9ae3f10c 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidwindow.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidwindow.c @@ -167,6 +167,12 @@ Android_MinimizeWindow(_THIS, SDL_Window *window) Android_JNI_MinizeWindow(); } +void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable) +{ + /* Set orientation */ + Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS)); +} + void Android_DestroyWindow(_THIS, SDL_Window *window) { diff --git a/Engine/lib/sdl/src/video/android/SDL_androidwindow.h b/Engine/lib/sdl/src/video/android/SDL_androidwindow.h index e78d5068e..58e459006 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidwindow.h +++ b/Engine/lib/sdl/src/video/android/SDL_androidwindow.h @@ -30,6 +30,7 @@ extern int Android_CreateWindow(_THIS, SDL_Window *window); extern void Android_SetWindowTitle(_THIS, SDL_Window *window); extern void Android_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen); extern void Android_MinimizeWindow(_THIS, SDL_Window *window); +extern void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable); extern void Android_DestroyWindow(_THIS, SDL_Window *window); extern SDL_bool Android_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info); diff --git a/Engine/lib/sdl/src/video/dummy/SDL_nullvideo.c b/Engine/lib/sdl/src/video/dummy/SDL_nullvideo.c index aafed848d..a7fb1aac2 100644 --- a/Engine/lib/sdl/src/video/dummy/SDL_nullvideo.c +++ b/Engine/lib/sdl/src/video/dummy/SDL_nullvideo.c @@ -46,6 +46,7 @@ #include "SDL_nullvideo.h" #include "SDL_nullevents_c.h" #include "SDL_nullframebuffer_c.h" +#include "SDL_hints.h" #define DUMMYVID_DRIVER_NAME "dummy" @@ -59,7 +60,7 @@ static void DUMMY_VideoQuit(_THIS); static int DUMMY_Available(void) { - const char *envr = SDL_getenv("SDL_VIDEODRIVER"); + const char *envr = SDL_GetHint(SDL_HINT_VIDEODRIVER); if ((envr) && (SDL_strcmp(envr, DUMMYVID_DRIVER_NAME) == 0)) { return (1); } diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c index d4e9cb8e8..372c6f5ac 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -26,6 +26,8 @@ #include "SDL_emscriptenframebuffer.h" #include "SDL_hints.h" +#include + int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) { @@ -57,18 +59,9 @@ int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * form return 0; } -int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +static void +Emscripten_UpdateWindowFramebufferWorker(SDL_Surface* surface) { - SDL_Surface *surface; - - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - surface = data->surface; - if (!surface) { - return SDL_SetError("Couldn't find framebuffer surface for window"); - } - - /* Send the data to the display */ - EM_ASM_INT({ var w = $0; var h = $1; @@ -156,6 +149,29 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec SDL2.ctx.putImageData(SDL2.image, 0, 0); return 0; }, surface->w, surface->h, surface->pixels); +} + +int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +{ + SDL_Surface *surface; + + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + surface = data->surface; + if (!surface) { + return SDL_SetError("Couldn't find framebuffer surface for window"); + } + + /* Send the data to the display */ + + if (emscripten_is_main_runtime_thread()) { + Emscripten_UpdateWindowFramebufferWorker(surface); + } else { + emscripten_sync_run_in_main_runtime_thread( + EM_FUNC_SIG_VI, + Emscripten_UpdateWindowFramebufferWorker, + (uint32_t)surface + ); + } if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) { /* give back control to browser for screen refresh */ diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c index e73072590..e41480725 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c @@ -24,6 +24,7 @@ #include #include +#include #include "SDL_emscriptenmouse.h" #include "SDL_emscriptenvideo.h" @@ -62,19 +63,10 @@ Emscripten_CreateDefaultCursor() return Emscripten_CreateCursorFromString("default", SDL_FALSE); } -static SDL_Cursor* -Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) +static const char* +Emscripten_GetCursorUrl(int w, int h, int hot_x, int hot_y, void* pixels) { - const char *cursor_url = NULL; - SDL_Surface *conv_surf; - - conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); - - if (!conv_surf) { - return NULL; - } - - cursor_url = (const char *)EM_ASM_INT({ + return (const char *)EM_ASM_INT({ var w = $0; var h = $1; var hot_x = $2; @@ -122,7 +114,40 @@ Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) stringToUTF8(url, urlBuf, url.length + 1); return urlBuf; - }, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels); + }, w, h, hot_x, hot_y, pixels); +} + +static SDL_Cursor* +Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) +{ + const char *cursor_url = NULL; + SDL_Surface *conv_surf; + + conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); + + if (!conv_surf) { + return NULL; + } + + if (emscripten_is_main_runtime_thread()) { + cursor_url = Emscripten_GetCursorUrl( + surface->w, + surface->h, + hot_x, + hot_y, + conv_surf->pixels + ); + } else { + cursor_url = (const char *)emscripten_sync_run_in_main_runtime_thread( + EM_FUNC_SIG_IIIIIII, + Emscripten_GetCursorUrl, + surface->w, + surface->h, + hot_x, + hot_y, + conv_surf->pixels + ); + } SDL_FreeSurface(conv_surf); @@ -206,16 +231,15 @@ Emscripten_ShowCursor(SDL_Cursor* cursor) curdata = (Emscripten_CursorData *) cursor->driverdata; if(curdata->system_cursor) { - EM_ASM_INT({ + MAIN_THREAD_EM_ASM({ if (Module['canvas']) { Module['canvas'].style['cursor'] = UTF8ToString($0); } - return 0; }, curdata->system_cursor); } } else { - EM_ASM( + MAIN_THREAD_EM_ASM( if (Module['canvas']) { Module['canvas'].style['cursor'] = 'none'; } diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c index f6ee1e7e5..4c6038f09 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c @@ -174,10 +174,10 @@ Emscripten_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * if (rect) { rect->x = 0; rect->y = 0; - rect->w = EM_ASM_INT_V({ + rect->w = MAIN_THREAD_EM_ASM_INT({ return window.innerWidth; }); - rect->h = EM_ASM_INT_V({ + rect->h = MAIN_THREAD_EM_ASM_INT({ return window.innerHeight; }); } diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitmessagebox.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitmessagebox.m index fdc20c086..b6d56f350 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitmessagebox.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitmessagebox.m @@ -186,8 +186,8 @@ UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *but #endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ } -int -UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +static void +UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid, int *returnValue) { BOOL success = NO; @@ -199,12 +199,26 @@ UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) } if (!success) { - return SDL_SetError("Could not show message box."); + *returnValue = SDL_SetError("Could not show message box."); + } else { + *returnValue = 0; } - - return 0; } +int +UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ @autoreleasepool +{ + __block int returnValue = 0; + + if ([NSThread isMainThread]) { + UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); }); + } + return returnValue; +}} + #endif /* SDL_VIDEO_DRIVER_UIKIT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitaframebuffer.c b/Engine/lib/sdl/src/video/vita/SDL_vitaframebuffer.c index 992c7af84..1c558486b 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitaframebuffer.c +++ b/Engine/lib/sdl/src/video/vita/SDL_vitaframebuffer.c @@ -31,7 +31,7 @@ #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) #define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8 -void *vita_gpu_alloc(SceKernelMemBlockType type, unsigned int size, SceUID *uid) +void *vita_gpu_alloc(unsigned int type, unsigned int size, SceUID *uid) { void *mem; diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr.c b/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr.c index 3b7fb7477..d51150c03 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr.c +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr.c @@ -20,11 +20,12 @@ */ #include "../../SDL_internal.h" -#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR +#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR && SDL_VIDEO_VITA_PVR_OGL #include #include #include #include +#include #include "SDL_error.h" #include "SDL_log.h" @@ -34,6 +35,16 @@ #define MAX_PATH 256 // vita limits are somehow wrong +/* Defaults */ +int FB_WIDTH = 960; +int FB_HEIGHT = 544; + +void getFBSize(int *width, int *height) +{ + *width = FB_WIDTH; + *height = FB_HEIGHT; +} + int VITA_GL_LoadLibrary(_THIS, const char *path) { @@ -53,6 +64,9 @@ VITA_GL_LoadLibrary(_THIS, const char *path) sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL); sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL); + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libGL.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx"); sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); @@ -74,30 +88,45 @@ VITA_GL_LoadLibrary(_THIS, const char *path) SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window) { - return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); -} + char gl_version[3]; + SDL_GLContext context = NULL; + int temp_major = _this->gl_config.major_version; + int temp_minor = _this->gl_config.minor_version; + int temp_profile = _this->gl_config.profile_mask; -int -VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) -{ - if (window && context) { - return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context); - } else { - return SDL_EGL_MakeCurrent(_this, NULL, NULL); + /* Set version to 2.0 and PROFILE to ES */ + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 0; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; + + context = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); + + if (context != NULL) + { + FB_WIDTH = window->w; + FB_HEIGHT = window->h; + set_getprocaddress((void *(*)(const char *))eglGetProcAddress); + set_getmainfbsize(getFBSize); + SDL_snprintf(gl_version, 3, "%d%d", temp_major, temp_minor); + gl4es_setenv("LIBGL_NOTEXRECT", "1", 1); /* Currently broken in driver */ + gl4es_setenv("LIBGL_GL", gl_version, 1); + initialize_gl4es(); } + + /* Restore gl_config */ + _this->gl_config.major_version = temp_major; + _this->gl_config.minor_version = temp_minor; + _this->gl_config.profile_mask = temp_profile; + + return context; } -int -VITA_GL_SwapWindow(_THIS, SDL_Window * window) +void * +VITA_GL_GetProcAddress(_THIS, const char *proc) { - SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; - if (videodata->ime_active) { - sceImeUpdate(); - } - return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); + return gl4es_GetProcAddress(proc); } - #endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr_c.h b/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr_c.h index 670eaebb0..2329d472b 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr_c.h +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagl_pvr_c.h @@ -19,17 +19,16 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SDL_vitagl_c_h_ -#define SDL_vitagl_c_h_ +#ifndef SDL_vitagl_pvr_c_h_ +#define SDL_vitagl_pvr_c_h_ #include "SDL_vitavideo.h" -extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); -extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window); extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); extern int VITA_GL_LoadLibrary(_THIS, const char *path); +extern void *VITA_GL_GetProcAddress(_THIS, const char *proc); -#endif /* SDL_vitagl_c_h_ */ +#endif /* SDL_vitagl_pvr_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagl.c b/Engine/lib/sdl/src/video/vita/SDL_vitagles.c similarity index 91% rename from Engine/lib/sdl/src/video/vita/SDL_vitagl.c rename to Engine/lib/sdl/src/video/vita/SDL_vitagles.c index f65022865..18ca7d57b 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitagl.c +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagles.c @@ -27,7 +27,7 @@ #include "SDL_error.h" #include "SDL_log.h" #include "SDL_vitavideo.h" -#include "SDL_vitagl_c.h" +#include "SDL_vitagles_c.h" /*****************************************************************************/ /* SDL OpenGL/OpenGL ES functions */ @@ -45,7 +45,7 @@ } while (0) void -VITA_GL_KeyboardCallback(ScePigletPreSwapData *data) +VITA_GLES_KeyboardCallback(ScePigletPreSwapData *data) { SceCommonDialogUpdateParam commonDialogParam; SDL_zero(commonDialogParam); @@ -62,20 +62,20 @@ VITA_GL_KeyboardCallback(ScePigletPreSwapData *data) } int -VITA_GL_LoadLibrary(_THIS, const char *path) +VITA_GLES_LoadLibrary(_THIS, const char *path) { pibInit(PIB_SHACCCG | PIB_GET_PROC_ADDR_CORE); return 0; } void * -VITA_GL_GetProcAddress(_THIS, const char *proc) +VITA_GLES_GetProcAddress(_THIS, const char *proc) { return eglGetProcAddress(proc); } void -VITA_GL_UnloadLibrary(_THIS) +VITA_GLES_UnloadLibrary(_THIS) { eglTerminate(_this->gl_data->display); } @@ -84,7 +84,7 @@ static EGLint width = 960; static EGLint height = 544; SDL_GLContext -VITA_GL_CreateContext(_THIS, SDL_Window * window) +VITA_GLES_CreateContext(_THIS, SDL_Window * window) { SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata; @@ -159,13 +159,13 @@ VITA_GL_CreateContext(_THIS, SDL_Window * window) _this->gl_data->surface = surface; preSwapCallback = (PFNEGLPIGLETVITASETPRESWAPCALLBACKSCEPROC) eglGetProcAddress("eglPigletVitaSetPreSwapCallbackSCE"); - preSwapCallback(VITA_GL_KeyboardCallback); + preSwapCallback(VITA_GLES_KeyboardCallback); return context; } int -VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) { if (!eglMakeCurrent(_this->gl_data->display, _this->gl_data->surface, _this->gl_data->surface, _this->gl_data->context)) @@ -176,7 +176,7 @@ VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) } int -VITA_GL_SetSwapInterval(_THIS, int interval) +VITA_GLES_SetSwapInterval(_THIS, int interval) { EGLBoolean status; status = eglSwapInterval(_this->gl_data->display, interval); @@ -190,13 +190,13 @@ VITA_GL_SetSwapInterval(_THIS, int interval) } int -VITA_GL_GetSwapInterval(_THIS) +VITA_GLES_GetSwapInterval(_THIS) { return _this->gl_data->swapinterval; } int -VITA_GL_SwapWindow(_THIS, SDL_Window * window) +VITA_GLES_SwapWindow(_THIS, SDL_Window * window) { if (!eglSwapBuffers(_this->gl_data->display, _this->gl_data->surface)) { return SDL_SetError("eglSwapBuffers() failed"); @@ -205,7 +205,7 @@ VITA_GL_SwapWindow(_THIS, SDL_Window * window) } void -VITA_GL_DeleteContext(_THIS, SDL_GLContext context) +VITA_GLES_DeleteContext(_THIS, SDL_GLContext context) { SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; EGLBoolean status; diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagl_c.h b/Engine/lib/sdl/src/video/vita/SDL_vitagles_c.h similarity index 67% rename from Engine/lib/sdl/src/video/vita/SDL_vitagl_c.h rename to Engine/lib/sdl/src/video/vita/SDL_vitagles_c.h index 272653d70..10fd8533a 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitagl_c.h +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagles_c.h @@ -19,8 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SDL_vitagl_c_h_ -#define SDL_vitagl_c_h_ +#ifndef SDL_vitagles_c_h_ +#define SDL_vitagles_c_h_ #include @@ -39,19 +39,19 @@ typedef struct SDL_GLDriverData { uint32_t swapinterval; }SDL_GLDriverData; -extern void * VITA_GL_GetProcAddress(_THIS, const char *proc); -extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); -extern void VITA_GL_SwapBuffers(_THIS); +extern void * VITA_GLES_GetProcAddress(_THIS, const char *proc); +extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); +extern void VITA_GLES_SwapBuffers(_THIS); -extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window); -extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); +extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); -extern int VITA_GL_LoadLibrary(_THIS, const char *path); -extern void VITA_GL_UnloadLibrary(_THIS); -extern int VITA_GL_SetSwapInterval(_THIS, int interval); -extern int VITA_GL_GetSwapInterval(_THIS); +extern int VITA_GLES_LoadLibrary(_THIS, const char *path); +extern void VITA_GLES_UnloadLibrary(_THIS); +extern int VITA_GLES_SetSwapInterval(_THIS, int interval); +extern int VITA_GLES_GetSwapInterval(_THIS); -#endif /* SDL_vitagl_c_h_ */ +#endif /* SDL_vitagles_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr.c b/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr.c new file mode 100644 index 000000000..bb06d2946 --- /dev/null +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr.c @@ -0,0 +1,103 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR +#include +#include +#include +#include + +#include "SDL_error.h" +#include "SDL_log.h" +#include "SDL_vitavideo.h" +#include "../SDL_egl_c.h" +#include "SDL_vitagles_pvr_c.h" + +#define MAX_PATH 256 // vita limits are somehow wrong + +int +VITA_GLES_LoadLibrary(_THIS, const char *path) +{ + PVRSRV_PSP2_APPHINT hint; + char* override = SDL_getenv("VITA_MODULE_PATH"); + char* skip_init = SDL_getenv("VITA_PVR_SKIP_INIT"); + char* default_path = "app0:module"; + char target_path[MAX_PATH]; + + if (skip_init == NULL) // we don't care about actual value + { + if (override != NULL) + { + default_path = override; + } + + sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL); + sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL); + + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libIMGEGL.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + + PVRSRVInitializeAppHint(&hint); + + SDL_snprintf(hint.szGLES1, MAX_PATH, "%s/%s", default_path, "libGLESv1_CM.suprx"); + SDL_snprintf(hint.szGLES2, MAX_PATH, "%s/%s", default_path, "libGLESv2.suprx"); + SDL_snprintf(hint.szWindowSystem, MAX_PATH, "%s/%s", default_path, "libpvrPSP2_WSEGL.suprx"); + + PVRSRVCreateVirtualAppHint(&hint); + } + + return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0); +} + +SDL_GLContext +VITA_GLES_CreateContext(_THIS, SDL_Window * window) +{ + return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); +} + +int +VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +{ + if (window && context) { + return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context); + } else { + return SDL_EGL_MakeCurrent(_this, NULL, NULL); + } +} + +int +VITA_GLES_SwapWindow(_THIS, SDL_Window * window) +{ + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + if (videodata->ime_active) { + sceImeUpdate(); + } + return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); +} + + +#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr_c.h b/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr_c.h new file mode 100644 index 000000000..c3a13c436 --- /dev/null +++ b/Engine/lib/sdl/src/video/vita/SDL_vitagles_pvr_c.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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_vitagles_pvr_c_h_ +#define SDL_vitagles_pvr_c_h_ + +#include "SDL_vitavideo.h" + +extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); +extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); +extern int VITA_GLES_LoadLibrary(_THIS, const char *path); + + +#endif /* SDL_vitagles_pvr_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitavideo.c b/Engine/lib/sdl/src/video/vita/SDL_vitavideo.c index 778a87073..60bd18f45 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitavideo.c +++ b/Engine/lib/sdl/src/video/vita/SDL_vitavideo.c @@ -41,15 +41,17 @@ #include "SDL_vitaframebuffer.h" #if defined(SDL_VIDEO_VITA_PIB) - #include "SDL_vitagl_c.h" + #include "SDL_vitagles_c.h" #elif defined(SDL_VIDEO_VITA_PVR) + #include "SDL_vitagles_pvr_c.h" +#if defined(SDL_VIDEO_VITA_PVR_OGL) #include "SDL_vitagl_pvr_c.h" - #include "../SDL_egl_c.h" - #define VITA_GL_GetProcAddress SDL_EGL_GetProcAddress - #define VITA_GL_UnloadLibrary SDL_EGL_UnloadLibrary - #define VITA_GL_SetSwapInterval SDL_EGL_SetSwapInterval - #define VITA_GL_GetSwapInterval SDL_EGL_GetSwapInterval - #define VITA_GL_DeleteContext SDL_EGL_DeleteContext +#endif + #define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddress + #define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary + #define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval + #define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval + #define VITA_GLES_DeleteContext SDL_EGL_DeleteContext #endif SDL_Window *Vita_Window; @@ -140,15 +142,26 @@ VITA_Create() */ #if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR) +#if defined(SDL_VIDEO_VITA_PVR_OGL) +if(SDL_getenv("VITA_PVR_OGL") != NULL) { device->GL_LoadLibrary = VITA_GL_LoadLibrary; - device->GL_GetProcAddress = VITA_GL_GetProcAddress; - device->GL_UnloadLibrary = VITA_GL_UnloadLibrary; device->GL_CreateContext = VITA_GL_CreateContext; - device->GL_MakeCurrent = VITA_GL_MakeCurrent; - device->GL_SetSwapInterval = VITA_GL_SetSwapInterval; - device->GL_GetSwapInterval = VITA_GL_GetSwapInterval; - device->GL_SwapWindow = VITA_GL_SwapWindow; - device->GL_DeleteContext = VITA_GL_DeleteContext; + device->GL_GetProcAddress = VITA_GL_GetProcAddress; +} else { +#endif + device->GL_LoadLibrary = VITA_GLES_LoadLibrary; + device->GL_CreateContext = VITA_GLES_CreateContext; + device->GL_GetProcAddress = VITA_GLES_GetProcAddress; +#if defined(SDL_VIDEO_VITA_PVR_OGL) +} +#endif + + device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary; + device->GL_MakeCurrent = VITA_GLES_MakeCurrent; + device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval; + device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval; + device->GL_SwapWindow = VITA_GLES_SwapWindow; + device->GL_DeleteContext = VITA_GLES_DeleteContext; #endif device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport; @@ -245,6 +258,9 @@ VITA_CreateWindow(_THIS, SDL_Window * window) SDL_WindowData *wdata; #if defined(SDL_VIDEO_VITA_PVR) Psp2NativeWindow win; + int temp_major = 2; + int temp_minor = 1; + int temp_profile = 0; #endif /* Allocate window internal data */ @@ -282,11 +298,26 @@ VITA_CreateWindow(_THIS, SDL_Window * window) win.windowSize = PSP2_WINDOW_960X544; } if ((window->flags & SDL_WINDOW_OPENGL) != 0) { - wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win); + if(SDL_getenv("VITA_PVR_OGL") != NULL) { + /* Set version to 2.1 and PROFILE to ES */ + temp_major = _this->gl_config.major_version; + temp_minor = _this->gl_config.minor_version; + temp_profile = _this->gl_config.profile_mask; + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 1; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; + } + wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win); if (wdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); } + if(SDL_getenv("VITA_PVR_OGL") != NULL) { + /* Revert */ + _this->gl_config.major_version = temp_major; + _this->gl_config.minor_version = temp_minor; + _this->gl_config.profile_mask = temp_profile; + } } #endif diff --git a/Engine/lib/sdl/src/video/vita/SDL_vitavideo.h b/Engine/lib/sdl/src/video/vita/SDL_vitavideo.h index 04488dde3..9fdf7e69c 100644 --- a/Engine/lib/sdl/src/video/vita/SDL_vitavideo.h +++ b/Engine/lib/sdl/src/video/vita/SDL_vitavideo.h @@ -90,16 +90,23 @@ SDL_bool VITA_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); #if SDL_VIDEO_DRIVER_VITA +#if defined(SDL_VIDEO_VITA_PVR_OGL) /* OpenGL functions */ int VITA_GL_LoadLibrary(_THIS, const char *path); -void *VITA_GL_GetProcAddress(_THIS, const char *proc); -void VITA_GL_UnloadLibrary(_THIS); SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); -int VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); -int VITA_GL_SetSwapInterval(_THIS, int interval); -int VITA_GL_GetSwapInterval(_THIS); -int VITA_GL_SwapWindow(_THIS, SDL_Window * window); -void VITA_GL_DeleteContext(_THIS, SDL_GLContext context); +void *VITA_GL_GetProcAddress(_THIS, const char *proc); +#endif + +/* OpenGLES functions */ +int VITA_GLES_LoadLibrary(_THIS, const char *path); +void *VITA_GLES_GetProcAddress(_THIS, const char *proc); +void VITA_GLES_UnloadLibrary(_THIS); +SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); +int VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); +int VITA_GLES_SetSwapInterval(_THIS, int interval); +int VITA_GLES_GetSwapInterval(_THIS); +int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +void VITA_GLES_DeleteContext(_THIS, SDL_GLContext context); #endif /* VITA on screen keyboard */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h index c867ec001..3d8d973cc 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h @@ -52,6 +52,14 @@ enum libdecor_window_state; #include "xkbcommon/xkbcommon.h" #include "xkbcommon/xkbcommon-compose.h" +/* Must be included before our #defines, see Bugzilla #4957 */ +#include "wayland-client-core.h" + +#define SDL_WAYLAND_CHECK_VERSION(x, y, z) \ + (WAYLAND_VERSION_MAJOR > x || \ + (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \ + (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z)) + #ifdef __cplusplus extern "C" { @@ -71,9 +79,6 @@ void SDL_WAYLAND_UnloadSymbols(void); } #endif -/* Must be included before our #defines, see Bugzilla #4957 */ -#include "wayland-client-core.h" - #ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC #if defined(_WAYLAND_CLIENT_H) || defined(WAYLAND_CLIENT_H) diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c index 55893201b..e515d9d6f 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c @@ -40,6 +40,7 @@ #include "xdg-shell-client-protocol.h" #include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -83,6 +84,7 @@ static const struct { { XKB_KEY_Super_R, SDLK_RGUI }, { XKB_KEY_Hyper_L, SDLK_LGUI }, { XKB_KEY_Hyper_R, SDLK_RGUI }, + { XKB_KEY_BackSpace, SDLK_BACKSPACE }, }; struct SDL_WaylandTouchPoint { @@ -387,8 +389,10 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, input->sx_w = sx_w; input->sy_w = sy_w; if (input->pointer_focus) { - const int sx = wl_fixed_to_int(sx_w); - const int sy = wl_fixed_to_int(sy_w); + const float sx_f = (float)wl_fixed_to_double(sx_w); + const float sy_f = (float)wl_fixed_to_double(sy_w); + const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x); + const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y); SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); } } @@ -472,6 +476,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) const uint32_t *directions_libdecor = directions; #endif + /* Hit tests shouldn't apply to xdg_popups, right? */ + SDL_assert(!WINDOW_IS_XDG_POPUP(window)); + switch (rc) { case SDL_HITTEST_DRAGGABLE: #ifdef HAVE_LIBDECOR_H @@ -715,8 +722,8 @@ touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial, int id, wl_fixed_t fx, wl_fixed_t fy) { SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); - const double dblx = wl_fixed_to_double(fx); - const double dbly = wl_fixed_to_double(fy); + const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; + const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; const float x = dblx / window_data->sdlwindow->w; const float y = dbly / window_data->sdlwindow->h; @@ -748,8 +755,8 @@ touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp, int id, wl_fixed_t fx, wl_fixed_t fy) { SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); - const double dblx = wl_fixed_to_double(fx); - const double dbly = wl_fixed_to_double(fy); + const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; + const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; const float x = dblx / window_data->sdlwindow->w; const float y = dbly / window_data->sdlwindow->h; @@ -815,6 +822,16 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, return; } + #define GET_MOD_INDEX(mod) \ + WAYLAND_xkb_keymap_mod_get_index(input->xkb.keymap, XKB_MOD_NAME_##mod) + input->xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT); + input->xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL); + input->xkb.idx_alt = 1 << GET_MOD_INDEX(ALT); + input->xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO); + input->xkb.idx_num = 1 << GET_MOD_INDEX(NUM); + input->xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS); + #undef GET_MOD_INDEX + input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); if (!input->xkb.state) { fprintf(stderr, "failed to create XKB state\n"); @@ -829,10 +846,14 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, */ /* Look up the preferred locale, falling back to "C" as default */ - if (!(locale = SDL_getenv("LC_ALL"))) - if (!(locale = SDL_getenv("LC_CTYPE"))) - if (!(locale = SDL_getenv("LANG"))) + if (!(locale = SDL_getenv("LC_ALL"))) { + if (!(locale = SDL_getenv("LC_CTYPE"))) { + if (!(locale = SDL_getenv("LANG"))) { locale = "C"; + } + } + } + /* Set up XKB compose table */ input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); @@ -903,7 +924,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, } static SDL_bool -keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime) +keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime) { SDL_WindowData *window = input->keyboard_focus; const xkb_keysym_t *syms; @@ -920,12 +941,16 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint sym = syms[0]; #ifdef SDL_USE_IME - if (SDL_IME_ProcessKeyEvent(sym, key + 8)) { + if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) { *handled_by_ime = SDL_TRUE; return SDL_TRUE; } #endif + if (state == SDL_RELEASED) { + return SDL_FALSE; + } + if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) { switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) { case XKB_COMPOSE_COMPOSING: @@ -959,7 +984,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, SDL_bool handled_by_ime = SDL_FALSE; if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - has_text = keyboard_input_get_text(text, input, key, &handled_by_ime); + has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime); } else { if (keyboard_repeat_is_set(&input->keyboard_repeat)) { // Send any due key repeat events before stopping the repeat and generating the key up event @@ -969,6 +994,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time); keyboard_repeat_clear(&input->keyboard_repeat); } + keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime); } if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) { @@ -1054,10 +1080,24 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, { struct SDL_WaylandInput *input = data; Wayland_Keymap keymap; + uint32_t modstate = (mods_depressed | mods_latched | mods_locked); WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + SDL_ToggleModState(KMOD_SHIFT, modstate & input->xkb.idx_shift); + SDL_ToggleModState(KMOD_CTRL, modstate & input->xkb.idx_ctrl); + SDL_ToggleModState(KMOD_ALT, modstate & input->xkb.idx_alt); + SDL_ToggleModState(KMOD_GUI, modstate & input->xkb.idx_gui); + SDL_ToggleModState(KMOD_NUM, modstate & input->xkb.idx_num); + SDL_ToggleModState(KMOD_CAPS, modstate & input->xkb.idx_caps); + + if (group == input->xkb.current_group) { + return; + } + + /* The layout changed, remap and fire an event */ + input->xkb.current_group = group; keymap.layout = group; SDL_GetDefaultKeymap(keymap.keymap); WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap, @@ -1646,6 +1686,363 @@ Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version) } } +static void +tablet_tool_handle_type(void* data, struct zwp_tablet_tool_v2* tool, uint32_t type) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_hardware_serial(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial_hi, uint32_t serial_lo) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_hardware_id_wacom(void* data, struct zwp_tablet_tool_v2* tool, uint32_t id_hi, uint32_t id_lo) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_capability(void* data, struct zwp_tablet_tool_v2* tool, uint32_t capability) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_done(void* data, struct zwp_tablet_tool_v2* tool) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_removed(void* data, struct zwp_tablet_tool_v2* tool) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_proximity_in(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, struct zwp_tablet_v2* tablet, struct wl_surface* surface) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window; + + if (!surface) { + return; + } + + if (!SDL_WAYLAND_own_surface(surface)) { + return; + } + + window = (SDL_WindowData*)wl_surface_get_user_data(surface); + + if (window) { + input->tool_focus = window; + input->tool_prox_serial = serial; + + input->is_down = SDL_FALSE; + + input->btn_stylus = SDL_FALSE; + input->btn_stylus2 = SDL_FALSE; + input->btn_stylus3 = SDL_FALSE; + + SDL_SetMouseFocus(window->sdlwindow); + SDL_SetCursor(NULL); + } +} + +static void +tablet_tool_handle_proximity_out(void* data, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + + if (input->tool_focus) { + SDL_SetMouseFocus(NULL); + input->tool_focus = NULL; + } +} + +uint32_t +tablet_tool_btn_to_sdl_button(struct SDL_WaylandTabletInput* input) +{ + unsigned int tool_btn = input->btn_stylus3 << 2 | input->btn_stylus2 << 1 | input->btn_stylus << 0; + switch (tool_btn) { + case 0b000: + return SDL_BUTTON_LEFT; + case 0b001: + return SDL_BUTTON_RIGHT; + case 0b010: + return SDL_BUTTON_MIDDLE; + case 0b100: + return SDL_BUTTON_X1; + default: + return SDL_BUTTON_LEFT; + } +} + +static void +tablet_tool_handle_down(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + input->is_down = SDL_TRUE; + if (!window) { + /* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd. + * that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still + * received. To prevent SIGSEGV this returns when this is the case. + */ + return; + } + + SDL_SendMouseButton(window->sdlwindow, 0, SDL_PRESSED, tablet_tool_btn_to_sdl_button(input)); +} + +static void +tablet_tool_handle_up(void* data, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + + input->is_down = SDL_FALSE; + + if (!window) { + /* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd. + * that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still + * received. To prevent SIGSEGV this returns when this is the case. + */ + return; + } + + SDL_SendMouseButton(window->sdlwindow, 0, SDL_RELEASED, tablet_tool_btn_to_sdl_button(input)); +} + +static void +tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + + input->sx_w = sx_w; + input->sy_w = sy_w; + if (input->tool_focus) { + const float sx_f = (float)wl_fixed_to_double(sx_w); + const float sy_f = (float)wl_fixed_to_double(sy_w); + const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x); + const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y); + SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); + } +} + +static void +tablet_tool_handle_pressure(void* data, struct zwp_tablet_tool_v2* tool, uint32_t pressure) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_distance(void* data, struct zwp_tablet_tool_v2* tool, uint32_t distance) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_tilt(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t xtilt, wl_fixed_t ytilt) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_button(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, uint32_t button, uint32_t state) +{ + struct SDL_WaylandTabletInput* input = data; + + if (input->is_down) { + tablet_tool_handle_up(data, tool); + input->is_down = SDL_TRUE; + } + + switch (button) { + /* see %{_includedir}/linux/input-event-codes.h */ + case 0x14b: /* BTN_STYLUS */ + input->btn_stylus = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + case 0x14c: /* BTN_STYLUS2 */ + input->btn_stylus2 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + case 0x149: /* BTN_STYLUS3 */ + input->btn_stylus3 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + } + + if (input->is_down) { + tablet_tool_handle_down(data, tool, serial); + } +} + +static void +tablet_tool_handle_rotation(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t degrees) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_slider(void* data, struct zwp_tablet_tool_v2* tool, int32_t position) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_wheel(void* data, struct zwp_tablet_tool_v2* tool, int32_t degrees, int32_t clicks) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_frame(void* data, struct zwp_tablet_tool_v2* tool, uint32_t time) +{ + /* unimplemented */ +} + + +static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { + tablet_tool_handle_type, + tablet_tool_handle_hardware_serial, + tablet_tool_handle_hardware_id_wacom, + tablet_tool_handle_capability, + tablet_tool_handle_done, + tablet_tool_handle_removed, + tablet_tool_handle_proximity_in, + tablet_tool_handle_proximity_out, + tablet_tool_handle_down, + tablet_tool_handle_up, + tablet_tool_handle_motion, + tablet_tool_handle_pressure, + tablet_tool_handle_distance, + tablet_tool_handle_tilt, + tablet_tool_handle_rotation, + tablet_tool_handle_slider, + tablet_tool_handle_wheel, + tablet_tool_handle_button, + tablet_tool_handle_frame +}; + +struct SDL_WaylandTabletObjectListNode* +tablet_object_list_new_node(void* object) +{ + struct SDL_WaylandTabletObjectListNode* node; + + node = SDL_calloc(1, sizeof *node); + if (node == NULL) { + return NULL; + } + + node->next = NULL; + node->object = object; + + return node; +} + +void tablet_object_list_append(struct SDL_WaylandTabletObjectListNode* head, void* object) +{ + if (head->object == NULL) { + head->object = object; + return; + } + + while (head->next) { + head = head->next; + } + + head->next = tablet_object_list_new_node(object); +} + +void tablet_object_list_destroy(struct SDL_WaylandTabletObjectListNode* head, void (*deleter)(void* object)) +{ + while (head) { + struct SDL_WaylandTabletObjectListNode* next = head->next; + if (head->object) { + (*deleter)(head->object); + } + SDL_free(head); + head = next; + } +} + + +static void +tablet_seat_handle_tablet_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_v2* tablet) +{ + struct SDL_WaylandTabletInput* input = data; + + tablet_object_list_append(input->tablets, tablet); +} + +static void +tablet_seat_handle_tool_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + + zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, data); + zwp_tablet_tool_v2_set_user_data(tool, data); + + tablet_object_list_append(input->tools, tool); +} + +static void +tablet_seat_handle_pad_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_pad_v2* pad) +{ + struct SDL_WaylandTabletInput* input = data; + + tablet_object_list_append(input->pads, pad); +} + +static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { + tablet_seat_handle_tablet_added, + tablet_seat_handle_tool_added, + tablet_seat_handle_pad_added +}; + +void +Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager) +{ + struct SDL_WaylandTabletInput* tablet_input; + + if (!tablet_manager || !input || !input->seat) { + return; + } + + tablet_input = SDL_calloc(1, sizeof *tablet_input); + if (tablet_input == NULL) { + return; + } + + input->tablet = tablet_input; + + tablet_input->seat = (struct SDL_WaylandTabletSeat*)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2*)tablet_manager, input->seat); + + tablet_input->tablets = tablet_object_list_new_node(NULL); + tablet_input->tools = tablet_object_list_new_node(NULL); + tablet_input->pads = tablet_object_list_new_node(NULL); + + zwp_tablet_seat_v2_add_listener((struct zwp_tablet_seat_v2*)tablet_input->seat, &tablet_seat_listener, tablet_input); +} + +#define TABLET_OBJECT_LIST_DELETER(fun) (void (*)(void*))fun +void +Wayland_input_destroy_tablet(struct SDL_WaylandInput* input) +{ + tablet_object_list_destroy(input->tablet->pads, TABLET_OBJECT_LIST_DELETER(zwp_tablet_pad_v2_destroy)); + tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy)); + tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy)); + + zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2*)input->tablet->seat); + + SDL_free(input->tablet); + input->tablet = NULL; +} + void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) { @@ -1659,6 +2056,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version)); input->sx_w = wl_fixed_from_int(0); input->sy_w = wl_fixed_from_int(0); + input->xkb.current_group = ~0; d->input = input; if (d->data_device_manager != NULL) { @@ -1671,6 +2069,10 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) wl_seat_add_listener(input->seat, &seat_listener, input); wl_seat_set_user_data(input->seat, input); + if (d->tablet_manager) { + Wayland_input_add_tablet(input, d->tablet_manager); + } + WAYLAND_wl_display_flush(d->display); } @@ -1711,6 +2113,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d) wl_touch_destroy(input->touch); } + if (input->tablet) { + Wayland_input_destroy_tablet(input); + } + if (input->seat) wl_seat_destroy(input->seat); @@ -1951,12 +2357,19 @@ int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *wi if (SDL_RectEmpty(&window->mouse_rect)) { confine_rect = NULL; } else { + SDL_Rect scaled_mouse_rect; + + scaled_mouse_rect.x = (int)SDL_floorf((float)window->mouse_rect.x / w->pointer_scale_x); + scaled_mouse_rect.y = (int)SDL_floorf((float)window->mouse_rect.y / w->pointer_scale_y); + scaled_mouse_rect.w = (int)SDL_ceilf((float)window->mouse_rect.w / w->pointer_scale_x); + scaled_mouse_rect.h = (int)SDL_ceilf((float)window->mouse_rect.h / w->pointer_scale_y); + confine_rect = wl_compositor_create_region(d->compositor); wl_region_add(confine_rect, - window->mouse_rect.x, - window->mouse_rect.y, - window->mouse_rect.w, - window->mouse_rect.h); + scaled_mouse_rect.x, + scaled_mouse_rect.y, + scaled_mouse_rect.w, + scaled_mouse_rect.h); } confined_pointer = diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h index 24256a7d0..59dc0c8af 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h @@ -29,6 +29,34 @@ #include "SDL_waylanddatamanager.h" #include "SDL_waylandkeyboard.h" +struct SDL_WaylandTabletSeat; + +struct SDL_WaylandTabletObjectListNode { + void* object; + struct SDL_WaylandTabletObjectListNode* next; +}; + +struct SDL_WaylandTabletInput { + struct SDL_WaylandTabletSeat* seat; + + struct SDL_WaylandTabletObjectListNode* tablets; + struct SDL_WaylandTabletObjectListNode* tools; + struct SDL_WaylandTabletObjectListNode* pads; + + SDL_WindowData *tool_focus; + uint32_t tool_prox_serial; + + /* Last motion location */ + wl_fixed_t sx_w; + wl_fixed_t sy_w; + + SDL_bool is_down; + + SDL_bool btn_stylus; + SDL_bool btn_stylus2; + SDL_bool btn_stylus3; +}; + typedef struct { // repeat_rate in range of [1, 1000] int32_t repeat_rate; @@ -68,6 +96,17 @@ struct SDL_WaylandInput { struct xkb_state *state; struct xkb_compose_table *compose_table; struct xkb_compose_state *compose_state; + + /* Keyboard layout "group" */ + uint32_t current_group; + + /* Modifier bitshift values */ + uint32_t idx_shift; + uint32_t idx_ctrl; + uint32_t idx_alt; + uint32_t idx_gui; + uint32_t idx_num; + uint32_t idx_caps; } xkb; /* information about axis events on current frame */ @@ -80,6 +119,8 @@ struct SDL_WaylandInput { } pointer_curr_axis_info; SDL_WaylandKeyboardRepeat keyboard_repeat; + + struct SDL_WaylandTabletInput* tablet; }; extern void Wayland_PumpEvents(_THIS); @@ -107,6 +148,9 @@ extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d); extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input); extern int Wayland_input_ungrab_keyboard(SDL_Window *window); +extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager); +extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input); + #endif /* SDL_waylandevents_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandopengles.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandopengles.c index 6b10cbee7..4c834fd86 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandopengles.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandopengles.c @@ -205,11 +205,11 @@ Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) data = (SDL_WindowData *) window->driverdata; if (w) { - *w = window->w * data->scale_factor; + *w = data->drawable_width; } if (h) { - *h = window->h * data->scale_factor; + *h = data->drawable_height; } } } diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h index fa29bedb1..6891325c7 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h @@ -72,21 +72,19 @@ SDL_WAYLAND_SYM(void, wl_list_remove, (struct wl_list *)) SDL_WAYLAND_SYM(int, wl_list_length, (const struct wl_list *)) SDL_WAYLAND_SYM(int, wl_list_empty, (const struct wl_list *)) SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *)) - -/* These functions are available in Wayland >= 1.4 */ -SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_4) SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy *, uint32_t opcode, const struct wl_interface *interface, ...)) - -SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10) SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...)) - -SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_18) SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *)) SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *)) -SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_20) +#if SDL_WAYLAND_CHECK_VERSION(1, 20, 0) +/* wayland-scanner 1.20 generates code that will call these, so these are + * non-optional when we are compiling against Wayland 1.20. We don't + * explicitly call them ourselves, though, so if we are only compiling + * against Wayland 1.18, they're unnecessary. */ SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interfac, uint32_t version, uint32_t flags, ...)) SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args)) +#endif SDL_WAYLAND_INTERFACE(wl_seat_interface) SDL_WAYLAND_INTERFACE(wl_surface_interface) @@ -149,6 +147,8 @@ SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *, xkb_layout_index_t, const xkb_keysym_t **) ) SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) ) +SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *, + const char *) ) #ifdef HAVE_LIBDECOR_H SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR) diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c index 61940cca4..0305c46a1 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c @@ -52,6 +52,9 @@ #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -59,6 +62,9 @@ #define WAYLANDVID_DRIVER_NAME "wayland" +static void +display_handle_done(void *data, struct wl_output *output); + /* Initialization/Query functions */ static int Wayland_VideoInit(_THIS); @@ -133,32 +139,22 @@ static const char *SDL_WAYLAND_output_tag = "sdl-output"; void SDL_WAYLAND_register_surface(struct wl_surface *surface) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag); - } + wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag); } void SDL_WAYLAND_register_output(struct wl_output *output) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag); - } + wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag); } SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag; - } - return SDL_TRUE; /* For older clients we have to assume this is us... */ + return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag; } SDL_bool SDL_WAYLAND_own_output(struct wl_output *output) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag; - } - return SDL_TRUE; /* For older clients we have to assume this is us... */ + return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag; } static void @@ -283,6 +279,8 @@ Wayland_CreateDevice(int devindex) device->free = Wayland_DeleteDevice; + device->disable_display_mode_switching = SDL_TRUE; + return device; } @@ -291,6 +289,155 @@ VideoBootStrap Wayland_bootstrap = { Wayland_CreateDevice }; +static void +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, + int32_t x, int32_t y) +{ + SDL_WaylandOutputData* driverdata = data; + + driverdata->x = x; + driverdata->y = y; + driverdata->has_logical_position = SDL_TRUE; +} + +static void +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, + int32_t width, int32_t height) +{ + SDL_WaylandOutputData* driverdata = data; + + if (driverdata->width != 0 && driverdata->height != 0) { + /* FIXME: GNOME has a bug where the logical size does not account for + * scale, resulting in bogus viewport sizes. + * + * Until this is fixed, validate that _some_ kind of scaling is being + * done (we can't match exactly because fractional scaling can't be + * detected otherwise), then override if necessary. + * -flibit + */ + const float scale = (float) driverdata->width / (float) width; + if ((scale == 1.0f) && (driverdata->scale_factor != 1.0f)) { + SDL_LogWarn( + SDL_LOG_CATEGORY_VIDEO, + "xdg_output scale did not match, overriding with wl_output scale" + ); + return; + } + } + + driverdata->width = width; + driverdata->height = height; + driverdata->has_logical_size = SDL_TRUE; +} + +static void +xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) +{ + SDL_WaylandOutputData* driverdata = data; + + /* + * xdg-output.done events are deprecated and only apply below version 3 of the protocol. + * A wl-output.done event will be emitted in version 3 or higher. + */ + if (zxdg_output_v1_get_version(driverdata->xdg_output) < 3) { + display_handle_done(data, driverdata->output); + } +} + +static void +xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, + const char *name) +{ +} + +static void +xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, + const char *description) +{ +} + +static const struct zxdg_output_v1_listener xdg_output_listener = { + xdg_output_handle_logical_position, + xdg_output_handle_logical_size, + xdg_output_handle_done, + xdg_output_handle_name, + xdg_output_handle_description, +}; + +static void +AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90) +{ + struct EmulatedMode + { + int w; + int h; + }; + + /* Resolution lists courtesy of XWayland */ + const struct EmulatedMode mode_list[] = { + /* 16:9 (1.77) */ + { 7680, 4320 }, + { 6144, 3160 }, + { 5120, 2880 }, + { 4096, 2304 }, + { 3840, 2160 }, + { 3200, 1800 }, + { 2880, 1620 }, + { 2560, 1440 }, + { 2048, 1152 }, + { 1920, 1080 }, + { 1600, 900 }, + { 1368, 768 }, + { 1280, 720 }, + { 864, 486 }, + + /* 16:10 (1.6) */ + { 2560, 1600 }, + { 1920, 1200 }, + { 1680, 1050 }, + { 1440, 900 }, + { 1280, 800 }, + + /* 3:2 (1.5) */ + { 720, 480 }, + + /* 4:3 (1.33) */ + { 2048, 1536 }, + { 1920, 1440 }, + { 1600, 1200 }, + { 1440, 1080 }, + { 1400, 1050 }, + { 1280, 1024 }, + { 1280, 960 }, + { 1152, 864 }, + { 1024, 768 }, + { 800, 600 }, + { 640, 480 } + }; + + int i; + const int native_width = dpy->display_modes->w; + const int native_height = dpy->display_modes->h; + + for (i = 0; i < SDL_arraysize(mode_list); ++i) { + /* Only add modes that are smaller than the native mode */ + if ((mode_list[i].w < native_width && mode_list[i].h < native_height) || + (mode_list[i].w < native_width && mode_list[i].h == native_height)) { + SDL_DisplayMode mode = *dpy->display_modes; + + if (rot_90) { + mode.w = mode_list[i].h; + mode.h = mode_list[i].w; + } else { + mode.w = mode_list[i].w; + mode.h = mode_list[i].h; + } + + SDL_AddDisplayMode(dpy, &mode); + } + } +} + static void display_handle_geometry(void *data, struct wl_output *output, @@ -307,7 +454,7 @@ display_handle_geometry(void *data, SDL_VideoDisplay *display; int i; - if (driverdata->done) { + if (driverdata->wl_output_done_count) { /* Clear the wl_output ref so Reset doesn't free it */ display = SDL_GetDisplay(driverdata->index); for (i = 0; i < display->num_display_modes; i += 1) { @@ -318,11 +465,14 @@ display_handle_geometry(void *data, SDL_ResetDisplayModes(driverdata->index); /* The display has officially started over. */ - driverdata->done = SDL_FALSE; + driverdata->wl_output_done_count = 0; } - driverdata->x = x; - driverdata->y = y; + /* Apply the change from wl-output only if xdg-output is not supported */ + if (!driverdata->has_logical_position) { + driverdata->x = x; + driverdata->y = y; + } driverdata->physical_width = physical_width; driverdata->physical_height = physical_height; if (driverdata->index == -1) { @@ -369,36 +519,21 @@ display_handle_mode(void *data, int refresh) { SDL_WaylandOutputData* driverdata = data; - SDL_DisplayMode mode; if (flags & WL_OUTPUT_MODE_CURRENT) { - /* Don't rotate this yet, handle_done will do it later */ - driverdata->width = width; - driverdata->height = height; - driverdata->refresh = refresh; - } + driverdata->native_width = width; + driverdata->native_height = height; - /* Note that the width/height are NOT multiplied by scale_factor! - * This is intentional and is designed to get the unscaled modes, which is - * important for high-DPI games intending to use the display mode as the - * target drawable size. The scaled desktop mode will be added at the end - * when display_handle_done is called (see below). - */ - SDL_zero(mode); - mode.format = SDL_PIXELFORMAT_RGB888; - if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { - mode.w = height; - mode.h = width; - } else { - mode.w = width; - mode.h = height; - } - mode.refresh_rate = (int)SDL_round(refresh / 1000.0); /* mHz to Hz */ - mode.driverdata = driverdata->output; - if (driverdata->index > -1) { - SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &mode); - } else { - SDL_AddDisplayMode(&driverdata->placeholder, &mode); + /* + * Don't rotate this yet, wl-output coordinates are transformed in + * handle_done and xdg-output coordinates are pre-transformed. + */ + if (!driverdata->has_logical_size) { + driverdata->width = width; + driverdata->height = height; + } + + driverdata->refresh = refresh; } } @@ -407,20 +542,73 @@ display_handle_done(void *data, struct wl_output *output) { SDL_WaylandOutputData* driverdata = data; - SDL_DisplayMode mode; + SDL_VideoData* video = driverdata->videodata; + SDL_DisplayMode native_mode, desktop_mode; SDL_VideoDisplay *dpy; - if (driverdata->done) + /* + * When using xdg-output, two wl-output.done events will be emitted: + * one at the completion of wl-display and one at the completion of xdg-output. + * + * All required events must be received before proceeding. + */ + const int event_await_count = 1 + (driverdata->xdg_output != NULL); + + driverdata->wl_output_done_count = SDL_min(driverdata->wl_output_done_count + 1, event_await_count + 1); + + if (driverdata->wl_output_done_count != event_await_count) { return; + } - driverdata->done = SDL_TRUE; + /* The native display resolution */ + SDL_zero(native_mode); + native_mode.format = SDL_PIXELFORMAT_RGB888; - SDL_zero(mode); - mode.format = SDL_PIXELFORMAT_RGB888; if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { - mode.w = driverdata->height / driverdata->scale_factor; - mode.h = driverdata->width / driverdata->scale_factor; + native_mode.w = driverdata->native_height; + native_mode.h = driverdata->native_width; + } else { + native_mode.w = driverdata->native_width; + native_mode.h = driverdata->native_height; + } + native_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */ + native_mode.driverdata = driverdata->output; + /* The scaled desktop mode */ + SDL_zero(desktop_mode); + desktop_mode.format = SDL_PIXELFORMAT_RGB888; + + /* Scale the desktop coordinates, if xdg-output isn't present */ + if (!driverdata->has_logical_size) { + driverdata->width /= driverdata->scale_factor; + driverdata->height /= driverdata->scale_factor; + } + + /* xdg-output dimensions are already transformed, so no need to rotate. */ + if (driverdata->has_logical_size || !(driverdata->transform & WL_OUTPUT_TRANSFORM_90)) { + desktop_mode.w = driverdata->width; + desktop_mode.h = driverdata->height; + } else { + desktop_mode.w = driverdata->height; + desktop_mode.h = driverdata->width; + } + desktop_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */ + desktop_mode.driverdata = driverdata->output; + + /* + * The native display mode is only exposed separately from the desktop size if: + * the desktop is scaled and the wp_viewporter protocol is supported. + */ + if (driverdata->scale_factor > 1.0f && video->viewporter != NULL) { + if (driverdata->index > -1) { + SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &native_mode); + } else { + SDL_AddDisplayMode(&driverdata->placeholder, &native_mode); + } + } + + /* Calculate the display DPI */ + if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { driverdata->hdpi = driverdata->physical_height ? (((float) driverdata->height) * 25.4f / driverdata->physical_height) : 0.0f; @@ -432,9 +620,6 @@ display_handle_done(void *data, ((float) driverdata->physical_height) / 25.4f, ((float) driverdata->physical_width) / 25.4f); } else { - mode.w = driverdata->width / driverdata->scale_factor; - mode.h = driverdata->height / driverdata->scale_factor; - driverdata->hdpi = driverdata->physical_width ? (((float) driverdata->width) * 25.4f / driverdata->physical_width) : 0.0f; @@ -446,8 +631,6 @@ display_handle_done(void *data, ((float) driverdata->physical_width) / 25.4f, ((float) driverdata->physical_height) / 25.4f); } - mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */ - mode.driverdata = driverdata->output; if (driverdata->index > -1) { dpy = SDL_GetDisplay(driverdata->index); @@ -455,9 +638,14 @@ display_handle_done(void *data, dpy = &driverdata->placeholder; } - SDL_AddDisplayMode(dpy, &mode); - SDL_SetCurrentDisplayMode(dpy, &mode); - SDL_SetDesktopDisplayMode(dpy, &mode); + SDL_AddDisplayMode(dpy, &desktop_mode); + SDL_SetCurrentDisplayMode(dpy, &desktop_mode); + SDL_SetDesktopDisplayMode(dpy, &desktop_mode); + + /* Add emulated modes if wp_viewporter is supported. */ + if (video->viewporter) { + AddEmulatedModes(dpy, (driverdata->transform & WL_OUTPUT_TRANSFORM_90) != 0); + } if (driverdata->index == -1) { /* First time getting display info, create the VideoDisplay */ @@ -504,11 +692,29 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id) data->videodata = d; data->output = output; data->registry_id = id; - data->scale_factor = 1.0; + data->scale_factor = 1.0f; data->index = -1; wl_output_add_listener(output, &output_listener, data); SDL_WAYLAND_register_output(output); + + /* Keep a list of outputs for deferred xdg-output initialization. */ + if (d->output_list != NULL) { + SDL_WaylandOutputData *node = (SDL_WaylandOutputData*)d->output_list; + + while (node->next != NULL) { + node = (SDL_WaylandOutputData*)node->next; + } + + node->next = (struct SDL_WaylandOutputData*)data; + } else { + d->output_list = (struct SDL_WaylandOutputData*)data; + } + + if (data->videodata->xdg_output_manager) { + data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output); + zxdg_output_v1_add_listener(data->xdg_output, &xdg_output_listener, data); + } } static void @@ -524,6 +730,9 @@ Wayland_free_display(uint32_t id) data = (SDL_WaylandOutputData *) display->driverdata; if (data->registry_id == id) { SDL_DelVideoDisplay(i); + if (data->xdg_output) { + zxdg_output_v1_destroy(data->xdg_output); + } wl_output_destroy(data->output); SDL_free(data); @@ -540,6 +749,16 @@ Wayland_free_display(uint32_t id) } } +static void +Wayland_init_xdg_output(SDL_VideoData *d) +{ + SDL_WaylandOutputData *node; + for (node = d->output_list; node != NULL; node = node->next) { + node->xdg_output = zxdg_output_manager_v1_get_xdg_output(node->videodata->xdg_output_manager, node->output); + zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node); + } +} + #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager, @@ -600,7 +819,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } else if (SDL_strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id, version); } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) { - d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1); + d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3)); xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL); } else if (SDL_strcmp(interface, "wl_shm") == 0) { d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); @@ -620,6 +839,17 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, Wayland_add_data_device_manager(d, id, version); } else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) { d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1); + } else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) { + d->tablet_manager = wl_registry_bind(d->registry, id, &zwp_tablet_manager_v2_interface, 1); + if (d->input) { + Wayland_input_add_tablet(d->input, d->tablet_manager); + } + } else if (SDL_strcmp(interface, "zxdg_output_manager_v1") == 0) { + version = SDL_min(version, 3); /* Versions 1 through 3 are supported. */ + d->xdg_output_manager = wl_registry_bind(d->registry, id, &zxdg_output_manager_v1_interface, version); + Wayland_init_xdg_output(d); + } else if (SDL_strcmp(interface, "wp_viewporter") == 0) { + d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1); #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (SDL_strcmp(interface, "qt_touch_extension") == 0) { @@ -646,6 +876,29 @@ static const struct wl_registry_listener registry_listener = { display_handle_global, display_remove_global }; + +#ifdef HAVE_LIBDECOR_H +static SDL_bool should_use_libdecor(SDL_VideoData *data) +{ + if (!SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR) { + return SDL_FALSE; + } + + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) { + return SDL_FALSE; + } + + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR, SDL_FALSE)) { + return SDL_TRUE; + } + + if (data->decoration_manager) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif int Wayland_VideoInit(_THIS) @@ -669,14 +922,8 @@ Wayland_VideoInit(_THIS) #ifdef HAVE_LIBDECOR_H /* Don't have server-side decorations? Try client-side instead. */ - if (!data->decoration_manager && SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR && SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) { + if (should_use_libdecor(data)) { data->shell.libdecor = libdecor_new(data->display, &libdecor_interface); - - /* If libdecor works, we don't need xdg-shell anymore. */ - if (data->shell.libdecor && data->shell.xdg) { - xdg_wm_base_destroy(data->shell.xdg); - data->shell.xdg = NULL; - } } #endif @@ -737,6 +984,10 @@ Wayland_VideoQuit(_THIS) for (i = 0; i < _this->num_displays; ++i) { SDL_VideoDisplay *display = &_this->displays[i]; + if (((SDL_WaylandOutputData*)display->driverdata)->xdg_output) { + zxdg_output_v1_destroy(((SDL_WaylandOutputData*)display->driverdata)->xdg_output); + } + wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output); SDL_free(display->driverdata); display->driverdata = NULL; @@ -779,6 +1030,9 @@ Wayland_VideoQuit(_THIS) Wayland_touch_destroy(data); #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + if (data->tablet_manager) + zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager); + if (data->data_device_manager) wl_data_device_manager_destroy(data->data_device_manager); @@ -798,6 +1052,14 @@ Wayland_VideoQuit(_THIS) } #endif + if (data->xdg_output_manager) { + zxdg_output_manager_v1_destroy(data->xdg_output_manager); + } + + if (data->viewporter) { + wp_viewporter_destroy(data->viewporter); + } + if (data->compositor) wl_compositor_destroy(data->compositor); diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h index 31168a9d5..6f941db80 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h @@ -34,6 +34,7 @@ struct xkb_context; struct SDL_WaylandInput; +struct SDL_WaylandTabletManager; #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch; @@ -46,6 +47,8 @@ typedef struct { int size; } SDL_WaylandCursorTheme; +typedef struct SDL_WaylandOutputData SDL_WaylandOutputData; + typedef struct { SDL_bool initializing; struct wl_display *display; @@ -70,6 +73,8 @@ typedef struct { struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; struct xdg_activation_v1 *activation_manager; struct zwp_text_input_manager_v3 *text_input_manager; + struct zxdg_output_manager_v1 *xdg_output_manager; + struct wp_viewporter *viewporter; EGLDisplay edpy; EGLContext context; @@ -77,6 +82,8 @@ typedef struct { struct xkb_context *xkb_context; struct SDL_WaylandInput *input; + struct SDL_WaylandTabletManager *tablet_manager; + SDL_WaylandOutputData *output_list; #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch *touch; @@ -89,19 +96,23 @@ typedef struct { int relative_mouse_mode; } SDL_VideoData; -typedef struct { +struct SDL_WaylandOutputData { SDL_VideoData *videodata; struct wl_output *output; + struct zxdg_output_v1 *xdg_output; uint32_t registry_id; float scale_factor; + int native_width, native_height; int x, y, width, height, refresh, transform; SDL_DisplayOrientation orientation; int physical_width, physical_height; float ddpi, hdpi, vdpi; + SDL_bool has_logical_position, has_logical_size; int index; SDL_VideoDisplay placeholder; - SDL_bool done; -} SDL_WaylandOutputData; + int wl_output_done_count; + SDL_WaylandOutputData *next; +}; /* Needed here to get wl_surface declaration, fixes GitHub#4594 */ #include "SDL_waylanddyn.h" diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandvulkan.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandvulkan.c index eb4435131..90b318fc8 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandvulkan.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandvulkan.c @@ -139,11 +139,11 @@ void Wayland_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) data = (SDL_WindowData *) window->driverdata; if (w) { - *w = window->w * data->scale_factor; + *w = data->drawable_width; } if (h) { - *h = window->h * data->scale_factor; + *h = data->drawable_height; } } } diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c index 635546af4..0bbae4691 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c @@ -25,22 +25,294 @@ #include "../SDL_sysvideo.h" #include "../../events/SDL_windowevents_c.h" +#include "../../events/SDL_mouse_c.h" #include "../SDL_egl_c.h" #include "SDL_waylandevents_c.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" #include "SDL_hints.h" +#include "SDL_events.h" #include "xdg-shell-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include #endif +static void +GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height) +{ + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + int fs_width, fs_height; + int buf_width, buf_height; + + /* + * Fullscreen desktop mandates a desktop sized window, so that's what applications will get. + * If the application is DPI aware, it will need to handle the transformations between the + * differently sized window and backbuffer spaces on its own. + */ + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { + fs_width = output->width; + fs_height = output->height; + + /* If the application is DPI aware, we can expose the true backbuffer size */ + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + buf_width = output->native_width; + buf_height = output->native_height; + } else { + buf_width = fs_width; + buf_height = fs_height; + } + } else { + /* + * If a mode was set, use it, otherwise use the native resolution + * for DPI aware apps and the desktop size for legacy apps. + */ + if (window->fullscreen_mode.w != 0 && window->fullscreen_mode.h != 0) { + fs_width = window->fullscreen_mode.w; + fs_height = window->fullscreen_mode.h; + } else if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + fs_width = output->native_width; + fs_height = output->native_height; + } else { + fs_width = output->width; + fs_height = output->height; + } + + buf_width = fs_width; + buf_height = fs_height; + } + + if (width) { + *width = fs_width; + } + if (height) { + *height = fs_height; + } + if (drawable_width) { + *drawable_width = buf_width; + } + if (drawable_height) { + *drawable_height = buf_height; + } +} + +static inline SDL_bool +DesktopIsScaled(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + + return data->scale_factor != 1.0f; +} + +static inline SDL_bool +DesktopIsFractionalScaled(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + if ((output->native_width != (int)(output->width * data->scale_factor) || + output->native_height != (int)(output->height * data->scale_factor))) { + return SDL_TRUE; + } + + return SDL_FALSE; +} + +static SDL_bool +NeedFullscreenViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *video = data->waylandData; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + int fs_width, fs_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL); + + /* + * Fullscreen needs a viewport: + * - If the desktop uses fractional scaling + * - Fullscreen desktop was not requested OR the window is DPI aware + * + * - The desktop uses non-fractional scaling + * - Fullscreen desktop was NOT requested + * + * - The desktop is not scaled + * - A non-native fullscreen mode was explicitly set by the client + */ + if (video->viewporter != NULL && (window->flags & SDL_WINDOW_FULLSCREEN)) { + if (DesktopIsFractionalScaled(window)) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP || + (window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { + return SDL_TRUE; + } + } else if (DesktopIsScaled(window)) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { + return SDL_TRUE; + } + } else if (fs_width != output->native_width && fs_height != output->native_height) { + return SDL_TRUE; + } + } + + return SDL_FALSE; +} + +static inline SDL_bool +NeedWindowedViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *video = data->waylandData; + + return !(window->flags & SDL_WINDOW_FULLSCREEN) && (video->viewporter != NULL) && + DesktopIsFractionalScaled(window) && (window->flags & SDL_WINDOW_ALLOW_HIGHDPI); +} + +/* Never set a fullscreen window size larger than the desktop. */ +SDL_FORCE_INLINE int +GetWindowWidth(SDL_Window *window) +{ + return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->width : window->w; +} + +SDL_FORCE_INLINE int +GetWindowHeight(SDL_Window *window) +{ + return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->height : window->h; +} + +static void +GetWindowBufferSize(SDL_Window *window, int *width, int *height) +{ + SDL_WindowData *data = window->driverdata; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + int buf_width; + int buf_height; + + if (NeedWindowedViewport(window)) { + const float frac_scale_x = (float)output->native_width / (float)output->width; + const float frac_scale_y = (float)output->native_height / (float)output->height; + + buf_width = (int)SDL_lroundf(window->w * frac_scale_x); + buf_height = (int)SDL_lroundf(window->h * frac_scale_y); + } else { /* Windowed or fullscreen with no viewport */ + buf_width = window->w * data->scale_factor; + buf_height = window->h * data->scale_factor; + } + + if (width) { + *width = buf_width; + } + if (height) { + *height = buf_height; + } +} + +static void +SetViewport(SDL_Window *window, int src_width, int src_height, int dst_width, int dst_height) +{ + SDL_WindowData *wind = window->driverdata; + SDL_VideoData *video = wind->waylandData; + + if (video->viewporter) { + if (wind->viewport == NULL) { + wind->viewport = wp_viewporter_get_viewport(video->viewporter, wind->surface); + } + + wp_viewport_set_source(wind->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(src_width), wl_fixed_from_int(src_height)); + wp_viewport_set_destination(wind->viewport, dst_width, dst_height); + } +} + +static void +UnsetViewport(SDL_Window *window) +{ + SDL_WindowData *wind = window->driverdata; + + if (wind->viewport) { + wp_viewport_destroy(wind->viewport); + wind->viewport = NULL; + } +} + +static void +ConfigureViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *viddata = data->waylandData; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + if (NeedFullscreenViewport(window)) { + int fs_width, fs_height; + int src_width, src_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, &src_width, &src_height); + SetViewport(window, src_width, src_height, output->width, output->height); + + data->damage_region.x = 0; + data->damage_region.y = 0; + data->damage_region.w = output->width; + data->damage_region.h = output->height; + + data->pointer_scale_x = (float)fs_width / (float)output->width; + data->pointer_scale_y = (float)fs_height / (float)output->height; + } else { + if (NeedWindowedViewport(window)) { + int src_width, src_height; + + GetWindowBufferSize(window, &src_width, &src_height); + SetViewport(window, src_width, src_height, window->w, window->h); + } else { + UnsetViewport(window); + } + + SDL_zero(data->damage_region); + + data->pointer_scale_x = 1.0f; + data->pointer_scale_y = 1.0f; + } + + /* + * If mouse_rect is not empty, re-create the confinement region with the new scale value. + * If the pointer is locked to the general surface with unspecified coordinates, it will + * be confined to the viewport region, so no update is required. + */ + if (!SDL_RectEmpty(&window->mouse_rect)) { + Wayland_input_confine_pointer(viddata->input, window); + } +} + +static void +SetDrawScale(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + + if (NeedFullscreenViewport(window)) { + int fs_width, fs_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, &data->drawable_width, &data->drawable_height); + + /* Set the buffer scale to 1 since a viewport will be used. */ + wl_surface_set_buffer_scale(data->surface, 1); + } else { + GetWindowBufferSize(window, &data->drawable_width, &data->drawable_height); + + if (NeedWindowedViewport(window)) { + /* Set the buffer scale to 1 since a viewport will be used. */ + wl_surface_set_buffer_scale(data->surface, 1); + } else { + wl_surface_set_buffer_scale(data->surface, (int32_t)data->scale_factor); + } + } +} + static void SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) { @@ -48,6 +320,15 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) SDL_VideoData *viddata = wind->waylandData; int min_width, min_height, max_width, max_height; + /* Pop-ups don't get to change size */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + if (window->flags & SDL_WINDOW_FULLSCREEN) { min_width = 0; min_height = 0; @@ -66,7 +347,7 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) } #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -100,13 +381,22 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = wind->waylandData; + /* Pop-ups don't get to be fullscreened */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + /* The desktop may try to enforce min/max sizes here, so turn them off for * fullscreen and on (if applicable) for windowed */ SetMinMaxDimensions(window, SDL_FALSE); #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -150,6 +440,11 @@ handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) SDL_WindowData *wind = (SDL_WindowData *) data; SDL_AtomicSet(&wind->swap_interval_ready, 1); /* mark window as ready to present again. */ + if (!SDL_RectEmpty(&wind->damage_region)) { + wl_surface_damage(wind->surface, wind->damage_region.x, wind->damage_region.y, + wind->damage_region.w, wind->damage_region.h); + } + /* reset this callback to fire again once a new frame was presented and compositor wants the next one. */ wind->frame_callback = wl_surface_frame(wind->frame_surface_wrapper); wl_callback_destroy(cb); @@ -303,9 +598,14 @@ handle_configure_xdg_toplevel(void *data, * UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug: * https://bugs.kde.org/show_bug.cgi?id=444962 */ - if (width != 0 && height != 0 && (window->w != width || window->h != height)) { - window->w = width; - window->h = height; + if (!NeedFullscreenViewport(window)) { + if (width != 0 && height != 0 && (window->w != width || window->h != height)) { + window->w = width; + window->h = height; + wind->needs_resize_event = SDL_TRUE; + } + } else { + GetFullScreenDimensions(window, &window->w, &window->h, NULL, NULL); wind->needs_resize_event = SDL_TRUE; } @@ -329,6 +629,60 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = { handle_close_xdg_toplevel }; +static void +handle_configure_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + /* No-op, we don't use x/y and width/height are fixed-size */ +} + +static void +handle_done_xdg_popup(void *data, struct xdg_popup *xdg_popup) +{ + SDL_WindowData *window = (SDL_WindowData *)data; + SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0); +} + +static void +handle_repositioned_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + uint32_t token) +{ + /* No-op, configure does all the work we care about */ +} + +static const struct xdg_popup_listener popup_listener_xdg = { + handle_configure_xdg_popup, + handle_done_xdg_popup, + handle_repositioned_xdg_popup +}; + +#define TOOLTIP_CURSOR_OFFSET 8 /* FIXME: Arbitrary, eyeballed from X tooltip */ + +static int +Wayland_PopupWatch(void *data, SDL_Event *event) +{ + if (event->type == SDL_MOUSEMOTION) { + SDL_Window *window = (SDL_Window *) data; + SDL_WindowData *wind = window->driverdata; + + /* Coordinates might be relative to the popup, which we don't want */ + if (event->motion.windowID == wind->shell_surface.xdg.roleobj.popup.parentID) { + xdg_positioner_set_offset(wind->shell_surface.xdg.roleobj.popup.positioner, + event->motion.x + TOOLTIP_CURSOR_OFFSET, + event->motion.y + TOOLTIP_CURSOR_OFFSET); + xdg_popup_reposition(wind->shell_surface.xdg.roleobj.popup.popup, + wind->shell_surface.xdg.roleobj.popup.positioner, + 0); + } + } + return 1; +} + #ifdef HAVE_LIBDECOR_H static void decoration_frame_configure(struct libdecor_frame *frame, @@ -399,17 +753,23 @@ decoration_frame_configure(struct libdecor_frame *frame, * Always assume the configure is wrong. */ if (fullscreen) { - /* FIXME: We have been explicitly told to respect the fullscreen size - * parameters here, even though they are known to be wrong on GNOME at - * bare minimum. If this is wrong, don't blame us, we were explicitly - * told to do this. - */ - if (!libdecor_configuration_get_content_size(configuration, frame, - &width, &height)) { - width = window->w; - height = window->h; + if (!NeedFullscreenViewport(window)) { + /* FIXME: We have been explicitly told to respect the fullscreen size + * parameters here, even though they are known to be wrong on GNOME at + * bare minimum. If this is wrong, don't blame us, we were explicitly + * told to do this. + */ + if (!libdecor_configuration_get_content_size(configuration, frame, + &width, &height)) { + width = window->w; + height = window->h; + } + } else { + GetFullScreenDimensions(window, &width, &height, NULL, NULL); } + wind->needs_resize_event = SDL_TRUE; + /* This part is good though. */ if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { scale_factor = driverdata->scale_factor; @@ -445,7 +805,7 @@ decoration_frame_configure(struct libdecor_frame *frame, wind->shell_surface.libdecor.initial_configure_seen = SDL_TRUE; /* ... then commit the changes on the libdecor side. */ - state = libdecor_state_new(width, height); + state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); @@ -554,9 +914,28 @@ Wayland_move_window(SDL_Window *window, int i, numdisplays = SDL_GetNumVideoDisplays(); for (i = 0; i < numdisplays; i += 1) { if (SDL_GetDisplay(i)->driverdata == driverdata) { - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, - SDL_WINDOWPOS_CENTERED_DISPLAY(i), - SDL_WINDOWPOS_CENTERED_DISPLAY(i)); + /* We want to send a very very specific combination here: + * + * 1. A coordinate that tells the application what display we're on + * 2. Exactly (0, 0) + * + * Part 1 is useful information but is also really important for + * ensuring we end up on the right display for fullscreen, while + * part 2 is important because numerous applications use a specific + * combination of GetWindowPosition and GetGlobalMouseState, and of + * course neither are supported by Wayland. Since global mouse will + * fall back to just GetMouseState, we need the window position to + * be zero so the cursor math works without it going off in some + * random direction. See UE5 Editor for a notable example of this! + * + * This may be an issue some day if we're ever able to implement + * SDL_GetDisplayUsableBounds! + * + * -flibit + */ + SDL_Rect bounds; + SDL_GetDisplayBounds(i, &bounds); + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, bounds.x, bounds.y); break; } } @@ -624,6 +1003,19 @@ static const struct wl_surface_listener surface_listener = { handle_surface_leave }; +static void +Wayland_FillEmptyShellInfo(SDL_SysWMinfo * info, const Uint32 version) +{ + info->info.wl.xdg_surface = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } +} + SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { @@ -656,23 +1048,40 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) info->info.wl.egl_window = data->egl_window; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor && data->shell_surface.libdecor.frame != NULL) { - info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (WINDOW_IS_LIBDECOR(viddata, window)) { + if (data->shell_surface.libdecor.frame != NULL) { + info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } + } else { + /* Not mapped yet */ + Wayland_FillEmptyShellInfo(info, version); } } else #endif if (viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) { info->info.wl.xdg_surface = data->shell_surface.xdg.surface; if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = data->shell_surface.xdg.roleobj.toplevel; + SDL_bool popup = WINDOW_IS_XDG_POPUP(window); + info->info.wl.xdg_toplevel = popup ? NULL : data->shell_surface.xdg.roleobj.toplevel; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + if (popup) { + info->info.wl.xdg_popup = data->shell_surface.xdg.roleobj.popup.popup; + info->info.wl.xdg_positioner = data->shell_surface.xdg.roleobj.popup.positioner; + } else { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } } } else { - info->info.wl.xdg_surface = NULL; - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = NULL; - } + /* Either it's not mapped yet or we don't have a shell protocol */ + Wayland_FillEmptyShellInfo(info, version); } } @@ -697,6 +1106,10 @@ Wayland_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_wi SDL_WindowData *modal_data = modal_window->driverdata; SDL_WindowData *parent_data = parent_window->driverdata; + if (WINDOW_IS_XDG_POPUP(modal_window) || WINDOW_IS_XDG_POPUP(parent_window)) { + return SDL_SetError("Modal/Parent was a popup, not a toplevel"); + } + #ifdef HAVE_LIBDECOR_H if (viddata->shell.libdecor) { if (modal_data->shell_surface.libdecor.frame == NULL) { @@ -731,9 +1144,26 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) SDL_VideoData *c = _this->driverdata; SDL_WindowData *data = window->driverdata; - /* Create the shell surface and map the toplevel */ + /* Detach any previous buffers before resetting everything, otherwise when + * calling this a second time you'll get an annoying protocol error! + * + * FIXME: This was originally moved to HideWindow, which _should_ make + * sense, but for whatever reason UE5's popups require that this actually + * be in both places at once? Possibly from renderers making commits? I can't + * fully remember if this location caused crashes or if I was fixing a pair + * of Hide/Show calls. In any case, UE gives us a pretty good test and having + * both detach calls passes. This bug may be relevant if I'm wrong: + * + * https://bugs.kde.org/show_bug.cgi?id=448856 + * + * -flibit + */ + wl_surface_attach(data->surface, NULL, 0, 0); + wl_surface_commit(data->surface); + + /* Create the shell surface and map the toplevel/popup */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, data->surface, &libdecor_frame_interface, @@ -751,10 +1181,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) xdg_surface_set_user_data(data->shell_surface.xdg.surface, data); xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data); - /* !!! FIXME: add popup role */ - data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); - xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); - xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + if (WINDOW_IS_XDG_POPUP(window)) { + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focused = SDL_GetMouseFocus(); + SDL_WindowData *focuseddata = focused->driverdata; + + /* This popup may be a child of another popup! */ + data->shell_surface.xdg.roleobj.popup.parentID = SDL_GetWindowID(focused); + data->shell_surface.xdg.roleobj.popup.child = NULL; + if (WINDOW_IS_XDG_POPUP(focused)) { + SDL_assert(focuseddata->shell_surface.xdg.roleobj.popup.child == NULL); + focuseddata->shell_surface.xdg.roleobj.popup.child = window; + } + + /* Set up the positioner for the popup */ + data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg); + xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner, + mouse->x + TOOLTIP_CURSOR_OFFSET, + mouse->y + TOOLTIP_CURSOR_OFFSET); + + /* Assign the popup role */ + data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface, + focuseddata->shell_surface.xdg.surface, + data->shell_surface.xdg.roleobj.popup.positioner); + xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data); + + /* For tooltips, track mouse motion so it follows the cursor */ + if (window->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(data->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_AddEventWatch(Wayland_PopupWatch, window); + } + } + } else { + data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); + xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); + xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + } } /* Restore state that was set prior to this call */ @@ -770,7 +1232,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * this surface will fail. This is a new rule for xdg_shell. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { if (data->shell_surface.libdecor.frame) { while (!data->shell_surface.libdecor.initial_configure_seen) { WAYLAND_wl_display_flush(c->display); @@ -794,7 +1256,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } /* Create the window decorations */ - if (data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { + if (!WINDOW_IS_XDG_POPUP(window) && data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel); } } else { @@ -807,11 +1269,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * them immediately afterward. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { /* ... but don't call it redundantly for libdecor, the decorator * may not interpret a redundant call nicely and cause weird stuff to happen */ - if (window->flags & SDL_WINDOW_BORDERLESS) { + if (data->shell_surface.libdecor.frame && window->flags & SDL_WINDOW_BORDERLESS) { Wayland_SetWindowBordered(_this, window, SDL_FALSE); } } else @@ -837,6 +1299,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } } +static void +Wayland_ReleasePopup(_THIS, SDL_Window *popup) +{ + SDL_WindowData *popupdata; + + /* Basic sanity checks to weed out the weird popup closures */ + if (popup == NULL || popup->magic != &_this->window_magic) { + return; + } + popupdata = popup->driverdata; + if (popupdata == NULL) { + return; + } + + /* This may already be freed by a parent popup! */ + if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) { + return; + } + + /* Release the child _first_, otherwise a protocol error triggers */ + if (popupdata->shell_surface.xdg.roleobj.popup.child != NULL) { + Wayland_ReleasePopup(_this, popupdata->shell_surface.xdg.roleobj.popup.child); + popupdata->shell_surface.xdg.roleobj.popup.child = NULL; + } + + if (popup->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(popupdata->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_DelEventWatch(Wayland_PopupWatch, popup); + } + } + xdg_popup_destroy(popupdata->shell_surface.xdg.roleobj.popup.popup); + xdg_positioner_destroy(popupdata->shell_surface.xdg.roleobj.popup.positioner); + popupdata->shell_surface.xdg.roleobj.popup.popup = NULL; + popupdata->shell_surface.xdg.roleobj.popup.positioner = NULL; +} + void Wayland_HideWindow(_THIS, SDL_Window *window) { SDL_VideoData *data = _this->driverdata; @@ -848,7 +1346,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_unref(wind->shell_surface.libdecor.frame); wind->shell_surface.libdecor.frame = NULL; @@ -856,7 +1354,9 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } else #endif if (data->shell.xdg) { - if (wind->shell_surface.xdg.roleobj.toplevel) { + if (WINDOW_IS_XDG_POPUP(window)) { + Wayland_ReleasePopup(_this, window); + } else if (wind->shell_surface.xdg.roleobj.toplevel) { xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel); wind->shell_surface.xdg.roleobj.toplevel = NULL; } @@ -1073,13 +1573,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + /* Set this flag now even if we never actually maximized, eventually * ShowWindow will take care of it along with the other window state. */ window->flags &= ~SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1102,8 +1606,13 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { SDL_WindowData *wind = window->driverdata; const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata; + + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered); } @@ -1122,7 +1631,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) SDL_VideoData *data = _this->driverdata; const SDL_WindowData *wind = window->driverdata; - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1144,6 +1653,10 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (!(window->flags & SDL_WINDOW_RESIZABLE)) { return; } @@ -1154,7 +1667,7 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) window->flags |= SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1177,8 +1690,12 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1269,7 +1786,9 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) data->waylandData = c; data->sdlwindow = window; - data->scale_factor = 1.0; + data->scale_factor = 1.0f; + data->pointer_scale_x = 1.0f; + data->pointer_scale_y = 1.0f; if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { int i; @@ -1316,16 +1835,18 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + data->drawable_width = window->w * data->scale_factor; + data->drawable_height = window->h * data->scale_factor; + if (window->flags & SDL_WINDOW_OPENGL) { - data->egl_window = WAYLAND_wl_egl_window_create(data->surface, - window->w * data->scale_factor, window->h * data->scale_factor); + data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height); #if SDL_VIDEO_OPENGL_EGL /* Create the GLES window surface */ data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window); if (data->egl_surface == EGL_NO_SURFACE) { - return SDL_SetError("failed to create an EGL window surface"); + return -1; /* SDL_EGL_CreateSurface should have set error */ } #endif } @@ -1375,12 +1896,13 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale) data->needs_resize_event = SDL_FALSE; } - wl_surface_set_buffer_scale(data->surface, data->scale_factor); + /* Configure the backbuffer size and scale factors */ + SetDrawScale(window); if (data->egl_window) { WAYLAND_wl_egl_window_resize(data->egl_window, - window->w * data->scale_factor, - window->h * data->scale_factor, + data->drawable_width, + data->drawable_height, 0, 0); } @@ -1394,9 +1916,18 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale) * It doesn't fix the first frames after resize being glitched visually, * but at least lets us not be terminated by the compositor. * Can be removed once SDL's resize logic becomes compliant. */ - if (viddata->shell.xdg && data->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, window->w, window->h); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(viddata, window) && +#endif + viddata->shell.xdg && + data->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } + + /* Update the viewport */ + ConfigureViewport(window); } void @@ -1422,7 +1953,7 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) #ifdef HAVE_LIBDECOR_H /* we must not resize the window while we have a static (non-floating) size */ - if (data->shell.libdecor && + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame && !libdecor_frame_is_floating(wind->shell_surface.libdecor.frame)) { /* Commit the resize when we re-enter floating state */ @@ -1431,18 +1962,18 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) } #endif - wl_surface_set_buffer_scale(wind->surface, wind->scale_factor); + SetDrawScale(window); if (wind->egl_window) { WAYLAND_wl_egl_window_resize(wind->egl_window, - window->w * wind->scale_factor, - window->h * wind->scale_factor, + wind->drawable_width, + wind->drawable_height, 0, 0); } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor && wind->shell_surface.libdecor.frame) { - state = libdecor_state_new(window->w, window->h); + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) { + state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); libdecor_state_free(state); } @@ -1458,8 +1989,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) wl_region_destroy(region); /* Update the geometry which may have been set by a hack in Wayland_HandleResize */ - if (data->shell.xdg && wind->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, window->w, window->h); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(data, window) && +#endif + data->shell.xdg && + wind->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } } @@ -1468,9 +2005,13 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (window->title != NULL) { #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1549,6 +2090,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) xdg_activation_token_v1_destroy(wind->activation_token); } + if (wind->viewport) { + wp_viewport_destroy(wind->viewport); + } + SDL_free(wind->outputs); if (wind->frame_callback) { diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h index 90e4d8cf6..b1ba98cf9 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h @@ -36,16 +36,27 @@ typedef struct { struct xdg_surface *surface; union { struct xdg_toplevel *toplevel; - struct xdg_popup *popup; + struct { + struct xdg_popup *popup; + struct xdg_positioner *positioner; + Uint32 parentID; + SDL_Window *child; + } popup; } roleobj; SDL_bool initial_configure_seen; } SDL_xdg_shell_surface; +#define WINDOW_IS_XDG_POPUP(window) \ + (window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) + #ifdef HAVE_LIBDECOR_H typedef struct { struct libdecor_frame *frame; SDL_bool initial_configure_seen; } SDL_libdecor_surface; + +#define WINDOW_IS_LIBDECOR(viddata, window) \ + (viddata->shell.libdecor && !WINDOW_IS_XDG_POPUP(window)) #endif typedef struct { @@ -72,6 +83,7 @@ typedef struct { struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor; struct zwp_idle_inhibitor_v1 *idle_inhibitor; struct xdg_activation_token_v1 *activation_token; + struct wp_viewport *viewport; /* floating dimensions for restoring from maximized and fullscreen */ int floating_width, floating_height; @@ -86,6 +98,10 @@ typedef struct { int num_outputs; float scale_factor; + float pointer_scale_x; + float pointer_scale_y; + int drawable_width, drawable_height; + SDL_Rect damage_region; SDL_bool needs_resize_event; SDL_bool floating_resize_pending; } SDL_WindowData; diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c b/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c index 0619f67dd..ebd0dd1f9 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c @@ -378,14 +378,14 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data) } static void -WIN_UpdateFocus(SDL_Window *window) +WIN_UpdateFocus(SDL_Window *window, SDL_bool expect_focus) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; HWND hwnd = data->hwnd; SDL_bool had_focus = (SDL_GetKeyboardFocus() == window) ? SDL_TRUE : SDL_FALSE; SDL_bool has_focus = (GetForegroundWindow() == hwnd) ? SDL_TRUE : SDL_FALSE; - if (had_focus == has_focus) { + if (had_focus == has_focus || has_focus != expect_focus) { return; } @@ -686,7 +686,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without actually being the foreground window, but this appears to get called in all cases where the global foreground window changes to and from this window. */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, !!wParam); WIN_CheckICMProfileChanged(data->window); } break; @@ -694,16 +694,22 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_ACTIVATE: { /* Update the focus in case we changed focus to a child window and then away from the application */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, !!LOWORD(wParam)); } break; case WM_SETFOCUS: + { + /* Update the focus in case it's changing between top-level windows in the same application */ + WIN_UpdateFocus(data->window, SDL_TRUE); + } + break; + case WM_KILLFOCUS: case WM_ENTERIDLE: { /* Update the focus in case it's changing between top-level windows in the same application */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, SDL_FALSE); } break; diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c index 890d790ea..6dcea5bf2 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c @@ -158,7 +158,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags) int w, h; /* Figure out what the window area will be */ - if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) { + if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { top = HWND_TOPMOST; } else { top = HWND_NOTOPMOST; @@ -734,7 +734,14 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, int x, y; int w, h; - if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { + if (!fullscreen && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0) { + /* Resizing the window on hide causes problems restoring it in Wine, and it's unnecessary. + * Also, Windows would preview the minimized window with the wrong size. + */ + return; + } + + if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { top = HWND_TOPMOST; } else { top = HWND_NOTOPMOST; diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11events.c b/Engine/lib/sdl/src/video/x11/SDL_x11events.c index c1260215d..63091fe98 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11events.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11events.c @@ -380,7 +380,7 @@ X11_GetScrollLockModifierMask(_THIS) return num_mask; } -static void +void X11_ReconcileKeyboardState(_THIS) { SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; @@ -408,7 +408,22 @@ X11_ReconcileKeyboardState(_THIS) SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED; if (x11KeyPressed && !sdlKeyPressed) { - SDL_SendKeyboardKey(SDL_PRESSED, scancode); + /* Only update modifier state for keys that are pressed in another application */ + switch (SDL_GetKeyFromScancode(scancode)) { + case SDLK_LCTRL: + case SDLK_RCTRL: + case SDLK_LSHIFT: + case SDLK_RSHIFT: + case SDLK_LALT: + case SDLK_RALT: + case SDLK_LGUI: + case SDLK_RGUI: + case SDLK_MODE: + SDL_SendKeyboardKey(SDL_PRESSED, scancode); + break; + default: + break; + } } else if (!x11KeyPressed && sdlKeyPressed) { SDL_SendKeyboardKey(SDL_RELEASED, scancode); } @@ -718,7 +733,6 @@ static void X11_DispatchEvent(_THIS, XEvent *xevent) { SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; - XkbEvent* xkbEvent = (XkbEvent*) xevent; Display *display; SDL_WindowData *data; int orig_event_type; @@ -805,11 +819,13 @@ X11_DispatchEvent(_THIS, XEvent *xevent) if (!data) { /* The window for KeymapNotify, etc events is 0 */ if (xevent->type == KeymapNotify) { +#ifdef DEBUG_XEVENTS + printf("window %p: KeymapNotify!\n", data); +#endif if (SDL_GetKeyboardFocus() != NULL) { X11_ReconcileKeyboardState(_this); } - } else if (xevent->type == MappingNotify || - (xevent->type == videodata->xkb_event && xkbEvent->any.xkb_type == XkbStateNotify)) { + } else if (xevent->type == MappingNotify) { /* Has the keyboard layout changed? */ const int request = xevent->xmapping.request; @@ -996,8 +1012,9 @@ X11_DispatchEvent(_THIS, XEvent *xevent) } break; - /* Key press? */ - case KeyPress:{ + /* Key press/release? */ + case KeyPress: + case KeyRelease: { KeyCode keycode = xevent->xkey.keycode; KeySym keysym = NoSymbol; char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; @@ -1005,7 +1022,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) SDL_bool handled_by_ime = SDL_FALSE; #ifdef DEBUG_XEVENTS - printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); + printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode); #endif #if 1 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { @@ -1021,7 +1038,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) /* */ SDL_zeroa(text); #ifdef X_HAVE_UTF8_STRING - if (data->ic) { + if (data->ic && xevent->type == KeyPress) { X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text), &keysym, &status); } else { @@ -1033,35 +1050,30 @@ X11_DispatchEvent(_THIS, XEvent *xevent) #ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode); + handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED)); } #endif if (!handled_by_ime) { - /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ - if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { - SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); - } - if(*text) { - SDL_SendKeyboardText(text); + if (xevent->type == KeyPress) { + /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ + if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { + SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); + } + if(*text) { + SDL_SendKeyboardText(text); + } + } else { + if (X11_KeyRepeat(display, xevent)) { + /* We're about to get a repeated key down, ignore the key up */ + break; + } + SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } } - X11_UpdateUserTime(data, xevent->xkey.time); - } - break; - - /* Key release? */ - case KeyRelease:{ - KeyCode keycode = xevent->xkey.keycode; - -#ifdef DEBUG_XEVENTS - printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); -#endif - if (X11_KeyRepeat(display, xevent)) { - /* We're about to get a repeated key down, ignore the key up */ - break; + if (xevent->type == KeyPress) { + X11_UpdateUserTime(data, xevent->xkey.time); } - SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } break; diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11events.h b/Engine/lib/sdl/src/video/x11/SDL_x11events.h index fc8a57ae2..de89110d0 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11events.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11events.h @@ -27,6 +27,7 @@ extern void X11_PumpEvents(_THIS); extern int X11_WaitEventTimeout(_THIS, int timeout); extern void X11_SendWakeupEvent(_THIS, SDL_Window *window); extern void X11_SuspendScreenSaver(_THIS); +extern void X11_ReconcileKeyboardState(_THIS); #endif /* SDL_x11events_h_ */ diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c index c82570c62..c84bcc798 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c @@ -409,6 +409,8 @@ X11_InitKeyboard(_THIS) SDL_IME_Init(); #endif + X11_ReconcileKeyboardState(_this); + return 0; } diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11messagebox.c b/Engine/lib/sdl/src/video/x11/SDL_x11messagebox.c index aafccca9b..9bc9702c0 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11messagebox.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11messagebox.c @@ -830,10 +830,11 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int exitcode = 0; close(fds[0]); status = X11_ShowMessageBoxImpl(messageboxdata, buttonid); - if (write(fds[1], &status, sizeof (int)) != sizeof (int)) + if (write(fds[1], &status, sizeof (int)) != sizeof (int)) { exitcode = 1; - else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) + } else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) { exitcode = 1; + } close(fds[1]); _exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */ } else { /* we're the parent */ @@ -846,13 +847,12 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) SDL_assert(rc == pid); /* not sure what to do if this fails. */ if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) { - return SDL_SetError("msgbox child process failed"); + status = SDL_SetError("msgbox child process failed"); + } else if ( (read(fds[0], &status, sizeof (int)) != sizeof (int)) || + (read(fds[0], buttonid, sizeof (int)) != sizeof (int)) ) { + status = SDL_SetError("read from msgbox child process failed"); + *buttonid = 0; } - - if (read(fds[0], &status, sizeof (int)) != sizeof (int)) - status = -1; - else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int)) - status = -1; close(fds[0]); return status; diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11modes.c b/Engine/lib/sdl/src/video/x11/SDL_x11modes.c index c1efe243c..f2cbdb45f 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11modes.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11modes.c @@ -1011,7 +1011,13 @@ static int (*PreXRRSetScreenSizeErrorHandler)(Display *, XErrorEvent *) = NULL; static int SDL_XRRSetScreenSizeErrHandler(Display *d, XErrorEvent *e) { - return (e->error_code == BadMatch) ? 0 : PreXRRSetScreenSizeErrorHandler(d, e); + /* BadMatch: https://github.com/libsdl-org/SDL/issues/4561 */ + /* BadValue: https://github.com/libsdl-org/SDL/issues/4840 */ + if ((e->error_code == BadMatch) || (e->error_code == BadValue)) { + return 0; + } + + return PreXRRSetScreenSizeErrorHandler(d, e); } int diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c b/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c index 64b06340a..3e17e97ff 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c @@ -247,11 +247,6 @@ X11_GL_LoadLibrary(_THIS, const char *path) X11_GL_UseEGL(_this) ) { #if SDL_VIDEO_OPENGL_EGL X11_GL_UnloadLibrary(_this); - /* Better avoid conflicts! */ - if (_this->gl_config.dll_handle != NULL ) { - GL_UnloadObject(_this->gl_config.dll_handle); - _this->gl_config.dll_handle = NULL; - } _this->GL_LoadLibrary = X11_GLES_LoadLibrary; _this->GL_GetProcAddress = X11_GLES_GetProcAddress; _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary; diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11sym.h b/Engine/lib/sdl/src/video/x11/SDL_x11sym.h index 67b0a793a..762a86596 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11sym.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11sym.h @@ -185,7 +185,6 @@ SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),) SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),) SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c),(a,b,c),return) -SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned int d),(a,b,c,d),return) #endif #if NeedWidePrototypes diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11window.c b/Engine/lib/sdl/src/video/x11/SDL_x11window.c index a6bd91d72..d31ac012a 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11window.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11window.c @@ -678,8 +678,6 @@ X11_CreateWindow(_THIS, SDL_Window * window) /* For _ICC_PROFILE. */ X11_XSelectInput(display, RootWindow(display, screen), PropertyChangeMask); - X11_XkbSelectEvents(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); - X11_XFlush(display); return 0; @@ -782,11 +780,22 @@ X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) X11_XFlush(display); } +static SDL_bool caught_x11_error = SDL_FALSE; +static int +X11_CatchAnyError(Display * d, XErrorEvent * e) +{ + /* this may happen during tumultuous times when we are polling anyhow, + so just note we had an error and return control. */ + caught_x11_error = SDL_TRUE; + return 0; +} + void X11_SetWindowPosition(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; + int (*prev_handler) (Display *, XErrorEvent *) = NULL; unsigned int childCount; Window childReturn, root, parent; Window* children; @@ -805,20 +814,27 @@ X11_SetWindowPosition(_THIS, SDL_Window * window) /* Wait a brief time to see if the window manager decided to let this move happen. If the window changes at all, even to an unexpected value, we break out. */ + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + timeout = SDL_GetTicks() + 100; while (SDL_TRUE) { int x, y; + + caught_x11_error = SDL_FALSE; X11_XSync(display, False); X11_XGetWindowAttributes(display, data->xwindow, &attrs); X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), attrs.x, attrs.y, &x, &y, &childReturn); - if ((x != orig_x) || (y != orig_y)) { - window->x = x; - window->y = y; - break; /* window moved, time to go. */ - } else if ((x == window->x) && (y == window->y)) { - break; /* we're at the place we wanted to be anyhow, drop out. */ + if (!caught_x11_error) { + if ((x != orig_x) || (y != orig_y)) { + window->x = x; + window->y = y; + break; /* window moved, time to go. */ + } else if ((x == window->x) && (y == window->y)) { + break; /* we're at the place we wanted to be anyhow, drop out. */ + } } if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) { @@ -827,6 +843,9 @@ X11_SetWindowPosition(_THIS, SDL_Window * window) SDL_Delay(10); } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } void @@ -892,6 +911,7 @@ X11_SetWindowSize(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; + int (*prev_handler) (Display *, XErrorEvent *) = NULL; XWindowAttributes attrs; int orig_w, orig_h; Uint32 timeout; @@ -943,19 +963,25 @@ X11_SetWindowSize(_THIS, SDL_Window * window) X11_XResizeWindow(display, data->xwindow, window->w, window->h); } + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + /* Wait a brief time to see if the window manager decided to let this resize happen. If the window changes at all, even to an unexpected value, we break out. */ timeout = SDL_GetTicks() + 100; while (SDL_TRUE) { + caught_x11_error = SDL_FALSE; X11_XSync(display, False); X11_XGetWindowAttributes(display, data->xwindow, &attrs); - if ((attrs.width != orig_w) || (attrs.height != orig_h)) { - window->w = attrs.width; - window->h = attrs.height; - break; /* window changed, time to go. */ - } else if ((attrs.width == window->w) && (attrs.height == window->h)) { - break; /* we're at the place we wanted to be anyhow, drop out. */ + if (!caught_x11_error) { + if ((attrs.width != orig_w) || (attrs.height != orig_h)) { + window->w = attrs.width; + window->h = attrs.height; + break; /* window changed, time to go. */ + } else if ((attrs.width == window->w) && (attrs.height == window->h)) { + break; /* we're at the place we wanted to be anyhow, drop out. */ + } } if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) { @@ -964,6 +990,9 @@ X11_SetWindowSize(_THIS, SDL_Window * window) SDL_Delay(10); } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } int @@ -1281,6 +1310,22 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis if (X11_IsWindowMapped(_this, window)) { XEvent e; + /* !!! FIXME: most of this waiting code is copy/pasted from elsewhere. */ + int (*prev_handler) (Display *, XErrorEvent *) = NULL; + unsigned int childCount; + Window childReturn, root, parent; + Window* children; + XWindowAttributes attrs; + int orig_w, orig_h, orig_x, orig_y; + Uint64 timeout; + + X11_XSync(display, False); + X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount); + X11_XGetWindowAttributes(display, data->xwindow, &attrs); + X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), + attrs.x, attrs.y, &orig_x, &orig_y, &childReturn); + orig_w = attrs.width; + orig_h = attrs.height; if (!(window->flags & SDL_WINDOW_RESIZABLE)) { /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we @@ -1330,6 +1375,41 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0, SubstructureNotifyMask | SubstructureRedirectMask, &e); } + + /* Wait a brief time to see if the window manager decided to let this happen. + If the window changes at all, even to an unexpected value, we break out. */ + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + + timeout = SDL_GetTicks64() + 100; + while (SDL_TRUE) { + int x, y; + + caught_x11_error = SDL_FALSE; + X11_XSync(display, False); + X11_XGetWindowAttributes(display, data->xwindow, &attrs); + X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), + attrs.x, attrs.y, &x, &y, &childReturn); + + if (!caught_x11_error) { + if ((x != orig_x) || (y != orig_y) || (attrs.width != orig_w) || (attrs.height != orig_h)) { + window->x = x; + window->y = y; + window->w = attrs.width; + window->h = attrs.height; + break; /* window moved, time to go. */ + } + } + + if (SDL_GetTicks64() >= timeout) { + break; + } + + SDL_Delay(10); + } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } else { Uint32 flags; diff --git a/Engine/lib/sdl/src/video/yuv2rgb/yuv_rgb_sse_func.h b/Engine/lib/sdl/src/video/yuv2rgb/yuv_rgb_sse_func.h index 3c5ee0db4..f541017a4 100644 --- a/Engine/lib/sdl/src/video/yuv2rgb/yuv_rgb_sse_func.h +++ b/Engine/lib/sdl/src/video/yuv2rgb/yuv_rgb_sse_func.h @@ -426,9 +426,17 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height, const int fix_read_nv12 = 0; #endif +#if YUV_FORMAT == YUV_FORMAT_422 + /* Avoid invalid read on last line */ + const int fix_read_422 = 1; +#else + const int fix_read_422 = 0; +#endif + + if (width >= 32) { uint32_t xpos, ypos; - for(ypos=0; ypos<(height-(uv_y_sample_interval-1)); ypos+=uv_y_sample_interval) + for(ypos=0; ypos<(height-(uv_y_sample_interval-1)) - fix_read_422; ypos+=uv_y_sample_interval) { const uint8_t *y_ptr1=Y+ypos*Y_stride, *y_ptr2=Y+(ypos+1)*Y_stride, @@ -459,6 +467,15 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height, } } + if (fix_read_422) { + const uint8_t *y_ptr=Y+ypos*Y_stride, + *u_ptr=U+(ypos/uv_y_sample_interval)*UV_stride, + *v_ptr=V+(ypos/uv_y_sample_interval)*UV_stride; + uint8_t *rgb_ptr=RGB+ypos*RGB_stride; + STD_FUNCTION_NAME(width, 1, y_ptr, u_ptr, v_ptr, Y_stride, UV_stride, rgb_ptr, RGB_stride, yuv_type); + ypos += uv_y_sample_interval; + } + /* Catch the last line, if needed */ if (uv_y_sample_interval == 2 && ypos == (height-1)) { diff --git a/Engine/lib/sdl/test/Makefile.in b/Engine/lib/sdl/test/Makefile.in index d29dc6ecf..f724618c6 100644 --- a/Engine/lib/sdl/test/Makefile.in +++ b/Engine/lib/sdl/test/Makefile.in @@ -364,6 +364,7 @@ DATA = \ testgles2_sdf_img_sdf.bmp \ testyuv.bmp \ unifont-13.0.06.hex \ + utf8.txt \ $(NULL) ifneq ($(srcdir), .) diff --git a/Engine/lib/sdl/test/testautomation_rect.c b/Engine/lib/sdl/test/testautomation_rect.c index 26f03e9bb..cd8f65c34 100644 --- a/Engine/lib/sdl/test/testautomation_rect.c +++ b/Engine/lib/sdl/test/testautomation_rect.c @@ -408,6 +408,32 @@ void _validateRectEqualsResults( refRectB->x, refRectB->y, refRectB->w, refRectB->h); } +/* ! + * \brief Private helper to check SDL_FRectEquals results + */ +void _validateFRectEqualsResults( + SDL_bool equals, SDL_bool expectedEquals, + SDL_FRect *rectA, SDL_FRect *rectB, SDL_FRect *refRectA, SDL_FRect *refRectB) +{ + int cmpRes; + SDLTest_AssertCheck(equals == expectedEquals, + "Check for correct equals result: expected %s, got %s testing (%f,%f,%f,%f) and (%f,%f,%f,%f)", + (expectedEquals == SDL_TRUE) ? "SDL_TRUE" : "SDL_FALSE", + (equals == SDL_TRUE) ? "SDL_TRUE" : "SDL_FALSE", + rectA->x, rectA->y, rectA->w, rectA->h, + rectB->x, rectB->y, rectB->w, rectB->h); + cmpRes = SDL_memcmp(rectA, refRectA, sizeof(*rectA)); + SDLTest_AssertCheck(cmpRes == 0, + "Check that source rectangle A was not modified: got (%f,%f,%f,%f) expected (%f,%f,%f,%f)", + rectA->x, rectA->y, rectA->w, rectA->h, + refRectA->x, refRectA->y, refRectA->w, refRectA->h); + cmpRes = SDL_memcmp(rectB, refRectB, sizeof(*rectB)); + SDLTest_AssertCheck(cmpRes == 0, + "Check that source rectangle B was not modified: got (%f,%f,%f,%f) expected (%f,%f,%f,%f)", + rectB->x, rectB->y, rectB->w, rectB->h, + refRectB->x, refRectB->y, refRectB->w, refRectB->h); +} + /* ! * \brief Tests SDL_IntersectRect() with B fully inside A * @@ -1574,6 +1600,69 @@ int rect_testRectEqualsParam(void *arg) return TEST_COMPLETED; } +/* ! + * \brief Tests SDL_FRectEquals() with various inputs + * + * \sa + * http://wiki.libsdl.org/SDL_FRectEquals + */ +int rect_testFRectEquals(void *arg) +{ + SDL_FRect refRectA; + SDL_FRect refRectB; + SDL_FRect rectA; + SDL_FRect rectB; + SDL_bool expectedResult; + SDL_bool result; + + /* Equals */ + refRectA.x=(float)SDLTest_RandomIntegerInRange(-1024, 1024); + refRectA.y=(float)SDLTest_RandomIntegerInRange(-1024, 1024); + refRectA.w=(float)SDLTest_RandomIntegerInRange(1, 1024); + refRectA.h=(float)SDLTest_RandomIntegerInRange(1, 1024); + refRectB = refRectA; + expectedResult = SDL_TRUE; + rectA = refRectA; + rectB = refRectB; + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)&rectA, (const SDL_FRect *)&rectB); + _validateFRectEqualsResults(result, expectedResult, &rectA, &rectB, &refRectA, &refRectB); + + return TEST_COMPLETED; +} + +/* ! + * \brief Negative tests against SDL_FRectEquals() with invalid parameters + * + * \sa + * http://wiki.libsdl.org/SDL_FRectEquals + */ +int rect_testFRectEqualsParam(void *arg) +{ + SDL_FRect rectA; + SDL_FRect rectB; + SDL_bool result; + + /* data setup -- For the purpose of this test, the values don't matter. */ + rectA.x=SDLTest_RandomFloat(); + rectA.y=SDLTest_RandomFloat(); + rectA.w=SDLTest_RandomFloat(); + rectA.h=SDLTest_RandomFloat(); + rectB.x=SDLTest_RandomFloat(); + rectB.y=SDLTest_RandomFloat(); + rectB.w=SDLTest_RandomFloat(); + rectB.h=SDLTest_RandomFloat(); + + /* invalid parameter combinations */ + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)NULL, (const SDL_FRect *)&rectB); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 1st parameter is NULL"); + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)&rectA, (const SDL_FRect *)NULL); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 2nd parameter is NULL"); + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)NULL, (const SDL_FRect *)NULL); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 1st and 2nd parameter are NULL"); + + return TEST_COMPLETED; +} + /* ================= Test References ================== */ /* Rect test cases */ @@ -1673,6 +1762,13 @@ static const SDLTest_TestCaseReference rectTest28 = static const SDLTest_TestCaseReference rectTest29 = { (SDLTest_TestCaseFp)rect_testRectEqualsParam, "rect_testRectEqualsParam", "Negative tests against SDL_RectEquals with invalid parameters", TEST_ENABLED }; +/* SDL_FRectEquals */ + +static const SDLTest_TestCaseReference rectTest30 = + { (SDLTest_TestCaseFp)rect_testFRectEquals, "rect_testFRectEquals", "Tests SDL_FRectEquals with various inputs", TEST_ENABLED }; + +static const SDLTest_TestCaseReference rectTest31 = + { (SDLTest_TestCaseFp)rect_testFRectEqualsParam, "rect_testFRectEqualsParam", "Negative tests against SDL_FRectEquals with invalid parameters", TEST_ENABLED }; /* ! * \brief Sequence of Rect test cases; functions that handle simple rectangles including overlaps and merges. @@ -1683,7 +1779,7 @@ static const SDLTest_TestCaseReference rectTest29 = static const SDLTest_TestCaseReference *rectTests[] = { &rectTest1, &rectTest2, &rectTest3, &rectTest4, &rectTest5, &rectTest6, &rectTest7, &rectTest8, &rectTest9, &rectTest10, &rectTest11, &rectTest12, &rectTest13, &rectTest14, &rectTest15, &rectTest16, &rectTest17, &rectTest18, &rectTest19, &rectTest20, &rectTest21, &rectTest22, &rectTest23, &rectTest24, &rectTest25, &rectTest26, &rectTest27, - &rectTest28, &rectTest29, NULL + &rectTest28, &rectTest29, &rectTest30, &rectTest31, NULL }; diff --git a/Engine/lib/sdl/test/testevdev.c b/Engine/lib/sdl/test/testevdev.c index 572c60a05..76a12ef7e 100644 --- a/Engine/lib/sdl/test/testevdev.c +++ b/Engine/lib/sdl/test/testevdev.c @@ -41,6 +41,7 @@ static const struct CLS(SOUND), CLS(TOUCHSCREEN), CLS(ACCELEROMETER), + CLS(TOUCHPAD), #undef CLS { 0, NULL } }; @@ -185,9 +186,7 @@ static const GuessTest guess_tests[] = .bus_type = 0x0003, .vendor_id = 0x054c, .product_id = 0x09cc, - /* TODO: Should this be MOUSE? That's what it most closely - * resembles */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_TOUCHPAD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* X, Y, multitouch */ @@ -596,7 +595,7 @@ static const GuessTest guess_tests[] = * to the arrow, page up and page down keys, so it's a joystick * with a subset of a keyboard attached. */ /* TODO: Should this be JOYSTICK, or even JOYSTICK|KEYBOARD? */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -608,7 +607,7 @@ static const GuessTest guess_tests[] = /* BTN_1, BTN_2, BTN_A, BTN_B, BTN_MODE */ /* 0x100 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, /* 0x140 */ ZEROx8, - /* next, previous */ + /* next (keyboard page down), previous (keyboard page up) */ /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4, }, }, @@ -659,7 +658,7 @@ static const GuessTest guess_tests[] = .name = "Wiimote - Classic Controller", /* TODO: Should this be JOYSTICK, or maybe JOYSTICK|KEYBOARD? * It's unusual in the same ways as the Wiimote */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* Hat 1-3 */ @@ -673,7 +672,7 @@ static const GuessTest guess_tests[] = /* A, B, X, Y, MODE, TL, TL2, TR, TR2 */ /* 0x100 */ ZEROx4, 0x00, 0x13, 0xdb, 0x10, /* 0x140 */ ZEROx8, - /* next, previous */ + /* next (keyboard page down), previous (keyboard page up) */ /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4, }, }, @@ -718,9 +717,7 @@ static const GuessTest guess_tests[] = .vendor_id = 0x06cb, .product_id = 0x0000, .version = 0x0000, - /* TODO: Should this be MOUSE? That's what it most closely - * resembles */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_TOUCHPAD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* X, Y, pressure, multitouch */ @@ -756,7 +753,8 @@ static const GuessTest guess_tests[] = }, { .name = "Thinkpad ACPI buttons", - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats this as a keyboard because it has a power button */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, MSC, SW */ .ev = { 0x33 }, .keys = { @@ -815,7 +813,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0003, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats KEY_SLEEP as indicating a keyboard */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -841,7 +840,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0001, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats KEY_POWER as indicating a keyboard */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -856,7 +856,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0006, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats brightness control, etc. as keyboard keys */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -873,7 +874,7 @@ static const GuessTest guess_tests[] = .vendor_id = 0x17aa, .product_id = 0x5054, .version = 0x4101, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -911,9 +912,8 @@ static const GuessTest guess_tests[] = .product_id = 0x6009, /* For some reason the special keys like mute and wlan toggle * show up here instead of, or in addition to, as part of - * the keyboard - so udev reports this as having keys too. - * SDL currently doesn't. */ - .expected = SDL_UDEV_DEVICE_MOUSE, + * the keyboard - so both udev and SDL report this as having keys too. */ + .expected = SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, REL, MSC, LED */ .ev = { 0x17, 0x00, 0x02 }, /* X, Y */ diff --git a/Engine/lib/sdl/test/testgles2.c b/Engine/lib/sdl/test/testgles2.c index 153ebe499..c42835ebb 100644 --- a/Engine/lib/sdl/test/testgles2.c +++ b/Engine/lib/sdl/test/testgles2.c @@ -38,6 +38,18 @@ typedef struct GLES2_Context #undef SDL_PROC } GLES2_Context; +typedef struct shader_data +{ + GLuint shader_program, shader_frag, shader_vert; + + GLint attr_position; + GLint attr_color, attr_mvp; + + int angle_x, angle_y, angle_z; + + GLuint position_buffer; + GLuint color_buffer; +} shader_data; static SDLTest_CommonState *state; static SDL_GLContext *context = NULL; @@ -197,13 +209,13 @@ multiply_matrix(float *lhs, float *rhs, float *r) * source: Passed-in shader source code. * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. */ -void +static void process_shader(GLuint *shader, const char * source, GLint shader_type) { GLint status = GL_FALSE; const char *shaders[1] = { NULL }; char buffer[1024]; - GLsizei length; + GLsizei length = 0; /* Create shader and load into GL. */ *shader = GL_CHECK(ctx.glCreateShader(shader_type)); @@ -221,13 +233,35 @@ process_shader(GLuint *shader, const char * source, GLint shader_type) /* Dump debug info (source and log) if compilation failed. */ if(status != GL_TRUE) { - ctx.glGetProgramInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); + ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); buffer[length] = '\0'; - SDL_Log("Shader compilation failed: %s", buffer);fflush(stderr); + SDL_Log("Shader compilation failed: %s", buffer); + fflush(stderr); quit(-1); } } +static void +link_program(struct shader_data *data) +{ + GLint status = GL_FALSE; + char buffer[1024]; + GLsizei length = 0; + + GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); + GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); + GL_CHECK(ctx.glLinkProgram(data->shader_program)); + GL_CHECK(ctx.glGetProgramiv(data->shader_program, GL_LINK_STATUS, &status)); + + if(status != GL_TRUE) { + ctx.glGetProgramInfoLog(data->shader_program, sizeof(buffer), &length, &buffer[0]); + buffer[length] = '\0'; + SDL_Log("Program linking failed: %s", buffer); + fflush(stderr); + quit(-1); + } +} + /* 3D data. Vertex range -0.5..0.5 in all axes. * Z -0.5 is near, 0.5 is far. */ const float _vertices[] = @@ -363,19 +397,6 @@ const char* _shader_frag_src = " gl_FragColor = vec4(vv3color, 1.0); " " } "; -typedef struct shader_data -{ - GLuint shader_program, shader_frag, shader_vert; - - GLint attr_position; - GLint attr_color, attr_mvp; - - int angle_x, angle_y, angle_z; - - GLuint position_buffer; - GLuint color_buffer; -} shader_data; - static void Render(unsigned int width, unsigned int height, shader_data* data) { @@ -672,9 +693,7 @@ main(int argc, char *argv[]) data->shader_program = GL_CHECK(ctx.glCreateProgram()); /* Attach shaders and link shader_program */ - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); - GL_CHECK(ctx.glLinkProgram(data->shader_program)); + link_program(data); /* Get attribute locations of non-fixed attributes like color and texture coordinates. */ data->attr_position = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av4position")); @@ -693,13 +712,13 @@ main(int argc, char *argv[]) GL_CHECK(ctx.glGenBuffers(1, &data->position_buffer)); GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->position_buffer)); - GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices) * 4, _vertices, GL_STATIC_DRAW)); + GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW)); GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, 0)); GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); GL_CHECK(ctx.glGenBuffers(1, &data->color_buffer)); GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->color_buffer)); - GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_colors) * 4, _colors, GL_STATIC_DRAW)); + GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_colors), _colors, GL_STATIC_DRAW)); GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, 0)); GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); diff --git a/Engine/lib/sdl/test/testmouse.c b/Engine/lib/sdl/test/testmouse.c index c73adca51..11a176066 100644 --- a/Engine/lib/sdl/test/testmouse.c +++ b/Engine/lib/sdl/test/testmouse.c @@ -39,6 +39,11 @@ static Line *active = NULL; static Line *lines = NULL; static int buttons = 0; +static SDL_bool wheel_x_active = SDL_FALSE; +static SDL_bool wheel_y_active = SDL_FALSE; +static float wheel_x = SCREEN_WIDTH * 0.5f; +static float wheel_y = SCREEN_HEIGHT * 0.5f; + static SDL_bool done = SDL_FALSE; void @@ -81,6 +86,25 @@ loop(void *arg) /* Check for events */ while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_MOUSEWHEEL: + if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { + event.wheel.preciseX *= -1.0f; + event.wheel.preciseY *= -1.0f; + event.wheel.x *= -1; + event.wheel.y *= -1; + } + if (event.wheel.preciseX != 0.0f) { + wheel_x_active = SDL_TRUE; + /* "positive to the right and negative to the left" */ + wheel_x += event.wheel.preciseX * 10.0f; + } + if (event.wheel.preciseY != 0.0f) { + wheel_y_active = SDL_TRUE; + /* "positive away from the user and negative towards the user" */ + wheel_y -= event.wheel.preciseY * 10.0f; + } + break; + case SDL_MOUSEMOTION: if (!active) break; @@ -134,6 +158,16 @@ loop(void *arg) SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); + /* Mouse wheel */ + SDL_SetRenderDrawColor(renderer, 0, 255, 128, 255); + if (wheel_x_active) { + SDL_RenderDrawLine(renderer, wheel_x, 0, wheel_x, SCREEN_HEIGHT); + } + if (wheel_y_active) { + SDL_RenderDrawLine(renderer, 0, wheel_y, SCREEN_WIDTH, wheel_y); + } + + /* Lines from mouse clicks */ DrawLines(renderer); if (active) DrawLine(renderer, active); diff --git a/Engine/lib/sdl/test/testshader.c b/Engine/lib/sdl/test/testshader.c index 2cee7d9b3..3c2da590f 100644 --- a/Engine/lib/sdl/test/testshader.c +++ b/Engine/lib/sdl/test/testshader.c @@ -126,21 +126,52 @@ static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; static SDL_bool CompileShader(GLhandleARB shader, const char *source) { - GLint status; + GLint status = 0; glShaderSourceARB(shader, 1, &source, NULL); glCompileShaderARB(shader); glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (status == 0) { - GLint length; + GLint length = 0; char *info; glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - info = SDL_stack_alloc(char, length+1); - glGetInfoLogARB(shader, length, NULL, info); - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); - SDL_stack_free(info); + info = (char *) SDL_malloc(length + 1); + if (!info) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); + } else { + glGetInfoLogARB(shader, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); + SDL_free(info); + } + return SDL_FALSE; + } else { + return SDL_TRUE; + } +} +static SDL_bool LinkProgram(ShaderData *data) +{ + GLint status = 0; + + glAttachObjectARB(data->program, data->vert_shader); + glAttachObjectARB(data->program, data->frag_shader); + glLinkProgramARB(data->program); + + glGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status); + if (status == 0) { + GLint length = 0; + char *info; + + glGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + info = (char *) SDL_malloc(length + 1); + if (!info) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); + } else { + glGetInfoLogARB(data->program, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info); + SDL_free(info); + } return SDL_FALSE; } else { return SDL_TRUE; @@ -171,9 +202,9 @@ static SDL_bool CompileShaderProgram(ShaderData *data) } /* ... and in the darkness bind them */ - glAttachObjectARB(data->program, data->vert_shader); - glAttachObjectARB(data->program, data->frag_shader); - glLinkProgramARB(data->program); + if (!LinkProgram(data)) { + return SDL_FALSE; + } /* Set up some uniform variables */ glUseProgramObjectARB(data->program); diff --git a/Engine/lib/sdl/wayland-protocols/tablet-unstable-v2.xml b/Engine/lib/sdl/wayland-protocols/tablet-unstable-v2.xml new file mode 100644 index 000000000..b286d964a --- /dev/null +++ b/Engine/lib/sdl/wayland-protocols/tablet-unstable-v2.xml @@ -0,0 +1,1178 @@ + + + + + Copyright 2014 © Stephen "Lyude" Chandler Paul + Copyright 2015-2016 © Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + + + This description provides a high-level overview of the interplay between + the interfaces defined this protocol. For details, see the protocol + specification. + + More than one tablet may exist, and device-specifics matter. Tablets are + not represented by a single virtual device like wl_pointer. A client + binds to the tablet manager object which is just a proxy object. From + that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat) + and that returns the actual interface that has all the tablets. With + this indirection, we can avoid merging wp_tablet into the actual Wayland + protocol, a long-term benefit. + + The wp_tablet_seat sends a "tablet added" event for each tablet + connected. That event is followed by descriptive events about the + hardware; currently that includes events for name, vid/pid and + a wp_tablet.path event that describes a local path. This path can be + used to uniquely identify a tablet or get more information through + libwacom. Emulated or nested tablets can skip any of those, e.g. a + virtual tablet may not have a vid/pid. The sequence of descriptive + events is terminated by a wp_tablet.done event to signal that a client + may now finalize any initialization for that tablet. + + Events from tablets require a tool in proximity. Tools are also managed + by the tablet seat; a "tool added" event is sent whenever a tool is new + to the compositor. That event is followed by a number of descriptive + events about the hardware; currently that includes capabilities, + hardware id and serial number, and tool type. Similar to the tablet + interface, a wp_tablet_tool.done event is sent to terminate that initial + sequence. + + Any event from a tool happens on the wp_tablet_tool interface. When the + tool gets into proximity of the tablet, a proximity_in event is sent on + the wp_tablet_tool interface, listing the tablet and the surface. That + event is followed by a motion event with the coordinates. After that, + it's the usual motion, axis, button, etc. events. The protocol's + serialisation means events are grouped by wp_tablet_tool.frame events. + + Two special events (that don't exist in X) are down and up. They signal + "tip touching the surface". For tablets without real proximity + detection, the sequence is: proximity_in, motion, down, frame. + + When the tool leaves proximity, a proximity_out event is sent. If any + button is still down, a button release event is sent before this + proximity event. These button events are sent in the same frame as the + proximity event to signal to the client that the buttons were held when + the tool left proximity. + + If the tool moves out of the surface but stays in proximity (i.e. + between windows), compositor-specific grab policies apply. This usually + means that the proximity-out is delayed until all buttons are released. + + Moving a tool physically from one tablet to the other has no real effect + on the protocol, since we already have the tool object from the "tool + added" event. All the information is already there and the proximity + events on both tablets are all a client needs to reconstruct what + happened. + + Some extra axes are normalized, i.e. the client knows the range as + specified in the protocol (e.g. [0, 65535]), the granularity however is + unknown. The current normalized axes are pressure, distance, and slider. + + Other extra axes are in physical units as specified in the protocol. + The current extra axes with physical units are tilt, rotation and + wheel rotation. + + Since tablets work independently of the pointer controlled by the mouse, + the focus handling is independent too and controlled by proximity. + The wp_tablet_tool.set_cursor request sets a tool-specific cursor. + This cursor surface may be the same as the mouse cursor, and it may be + the same across tools but it is possible to be more fine-grained. For + example, a client may set different cursors for the pen and eraser. + + Tools are generally independent of tablets and it is + compositor-specific policy when a tool can be removed. Common approaches + will likely include some form of removing a tool when all tablets the + tool was used on are removed. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + An object that provides access to the graphics tablets available on this + system. All tablets are associated with a seat, to get access to the + actual tablets, use wp_tablet_manager.get_tablet_seat. + + + + + Get the wp_tablet_seat object for the given seat. This object + provides access to all graphics tablets in this seat. + + + + + + + + Destroy the wp_tablet_manager object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + + An object that provides access to the graphics tablets available on this + seat. After binding to this interface, the compositor sends a set of + wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. + + + + + Destroy the wp_tablet_seat object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + This event is sent whenever a new tablet becomes available on this + seat. This event only provides the object id of the tablet, any + static information about the tablet (device name, vid/pid, etc.) is + sent through the wp_tablet interface. + + + + + + + This event is sent whenever a tool that has not previously been used + with a tablet comes into use. This event only provides the object id + of the tool; any static information about the tool (capabilities, + type, etc.) is sent through the wp_tablet_tool interface. + + + + + + + This event is sent whenever a new pad is known to the system. Typically, + pads are physically attached to tablets and a pad_added event is + sent immediately after the wp_tablet_seat.tablet_added. + However, some standalone pad devices logically attach to tablets at + runtime, and the client must wait for wp_tablet_pad.enter to know + the tablet a pad is attached to. + + This event only provides the object id of the pad. All further + features (buttons, strips, rings) are sent through the wp_tablet_pad + interface. + + + + + + + + An object that represents a physical tool that has been, or is + currently in use with a tablet in this seat. Each wp_tablet_tool + object stays valid until the client destroys it; the compositor + reuses the wp_tablet_tool object to indicate that the object's + respective physical tool has come into proximity of a tablet again. + + A wp_tablet_tool object's relation to a physical tool depends on the + tablet's ability to report serial numbers. If the tablet supports + this capability, then the object represents a specific physical tool + and can be identified even when used on multiple tablets. + + A tablet tool has a number of static characteristics, e.g. tool type, + hardware_serial and capabilities. These capabilities are sent in an + event sequence after the wp_tablet_seat.tool_added event before any + actual events from this tool. This initial event sequence is + terminated by a wp_tablet_tool.done event. + + Tablet tool events are grouped by wp_tablet_tool.frame events. + Any events received before a wp_tablet_tool.frame event should be + considered part of the same hardware state change. + + + + + Sets the surface of the cursor used for this tool on the given + tablet. This request only takes effect if the tool is in proximity + of one of the requesting client's surfaces or the surface parameter + is the current pointer surface. If there was a previous surface set + with this request it is replaced. If surface is NULL, the cursor + image is hidden. + + The parameters hotspot_x and hotspot_y define the position of the + pointer surface relative to the pointer location. Its top-left corner + is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the + coordinates of the pointer location, in surface-local coordinates. + + On surface.attach requests to the pointer surface, hotspot_x and + hotspot_y are decremented by the x and y parameters passed to the + request. Attach must be confirmed by wl_surface.commit as usual. + + The hotspot can also be updated by passing the currently set pointer + surface to this request with new values for hotspot_x and hotspot_y. + + The current and pending input regions of the wl_surface are cleared, + and wl_surface.set_input_region is ignored until the wl_surface is no + longer used as the cursor. When the use as a cursor ends, the current + and pending input regions become undefined, and the wl_surface is + unmapped. + + This request gives the surface the role of a wp_tablet_tool cursor. A + surface may only ever be used as the cursor surface for one + wp_tablet_tool. If the surface already has another role or has + previously been used as cursor surface for a different tool, a + protocol error is raised. + + + + + + + + + + This destroys the client's resource for this tool object. + + + + + + Describes the physical type of a tool. The physical type of a tool + generally defines its base usage. + + The mouse tool represents a mouse-shaped tool that is not a relative + device but bound to the tablet's surface, providing absolute + coordinates. + + The lens tool is a mouse-shaped tool with an attached lens to + provide precision focus. + + + + + + + + + + + + + + The tool type is the high-level type of the tool and usually decides + the interaction expected from this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + If the physical tool can be identified by a unique 64-bit serial + number, this event notifies the client of this serial number. + + If multiple tablets are available in the same seat and the tool is + uniquely identifiable by the serial number, that tool may move + between tablets. + + Otherwise, if the tool has no serial number and this event is + missing, the tool is tied to the tablet it first comes into + proximity with. Even if the physical tool is used on multiple + tablets, separate wp_tablet_tool objects will be created, one per + tablet. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + + This event notifies the client of a hardware id available on this tool. + + The hardware id is a device-specific 64-bit id that provides extra + information about the tool in use, beyond the wl_tool.type + enumeration. The format of the id is specific to tablets made by + Wacom Inc. For example, the hardware id of a Wacom Grip + Pen (a stylus) is 0x802. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + + Describes extra capabilities on a tablet. + + Any tool must provide x and y values, extra axes are + device-specific. + + + + + + + + + + + + This event notifies the client of any capabilities of this tool, + beyond the main set of x/y axes and tip up/down detection. + + One event is sent for each extra capability available on this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the tool to + be complete and finalize initialization of the tool. + + + + + + This event is sent when the tool is removed from the system and will + send no further events. Should the physical tool come back into + proximity later, a new wp_tablet_tool object will be created. + + It is compositor-dependent when a tool is removed. A compositor may + remove a tool on proximity out, tablet removal or any other reason. + A compositor may also keep a tool alive until shutdown. + + If the tool is currently in proximity, a proximity_out event will be + sent before the removed event. See wp_tablet_tool.proximity_out for + the handling of any buttons logically down. + + When this event is received, the client must wp_tablet_tool.destroy + the object. + + + + + + Notification that this tool is focused on a certain surface. + + This event can be received when the tool has moved from one surface to + another, or when the tool has come back into proximity above the + surface. + + If any button is logically down when the tool comes into proximity, + the respective button event is sent after the proximity_in event but + within the same frame as the proximity_in event. + + + + + + + + + Notification that this tool has either left proximity, or is no + longer focused on a certain surface. + + When the tablet tool leaves proximity of the tablet, button release + events are sent for each button that was held down at the time of + leaving proximity. These events are sent before the proximity_out + event but within the same wp_tablet.frame. + + If the tool stays within proximity of the tablet, but the focus + changes from one surface to another, a button release event may not + be sent until the button is actually released or the tool leaves the + proximity of the tablet. + + + + + + Sent whenever the tablet tool comes in contact with the surface of the + tablet. + + If the tool is already in contact with the tablet when entering the + input region, the client owning said region will receive a + wp_tablet.proximity_in event, followed by a wp_tablet.down + event and a wp_tablet.frame event. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool in + logical contact until a minimum physical pressure threshold is + exceeded. + + + + + + + Sent whenever the tablet tool stops making contact with the surface of + the tablet, or when the tablet tool moves out of the input region + and the compositor grab (if any) is dismissed. + + If the tablet tool moves out of the input region while in contact + with the surface of the tablet and the compositor does not have an + ongoing grab on the surface, the client owning said region will + receive a wp_tablet.up event, followed by a wp_tablet.proximity_out + event and a wp_tablet.frame event. If the compositor has an ongoing + grab on this device, this event sequence is sent whenever the grab + is dismissed in the future. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool out + of logical contact until physical pressure falls below a specific + threshold. + + + + + + Sent whenever a tablet tool moves. + + + + + + + + Sent whenever the pressure axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that pressure may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + + + + + + + Sent whenever the distance axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that distance may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + + + + + + + Sent whenever one or both of the tilt axes on a tool change. Each tilt + value is in degrees, relative to the z-axis of the tablet. + The angle is positive when the top of a tool tilts along the + positive x or y axis. + + + + + + + + Sent whenever the z-rotation axis on the tool changes. The + rotation value is in degrees clockwise from the tool's + logical neutral position. + + + + + + + Sent whenever the slider position on the tool changes. The + value is normalized between -65535 and 65535, with 0 as the logical + neutral position of the slider. + + The slider is available on e.g. the Wacom Airbrush tool. + + + + + + + Sent whenever the wheel on the tool emits an event. This event + contains two values for the same axis change. The degrees value is + in the same orientation as the wl_pointer.vertical_scroll axis. The + clicks value is in discrete logical clicks of the mouse wheel. This + value may be zero if the movement of the wheel was less + than one logical click. + + Clients should choose either value and avoid mixing degrees and + clicks. The compositor may accumulate values smaller than a logical + click and emulate click events when a certain threshold is met. + Thus, wl_tablet_tool.wheel events with non-zero clicks values may + have different degrees values. + + + + + + + + Describes the physical state of a button that produced the button event. + + + + + + + + Sent whenever a button on the tool is pressed or released. + + If a button is held down when the tool moves in or out of proximity, + button events are generated by the compositor. See + wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for + details. + + + + + + + + + Marks the end of a series of axis and/or button updates from the + tablet. The Wayland protocol requires axis updates to be sent + sequentially, however all events within a frame should be considered + one hardware event. + + + + + + + + + + + + The wp_tablet interface represents one graphics tablet device. The + tablet interface itself does not generate events; all events are + generated by wp_tablet_tool objects when in proximity above a tablet. + + A tablet has a number of static characteristics, e.g. device name and + pid/vid. These capabilities are sent in an event sequence after the + wp_tablet_seat.tablet_added event. This initial event sequence is + terminated by a wp_tablet.done event. + + + + + This destroys the client's resource for this tablet object. + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + + A system-specific device path that indicates which device is behind + this wp_tablet. This information may be used to gather additional + information about the device, e.g. through libwacom. + + A device may have more than one device path. If so, multiple + wp_tablet.path events are sent. A device may be emulated and not + have a device path, and in that case this event will not be sent. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet. + + + + + + Sent when the tablet has been removed from the system. When a tablet + is removed, some tools may be removed. + + When this event is received, the client must wp_tablet.destroy + the object. + + + + + + + A circular interaction area, such as the touch ring on the Wacom Intuos + Pro series tablets. + + Events on a ring are logically grouped by the wl_tablet_pad_ring.frame + event. + + + + + Request that the compositor use the provided feedback string + associated with this ring. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the ring is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the ring; compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + ring. Requests providing other serials than the most recent one will be + ignored. + + + + + + + + This destroys the client's resource for this ring object. + + + + + + Describes the source types for ring events. This indicates to the + client how a ring event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + + + + + + + Source information for ring events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_ring.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event + will be sent when the user lifts the finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + + + + + + + Sent whenever the angle on a ring changes. + + The angle is provided in degrees clockwise from the logical + north of the ring in the pad's current rotation. + + + + + + + Stop notification for ring events. + + For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop + event is sent to notify a client that the interaction with the ring + has terminated. This enables the client to implement kinetic scrolling. + See the wp_tablet_pad_ring.source documentation for information on + when this event may be generated. + + Any wp_tablet_pad_ring.angle events with the same source after this + event should be considered as the start of a new interaction. + + + + + + Indicates the end of a set of ring events that logically belong + together. A client is expected to accumulate the data in all events + within the frame before proceeding. + + All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong + logically together. For example, on termination of a finger interaction + on a ring the compositor will send a wp_tablet_pad_ring.source event, + a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event. + + A wp_tablet_pad_ring.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_ring + event. Specifically, a client may get a sequence: angle, frame, + angle, frame, etc. + + + + + + + + A linear interaction area, such as the strips found in Wacom Cintiq + models. + + Events on a strip are logically grouped by the wl_tablet_pad_strip.frame + event. + + + + + Requests the compositor to use the provided feedback string + associated with this strip. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the strip is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the strip, and compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + strip. Requests providing other serials than the most recent one will be + ignored. + + + + + + + + This destroys the client's resource for this strip object. + + + + + + Describes the source types for strip events. This indicates to the + client how a strip event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + + + + + + + Source information for strip events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_strip.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event + will be sent when the user lifts their finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + + + + + + + Sent whenever the position on a strip changes. + + The position is normalized to a range of [0, 65535], the 0-value + represents the top-most and/or left-most position of the strip in + the pad's current rotation. + + + + + + + Stop notification for strip events. + + For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop + event is sent to notify a client that the interaction with the strip + has terminated. This enables the client to implement kinetic + scrolling. See the wp_tablet_pad_strip.source documentation for + information on when this event may be generated. + + Any wp_tablet_pad_strip.position events with the same source after this + event should be considered as the start of a new interaction. + + + + + + Indicates the end of a set of events that represent one logical + hardware strip event. A client is expected to accumulate the data + in all events within the frame before proceeding. + + All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong + logically together. For example, on termination of a finger interaction + on a strip the compositor will send a wp_tablet_pad_strip.source event, + a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame + event. + + A wp_tablet_pad_strip.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_strip + event. Specifically, a client may get a sequence: position, frame, + position, frame, etc. + + + + + + + + A pad group describes a distinct (sub)set of buttons, rings and strips + present in the tablet. The criteria of this grouping is usually positional, + eg. if a tablet has buttons on the left and right side, 2 groups will be + presented. The physical arrangement of groups is undisclosed and may + change on the fly. + + Pad groups will announce their features during pad initialization. Between + the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the + pad group will announce the buttons, rings and strips contained in it, + plus the number of supported modes. + + Modes are a mechanism to allow multiple groups of actions for every element + in the pad group. The number of groups and available modes in each is + persistent across device plugs. The current mode is user-switchable, it + will be announced through the wp_tablet_pad_group.mode_switch event both + whenever it is switched, and after wp_tablet_pad.enter. + + The current mode logically applies to all elements in the pad group, + although it is at clients' discretion whether to actually perform different + actions, and/or issue the respective .set_feedback requests to notify the + compositor. See the wp_tablet_pad_group.mode_switch event for more details. + + + + + Destroy the wp_tablet_pad_group object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + Sent on wp_tablet_pad_group initialization to announce the available + buttons in the group. Button indices start at 0, a button may only be + in one group at a time. + + This event is first sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + Some buttons are reserved by the compositor. These buttons may not be + assigned to any wp_tablet_pad_group. Compositors may broadcast this + event in the case of changes to the mapping of these reserved buttons. + If the compositor happens to reserve all buttons in a group, this event + will be sent with an empty array. + + + + + + + Sent on wp_tablet_pad_group initialization to announce available rings. + One event is sent for each ring available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + + + + + + Sent on wp_tablet_pad initialization to announce available strips. + One event is sent for each strip available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + + + + + + Sent on wp_tablet_pad_group initialization to announce that the pad + group may switch between modes. A client may use a mode to store a + specific configuration for buttons, rings and strips and use the + wl_tablet_pad_group.mode_switch event to toggle between these + configurations. Mode indices start at 0. + + Switching modes is compositor-dependent. See the + wp_tablet_pad_group.mode_switch event for more details. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. This event is only sent when more than + more than one mode is available. + + + + + + + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet group. + + + + + + Notification that the mode was switched. + + A mode applies to all buttons, rings and strips in a group + simultaneously, but a client is not required to assign different actions + for each mode. For example, a client may have mode-specific button + mappings but map the ring to vertical scrolling in all modes. Mode + indices start at 0. + + Switching modes is compositor-dependent. The compositor may provide + visual cues to the client about the mode, e.g. by toggling LEDs on + the tablet device. Mode-switching may be software-controlled or + controlled by one or more physical buttons. For example, on a Wacom + Intuos Pro, the button inside the ring may be assigned to switch + between modes. + + The compositor will also send this event after wp_tablet_pad.enter on + each group in order to notify of the current mode. Groups that only + feature one mode will use mode=0 when emitting this event. + + If a button action in the new mode differs from the action in the + previous mode, the client should immediately issue a + wp_tablet_pad.set_feedback request for each changed button. + + If a ring or strip action in the new mode differs from the action + in the previous mode, the client should immediately issue a + wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request + for each changed ring or strip. + + + + + + + + + + A pad device is a set of buttons, rings and strips + usually physically present on the tablet device itself. Some + exceptions exist where the pad device is physically detached, e.g. the + Wacom ExpressKey Remote. + + Pad devices have no axes that control the cursor and are generally + auxiliary devices to the tool devices used on the tablet surface. + + A pad device has a number of static characteristics, e.g. the number + of rings. These capabilities are sent in an event sequence after the + wp_tablet_seat.pad_added event before any actual events from this pad. + This initial event sequence is terminated by a wp_tablet_pad.done + event. + + All pad features (buttons, rings and strips) are logically divided into + groups and all pads have at least one group. The available groups are + notified through the wp_tablet_pad.group event; the compositor will + emit one event per group before emitting wp_tablet_pad.done. + + Groups may have multiple modes. Modes allow clients to map multiple + actions to a single pad feature. Only one mode can be active per group, + although different groups may have different active modes. + + + + + Requests the compositor to use the provided feedback string + associated with this button. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever a button is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with each button, and compositors may use + this information to offer visual feedback on the button layout + (e.g. on-screen displays). + + Button indices start at 0. Setting the feedback string on a button + that is reserved by the compositor (i.e. not belonging to any + wp_tablet_pad_group) does not generate an error but the compositor + is free to ignore the request. + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + button. Requests providing other serials than the most recent one will + be ignored. + + + + + + + + + Destroy the wp_tablet_pad object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + Sent on wp_tablet_pad initialization to announce available groups. + One event is sent for each pad group available. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. At least one group will be announced. + + + + + + + A system-specific device path that indicates which device is behind + this wp_tablet_pad. This information may be used to gather additional + information about the device, e.g. through libwacom. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. + + + + + + + Sent on wp_tablet_pad initialization to announce the available + buttons. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. This event is only sent when at least one + button is available. + + + + + + + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the pad to + be complete and finalize initialization of the pad. + + + + + + Describes the physical state of a button that caused the button + event. + + + + + + + + Sent whenever the physical state of a button changes. + + + + + + + + + Notification that this pad is focused on the specified surface. + + + + + + + + + Notification that this pad is no longer focused on the specified + surface. + + + + + + + + Sent when the pad has been removed from the system. When a tablet + is removed its pad(s) will be removed too. + + When this event is received, the client must destroy all rings, strips + and groups that were offered by this pad, and issue wp_tablet_pad.destroy + the pad itself. + + + + diff --git a/Engine/lib/sdl/wayland-protocols/viewporter.xml b/Engine/lib/sdl/wayland-protocols/viewporter.xml new file mode 100644 index 000000000..c732d8c35 --- /dev/null +++ b/Engine/lib/sdl/wayland-protocols/viewporter.xml @@ -0,0 +1,186 @@ + + + + + Copyright © 2013-2016 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + The global interface exposing surface cropping and scaling + capabilities is used to instantiate an interface extension for a + wl_surface object. This extended interface will then allow + cropping and scaling the surface contents, effectively + disconnecting the direct relationship between the buffer and the + surface size. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other objects, + wp_viewport objects included. + + + + + + + + + + Instantiate an interface extension for the given wl_surface to + crop and scale its content. If the given wl_surface already has + a wp_viewport object associated, the viewport_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object, which allows the + client to specify the cropping and scaling of the surface + contents. + + This interface works with two concepts: the source rectangle (src_x, + src_y, src_width, src_height), and the destination size (dst_width, + dst_height). The contents of the source rectangle are scaled to the + destination size, and content outside the source rectangle is ignored. + This state is double-buffered, and is applied on the next + wl_surface.commit. + + The two parts of crop and scale state are independent: the source + rectangle, and the destination size. Initially both are unset, that + is, no scaling is applied. The whole of the current wl_buffer is + used as the source, and the surface size is as defined in + wl_surface.attach. + + If the destination size is set, it causes the surface size to become + dst_width, dst_height. The source (rectangle) is scaled to exactly + this size. This overrides whatever the attached wl_buffer size is, + unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + has no content and therefore no size. Otherwise, the size is always + at least 1x1 in surface local coordinates. + + If the source rectangle is set, it defines what area of the wl_buffer is + taken as the source. If the source rectangle is set and the destination + size is not set, then src_width and src_height must be integers, and the + surface size becomes the source rectangle size. This results in cropping + without scaling. If src_width or src_height are not integers and + destination size is not set, the bad_size protocol error is raised when + the surface state is applied. + + The coordinate transformations from buffer pixel coordinates up to + the surface-local coordinates happen in the following order: + 1. buffer_transform (wl_surface.set_buffer_transform) + 2. buffer_scale (wl_surface.set_buffer_scale) + 3. crop and scale (wp_viewport.set*) + This means, that the source rectangle coordinates of crop and scale + are given in the coordinates after the buffer transform and scale, + i.e. in the coordinates that would be the surface-local coordinates + if the crop and scale was not applied. + + If src_x or src_y are negative, the bad_value protocol error is raised. + Otherwise, if the source rectangle is partially or completely outside of + the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + when the surface state is applied. A NULL wl_buffer does not raise the + out_of_buffer error. + + The x, y arguments of wl_surface.attach are applied as normal to + the surface. They indicate how many pixels to remove from the + surface size from the left and the top. In other words, they are + still in the surface-local coordinate system, just like dst_width + and dst_height are. + + If the wl_surface associated with the wp_viewport is destroyed, + all wp_viewport requests except 'destroy' raise the protocol error + no_surface. + + If the wp_viewport object is destroyed, the crop and scale + state is removed from the wl_surface. The change will be applied + on the next wl_surface.commit. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + + + + Set the source rectangle of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If all of x, y, width and height are -1.0, the source rectangle is + unset instead. Any other set of values where width or height are zero + or negative, or x or y are negative, raise the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + + + + Set the destination size of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If width is -1 and height is -1, the destination size is unset + instead. Any other pair of values for width and height that + contains zero or negative values raises the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + diff --git a/Engine/lib/sdl/wayland-protocols/xdg-output-unstable-v1.xml b/Engine/lib/sdl/wayland-protocols/xdg-output-unstable-v1.xml new file mode 100644 index 000000000..9a5b79000 --- /dev/null +++ b/Engine/lib/sdl/wayland-protocols/xdg-output-unstable-v1.xml @@ -0,0 +1,220 @@ + + + + + Copyright © 2017 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol aims at describing outputs in a way which is more in line + with the concept of an output on desktop oriented systems. + + Some information are more specific to the concept of an output for + a desktop oriented system and may not make sense in other applications, + such as IVI systems for example. + + Typically, the global compositor space on a desktop system is made of + a contiguous or overlapping set of rectangular regions. + + Some of the information provided in this protocol might be identical + to their counterparts already available from wl_output, in which case + the information provided by this protocol should be preferred to their + equivalent in wl_output. The goal is to move the desktop specific + concepts (such as output location within the global compositor space, + the connector name and types, etc.) out of the core wl_output protocol. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + A global factory interface for xdg_output objects. + + + + + Using this request a client can tell the server that it is not + going to use the xdg_output_manager object anymore. + + Any objects already created through this instance are not affected. + + + + + + This creates a new xdg_output object for the given wl_output. + + + + + + + + + An xdg_output describes part of the compositor geometry. + + This typically corresponds to a monitor that displays part of the + compositor space. + + For objects version 3 onwards, after all xdg_output properties have been + sent (when the object is created and when properties are updated), a + wl_output.done event is sent. This allows changes to the output + properties to be seen as atomic, even if they happen via multiple events. + + + + + Using this request a client can tell the server that it is not + going to use the xdg_output object anymore. + + + + + + The position event describes the location of the wl_output within + the global compositor space. + + The logical_position event is sent after creating an xdg_output + (see xdg_output_manager.get_xdg_output) and whenever the location + of the output changes within the global compositor space. + + + + + + + + The logical_size event describes the size of the output in the + global compositor space. + + For example, a surface without any buffer scale, transformation + nor rotation set, with the size matching the logical_size will + have the same size as the corresponding output when displayed. + + Most regular Wayland clients should not pay attention to the + logical size and would rather rely on xdg_shell interfaces. + + Some clients such as Xwayland, however, need this to configure + their surfaces in the global compositor space as the compositor + may apply a different scale from what is advertised by the output + scaling property (to achieve fractional scaling, for example). + + For example, for a wl_output mode 3840×2160 and a scale factor 2: + + - A compositor not scaling the surface buffers will advertise a + logical size of 3840×2160, + + - A compositor automatically scaling the surface buffers will + advertise a logical size of 1920×1080, + + - A compositor using a fractional scale of 1.5 will advertise a + logical size of 2560×1440. + + For example, for a wl_output mode 1920×1080 and a 90 degree rotation, + the compositor will advertise a logical size of 1080x1920. + + The logical_size event is sent after creating an xdg_output + (see xdg_output_manager.get_xdg_output) and whenever the logical + size of the output changes, either as a result of a change in the + applied scale or because of a change in the corresponding output + mode(see wl_output.mode) or transform (see wl_output.transform). + + + + + + + + This event is sent after all other properties of an xdg_output + have been sent. + + This allows changes to the xdg_output properties to be seen as + atomic, even if they happen via multiple events. + + For objects version 3 onwards, this event is deprecated. Compositors + are not required to send it anymore and must send wl_output.done + instead. + + + + + + + + Many compositors will assign names to their outputs, show them to the + user, allow them to be configured by name, etc. The client may wish to + know this name as well to offer the user similar behaviors. + + The naming convention is compositor defined, but limited to + alphanumeric characters and dashes (-). Each name is unique among all + wl_output globals, but if a wl_output global is destroyed the same name + may be reused later. The names will also remain consistent across + sessions with the same hardware and software configuration. + + Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do + not assume that the name is a reflection of an underlying DRM + connector, X11 connection, etc. + + The name event is sent after creating an xdg_output (see + xdg_output_manager.get_xdg_output). This event is only sent once per + xdg_output, and the name does not change over the lifetime of the + wl_output global. + + + + + + + Many compositors can produce human-readable descriptions of their + outputs. The client may wish to know this description as well, to + communicate the user for various purposes. + + The description is a UTF-8 string with no convention defined for its + contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11 + output via :1'. + + The description event is sent after creating an xdg_output (see + xdg_output_manager.get_xdg_output) and whenever the description + changes. The description is optional, and may not be sent at all. + + For objects of version 2 and lower, this event is only sent once per + xdg_output, and the description does not change over the lifetime of + the wl_output global. + + + + + +