mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-07-16 22:11:07 +00:00
Compare commits
36 Commits
release-3.
...
release-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e536ede68 | ||
|
|
29d07d3ed1 | ||
|
|
7626a9c313 | ||
|
|
d8b18a7e18 | ||
|
|
558f62eb07 | ||
|
|
4ad0d1f7eb | ||
|
|
432719facc | ||
|
|
5b5713b955 | ||
|
|
ecd15e9535 | ||
|
|
758e323b93 | ||
|
|
5311486a9a | ||
|
|
6ebd9cf86b | ||
|
|
1453f46178 | ||
|
|
da8614ff0f | ||
|
|
99ca7097d2 | ||
|
|
480ab44f9e | ||
|
|
5671b0f3ce | ||
|
|
dcb3da5489 | ||
|
|
3eb9b5e49a | ||
|
|
e5648d4437 | ||
|
|
af5b015b21 | ||
|
|
4f629701fb | ||
|
|
ffc7381337 | ||
|
|
27e6b7a119 | ||
|
|
b18591f4a0 | ||
|
|
1ac361c3fe | ||
|
|
6c10cdb6eb | ||
|
|
7e593a2b4f | ||
|
|
a19040c84d | ||
|
|
c42843c389 | ||
|
|
1cb193a414 | ||
|
|
64f058d050 | ||
|
|
c715180e01 | ||
|
|
3348fc6466 | ||
|
|
81c39b0cc5 | ||
|
|
932f36590f |
2
.github/workflows/create-test-plan.py
vendored
2
.github/workflows/create-test-plan.py
vendored
@@ -781,7 +781,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
|||||||
match spec.platform:
|
match spec.platform:
|
||||||
case SdlPlatform.FreeBSD:
|
case SdlPlatform.FreeBSD:
|
||||||
job.cpactions_os = "freebsd"
|
job.cpactions_os = "freebsd"
|
||||||
job.cpactions_version = "14.3"
|
job.cpactions_version = "14.4"
|
||||||
job.cpactions_arch = "x86-64"
|
job.cpactions_arch = "x86-64"
|
||||||
job.cpactions_setup_cmd = "sudo pkg update"
|
job.cpactions_setup_cmd = "sudo pkg update"
|
||||||
job.cpactions_install_cmd = "sudo pkg install -y cmake ninja pkgconf libXcursor libXext libXinerama libXi libXfixes libXrandr libXScrnSaver libXxf86vm wayland wayland-protocols libxkbcommon mesa-libs libglvnd evdev-proto libinotify alsa-lib jackit pipewire pulseaudio sndio dbus zh-fcitx ibus libudev-devd"
|
job.cpactions_install_cmd = "sudo pkg install -y cmake ninja pkgconf libXcursor libXext libXinerama libXi libXfixes libXrandr libXScrnSaver libXxf86vm wayland wayland-protocols libxkbcommon mesa-libs libglvnd evdev-proto libinotify alsa-lib jackit pipewire pulseaudio sndio dbus zh-fcitx ibus libudev-devd"
|
||||||
|
|||||||
4
.github/workflows/generic.yml
vendored
4
.github/workflows/generic.yml
vendored
@@ -200,7 +200,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
${{ matrix.platform.source-cmd }}
|
${{ matrix.platform.source-cmd }}
|
||||||
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -G "${{ matrix.platform.cmake-generator }}" \
|
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -G "${{ matrix.platform.cmake-generator }}" \
|
||||||
-Wdeprecated -Wdev -Werror \
|
-Wdeprecated -Wdev -Werror=dev -Werror=deprecated \
|
||||||
${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \
|
${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \
|
||||||
-DSDL_WERROR=${{ matrix.platform.werror }} \
|
-DSDL_WERROR=${{ matrix.platform.werror }} \
|
||||||
-DSDL_EXAMPLES=${{ matrix.platform.build-tests }} \
|
-DSDL_EXAMPLES=${{ matrix.platform.build-tests }} \
|
||||||
@@ -319,7 +319,7 @@ jobs:
|
|||||||
- name: 'Build (cross-platform-actions, BSD)'
|
- name: 'Build (cross-platform-actions, BSD)'
|
||||||
id: cpactions
|
id: cpactions
|
||||||
if: ${{ matrix.platform.cpactions }}
|
if: ${{ matrix.platform.cpactions }}
|
||||||
uses: cross-platform-actions/action@v0.32.0
|
uses: cross-platform-actions/action@v1
|
||||||
with:
|
with:
|
||||||
operating_system: '${{ matrix.platform.cpactions-os }}'
|
operating_system: '${{ matrix.platform.cpactions-os }}'
|
||||||
architecture: '${{ matrix.platform.cpactions-arch }}'
|
architecture: '${{ matrix.platform.cpactions-arch }}'
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# See docs/release_checklist.md
|
# See docs/release_checklist.md
|
||||||
project(SDL3 LANGUAGES C VERSION "3.4.12")
|
project(SDL3 LANGUAGES C VERSION "3.4.13")
|
||||||
|
|
||||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||||
set(SDL3_MAINPROJECT ON)
|
set(SDL3_MAINPROJECT ON)
|
||||||
@@ -2203,11 +2203,32 @@ elseif(WINDOWS)
|
|||||||
string(APPEND CMAKE_REQUIRED_FLAGS " /I\"$ENV{DXSDK_DIR}\\Include\"")
|
string(APPEND CMAKE_REQUIRED_FLAGS " /I\"$ENV{DXSDK_DIR}\\Include\"")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
check_include_file(d3d9.h HAVE_D3D9_H)
|
# d3d9.h may need windows.h, but does not include it itself.
|
||||||
check_include_file(d3d11_1.h HAVE_D3D11_H)
|
check_c_source_compiles("
|
||||||
check_include_file(ddraw.h HAVE_DDRAW_H)
|
#include <windows.h>
|
||||||
check_include_file(dsound.h HAVE_DSOUND_H)
|
#include <d3d9.h>
|
||||||
check_include_file(dinput.h HAVE_DINPUT_H)
|
int main(int argc, char **argv) { (void)argc; (void)argv; return 0; }" HAVE_D3D9_H
|
||||||
|
)
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <d3d11_1.h>
|
||||||
|
int main(int argc, char **argv) { (void)argc; (void)argv; return 0; }" HAVE_D3D11_H
|
||||||
|
)
|
||||||
|
# ddraw.h, dsound.h, and dinput.h may need windows.h, but does not include it itself.
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ddraw.h>
|
||||||
|
int main(int argc, char **argv) { (void)argc; (void)argv; return 0; }" HAVE_DDRAW_H
|
||||||
|
)
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <windows.h>
|
||||||
|
#include <dsound.h>
|
||||||
|
int main(int argc, char **argv) { (void)argc; (void)argv; return 0; }" HAVE_DSOUND_H
|
||||||
|
)
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <windows.h>
|
||||||
|
#include <dinput.h>
|
||||||
|
int main(int argc, char **argv) { (void)argc; (void)argv; return 0; }" HAVE_DINPUT_H
|
||||||
|
)
|
||||||
if(SDL_CPU_ARM32) # !!! FIXME: this should probably check if we're !(x86 or x86-64) instead of arm.
|
if(SDL_CPU_ARM32) # !!! FIXME: this should probably check if we're !(x86 or x86-64) instead of arm.
|
||||||
set(HAVE_DINPUT_H 0)
|
set(HAVE_DINPUT_H 0)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -19,10 +19,10 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>3.4.12</string>
|
<string>3.4.13</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>SDLX</string>
|
<string>SDLX</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>3.4.12</string>
|
<string>3.4.13</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -3162,7 +3162,7 @@
|
|||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
DEPLOYMENT_POSTPROCESSING = YES;
|
DEPLOYMENT_POSTPROCESSING = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 401.0.0;
|
DYLIB_COMPATIBILITY_VERSION = 401.0.0;
|
||||||
DYLIB_CURRENT_VERSION = 401.12.0;
|
DYLIB_CURRENT_VERSION = 401.13.0;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||||
@@ -3197,7 +3197,7 @@
|
|||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
MARKETING_VERSION = 3.4.12;
|
MARKETING_VERSION = 3.4.13;
|
||||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||||
PRODUCT_NAME = SDL3;
|
PRODUCT_NAME = SDL3;
|
||||||
@@ -3228,7 +3228,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 401.0.0;
|
DYLIB_COMPATIBILITY_VERSION = 401.0.0;
|
||||||
DYLIB_CURRENT_VERSION = 401.12.0;
|
DYLIB_CURRENT_VERSION = 401.13.0;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
@@ -3260,7 +3260,7 @@
|
|||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
MARKETING_VERSION = 3.4.12;
|
MARKETING_VERSION = 3.4.13;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Title SDL 3.4.12
|
Title SDL 3.4.13
|
||||||
Version 1
|
Version 1
|
||||||
Description SDL Library for macOS (http://www.libsdl.org)
|
Description SDL Library for macOS (http://www.libsdl.org)
|
||||||
DefaultLocation /Library/Frameworks
|
DefaultLocation /Library/Frameworks
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
private static final String TAG = "SDL";
|
private static final String TAG = "SDL";
|
||||||
private static final int SDL_MAJOR_VERSION = 3;
|
private static final int SDL_MAJOR_VERSION = 3;
|
||||||
private static final int SDL_MINOR_VERSION = 4;
|
private static final int SDL_MINOR_VERSION = 4;
|
||||||
private static final int SDL_MICRO_VERSION = 12;
|
private static final int SDL_MICRO_VERSION = 13;
|
||||||
/*
|
/*
|
||||||
// Display InputType.SOURCE/CLASS of events and devices
|
// Display InputType.SOURCE/CLASS of events and devices
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main include header for the SDL library, version 3.4.12
|
* Main include header for the SDL library, version 3.4.13
|
||||||
*
|
*
|
||||||
* It is almost always best to include just this one header instead of
|
* It is almost always best to include just this one header instead of
|
||||||
* picking out individual headers included here. There are exceptions to
|
* picking out individual headers included here. There are exceptions to
|
||||||
|
|||||||
@@ -232,11 +232,16 @@ extern "C" {
|
|||||||
#define SDL_LINE __LINE__
|
#define SDL_LINE __LINE__
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sizeof (x) makes the compiler still parse the expression even without
|
sizeof ((x) ? 1 : 0) makes the compiler still parse the expression even
|
||||||
assertions enabled, so the code is always checked at compile time, but
|
without assertions enabled, so the code is always checked at compile time, but
|
||||||
doesn't actually generate code for it, so there are no side effects or
|
doesn't actually generate code for it, so there are no side effects or
|
||||||
expensive checks at run time, just the constant size of what x WOULD be,
|
expensive checks at run time, just the constant size of what int would be,
|
||||||
which presumably gets optimized out as unused.
|
which presumably gets optimized out as unused.
|
||||||
|
|
||||||
|
(The `? 1 : 0` is so this always dithers down to `sizeof (int)`...otherwise
|
||||||
|
you'll have problems when bitfields are used as the condition, since the
|
||||||
|
compiler will error out on the sizeof.)
|
||||||
|
|
||||||
This also solves the problem of...
|
This also solves the problem of...
|
||||||
|
|
||||||
int somevalue = blah();
|
int somevalue = blah();
|
||||||
@@ -284,14 +289,14 @@ disable assertions.
|
|||||||
*
|
*
|
||||||
* The code does nothing, but wraps `condition` in a sizeof operator, which
|
* The code does nothing, but wraps `condition` in a sizeof operator, which
|
||||||
* generates no code and has no side effects, but avoid compiler warnings
|
* generates no code and has no side effects, but avoid compiler warnings
|
||||||
* about unused variables.
|
* about unused variables, and still checks syntax even when disabled.
|
||||||
*
|
*
|
||||||
* \param condition the condition to assert (but not actually run here).
|
* \param condition the condition to assert (but not actually run here).
|
||||||
*
|
*
|
||||||
* \since This macro is available since SDL 3.2.0.
|
* \since This macro is available since SDL 3.2.0.
|
||||||
*/
|
*/
|
||||||
#define SDL_disabled_assert(condition) \
|
#define SDL_disabled_assert(condition) \
|
||||||
do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
|
do { (void) sizeof ((condition) ? 1 : 0); } while (SDL_NULL_WHILE_LOOP_CONDITION)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible outcomes from a triggered assertion.
|
* Possible outcomes from a triggered assertion.
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ typedef enum SDL_CameraPermissionState
|
|||||||
{
|
{
|
||||||
SDL_CAMERA_PERMISSION_STATE_DENIED = -1,
|
SDL_CAMERA_PERMISSION_STATE_DENIED = -1,
|
||||||
SDL_CAMERA_PERMISSION_STATE_PENDING,
|
SDL_CAMERA_PERMISSION_STATE_PENDING,
|
||||||
SDL_CAMERA_PERMISSION_STATE_APPROVED,
|
SDL_CAMERA_PERMISSION_STATE_APPROVED
|
||||||
} SDL_CameraPermissionState;
|
} SDL_CameraPermissionState;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
* \since This macro is available since SDL 3.2.0.
|
* \since This macro is available since SDL 3.2.0.
|
||||||
*/
|
*/
|
||||||
#define SDL_MICRO_VERSION 12
|
#define SDL_MICRO_VERSION 13
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This macro turns the version numbers into a numeric value.
|
* This macro turns the version numbers into a numeric value.
|
||||||
|
|||||||
@@ -813,7 +813,7 @@ void SDL_DestroyProperties(SDL_PropertiesID props)
|
|||||||
{
|
{
|
||||||
if (props) {
|
if (props) {
|
||||||
// this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because
|
// this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because
|
||||||
// other destructors under this might cause use to attempt a recursive lock on SDL_properties,
|
// other destructors under this might cause us to attempt a recursive lock on SDL_properties,
|
||||||
// which isn't allowed with rwlocks. So manually look it up and remove/free it.
|
// which isn't allowed with rwlocks. So manually look it up and remove/free it.
|
||||||
SDL_Properties *properties = NULL;
|
SDL_Properties *properties = NULL;
|
||||||
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
||||||
|
|||||||
@@ -250,8 +250,6 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
|||||||
|
|
||||||
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
|
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
|
||||||
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
|
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
|
||||||
} else if (navigator.webkitGetUserMedia !== undefined) {
|
|
||||||
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
|
||||||
}
|
}
|
||||||
}, device->spec.channels, device->sample_frames, SDL_RecordingAudioThreadIterate, device);
|
}, device->spec.channels, device->sample_frames, SDL_RecordingAudioThreadIterate, device);
|
||||||
} else {
|
} else {
|
||||||
@@ -331,8 +329,6 @@ static bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
|||||||
recording_available = available && MAIN_THREAD_EM_ASM_INT({
|
recording_available = available && MAIN_THREAD_EM_ASM_INT({
|
||||||
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
|
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
|
||||||
return true;
|
return true;
|
||||||
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ HICON WIN_CreateIconFromSurface(SDL_Surface *surface)
|
|||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
BYTE* pixel = (BYTE*)pBits + (y * width + x) * 4;
|
BYTE* pixel = (BYTE*)pBits + (y * width + x) * 4;
|
||||||
BYTE alpha = pixel[3];
|
BYTE alpha = pixel[3];
|
||||||
COLORREF maskColor = (alpha == 0) ? RGB(0, 0, 0) : RGB(255, 255, 255);
|
COLORREF maskColor = (alpha == 0) ? RGB(255, 255, 255) : RGB(0, 0, 0);
|
||||||
SetPixel(hdcMem, x, y, maskColor);
|
SetPixel(hdcMem, x, y, maskColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 3,4,12,0
|
FILEVERSION 3,4,13,0
|
||||||
PRODUCTVERSION 3,4,12,0
|
PRODUCTVERSION 3,4,13,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
FILEFLAGS 0x0L
|
FILEFLAGS 0x0L
|
||||||
FILEOS 0x40004L
|
FILEOS 0x40004L
|
||||||
@@ -23,12 +23,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "\0"
|
VALUE "CompanyName", "\0"
|
||||||
VALUE "FileDescription", "SDL\0"
|
VALUE "FileDescription", "SDL\0"
|
||||||
VALUE "FileVersion", "3, 4, 12, 0\0"
|
VALUE "FileVersion", "3, 4, 13, 0\0"
|
||||||
VALUE "InternalName", "SDL\0"
|
VALUE "InternalName", "SDL\0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2026 Sam Lantinga\0"
|
VALUE "LegalCopyright", "Copyright (C) 2026 Sam Lantinga\0"
|
||||||
VALUE "OriginalFilename", "SDL3.dll\0"
|
VALUE "OriginalFilename", "SDL3.dll\0"
|
||||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||||
VALUE "ProductVersion", "3, 4, 12, 0\0"
|
VALUE "ProductVersion", "3, 4, 13, 0\0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|||||||
@@ -1411,6 +1411,13 @@ SDL_GPUTransferBuffer *SDL_CreateGPUTransferBuffer(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device->debug_mode) {
|
||||||
|
if (createinfo->usage != SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD &&
|
||||||
|
createinfo->usage != SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD) {
|
||||||
|
SDL_assert_release(!"Invalid transfer buffer usage!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING, NULL);
|
const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING, NULL);
|
||||||
|
|
||||||
return device->CreateTransferBuffer(
|
return device->CreateTransferBuffer(
|
||||||
|
|||||||
@@ -424,6 +424,7 @@ static MTLDepthClipMode SDLToMetal_DepthClipMode(
|
|||||||
// Structs
|
// Structs
|
||||||
|
|
||||||
typedef struct MetalRenderer MetalRenderer;
|
typedef struct MetalRenderer MetalRenderer;
|
||||||
|
typedef struct MetalCommandBuffer MetalCommandBuffer;
|
||||||
|
|
||||||
typedef struct MetalTexture
|
typedef struct MetalTexture
|
||||||
{
|
{
|
||||||
@@ -447,7 +448,7 @@ typedef struct MetalTextureContainer
|
|||||||
|
|
||||||
typedef struct MetalFence
|
typedef struct MetalFence
|
||||||
{
|
{
|
||||||
SDL_AtomicInt complete;
|
id<MTLCommandBuffer> commandBuffer;
|
||||||
SDL_AtomicInt referenceCount;
|
SDL_AtomicInt referenceCount;
|
||||||
} MetalFence;
|
} MetalFence;
|
||||||
|
|
||||||
@@ -2087,7 +2088,6 @@ static Uint8 METAL_INTERNAL_CreateFence(
|
|||||||
MetalFence *fence;
|
MetalFence *fence;
|
||||||
|
|
||||||
fence = SDL_calloc(1, sizeof(MetalFence));
|
fence = SDL_calloc(1, sizeof(MetalFence));
|
||||||
SDL_SetAtomicInt(&fence->complete, 0);
|
|
||||||
SDL_SetAtomicInt(&fence->referenceCount, 0);
|
SDL_SetAtomicInt(&fence->referenceCount, 0);
|
||||||
|
|
||||||
// Add it to the available pool
|
// Add it to the available pool
|
||||||
@@ -2130,7 +2130,7 @@ static bool METAL_INTERNAL_AcquireFence(
|
|||||||
|
|
||||||
// Associate the fence with the command buffer
|
// Associate the fence with the command buffer
|
||||||
commandBuffer->fence = fence;
|
commandBuffer->fence = fence;
|
||||||
SDL_SetAtomicInt(&fence->complete, 0); // FIXME: Is this right?
|
fence->commandBuffer = commandBuffer->handle;
|
||||||
(void)SDL_AtomicIncRef(&commandBuffer->fence->referenceCount);
|
(void)SDL_AtomicIncRef(&commandBuffer->fence->referenceCount);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -3400,6 +3400,7 @@ static void METAL_ReleaseFence(
|
|||||||
SDL_GPUFence *fence)
|
SDL_GPUFence *fence)
|
||||||
{
|
{
|
||||||
MetalFence *metalFence = (MetalFence *)fence;
|
MetalFence *metalFence = (MetalFence *)fence;
|
||||||
|
metalFence->commandBuffer = nil;
|
||||||
if (SDL_AtomicDecRef(&metalFence->referenceCount)) {
|
if (SDL_AtomicDecRef(&metalFence->referenceCount)) {
|
||||||
METAL_INTERNAL_ReleaseFenceToPool(
|
METAL_INTERNAL_ReleaseFenceToPool(
|
||||||
(MetalRenderer *)driverData,
|
(MetalRenderer *)driverData,
|
||||||
@@ -3581,6 +3582,12 @@ static void METAL_INTERNAL_PerformPendingDestroys(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fences
|
// Fences
|
||||||
|
static bool METAL_INTERNAL_IsFenceBusy(
|
||||||
|
MetalFence *fence
|
||||||
|
) {
|
||||||
|
MTLCommandBufferStatus status = fence->commandBuffer.status;
|
||||||
|
return status == MTLCommandBufferStatusCommitted || status == MTLCommandBufferStatusScheduled;
|
||||||
|
}
|
||||||
|
|
||||||
static bool METAL_WaitForFences(
|
static bool METAL_WaitForFences(
|
||||||
SDL_GPURenderer *driverData,
|
SDL_GPURenderer *driverData,
|
||||||
@@ -3590,20 +3597,19 @@ static bool METAL_WaitForFences(
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
MetalRenderer *renderer = (MetalRenderer *)driverData;
|
MetalRenderer *renderer = (MetalRenderer *)driverData;
|
||||||
bool waiting;
|
|
||||||
|
|
||||||
if (waitAll) {
|
if (waitAll) {
|
||||||
for (Uint32 i = 0; i < numFences; i += 1) {
|
for (Uint32 i = 0; i < numFences; i += 1) {
|
||||||
while (!SDL_GetAtomicInt(&((MetalFence *)fences[i])->complete)) {
|
MetalFence *fence = (MetalFence *)fences[i];
|
||||||
// Spin!
|
[fence->commandBuffer waitUntilCompleted];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
waiting = 1;
|
bool waiting = true;
|
||||||
while (waiting) {
|
while (waiting) {
|
||||||
for (Uint32 i = 0; i < numFences; i += 1) {
|
for (Uint32 i = 0; i < numFences; i += 1) {
|
||||||
if (SDL_GetAtomicInt(&((MetalFence *)fences[i])->complete) > 0) {
|
MetalFence *fence = (MetalFence *)fences[i];
|
||||||
waiting = 0;
|
if (!METAL_INTERNAL_IsFenceBusy(fence)) {
|
||||||
|
waiting = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3621,7 +3627,7 @@ static bool METAL_QueryFence(
|
|||||||
SDL_GPUFence *fence)
|
SDL_GPUFence *fence)
|
||||||
{
|
{
|
||||||
MetalFence *metalFence = (MetalFence *)fence;
|
MetalFence *metalFence = (MetalFence *)fence;
|
||||||
return SDL_GetAtomicInt(&metalFence->complete) == 1;
|
return METAL_INTERNAL_IsFenceBusy(metalFence);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window and Swapchain Management
|
// Window and Swapchain Management
|
||||||
@@ -4084,11 +4090,6 @@ static bool METAL_Submit(
|
|||||||
windowData->frameCounter = (windowData->frameCounter + 1) % renderer->allowedFramesInFlight;
|
windowData->frameCounter = (windowData->frameCounter + 1) % renderer->allowedFramesInFlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the fence when the command buffer has completed
|
|
||||||
[metalCommandBuffer->handle addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
|
||||||
SDL_AtomicIncRef(&metalCommandBuffer->fence->complete);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// Submit the command buffer
|
// Submit the command buffer
|
||||||
[metalCommandBuffer->handle commit];
|
[metalCommandBuffer->handle commit];
|
||||||
metalCommandBuffer->handle = nil;
|
metalCommandBuffer->handle = nil;
|
||||||
@@ -4106,7 +4107,7 @@ static bool METAL_Submit(
|
|||||||
|
|
||||||
// Check if we can perform any cleanups
|
// Check if we can perform any cleanups
|
||||||
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
|
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
|
||||||
if (SDL_GetAtomicInt(&renderer->submittedCommandBuffers[i]->fence->complete)) {
|
if (!METAL_INTERNAL_IsFenceBusy(renderer->submittedCommandBuffers[i]->fence)) {
|
||||||
METAL_INTERNAL_CleanCommandBuffer(
|
METAL_INTERNAL_CleanCommandBuffer(
|
||||||
renderer,
|
renderer,
|
||||||
renderer->submittedCommandBuffers[i],
|
renderer->submittedCommandBuffers[i],
|
||||||
@@ -4159,9 +4160,8 @@ static bool METAL_Wait(
|
|||||||
* Sort of equivalent to vkDeviceWaitIdle.
|
* Sort of equivalent to vkDeviceWaitIdle.
|
||||||
*/
|
*/
|
||||||
for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
|
for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
|
||||||
while (!SDL_GetAtomicInt(&renderer->submittedCommandBuffers[i]->fence->complete)) {
|
SDL_GPUFence *opaqueFence = (SDL_GPUFence *)renderer->submittedCommandBuffers[i]->fence;
|
||||||
// Spin!
|
METAL_WaitForFences(driverData, true, &opaqueFence, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LockMutex(renderer->submitLock);
|
SDL_LockMutex(renderer->submitLock);
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ static const char *s_GamepadMappings[] = {
|
|||||||
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||||
"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
|
"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
|
||||||
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,",
|
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,",
|
||||||
|
"030000008f0e00001330000000000000,Mayflash N64 Controller Adapter,crc:226d,a:b1,b:b2,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3~,righty:a2,",
|
||||||
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,",
|
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,",
|
||||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||||
|
|||||||
@@ -3086,7 +3086,7 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons
|
|||||||
if (forUI) {
|
if (forUI) {
|
||||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO;
|
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO;
|
||||||
} else {
|
} else {
|
||||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
type = SDL_GAMEPAD_TYPE_XBOX360;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -386,6 +386,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|||||||
HIDAPI_IsDevicePresent(USB_VENDOR_DRAGONRISE, USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3, 0, ""))) ||
|
HIDAPI_IsDevicePresent(USB_VENDOR_DRAGONRISE, USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3, 0, ""))) ||
|
||||||
(SDL_strcmp(name, "8Bitdo SN30 Pro") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO_BT, 0, ""))) ||
|
(SDL_strcmp(name, "8Bitdo SN30 Pro") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO_BT, 0, ""))) ||
|
||||||
(SDL_strcmp(name, "8BitDo Pro 2") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2_BT, 0, ""))) ||
|
(SDL_strcmp(name, "8BitDo Pro 2") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2_BT, 0, ""))) ||
|
||||||
|
(SDL_strcmp(name, "8BitDo Pro 3") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_3, 0, ""))) ||
|
||||||
(SDL_startswith(name, "8BitDo Ultimate 2 Wireless") && HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS, 0, ""))) {
|
(SDL_startswith(name, "8BitDo Ultimate 2 Wireless") && HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS, 0, ""))) {
|
||||||
// The HIDAPI driver is taking care of this device
|
// The HIDAPI driver is taking care of this device
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -155,13 +155,38 @@ static void SDL_GetEmscriptenNormalizedName(int device_index, char *out, int len
|
|||||||
}, device_index, out, length);
|
}, device_index, out, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_EQUAL_APPROX(a, b) (((a)-(b)) < 0.00001 && ((a)-(b)) > -0.00001)
|
||||||
|
static Uint8 SDL_GetHatFromEmscriptenAxis(float hat_axis)
|
||||||
|
{
|
||||||
|
if (IS_EQUAL_APPROX(hat_axis, -7.0/7)) {
|
||||||
|
return SDL_HAT_UP;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, -5.0/7)) {
|
||||||
|
return SDL_HAT_UP | SDL_HAT_RIGHT;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, -3.0/7)) {
|
||||||
|
return SDL_HAT_RIGHT;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, -1.0/7)) {
|
||||||
|
return SDL_HAT_DOWN | SDL_HAT_RIGHT;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, 1.0/7)) {
|
||||||
|
return SDL_HAT_DOWN;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, 3.0/7)) {
|
||||||
|
return SDL_HAT_DOWN | SDL_HAT_LEFT;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, 5.0/7)) {
|
||||||
|
return SDL_HAT_LEFT;
|
||||||
|
} else if (IS_EQUAL_APPROX(hat_axis, 7.0/7)) {
|
||||||
|
return SDL_HAT_UP | SDL_HAT_LEFT;
|
||||||
|
} else {
|
||||||
|
return SDL_HAT_CENTERED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef IS_EQUAL_APPROX
|
||||||
|
|
||||||
static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||||
{
|
{
|
||||||
SDL_joylist_item *item;
|
SDL_joylist_item *item;
|
||||||
int i;
|
int i;
|
||||||
Uint16 bus;
|
Uint16 bus;
|
||||||
Uint16 vendor, product;
|
Uint16 vendor, product;
|
||||||
Uint8 os_id;
|
Uint8 os_id, subtype;
|
||||||
bool is_xinput;
|
bool is_xinput;
|
||||||
char name[128];
|
char name[128];
|
||||||
|
|
||||||
@@ -185,6 +210,7 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index);
|
is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index);
|
||||||
|
|
||||||
os_id = SDL_GetEmscriptenOSID();
|
os_id = SDL_GetEmscriptenOSID();
|
||||||
|
subtype = os_id;
|
||||||
|
|
||||||
item->trigger_rumble_available = MAIN_THREAD_EM_ASM_INT({
|
item->trigger_rumble_available = MAIN_THREAD_EM_ASM_INT({
|
||||||
let gamepad = navigator['getGamepads']()[$0];
|
let gamepad = navigator['getGamepads']()[$0];
|
||||||
@@ -220,7 +246,7 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
|
|
||||||
if (SDL_strcmp(gamepadEvent->mapping, "standard") == 0) {
|
if (SDL_strcmp(gamepadEvent->mapping, "standard") == 0) {
|
||||||
// We should differentiate between devices that are mapped or unmapped by the browser.
|
// We should differentiate between devices that are mapped or unmapped by the browser.
|
||||||
os_id += 0x80;
|
subtype += 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GetEmscriptenNormalizedName(gamepadEvent->index, name, sizeof(name));
|
SDL_GetEmscriptenNormalizedName(gamepadEvent->index, name, sizeof(name));
|
||||||
@@ -231,10 +257,10 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vendor && product) {
|
if (vendor && product) {
|
||||||
item->guid = SDL_CreateJoystickGUID(bus, vendor, product, 0, NULL, name, 0, os_id);
|
item->guid = SDL_CreateJoystickGUID(bus, vendor, product, 0, NULL, name, 0, subtype);
|
||||||
} else {
|
} else {
|
||||||
item->guid = SDL_CreateJoystickGUIDForName(item->name);
|
item->guid = SDL_CreateJoystickGUIDForName(item->name);
|
||||||
item->guid.data[15] = os_id;
|
item->guid.data[15] = subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->mapping = SDL_strdup(gamepadEvent->mapping);
|
item->mapping = SDL_strdup(gamepadEvent->mapping);
|
||||||
@@ -263,12 +289,16 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
// dump the digital trigger buttons in any case.
|
// dump the digital trigger buttons in any case.
|
||||||
first_trigger_button = 6;
|
first_trigger_button = 6;
|
||||||
num_buttons -= 2;
|
num_buttons -= 2;
|
||||||
|
} else if ((SDL_strcmp(gamepadEvent->mapping, "standard") != 0) && (num_axes >= 10) && (os_id == 5)) {
|
||||||
|
// The browsers (Chromium and Firefox) on Windows usually convert the hat on unmapped controllers to axis 9
|
||||||
|
// We can't know for sure that this axis is a hat, but most of the time it is
|
||||||
|
item->hat_is_axis = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->first_hat_button = first_hat_button;
|
item->first_hat_button = first_hat_button;
|
||||||
item->first_trigger_button = first_trigger_button;
|
item->first_trigger_button = first_trigger_button;
|
||||||
item->triggers_are_buttons = triggers_are_buttons;
|
item->triggers_are_buttons = triggers_are_buttons;
|
||||||
item->nhats = (first_hat_button >= 0) ? 1 : 0;
|
item->nhats = (first_hat_button >= 0 || item->hat_is_axis) ? 1 : 0;
|
||||||
item->naxes = num_axes;
|
item->naxes = num_axes;
|
||||||
item->nbuttons = num_buttons;
|
item->nbuttons = num_buttons;
|
||||||
item->device_instance = SDL_GetNextObjectID();
|
item->device_instance = SDL_GetNextObjectID();
|
||||||
@@ -295,7 +325,7 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f;
|
item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons or the axis 9.
|
||||||
if (first_hat_button != -1) {
|
if (first_hat_button != -1) {
|
||||||
Uint8 value = SDL_HAT_CENTERED;
|
Uint8 value = SDL_HAT_CENTERED;
|
||||||
// this currently expects the first button to be up, then down, then left, then right.
|
// this currently expects the first button to be up, then down, then left, then right.
|
||||||
@@ -312,6 +342,9 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
value |= SDL_HAT_RIGHT;
|
value |= SDL_HAT_RIGHT;
|
||||||
}
|
}
|
||||||
item->hat = value;
|
item->hat = value;
|
||||||
|
} else if (item->hat_is_axis) {
|
||||||
|
item->hat = SDL_GetHatFromEmscriptenAxis(gamepadEvent->axis[9]);
|
||||||
|
item->axis[9] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_joylist_tail) {
|
if (!SDL_joylist_tail) {
|
||||||
@@ -617,6 +650,9 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < real_axis_count; i++) {
|
for (i = 0; i < real_axis_count; i++) {
|
||||||
|
if (item->hat_is_axis && i == 9) {
|
||||||
|
continue; // this axis is a hat
|
||||||
|
}
|
||||||
if (item->axis[i] != gamepadState.axis[i]) {
|
if (item->axis[i] != gamepadState.axis[i]) {
|
||||||
SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i]));
|
SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i]));
|
||||||
item->axis[i] = gamepadState.axis[i];
|
item->axis[i] = gamepadState.axis[i];
|
||||||
@@ -635,16 +671,20 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
|||||||
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||||
if (item->nhats) {
|
if (item->nhats) {
|
||||||
Uint8 value = SDL_HAT_CENTERED;
|
Uint8 value = SDL_HAT_CENTERED;
|
||||||
// this currently expects the first button to be up, then down, then left, then right.
|
if (first_hat_button >= 0) {
|
||||||
if (gamepadState.digitalButton[first_hat_button + 0]) {
|
// this currently expects the first button to be up, then down, then left, then right.
|
||||||
value |= SDL_HAT_UP;
|
if (gamepadState.digitalButton[first_hat_button + 0]) {
|
||||||
} else if (gamepadState.digitalButton[first_hat_button + 1]) {
|
value |= SDL_HAT_UP;
|
||||||
value |= SDL_HAT_DOWN;
|
} else if (gamepadState.digitalButton[first_hat_button + 1]) {
|
||||||
}
|
value |= SDL_HAT_DOWN;
|
||||||
if (gamepadState.digitalButton[first_hat_button + 2]) {
|
}
|
||||||
value |= SDL_HAT_LEFT;
|
if (gamepadState.digitalButton[first_hat_button + 2]) {
|
||||||
} else if (gamepadState.digitalButton[first_hat_button + 3]) {
|
value |= SDL_HAT_LEFT;
|
||||||
value |= SDL_HAT_RIGHT;
|
} else if (gamepadState.digitalButton[first_hat_button + 3]) {
|
||||||
|
value |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
} else if (item->hat_is_axis) {
|
||||||
|
value = SDL_GetHatFromEmscriptenAxis(gamepadState.axis[9]);
|
||||||
}
|
}
|
||||||
if (item->hat != value) {
|
if (item->hat != value) {
|
||||||
item->hat = value;
|
item->hat = value;
|
||||||
@@ -652,7 +692,6 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
item->timestamp = gamepadState.timestamp;
|
item->timestamp = gamepadState.timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ typedef struct SDL_joylist_item
|
|||||||
int first_hat_button;
|
int first_hat_button;
|
||||||
int first_trigger_button;
|
int first_trigger_button;
|
||||||
bool triggers_are_buttons;
|
bool triggers_are_buttons;
|
||||||
|
bool hat_is_axis;
|
||||||
int nhats;
|
int nhats;
|
||||||
SDL_GUID guid;
|
SDL_GUID guid;
|
||||||
int nbuttons;
|
int nbuttons;
|
||||||
@@ -45,7 +46,7 @@ typedef struct SDL_joylist_item
|
|||||||
double axis[64]; // !!! FIXME: don't hardcode 64 on all of these.
|
double axis[64]; // !!! FIXME: don't hardcode 64 on all of these.
|
||||||
double analogButton[64];
|
double analogButton[64];
|
||||||
EM_BOOL digitalButton[64];
|
EM_BOOL digitalButton[64];
|
||||||
Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons.
|
Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons or the axis 9.
|
||||||
bool rumble_available;
|
bool rumble_available;
|
||||||
bool trigger_rumble_available;
|
bool trigger_rumble_available;
|
||||||
Uint16 weak_magnitude_rumble;
|
Uint16 weak_magnitude_rumble;
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ enum
|
|||||||
SDL_GAMEPAD_NUM_8BITDO_BUTTONS,
|
SDL_GAMEPAD_NUM_8BITDO_BUTTONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SDL_GAMEPAD_BUTTON_8BITDO_SHARE = 15,
|
||||||
|
SDL_GAMEPAD_NUM_8BITDO_ULTIMATE3_BUTTONS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SDL_8BITDO_FEATURE_REPORTID 0x30
|
||||||
#define SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID 0x06
|
#define SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID 0x06
|
||||||
#define SDL_8BITDO_REPORTID_SDL_REPORTID 0x04
|
#define SDL_8BITDO_REPORTID_SDL_REPORTID 0x04
|
||||||
#define SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID 0x03
|
#define SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID 0x03
|
||||||
@@ -65,6 +72,7 @@ typedef struct
|
|||||||
bool touchpad_01_supported;
|
bool touchpad_01_supported;
|
||||||
bool touchpad_02_supported;
|
bool touchpad_02_supported;
|
||||||
bool rumble_supported;
|
bool rumble_supported;
|
||||||
|
bool trigger_rumble_supported;
|
||||||
bool rumble_type;
|
bool rumble_type;
|
||||||
bool rgb_supported;
|
bool rgb_supported;
|
||||||
bool player_led_supported;
|
bool player_led_supported;
|
||||||
@@ -78,6 +86,10 @@ typedef struct
|
|||||||
Uint8 last_state[USB_PACKET_LENGTH];
|
Uint8 last_state[USB_PACKET_LENGTH];
|
||||||
Uint64 sensor_timestamp; // Nanoseconds. Simulate onboard clock. Different models have different rates vs different connection styles.
|
Uint64 sensor_timestamp; // Nanoseconds. Simulate onboard clock. Different models have different rates vs different connection styles.
|
||||||
Uint64 sensor_timestamp_interval;
|
Uint64 sensor_timestamp_interval;
|
||||||
|
Uint8 rumble_left_value;
|
||||||
|
Uint8 rumble_right_value;
|
||||||
|
Uint8 trigger_rumble_left_value;
|
||||||
|
Uint8 trigger_rumble_right_value;
|
||||||
Uint32 last_tick;
|
Uint32 last_tick;
|
||||||
} SDL_Driver8BitDo_Context;
|
} SDL_Driver8BitDo_Context;
|
||||||
|
|
||||||
@@ -147,6 +159,7 @@ static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, con
|
|||||||
case USB_PRODUCT_8BITDO_PRO_2_BT:
|
case USB_PRODUCT_8BITDO_PRO_2_BT:
|
||||||
case USB_PRODUCT_8BITDO_PRO_3:
|
case USB_PRODUCT_8BITDO_PRO_3:
|
||||||
case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
|
case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
|
||||||
|
case USB_PRODUCT_8BITDO_ULTIMATE3:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -182,7 +195,41 @@ static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (device->product_id == USB_PRODUCT_8BITDO_ULTIMATE3) {
|
||||||
|
// Supported by default
|
||||||
|
ctx->sensors_supported = true;
|
||||||
|
ctx->rumble_supported = true;
|
||||||
|
ctx->powerstate_supported = true;
|
||||||
|
ctx->sensor_timestamp_supported = true;
|
||||||
|
Uint8 data[USB_PACKET_LENGTH];
|
||||||
|
const int MAX_ATTEMPTS = 5;
|
||||||
|
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||||
|
int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID, data, sizeof(data));
|
||||||
|
if (size > 0) {
|
||||||
|
if (data[3] == 0) {
|
||||||
|
ctx->rumble_supported = false;
|
||||||
|
ctx->trigger_rumble_supported = false;
|
||||||
|
}
|
||||||
|
if (data[3] & 0x02) {
|
||||||
|
ctx->trigger_rumble_supported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[4] == 0) {
|
||||||
|
ctx->sensors_supported = false;
|
||||||
|
ctx->sensor_timestamp_supported = false;
|
||||||
|
}
|
||||||
|
if (size >= 17 && data[11] != 0) {
|
||||||
|
char serial[18];
|
||||||
|
(void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||||
|
data[16], data[15], data[14], data[13], data[12], data[11]);
|
||||||
|
HIDAPI_SetDeviceSerial(device, serial);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SDL_Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
Uint8 data[USB_PACKET_LENGTH];
|
Uint8 data[USB_PACKET_LENGTH];
|
||||||
const int MAX_ATTEMPTS = 5;
|
const int MAX_ATTEMPTS = 5;
|
||||||
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||||
@@ -277,6 +324,8 @@ static Uint64 HIDAPI_Driver8BitDo_GetIMURateForProductID(SDL_HIDAPI_Device *devi
|
|||||||
// This firmware appears to update at 1000 Hz over USB dongle
|
// This firmware appears to update at 1000 Hz over USB dongle
|
||||||
return 1000;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
case USB_PRODUCT_8BITDO_ULTIMATE3:
|
||||||
|
return 120;
|
||||||
default:
|
default:
|
||||||
return 120;
|
return 120;
|
||||||
}
|
}
|
||||||
@@ -299,8 +348,10 @@ static bool HIDAPI_Driver8BitDo_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
|||||||
device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT ||
|
device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT ||
|
||||||
device->product_id == USB_PRODUCT_8BITDO_PRO_3 ||
|
device->product_id == USB_PRODUCT_8BITDO_PRO_3 ||
|
||||||
device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||||
// This controller has additional buttons
|
// This controller has additional buttons
|
||||||
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
|
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
|
||||||
|
} else if (device->product_id == USB_PRODUCT_8BITDO_ULTIMATE3) {
|
||||||
|
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_ULTIMATE3_BUTTONS;
|
||||||
} else {
|
} else {
|
||||||
joystick->nbuttons = 11;
|
joystick->nbuttons = 11;
|
||||||
}
|
}
|
||||||
@@ -331,6 +382,12 @@ static bool HIDAPI_Driver8BitDo_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Jo
|
|||||||
Uint8 rumble_packet[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
|
Uint8 rumble_packet[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
|
||||||
rumble_packet[1] = low_frequency_rumble >> 8;
|
rumble_packet[1] = low_frequency_rumble >> 8;
|
||||||
rumble_packet[2] = high_frequency_rumble >> 8;
|
rumble_packet[2] = high_frequency_rumble >> 8;
|
||||||
|
if (ctx->trigger_rumble_supported) {
|
||||||
|
rumble_packet[3] = ctx->trigger_rumble_left_value;
|
||||||
|
rumble_packet[4] = ctx->trigger_rumble_right_value;
|
||||||
|
ctx->rumble_left_value = rumble_packet[1];
|
||||||
|
ctx->rumble_right_value = rumble_packet[2];
|
||||||
|
}
|
||||||
|
|
||||||
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||||
return SDL_SetError("Couldn't send rumble packet");
|
return SDL_SetError("Couldn't send rumble packet");
|
||||||
@@ -343,7 +400,25 @@ static bool HIDAPI_Driver8BitDo_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Jo
|
|||||||
|
|
||||||
static bool HIDAPI_Driver8BitDo_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
static bool HIDAPI_Driver8BitDo_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||||
{
|
{
|
||||||
return SDL_Unsupported();
|
SDL_Driver8BitDo_Context* ctx = (SDL_Driver8BitDo_Context*)device->context;
|
||||||
|
if (ctx->trigger_rumble_supported) {
|
||||||
|
Uint8 rumble_packet[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
rumble_packet[3] = left_rumble >> 8;
|
||||||
|
rumble_packet[4] = right_rumble >> 8;
|
||||||
|
if (ctx->rumble_supported) {
|
||||||
|
rumble_packet[1] = ctx->rumble_left_value;
|
||||||
|
rumble_packet[2] = ctx->rumble_right_value;
|
||||||
|
ctx->trigger_rumble_left_value = rumble_packet[3];
|
||||||
|
ctx->trigger_rumble_right_value = rumble_packet[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||||
|
return SDL_SetError("Couldn't send rumble packet");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return SDL_Unsupported();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint32 HIDAPI_Driver8BitDo_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
static Uint32 HIDAPI_Driver8BitDo_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||||
@@ -525,6 +600,9 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|||||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[9] & 0x08) != 0));
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[9] & 0x08) != 0));
|
||||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[9] & 0x20) != 0));
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[9] & 0x20) != 0));
|
||||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
|
||||||
|
if (joystick->nbuttons >= SDL_GAMEPAD_NUM_8BITDO_ULTIMATE3_BUTTONS) {
|
||||||
|
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_SHARE, ((data[9] & 0x80) != 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 10 && ctx->last_state[10] != data[10]) {
|
if (size > 10 && ctx->last_state[10] != data[10]) {
|
||||||
|
|||||||
@@ -1332,7 +1332,7 @@ bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version,
|
|||||||
// changes when that happens, we'll pretend the driver isn't available so the XInput
|
// changes when that happens, we'll pretend the driver isn't available so the XInput
|
||||||
// interface will always show up (but won't have any input when the controller is in
|
// interface will always show up (but won't have any input when the controller is in
|
||||||
// enhanced mode)
|
// enhanced mode)
|
||||||
if (device->vendor_id == USB_VENDOR_FLYDIGI_V2) {
|
if (device->vendor_id == USB_VENDOR_FLYDIGI_V2 && device->driver == &SDL_HIDAPI_DriverFlydigi) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
#define USB_PRODUCT_8BITDO_PRO_2_BT 0x6006 // mode switch to D
|
#define USB_PRODUCT_8BITDO_PRO_2_BT 0x6006 // mode switch to D
|
||||||
#define USB_PRODUCT_8BITDO_PRO_3 0x6009 // mode switch to D
|
#define USB_PRODUCT_8BITDO_PRO_3 0x6009 // mode switch to D
|
||||||
#define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS 0x6012 // mode switch to BT
|
#define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS 0x6012 // mode switch to BT
|
||||||
|
#define USB_PRODUCT_8BITDO_ULTIMATE3 0x202f // mode switch to BT
|
||||||
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
|
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
|
||||||
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
|
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
|
||||||
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
|
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ SDL_Process *SDL_CreateProcess(const char * const *args, bool pipe_stdio)
|
|||||||
SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props)
|
SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props)
|
||||||
{
|
{
|
||||||
const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL);
|
const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL);
|
||||||
#if defined(SDL_PLATFORM_WINDOWS)
|
#if defined(SDL_PROCESS_WINDOWS)
|
||||||
const char *cmdline = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, NULL);
|
const char *cmdline = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, NULL);
|
||||||
CHECK_PARAM((!args || !args[0] || !args[0][0]) && (!cmdline || !cmdline[0])) {
|
CHECK_PARAM((!args || !args[0] || !args[0][0]) && (!cmdline || !cmdline[0])) {
|
||||||
SDL_SetError("Either SDL_PROP_PROCESS_CREATE_ARGS_POINTER or SDL_PROP_PROCESS_CREATE_CMDLINE_STRING must be valid");
|
SDL_SetError("Either SDL_PROP_PROCESS_CREATE_ARGS_POINTER or SDL_PROP_PROCESS_CREATE_CMDLINE_STRING must be valid");
|
||||||
|
|||||||
@@ -1564,6 +1564,9 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||||||
if (statecache->shader_constants_dirty ||
|
if (statecache->shader_constants_dirty ||
|
||||||
SDL_memcmp(shader_constants, &statecache->shader_constants, sizeof(*shader_constants)) != 0) {
|
SDL_memcmp(shader_constants, &statecache->shader_constants, sizeof(*shader_constants)) != 0) {
|
||||||
id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:sizeof(*shader_constants) options:MTLResourceStorageModeShared];
|
id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:sizeof(*shader_constants) options:MTLResourceStorageModeShared];
|
||||||
|
if (mtlbufconstants == nil) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
mtlbufconstants.label = @"SDL shader constants data";
|
mtlbufconstants.label = @"SDL shader constants data";
|
||||||
SDL_memcpy([mtlbufconstants contents], shader_constants, sizeof(*shader_constants));
|
SDL_memcpy([mtlbufconstants contents], shader_constants, sizeof(*shader_constants));
|
||||||
[data.mtlcmdencoder setFragmentBuffer:mtlbufconstants offset:0 atIndex:0];
|
[data.mtlcmdencoder setFragmentBuffer:mtlbufconstants offset:0 atIndex:0];
|
||||||
@@ -1734,6 +1737,9 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
|
|||||||
* practices guide recommends this approach for streamed vertex data.
|
* practices guide recommends this approach for streamed vertex data.
|
||||||
*/
|
*/
|
||||||
mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
|
mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
|
||||||
|
if (mtlbufvertex == nil) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
mtlbufvertex.label = @"SDL vertex data";
|
mtlbufvertex.label = @"SDL vertex data";
|
||||||
SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
|
SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
|
||||||
|
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ static bool VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|||||||
const SDL_Rect *rect, const void *pixels, int pitch)
|
const SDL_Rect *rect, const void *pixels, int pitch)
|
||||||
{
|
{
|
||||||
VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)texture->internal;
|
VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)texture->internal;
|
||||||
|
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal;
|
||||||
Uint8 *dst;
|
Uint8 *dst;
|
||||||
int row, length, dpitch;
|
int row, length, dpitch;
|
||||||
|
|
||||||
@@ -422,6 +423,7 @@ static bool VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
data->drawstate.texture = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,6 +437,7 @@ static bool VITA_GXM_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *textu
|
|||||||
Uint8 *dst;
|
Uint8 *dst;
|
||||||
int row, length, dpitch;
|
int row, length, dpitch;
|
||||||
SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
||||||
|
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal;
|
||||||
|
|
||||||
VITA_GXM_SetYUVProfile(renderer, texture);
|
VITA_GXM_SetYUVProfile(renderer, texture);
|
||||||
|
|
||||||
@@ -497,6 +500,7 @@ static bool VITA_GXM_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *textu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->drawstate.texture = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,6 +513,7 @@ static bool VITA_GXM_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *textur
|
|||||||
Uint8 *dst;
|
Uint8 *dst;
|
||||||
int row, length, dpitch;
|
int row, length, dpitch;
|
||||||
SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
||||||
|
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal;
|
||||||
|
|
||||||
VITA_GXM_SetYUVProfile(renderer, texture);
|
VITA_GXM_SetYUVProfile(renderer, texture);
|
||||||
|
|
||||||
@@ -552,6 +557,7 @@ static bool VITA_GXM_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *textur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->drawstate.texture = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,6 +586,8 @@ static void VITA_GXM_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
|||||||
// No need to update texture data on ps vita.
|
// No need to update texture data on ps vita.
|
||||||
// VITA_GXM_LockTexture already returns a pointer to the texture pixels buffer.
|
// VITA_GXM_LockTexture already returns a pointer to the texture pixels buffer.
|
||||||
// This really improves framerate when using lock/unlock.
|
// This really improves framerate when using lock/unlock.
|
||||||
|
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal;
|
||||||
|
data->drawstate.texture = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VITA_GXM_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
|
static bool VITA_GXM_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
|
||||||
@@ -1259,6 +1267,12 @@ static void VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture
|
|||||||
SDL_free(vita_texture);
|
SDL_free(vita_texture);
|
||||||
|
|
||||||
texture->internal = NULL;
|
texture->internal = NULL;
|
||||||
|
if (data->drawstate.texture == texture) {
|
||||||
|
data->drawstate.texture = NULL;
|
||||||
|
}
|
||||||
|
if (data->drawstate.target == texture) {
|
||||||
|
data->drawstate.target = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VITA_GXM_DestroyRenderer(SDL_Renderer *renderer)
|
static void VITA_GXM_DestroyRenderer(SDL_Renderer *renderer)
|
||||||
|
|||||||
@@ -891,11 +891,16 @@ static VkResult VULKAN_AllocateImage(VULKAN_RenderData *rendererData, SDL_Proper
|
|||||||
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
|
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
imageViewCreateInfo.subresourceRange.layerCount = 1;
|
imageViewCreateInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
VkImageViewUsageCreateInfo imageViewUsageCreateInfo = { 0 };
|
||||||
|
imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
|
||||||
|
imageViewUsageCreateInfo.usage = imageUsage;
|
||||||
|
imageViewCreateInfo.pNext = &imageViewUsageCreateInfo;
|
||||||
|
|
||||||
// If it's a YCbCr image, we need to pass the conversion info to the VkImageView (and the VkSampler)
|
// If it's a YCbCr image, we need to pass the conversion info to the VkImageView (and the VkSampler)
|
||||||
if (samplerYcbcrConversion != VK_NULL_HANDLE) {
|
if (samplerYcbcrConversion != VK_NULL_HANDLE) {
|
||||||
samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR;
|
samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR;
|
||||||
samplerYcbcrConversionInfo.conversion = samplerYcbcrConversion;
|
samplerYcbcrConversionInfo.conversion = samplerYcbcrConversion;
|
||||||
imageViewCreateInfo.pNext = &samplerYcbcrConversionInfo;
|
imageViewUsageCreateInfo.pNext = &samplerYcbcrConversionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = vkCreateImageView(rendererData->device, &imageViewCreateInfo, NULL, &imageOut->imageView);
|
result = vkCreateImageView(rendererData->device, &imageViewCreateInfo, NULL, &imageOut->imageView);
|
||||||
@@ -2735,8 +2740,8 @@ static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, S
|
|||||||
// Also create VkSampler object which we will need to pass to the PSO as an immutable sampler
|
// Also create VkSampler object which we will need to pass to the PSO as an immutable sampler
|
||||||
VkSamplerCreateInfo samplerCreateInfo = { 0 };
|
VkSamplerCreateInfo samplerCreateInfo = { 0 };
|
||||||
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_NEAREST;
|
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_NEAREST;
|
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
@@ -4039,6 +4044,9 @@ static void VULKAN_InvalidateCachedState(SDL_Renderer *renderer)
|
|||||||
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
|
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
|
||||||
rendererData->currentPipelineState = NULL;
|
rendererData->currentPipelineState = NULL;
|
||||||
rendererData->cliprectDirty = true;
|
rendererData->cliprectDirty = true;
|
||||||
|
|
||||||
|
// Make sure pending drawing is submitted to the GPU
|
||||||
|
VULKAN_IssueBatch(rendererData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
|
static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
|
||||||
|
|||||||
@@ -1509,9 +1509,6 @@ const SDL_DisplayMode *SDL_GetCurrentDisplayMode(SDL_DisplayID displayID)
|
|||||||
|
|
||||||
CHECK_DISPLAY_MAGIC(display, NULL);
|
CHECK_DISPLAY_MAGIC(display, NULL);
|
||||||
|
|
||||||
// Make sure our mode list is updated
|
|
||||||
SDL_UpdateFullscreenDisplayModes(display);
|
|
||||||
|
|
||||||
return display->current_mode;
|
return display->current_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -618,17 +618,18 @@ void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
|
|||||||
SDL_MouseWheelDirection direction;
|
SDL_MouseWheelDirection direction;
|
||||||
CGFloat x, y;
|
CGFloat x, y;
|
||||||
|
|
||||||
x = -[event deltaX];
|
|
||||||
y = [event deltaY];
|
|
||||||
direction = SDL_MOUSEWHEEL_NORMAL;
|
direction = SDL_MOUSEWHEEL_NORMAL;
|
||||||
|
|
||||||
if ([event isDirectionInvertedFromDevice] == YES) {
|
if ([event isDirectionInvertedFromDevice] == YES) {
|
||||||
direction = SDL_MOUSEWHEEL_FLIPPED;
|
direction = SDL_MOUSEWHEEL_FLIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For discrete scroll events from conventional mice, always send a full tick.
|
if ([event hasPreciseScrollingDeltas]) {
|
||||||
For continuous scroll events from trackpads, send fractional deltas for smoother scrolling. */
|
x = -[event scrollingDeltaX] * 0.1f;
|
||||||
if (![event hasPreciseScrollingDeltas]) {
|
y = [event scrollingDeltaY] * 0.1f;
|
||||||
|
} else {
|
||||||
|
x = -[event deltaX];
|
||||||
|
y = [event deltaY];
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
x = SDL_ceil(x);
|
x = SDL_ceil(x);
|
||||||
} else if (x < 0) {
|
} else if (x < 0) {
|
||||||
|
|||||||
@@ -1430,12 +1430,18 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This is usually sent after an unexpected windowDidExitFullscreen if the window
|
/* This is usually sent after an unexpected windowDidExitFullscreen if the window
|
||||||
* failed to become fullscreen.
|
* failed to become fullscreen, but not always, so ensure that the state variables
|
||||||
|
* are cleared.
|
||||||
*
|
*
|
||||||
* Since something went wrong and the current state is unknown, dump any pending events.
|
* Since something went wrong and the current state is unknown, dump any pending events.
|
||||||
|
*
|
||||||
|
* For testing purposes, this error can usually be induced by starting something that
|
||||||
|
* immedately enters a fullscreen space from a terminal that is in a fullscreen space.
|
||||||
*/
|
*/
|
||||||
- (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
|
- (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
|
inFullscreenTransition = NO;
|
||||||
|
isFullscreenSpace = NO;
|
||||||
[self clearAllPendingWindowOperations];
|
[self clearAllPendingWindowOperations];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,9 @@
|
|||||||
#define SDL_WL_DATA_DEVICE_VERSION 3
|
#define SDL_WL_DATA_DEVICE_VERSION 3
|
||||||
|
|
||||||
// wl_fixes was introduced in 1.24.0
|
// wl_fixes was introduced in 1.24.0
|
||||||
#if SDL_WAYLAND_CHECK_VERSION(1, 24, 0)
|
#if SDL_WAYLAND_CHECK_VERSION(1, 26, 0)
|
||||||
|
#define SDL_WL_FIXES_VERSION 2
|
||||||
|
#elif SDL_WAYLAND_CHECK_VERSION(1, 24, 0)
|
||||||
#define SDL_WL_FIXES_VERSION 1
|
#define SDL_WL_FIXES_VERSION 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -506,7 +508,11 @@ static void wayland_preferred_check_handle_global(void *data, struct wl_registry
|
|||||||
|
|
||||||
static void wayland_preferred_check_remove_global(void *data, struct wl_registry *registry, uint32_t id)
|
static void wayland_preferred_check_remove_global(void *data, struct wl_registry *registry, uint32_t id)
|
||||||
{
|
{
|
||||||
// No need to do anything here.
|
SDL_WaylandPreferredData *d = (SDL_WaylandPreferredData *)data;
|
||||||
|
|
||||||
|
if (d->wl_fixes && wl_fixes_get_version(d->wl_fixes) >= WL_FIXES_ACK_GLOBAL_REMOVE_SINCE_VERSION) {
|
||||||
|
wl_fixes_ack_global_remove(d->wl_fixes, registry, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_registry_listener preferred_registry_listener = {
|
static const struct wl_registry_listener preferred_registry_listener = {
|
||||||
@@ -1370,18 +1376,22 @@ static void handle_registry_remove_global(void *data, struct wl_registry *regist
|
|||||||
}
|
}
|
||||||
|
|
||||||
d->output_count--;
|
d->output_count--;
|
||||||
return;
|
goto ack_remove;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_WaylandSeat *seat, *temp;
|
SDL_WaylandSeat *seat, *temp;
|
||||||
wl_list_for_each_safe (seat, temp, &d->seat_list, link)
|
wl_list_for_each_safe (seat, temp, &d->seat_list, link) {
|
||||||
{
|
|
||||||
if (seat->registry_id == id) {
|
if (seat->registry_id == id) {
|
||||||
Wayland_SeatDestroy(seat, false);
|
Wayland_SeatDestroy(seat, false);
|
||||||
return;
|
goto ack_remove;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ack_remove:
|
||||||
|
if (d->wl_fixes && wl_fixes_get_version(d->wl_fixes) >= WL_FIXES_ACK_GLOBAL_REMOVE_SINCE_VERSION) {
|
||||||
|
wl_fixes_ack_global_remove(d->wl_fixes, registry, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_registry_listener registry_listener = {
|
static const struct wl_registry_listener registry_listener = {
|
||||||
|
|||||||
@@ -2136,8 +2136,11 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||||||
Wayland_SetWindowResizable(_this, window, !!(window->flags & SDL_WINDOW_RESIZABLE));
|
Wayland_SetWindowResizable(_this, window, !!(window->flags & SDL_WINDOW_RESIZABLE));
|
||||||
|
|
||||||
// We're finally done putting the window together, raise if possible
|
// We're finally done putting the window together, raise if possible
|
||||||
if (c->activation_manager) {
|
if (c->activation_manager && SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, true)) {
|
||||||
/* Note that we don't check for empty strings, as that is still
|
/* if the process was passed an activation token, use it when showing
|
||||||
|
* the initial window.
|
||||||
|
*
|
||||||
|
* Note that we don't check for empty strings, as that is still
|
||||||
* considered a valid activation token!
|
* considered a valid activation token!
|
||||||
*/
|
*/
|
||||||
const char *activation_token = SDL_getenv("XDG_ACTIVATION_TOKEN");
|
const char *activation_token = SDL_getenv("XDG_ACTIVATION_TOKEN");
|
||||||
@@ -2148,7 +2151,13 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||||||
|
|
||||||
// Clear this variable, per the protocol's request
|
// Clear this variable, per the protocol's request
|
||||||
SDL_unsetenv_unsafe("XDG_ACTIVATION_TOKEN");
|
SDL_unsetenv_unsafe("XDG_ACTIVATION_TOKEN");
|
||||||
|
} else {
|
||||||
|
// Try to generate an activation token for this window.
|
||||||
|
Wayland_RaiseWindow(_this, window);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Clear the ignored activation token, as it won't be used.
|
||||||
|
SDL_unsetenv_unsafe("XDG_ACTIVATION_TOKEN");
|
||||||
}
|
}
|
||||||
|
|
||||||
// No frame callback on an external surface, as it may already have one attached.
|
// No frame callback on an external surface, as it may already have one attached.
|
||||||
|
|||||||
@@ -1642,14 +1642,16 @@ void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||||||
Display *display = data->videodata->display;
|
Display *display = data->videodata->display;
|
||||||
XEvent event;
|
XEvent event;
|
||||||
|
|
||||||
if (X11_IsWindowMapped(_this, window)) {
|
/* Some window managers will mark minimized or offscreen windows as unmapped, so we
|
||||||
X11_XWithdrawWindow(display, data->xwindow, screen);
|
* must not block while waiting for an UnmapNotify event that will never arrive.
|
||||||
// Blocking wait for "UnmapNotify" event
|
*/
|
||||||
if (!(window->flags & SDL_WINDOW_EXTERNAL) && X11_IsDisplayOk(display)) {
|
const bool is_mapped = X11_IsWindowMapped(_this, window);
|
||||||
X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
|
X11_XWithdrawWindow(display, data->xwindow, screen);
|
||||||
}
|
if (is_mapped && !(window->flags & SDL_WINDOW_EXTERNAL) && X11_IsDisplayOk(display)) {
|
||||||
X11_XFlush(display);
|
// Blocking wait for "UnmapNotify" event.
|
||||||
|
X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
|
||||||
}
|
}
|
||||||
|
X11_XFlush(display);
|
||||||
|
|
||||||
// Transfer keyboard focus back to the parent
|
// Transfer keyboard focus back to the parent
|
||||||
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ static SDL_Renderer *renderer;
|
|||||||
static SDL_AudioStream *audio;
|
static SDL_AudioStream *audio;
|
||||||
static SDL_Texture *video_texture;
|
static SDL_Texture *video_texture;
|
||||||
static Uint64 video_start;
|
static Uint64 video_start;
|
||||||
|
static bool nodelay;
|
||||||
static bool software_only;
|
static bool software_only;
|
||||||
static bool has_eglCreateImage;
|
static bool has_eglCreateImage;
|
||||||
#ifdef HAVE_EGL
|
#ifdef HAVE_EGL
|
||||||
@@ -1087,6 +1088,10 @@ static void DisplayVideoTexture(AVFrame *frame)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BeginFrameRendering(frame) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_FRect src;
|
SDL_FRect src;
|
||||||
src.x = 0.0f;
|
src.x = 0.0f;
|
||||||
src.y = 0.0f;
|
src.y = 0.0f;
|
||||||
@@ -1097,6 +1102,9 @@ static void DisplayVideoTexture(AVFrame *frame)
|
|||||||
} else {
|
} else {
|
||||||
SDL_RenderTexture(renderer, video_texture, &src, NULL);
|
SDL_RenderTexture(renderer, video_texture, &src, NULL);
|
||||||
}
|
}
|
||||||
|
SDL_FlushRenderer(renderer);
|
||||||
|
|
||||||
|
FinishFrameRendering(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DisplayVideoFrame(AVFrame *frame)
|
static void DisplayVideoFrame(AVFrame *frame)
|
||||||
@@ -1106,17 +1114,15 @@ static void DisplayVideoFrame(AVFrame *frame)
|
|||||||
|
|
||||||
static void HandleVideoFrame(AVFrame *frame, double pts)
|
static void HandleVideoFrame(AVFrame *frame, double pts)
|
||||||
{
|
{
|
||||||
/* Quick and dirty PTS handling */
|
if (!nodelay) {
|
||||||
if (!video_start) {
|
/* Quick and dirty PTS handling */
|
||||||
video_start = SDL_GetTicks();
|
if (!video_start) {
|
||||||
}
|
video_start = SDL_GetTicks();
|
||||||
double now = (double)(SDL_GetTicks() - video_start) / 1000.0;
|
}
|
||||||
if (now < pts) {
|
double now = (double)(SDL_GetTicks() - video_start) / 1000.0;
|
||||||
SDL_DelayPrecise((Uint64)((pts - now) * SDL_NS_PER_SECOND));
|
if (now < pts) {
|
||||||
}
|
SDL_DelayPrecise((Uint64)((pts - now) * SDL_NS_PER_SECOND));
|
||||||
|
}
|
||||||
if (BeginFrameRendering(frame) < 0) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
@@ -1128,8 +1134,6 @@ static void HandleVideoFrame(AVFrame *frame, double pts)
|
|||||||
MoveSprite();
|
MoveSprite();
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
FinishFrameRendering(frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static AVCodecContext *OpenAudioStream(AVFormatContext *ic, int stream, const AVCodec *codec)
|
static AVCodecContext *OpenAudioStream(AVFormatContext *ic, int stream, const AVCodec *codec)
|
||||||
@@ -1287,7 +1291,7 @@ static void av_log_callback(void *avcl, int level, const char *fmt, va_list vl)
|
|||||||
|
|
||||||
static void print_usage(SDLTest_CommonState *state, const char *argv0)
|
static void print_usage(SDLTest_CommonState *state, const char *argv0)
|
||||||
{
|
{
|
||||||
static const char *options[] = { "[--verbose]", "[--sprites N]", "[--audio-codec codec]", "[--video-codec codec]", "[--software]", "video_file", NULL };
|
static const char *options[] = { "[--verbose]", "[--sprites N]", "[--audio-codec codec]", "[--video-codec codec]", "[--software]", "[--nodelay]", "video_file", NULL };
|
||||||
SDLTest_CommonLogUsage(state, argv0, options);
|
SDLTest_CommonLogUsage(state, argv0, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1345,6 +1349,9 @@ int main(int argc, char *argv[])
|
|||||||
} else if (SDL_strcmp(argv[i], "--software") == 0) {
|
} else if (SDL_strcmp(argv[i], "--software") == 0) {
|
||||||
software_only = true;
|
software_only = true;
|
||||||
consumed = 1;
|
consumed = 1;
|
||||||
|
} else if (SDL_strcmp(argv[i], "--nodelay") == 0) {
|
||||||
|
nodelay = true;
|
||||||
|
consumed = 1;
|
||||||
} else if (!file) {
|
} else if (!file) {
|
||||||
/* We'll try to open this as a media file */
|
/* We'll try to open this as a media file */
|
||||||
file = argv[i];
|
file = argv[i];
|
||||||
@@ -1566,7 +1573,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flushing && !decoded) {
|
if (flushing && !decoded) {
|
||||||
if (SDL_GetAudioStreamQueued(audio) > 0) {
|
if (SDL_GetAudioStreamQueued(audio) > 0 && !nodelay) {
|
||||||
/* Wait a little bit for the audio to finish */
|
/* Wait a little bit for the audio to finish */
|
||||||
SDL_Delay(10);
|
SDL_Delay(10);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -78,10 +78,6 @@ struct VulkanVideoContext
|
|||||||
VkCommandBuffer *commandBuffers;
|
VkCommandBuffer *commandBuffers;
|
||||||
uint32_t commandBufferCount;
|
uint32_t commandBufferCount;
|
||||||
uint32_t commandBufferIndex;
|
uint32_t commandBufferIndex;
|
||||||
VkSemaphore *waitSemaphores;
|
|
||||||
uint32_t waitSemaphoreCount;
|
|
||||||
VkSemaphore *signalSemaphores;
|
|
||||||
uint32_t signalSemaphoreCount;
|
|
||||||
|
|
||||||
const char **instanceExtensions;
|
const char **instanceExtensions;
|
||||||
int instanceExtensionsCount;
|
int instanceExtensionsCount;
|
||||||
@@ -202,8 +198,10 @@ static int createInstance(VulkanVideoContext *context)
|
|||||||
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
|
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
|
||||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
||||||
};
|
};
|
||||||
VkApplicationInfo appInfo = { 0 };
|
VkApplicationInfo appInfo;
|
||||||
VkInstanceCreateInfo instanceCreateInfo = { 0 };
|
SDL_zero(appInfo);
|
||||||
|
VkInstanceCreateInfo instanceCreateInfo;
|
||||||
|
SDL_zero(instanceCreateInfo);
|
||||||
VkResult result;
|
VkResult result;
|
||||||
char const *const *instanceExtensions = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount);
|
char const *const *instanceExtensions = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount);
|
||||||
|
|
||||||
@@ -212,7 +210,7 @@ static int createInstance(VulkanVideoContext *context)
|
|||||||
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
instanceCreateInfo.pApplicationInfo = &appInfo;
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
||||||
|
|
||||||
const char **instanceExtensionsCopy = SDL_calloc(instanceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
|
const char **instanceExtensionsCopy = (const char **)SDL_calloc(instanceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
|
||||||
for (uint32_t i = 0; i < instanceCreateInfo.enabledExtensionCount; i++) {
|
for (uint32_t i = 0; i < instanceCreateInfo.enabledExtensionCount; i++) {
|
||||||
instanceExtensionsCopy[i] = instanceExtensions[i];
|
instanceExtensionsCopy[i] = instanceExtensions[i];
|
||||||
}
|
}
|
||||||
@@ -221,7 +219,7 @@ static int createInstance(VulkanVideoContext *context)
|
|||||||
{
|
{
|
||||||
uint32_t extensionCount;
|
uint32_t extensionCount;
|
||||||
if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
|
if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
|
||||||
VkExtensionProperties *extensionProperties = SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
|
VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
|
||||||
if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
|
if (context->vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
|
||||||
for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
|
for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
|
||||||
for (uint32_t j = 0; j < extensionCount; ++j) {
|
for (uint32_t j = 0; j < extensionCount; ++j) {
|
||||||
@@ -261,14 +259,14 @@ static int createSurface(VulkanVideoContext *context, SDL_Window *window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the same queue scoring algorithm as ffmpeg to make sure we get the same device configuration
|
// Use the same queue scoring algorithm as ffmpeg to make sure we get the same device configuration
|
||||||
static int selectQueueFamily(VkQueueFamilyProperties *queueFamiliesProperties, uint32_t queueFamiliesCount, VkQueueFlagBits flags, int *queueCount)
|
static int selectQueueFamily(VkQueueFamilyProperties *queueFamiliesProperties, uint32_t queueFamiliesCount, VkQueueFlags flags, int *queueCount)
|
||||||
{
|
{
|
||||||
uint32_t queueFamilyIndex;
|
uint32_t queueFamilyIndex;
|
||||||
uint32_t selectedQueueFamilyIndex = queueFamiliesCount;
|
uint32_t selectedQueueFamilyIndex = queueFamiliesCount;
|
||||||
uint32_t min_score = ~0u;
|
uint32_t min_score = ~0u;
|
||||||
|
|
||||||
for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; ++queueFamilyIndex) {
|
for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; ++queueFamilyIndex) {
|
||||||
VkQueueFlagBits current_flags = queueFamiliesProperties[queueFamilyIndex].queueFlags;
|
VkQueueFlags current_flags = queueFamiliesProperties[queueFamilyIndex].queueFlags;
|
||||||
if (current_flags & flags) {
|
if (current_flags & flags) {
|
||||||
uint32_t score = av_popcount(current_flags) + queueFamiliesProperties[queueFamilyIndex].timestampValidBits;
|
uint32_t score = av_popcount(current_flags) + queueFamiliesProperties[queueFamilyIndex].timestampValidBits;
|
||||||
if (score < min_score) {
|
if (score < min_score) {
|
||||||
@@ -408,7 +406,7 @@ static int findPhysicalDevice(VulkanVideoContext *context)
|
|||||||
if (deviceExtensionsAllocatedSize < deviceExtensionCount) {
|
if (deviceExtensionsAllocatedSize < deviceExtensionCount) {
|
||||||
SDL_free(deviceExtensions);
|
SDL_free(deviceExtensions);
|
||||||
deviceExtensionsAllocatedSize = deviceExtensionCount;
|
deviceExtensionsAllocatedSize = deviceExtensionCount;
|
||||||
deviceExtensions = SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize);
|
deviceExtensions = (VkExtensionProperties *)SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize);
|
||||||
if (!deviceExtensions) {
|
if (!deviceExtensions) {
|
||||||
SDL_free(physicalDevices);
|
SDL_free(physicalDevices);
|
||||||
SDL_free(queueFamiliesProperties);
|
SDL_free(queueFamiliesProperties);
|
||||||
@@ -558,12 +556,14 @@ static int createDevice(VulkanVideoContext *context)
|
|||||||
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
|
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
|
||||||
VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
|
VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
|
||||||
VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
|
VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
|
||||||
VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME
|
VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME,
|
||||||
|
VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME
|
||||||
};
|
};
|
||||||
VkDeviceCreateInfo deviceCreateInfo = { 0 };
|
VkDeviceCreateInfo deviceCreateInfo;
|
||||||
VkDeviceQueueCreateInfo *queueCreateInfos = NULL;
|
VkDeviceQueueCreateInfo *queueCreateInfos = NULL;
|
||||||
uint32_t queueCreateInfoCount = 0;
|
uint32_t queueCreateInfoCount = 0;
|
||||||
VulkanDeviceFeatures supported_features;
|
VulkanDeviceFeatures supported_features;
|
||||||
|
const char **deviceExtensionsCopy = NULL;
|
||||||
VkResult result = VK_ERROR_UNKNOWN;
|
VkResult result = VK_ERROR_UNKNOWN;
|
||||||
|
|
||||||
if (addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->presentQueueFamilyIndex, context->presentQueueCount) < 0 ||
|
if (addQueueFamily(&queueCreateInfos, &queueCreateInfoCount, context->presentQueueFamilyIndex, context->presentQueueCount) < 0 ||
|
||||||
@@ -579,6 +579,7 @@ static int createDevice(VulkanVideoContext *context)
|
|||||||
context->vkGetPhysicalDeviceFeatures2(context->physicalDevice, &supported_features.device_features);
|
context->vkGetPhysicalDeviceFeatures2(context->physicalDevice, &supported_features.device_features);
|
||||||
copyDeviceFeatures(&supported_features, &context->features);
|
copyDeviceFeatures(&supported_features, &context->features);
|
||||||
|
|
||||||
|
SDL_zero(deviceCreateInfo);
|
||||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
deviceCreateInfo.queueCreateInfoCount = queueCreateInfoCount;
|
deviceCreateInfo.queueCreateInfoCount = queueCreateInfoCount;
|
||||||
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos;
|
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos;
|
||||||
@@ -586,7 +587,7 @@ static int createDevice(VulkanVideoContext *context)
|
|||||||
deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames);
|
deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames);
|
||||||
deviceCreateInfo.pNext = &context->features.device_features;
|
deviceCreateInfo.pNext = &context->features.device_features;
|
||||||
|
|
||||||
const char **deviceExtensionsCopy = SDL_calloc(deviceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
|
deviceExtensionsCopy = (const char **)SDL_calloc(deviceCreateInfo.enabledExtensionCount + SDL_arraysize(optional_extensions), sizeof(const char *));
|
||||||
for (uint32_t i = 0; i < deviceCreateInfo.enabledExtensionCount; i++) {
|
for (uint32_t i = 0; i < deviceCreateInfo.enabledExtensionCount; i++) {
|
||||||
deviceExtensionsCopy[i] = deviceExtensionNames[i];
|
deviceExtensionsCopy[i] = deviceExtensionNames[i];
|
||||||
}
|
}
|
||||||
@@ -595,7 +596,7 @@ static int createDevice(VulkanVideoContext *context)
|
|||||||
{
|
{
|
||||||
uint32_t extensionCount;
|
uint32_t extensionCount;
|
||||||
if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
|
if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, NULL) == VK_SUCCESS && extensionCount > 0) {
|
||||||
VkExtensionProperties *extensionProperties = SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
|
VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties));
|
||||||
if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
|
if (context->vkEnumerateDeviceExtensionProperties(context->physicalDevice, NULL, &extensionCount, extensionProperties) == VK_SUCCESS) {
|
||||||
for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
|
for (uint32_t i = 0; i < SDL_arraysize(optional_extensions); ++i) {
|
||||||
for (uint32_t j = 0; j < extensionCount; ++j) {
|
for (uint32_t j = 0; j < extensionCount; ++j) {
|
||||||
@@ -630,7 +631,8 @@ static int createDevice(VulkanVideoContext *context)
|
|||||||
context->vkGetDeviceQueue(context->device, context->graphicsQueueFamilyIndex, 0, &context->graphicsQueue);
|
context->vkGetDeviceQueue(context->device, context->graphicsQueueFamilyIndex, 0, &context->graphicsQueue);
|
||||||
|
|
||||||
// Create a command pool
|
// Create a command pool
|
||||||
VkCommandPoolCreateInfo commandPoolCreateInfo = { 0 };
|
VkCommandPoolCreateInfo commandPoolCreateInfo;
|
||||||
|
SDL_zero(commandPoolCreateInfo);
|
||||||
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
commandPoolCreateInfo.queueFamilyIndex = context->graphicsQueueFamilyIndex;
|
commandPoolCreateInfo.queueFamilyIndex = context->graphicsQueueFamilyIndex;
|
||||||
@@ -654,7 +656,7 @@ done:
|
|||||||
|
|
||||||
VulkanVideoContext *CreateVulkanVideoContext(SDL_Window *window)
|
VulkanVideoContext *CreateVulkanVideoContext(SDL_Window *window)
|
||||||
{
|
{
|
||||||
VulkanVideoContext *context = SDL_calloc(1, sizeof(*context));
|
VulkanVideoContext *context = (VulkanVideoContext *)SDL_calloc(1, sizeof(*context));
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -723,44 +725,6 @@ static int CreateCommandBuffers(VulkanVideoContext *context, SDL_Renderer *rende
|
|||||||
{
|
{
|
||||||
uint32_t commandBufferCount = (uint32_t)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VULKAN_SWAPCHAIN_IMAGE_COUNT_NUMBER, 1);
|
uint32_t commandBufferCount = (uint32_t)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VULKAN_SWAPCHAIN_IMAGE_COUNT_NUMBER, 1);
|
||||||
|
|
||||||
if (commandBufferCount > context->waitSemaphoreCount) {
|
|
||||||
VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(context->waitSemaphores, commandBufferCount * sizeof(*semaphores));
|
|
||||||
if (!semaphores) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
context->waitSemaphores = semaphores;
|
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 };
|
|
||||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
while (context->waitSemaphoreCount < commandBufferCount) {
|
|
||||||
VkResult result = context->vkCreateSemaphore(context->device, &semaphoreCreateInfo, NULL, &context->waitSemaphores[context->waitSemaphoreCount]);
|
|
||||||
if (result != VK_SUCCESS) {
|
|
||||||
SDL_SetError("vkCreateSemaphore(): %s", getVulkanResultString(result));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
++context->waitSemaphoreCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commandBufferCount > context->signalSemaphoreCount) {
|
|
||||||
VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(context->signalSemaphores, commandBufferCount * sizeof(*semaphores));
|
|
||||||
if (!semaphores) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
context->signalSemaphores = semaphores;
|
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 };
|
|
||||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
while (context->signalSemaphoreCount < commandBufferCount) {
|
|
||||||
VkResult result = context->vkCreateSemaphore(context->device, &semaphoreCreateInfo, NULL, &context->signalSemaphores[context->signalSemaphoreCount]);
|
|
||||||
if (result != VK_SUCCESS) {
|
|
||||||
SDL_SetError("vkCreateSemaphore(): %s", getVulkanResultString(result));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
++context->signalSemaphoreCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commandBufferCount > context->commandBufferCount) {
|
if (commandBufferCount > context->commandBufferCount) {
|
||||||
uint32_t needed = (commandBufferCount - context->commandBufferCount);
|
uint32_t needed = (commandBufferCount - context->commandBufferCount);
|
||||||
VkCommandBuffer *commandBuffers = (VkCommandBuffer *)SDL_realloc(context->commandBuffers, commandBufferCount * sizeof(*commandBuffers));
|
VkCommandBuffer *commandBuffers = (VkCommandBuffer *)SDL_realloc(context->commandBuffers, commandBufferCount * sizeof(*commandBuffers));
|
||||||
@@ -769,7 +733,8 @@ static int CreateCommandBuffers(VulkanVideoContext *context, SDL_Renderer *rende
|
|||||||
}
|
}
|
||||||
context->commandBuffers = commandBuffers;
|
context->commandBuffers = commandBuffers;
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo commandBufferAllocateInfo = { 0 };
|
VkCommandBufferAllocateInfo commandBufferAllocateInfo;
|
||||||
|
SDL_zero(commandBufferAllocateInfo);
|
||||||
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
commandBufferAllocateInfo.commandPool = context->commandPool;
|
commandBufferAllocateInfo.commandPool = context->commandPool;
|
||||||
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
@@ -797,30 +762,32 @@ int BeginVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_R
|
|||||||
|
|
||||||
vk->lock_frame(frames, pVkFrame);
|
vk->lock_frame(frames, pVkFrame);
|
||||||
|
|
||||||
VkTimelineSemaphoreSubmitInfo timeline = { 0 };
|
VkTimelineSemaphoreSubmitInfo timeline;
|
||||||
|
SDL_zero(timeline);
|
||||||
timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
|
timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
|
||||||
timeline.waitSemaphoreValueCount = 1;
|
timeline.waitSemaphoreValueCount = 1;
|
||||||
timeline.pWaitSemaphoreValues = pVkFrame->sem_value;
|
timeline.pWaitSemaphoreValues = pVkFrame->sem_value;
|
||||||
|
|
||||||
VkPipelineStageFlags pipelineStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
VkPipelineStageFlags pipelineStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
VkSubmitInfo submitInfo = { 0 };
|
VkSubmitInfo submitInfo;
|
||||||
|
SDL_zero(submitInfo);
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
submitInfo.pWaitSemaphores = pVkFrame->sem;
|
submitInfo.pWaitSemaphores = pVkFrame->sem;
|
||||||
submitInfo.pWaitDstStageMask = &pipelineStageMask;
|
submitInfo.pWaitDstStageMask = &pipelineStageMask;
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
|
||||||
submitInfo.pSignalSemaphores = &context->waitSemaphores[context->commandBufferIndex];
|
|
||||||
submitInfo.pNext = &timeline;
|
submitInfo.pNext = &timeline;
|
||||||
|
|
||||||
if (pVkFrame->layout[0] != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
if (pVkFrame->layout[0] != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||||
VkCommandBuffer commandBuffer = context->commandBuffers[context->commandBufferIndex];
|
VkCommandBuffer commandBuffer = context->commandBuffers[context->commandBufferIndex];
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo = { 0 };
|
VkCommandBufferBeginInfo beginInfo;
|
||||||
|
SDL_zero(beginInfo);
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
beginInfo.flags = 0;
|
beginInfo.flags = 0;
|
||||||
context->vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
context->vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||||
|
|
||||||
VkImageMemoryBarrier2 barrier = { 0 };
|
VkImageMemoryBarrier2 barrier;
|
||||||
|
SDL_zero(barrier);
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||||
barrier.srcAccessMask = VK_ACCESS_2_NONE;
|
barrier.srcAccessMask = VK_ACCESS_2_NONE;
|
||||||
barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
|
||||||
@@ -835,7 +802,8 @@ int BeginVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_R
|
|||||||
barrier.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
barrier.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
barrier.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
barrier.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
|
||||||
VkDependencyInfo dep = { 0 };
|
VkDependencyInfo dep;
|
||||||
|
SDL_zero(dep);
|
||||||
dep.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
dep.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||||
dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||||
dep.imageMemoryBarrierCount = 1;
|
dep.imageMemoryBarrierCount = 1;
|
||||||
@@ -858,8 +826,6 @@ int BeginVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_R
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION , "vkQueueSubmit(): %s", getVulkanResultString(result));
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION , "vkQueueSubmit(): %s", getVulkanResultString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AddVulkanRenderSemaphores(renderer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (Sint64)context->waitSemaphores[context->commandBufferIndex], (Sint64)context->signalSemaphores[context->commandBufferIndex]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,17 +838,15 @@ int FinishVulkanFrameRendering(VulkanVideoContext *context, AVFrame *frame, SDL_
|
|||||||
// Transition the frame back to ffmpeg
|
// Transition the frame back to ffmpeg
|
||||||
++pVkFrame->sem_value[0];
|
++pVkFrame->sem_value[0];
|
||||||
|
|
||||||
VkTimelineSemaphoreSubmitInfo timeline = { 0 };
|
VkTimelineSemaphoreSubmitInfo timeline;
|
||||||
|
SDL_zero(timeline);
|
||||||
timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
|
timeline.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
|
||||||
timeline.signalSemaphoreValueCount = 1;
|
timeline.signalSemaphoreValueCount = 1;
|
||||||
timeline.pSignalSemaphoreValues = pVkFrame->sem_value;
|
timeline.pSignalSemaphoreValues = pVkFrame->sem_value;
|
||||||
|
|
||||||
VkPipelineStageFlags pipelineStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
VkSubmitInfo submitInfo;
|
||||||
VkSubmitInfo submitInfo = { 0 };
|
SDL_zero(submitInfo);
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
|
||||||
submitInfo.pWaitSemaphores = &context->signalSemaphores[context->commandBufferIndex];
|
|
||||||
submitInfo.pWaitDstStageMask = &pipelineStageMask;
|
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = pVkFrame->sem;
|
submitInfo.pSignalSemaphores = pVkFrame->sem;
|
||||||
submitInfo.pNext = &timeline;
|
submitInfo.pNext = &timeline;
|
||||||
@@ -940,20 +904,6 @@ void DestroyVulkanVideoContext(VulkanVideoContext *context)
|
|||||||
}
|
}
|
||||||
SDL_free(context->instanceExtensions);
|
SDL_free(context->instanceExtensions);
|
||||||
SDL_free(context->deviceExtensions);
|
SDL_free(context->deviceExtensions);
|
||||||
if (context->waitSemaphores) {
|
|
||||||
for (uint32_t i = 0; i < context->waitSemaphoreCount; ++i) {
|
|
||||||
context->vkDestroySemaphore(context->device, context->waitSemaphores[i], NULL);
|
|
||||||
}
|
|
||||||
SDL_free(context->waitSemaphores);
|
|
||||||
context->waitSemaphores = NULL;
|
|
||||||
}
|
|
||||||
if (context->signalSemaphores) {
|
|
||||||
for (uint32_t i = 0; i < context->signalSemaphoreCount; ++i) {
|
|
||||||
context->vkDestroySemaphore(context->device, context->signalSemaphores[i], NULL);
|
|
||||||
}
|
|
||||||
SDL_free(context->signalSemaphores);
|
|
||||||
context->signalSemaphores = NULL;
|
|
||||||
}
|
|
||||||
if (context->commandBuffers) {
|
if (context->commandBuffers) {
|
||||||
context->vkFreeCommandBuffers(context->device, context->commandPool, context->commandBufferCount, context->commandBuffers);
|
context->vkFreeCommandBuffers(context->device, context->commandPool, context->commandBufferCount, context->commandBuffers);
|
||||||
SDL_free(context->commandBuffers);
|
SDL_free(context->commandBuffers);
|
||||||
|
|||||||
@@ -789,6 +789,8 @@ static int process_testNonExistingExecutable(void *arg)
|
|||||||
char *random_stem;
|
char *random_stem;
|
||||||
char *random_path;
|
char *random_path;
|
||||||
SDL_Process *process = NULL;
|
SDL_Process *process = NULL;
|
||||||
|
bool result;
|
||||||
|
int exit_code = 0;
|
||||||
|
|
||||||
random_stem = SDLTest_RandomAsciiStringOfSize(STEM_LENGTH);
|
random_stem = SDLTest_RandomAsciiStringOfSize(STEM_LENGTH);
|
||||||
random_path = SDL_malloc(STEM_LENGTH + SDL_strlen(EXE) + 1);
|
random_path = SDL_malloc(STEM_LENGTH + SDL_strlen(EXE) + 1);
|
||||||
@@ -801,7 +803,15 @@ static int process_testNonExistingExecutable(void *arg)
|
|||||||
|
|
||||||
SDLTest_AssertPass("About to call SDL_CreateProcess");
|
SDLTest_AssertPass("About to call SDL_CreateProcess");
|
||||||
process = SDL_CreateProcess((const char * const *)process_args, false);
|
process = SDL_CreateProcess((const char * const *)process_args, false);
|
||||||
SDLTest_AssertCheck(process == NULL, "SDL_CreateProcess() should have failed (%s)", SDL_GetError());
|
if (process) {
|
||||||
|
SDLTest_AssertPass("SDL_CreateProcess() returned a process, waiting for exec failure");
|
||||||
|
result = SDL_WaitProcess(process, true, &exit_code);
|
||||||
|
SDLTest_AssertCheck(result, "SDL_WaitProcess()");
|
||||||
|
SDLTest_AssertCheck(exit_code != 0, "Exit code should be non-zero, is %d", exit_code);
|
||||||
|
SDL_DestroyProcess(process);
|
||||||
|
} else {
|
||||||
|
SDLTest_AssertPass("SDL_CreateProcess() failed synchronously (%s)", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
DestroyStringArray(process_args);
|
DestroyStringArray(process_args);
|
||||||
return TEST_COMPLETED;
|
return TEST_COMPLETED;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user