upgrading to sdl 3.16
This commit is contained in:
parent
826c057bea
commit
6f2396c814
|
|
@ -9,7 +9,7 @@ This is a port of [SDL](https://libsdl.org/) to the Zig build system, packaged f
|
|||
|
||||
## Usage
|
||||
|
||||
Requires Zig 0.14.0 or 0.15.0-dev (master).
|
||||
Requires Zig 0.14.1 or 0.15.0-dev (master).
|
||||
|
||||
```sh
|
||||
zig fetch --save git+https://github.com/castholm/SDL.git
|
||||
|
|
@ -21,6 +21,7 @@ const sdl_dep = b.dependency("sdl", .{
|
|||
.optimize = optimize,
|
||||
//.preferred_linkage = .static,
|
||||
//.strip = null,
|
||||
//.sanitize_c = null,
|
||||
//.pic = null,
|
||||
//.lto = null,
|
||||
//.emscripten_pthreads = false,
|
||||
|
|
@ -79,7 +80,7 @@ When building for non-native macOS targets (for example for x86-64 from an AArch
|
|||
|
||||
```sh
|
||||
sysroot_path=$(xcrun --sdk macosx --show-sdk-path)
|
||||
zig build -Dtarget=x86_64-macos-none --sysroot "$sysroot_path"
|
||||
zig build -Dtarget=x86_64-macos --sysroot "$sysroot_path"
|
||||
```
|
||||
|
||||
### Emscripten (web)
|
||||
|
|
@ -103,7 +104,7 @@ When building for Emscripten, you need to provide a path to the Emscripten sysro
|
|||
```sh
|
||||
cache_path=$(em-config CACHE)
|
||||
sysroot_path="$cache_path/sysroot"
|
||||
zig build -Dtarget=wasm32-emscripten-musl --sysroot "$sysroot_path"
|
||||
zig build -Dtarget=wasm32-emscripten --sysroot "$sysroot_path"
|
||||
```
|
||||
|
||||
Depending on the state of your Emscripten cache, you might need to run `embuilder build sysroot` to ensure that the Emscripten sysroot is built before you run `zig build`.
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
const std = @import("std");
|
||||
|
||||
pub const version: std.SemanticVersion = .{ .major = 3, .minor = 2, .patch = 10 };
|
||||
pub const version: std.SemanticVersion = .{ .major = 3, .minor = 2, .patch = 16 };
|
||||
const formatted_version = std.fmt.comptimePrint("SDL3-{}", .{version});
|
||||
pub const vendor_info = "https://github.com/castholm/SDL 0.2.1";
|
||||
pub const vendor_info = "https://github.com/castholm/SDL 0.2.4";
|
||||
pub const revision = formatted_version ++ " (" ++ vendor_info ++ ")";
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
var preferred_linkage: std.builtin.LinkMode = b.option(
|
||||
const preferred_linkage = b.option(
|
||||
std.builtin.LinkMode,
|
||||
"preferred_linkage",
|
||||
"Prefer building statically or dynamically linked libraries (default: static)",
|
||||
|
|
@ -20,23 +20,50 @@ pub fn build(b: *std.Build) void {
|
|||
"preferred_link_mode",
|
||||
"Deprecated; use 'preferred_linkage' instead",
|
||||
) orelse .static;
|
||||
|
||||
preferred_linkage = .dynamic;
|
||||
const strip = b.option(
|
||||
bool,
|
||||
"strip",
|
||||
"Strip debug symbols (default: varies)",
|
||||
);
|
||||
const sanitize_c = b.option(
|
||||
enum { off, trap, full }, // TODO: Change to std.zig.SanitizeC after 0.15
|
||||
"sanitize_c",
|
||||
"Detect C undefined behavior (default: varies)",
|
||||
);
|
||||
const legacy_sanitize_c_field = @FieldType(std.Build.Module.CreateOptions, "sanitize_c") == ?bool;
|
||||
const resolved_sanitize_c = if (sanitize_c) |x| switch (legacy_sanitize_c_field) {
|
||||
true => switch (x) {
|
||||
.off => false,
|
||||
.trap, .full => true,
|
||||
},
|
||||
false => @as(std.zig.SanitizeC, switch (x) {
|
||||
.off => .off,
|
||||
.trap => .trap,
|
||||
.full => .full,
|
||||
}),
|
||||
} else null;
|
||||
const pic = b.option(
|
||||
bool,
|
||||
"pic",
|
||||
"Produce position-independent code (default: varies)",
|
||||
);
|
||||
const lto = b.option(
|
||||
bool,
|
||||
enum { true, false, none, full, thin }, // TODO: Change to std.zig.LtoMode after 0.15
|
||||
"lto",
|
||||
"Perform link time optimization (default: varies)",
|
||||
);
|
||||
const legacy_lto_field = !@hasField(std.Build.Step.Compile, "lto");
|
||||
const resolved_lto = if (lto) |x| switch (legacy_lto_field) {
|
||||
true => switch (x) {
|
||||
.false, .none => false,
|
||||
.true, .full, .thin => true,
|
||||
},
|
||||
false => @as(std.zig.LtoMode, switch (x) {
|
||||
.false, .none => .none,
|
||||
.true, .full => .full,
|
||||
.thin => .thin,
|
||||
}),
|
||||
} else null;
|
||||
const emscripten_pthreads = b.option(
|
||||
bool,
|
||||
"emscripten_pthreads",
|
||||
|
|
@ -52,11 +79,12 @@ pub fn build(b: *std.Build) void {
|
|||
var linux = false;
|
||||
var linux_deps_values: ?LinuxDepsValues = null;
|
||||
var macos = false;
|
||||
var macos_system_include_path: ?std.Build.LazyPath = null;
|
||||
var macos_system_framework_path: ?std.Build.LazyPath = null;
|
||||
var macos_library_path: ?std.Build.LazyPath = null;
|
||||
var emscripten = false;
|
||||
var emscripten_system_include_path: ?std.Build.LazyPath = null;
|
||||
var system_include_path: ?std.Build.LazyPath = null;
|
||||
var system_framework_path: ?std.Build.LazyPath = null;
|
||||
var library_path: ?std.Build.LazyPath = null;
|
||||
var glibc = false;
|
||||
var musl = false;
|
||||
switch (target.result.os.tag) {
|
||||
.windows => {
|
||||
windows = true;
|
||||
|
|
@ -66,13 +94,15 @@ pub fn build(b: *std.Build) void {
|
|||
if (b.lazyImport(@This(), "sdl_linux_deps")) |build_zig| {
|
||||
linux_deps_values = LinuxDepsValues.fromBuildZig(b, build_zig);
|
||||
}
|
||||
glibc = target.result.abi.isGnu();
|
||||
musl = target.result.abi.isMusl();
|
||||
},
|
||||
.macos => {
|
||||
macos = true;
|
||||
if (b.sysroot) |sysroot| {
|
||||
macos_system_include_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "usr/include" }) };
|
||||
macos_system_framework_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "System/Library/Frameworks" }) };
|
||||
macos_library_path = .{ .cwd_relative = "/usr/lib" }; // ???
|
||||
system_include_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "usr/include" }) };
|
||||
system_framework_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "System/Library/Frameworks" }) };
|
||||
library_path = .{ .cwd_relative = "/usr/lib" }; // ???
|
||||
} else if (!target.query.isNative()) {
|
||||
std.log.err("'--sysroot' is required when building SDL for non-native macOS targets", .{});
|
||||
std.process.exit(1);
|
||||
|
|
@ -81,7 +111,7 @@ pub fn build(b: *std.Build) void {
|
|||
.emscripten => {
|
||||
emscripten = true;
|
||||
if (b.sysroot) |sysroot| {
|
||||
emscripten_system_include_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "include" }) };
|
||||
system_include_path = .{ .cwd_relative = b.pathJoin(&.{ sysroot, "include" }) };
|
||||
} else {
|
||||
std.log.err("'--sysroot' is required when building SDL for Emscripten", .{});
|
||||
std.process.exit(1);
|
||||
|
|
@ -147,8 +177,8 @@ pub fn build(b: *std.Build) void {
|
|||
.HAVE_WCSTOL = windows or linux or macos or emscripten,
|
||||
.HAVE_STRLEN = windows or linux or macos or emscripten,
|
||||
.HAVE_STRNLEN = windows or linux or macos or emscripten,
|
||||
.HAVE_STRLCPY = macos or emscripten,
|
||||
.HAVE_STRLCAT = macos or emscripten,
|
||||
.HAVE_STRLCPY = linux and musl or macos or emscripten,
|
||||
.HAVE_STRLCAT = linux and musl or macos or emscripten,
|
||||
.HAVE_STRPBRK = windows or linux or macos or emscripten,
|
||||
.HAVE__STRREV = windows,
|
||||
.HAVE_INDEX = linux or macos or emscripten,
|
||||
|
|
@ -199,10 +229,10 @@ pub fn build(b: *std.Build) void {
|
|||
.HAVE_FMOD = windows or linux or macos or emscripten,
|
||||
.HAVE_FMODF = windows or linux or macos or emscripten,
|
||||
.HAVE_ISINF = windows or linux or macos or emscripten,
|
||||
.HAVE_ISINFF = linux or emscripten,
|
||||
.HAVE_ISINFF = linux and !musl or emscripten,
|
||||
.HAVE_ISINF_FLOAT_MACRO = windows or linux or macos or emscripten,
|
||||
.HAVE_ISNAN = windows or linux or macos or emscripten,
|
||||
.HAVE_ISNANF = linux or emscripten,
|
||||
.HAVE_ISNANF = linux and !musl or emscripten,
|
||||
.HAVE_ISNAN_FLOAT_MACRO = windows or linux or macos or emscripten,
|
||||
.HAVE_LOG = windows or linux or macos or emscripten,
|
||||
.HAVE_LOGF = windows or linux or macos or emscripten,
|
||||
|
|
@ -227,9 +257,9 @@ pub fn build(b: *std.Build) void {
|
|||
.HAVE_TRUNC = windows or linux or macos or emscripten,
|
||||
.HAVE_TRUNCF = windows or linux or macos or emscripten,
|
||||
.HAVE__FSEEKI64 = windows,
|
||||
.HAVE_FOPEN64 = windows or linux or emscripten,
|
||||
.HAVE_FOPEN64 = windows or linux and !musl or emscripten,
|
||||
.HAVE_FSEEKO = windows or linux or macos or emscripten,
|
||||
.HAVE_FSEEKO64 = windows or linux or emscripten,
|
||||
.HAVE_FSEEKO64 = windows or linux and !musl or emscripten,
|
||||
.HAVE_MEMFD_CREATE = linux,
|
||||
.HAVE_POSIX_FALLOCATE = linux or emscripten,
|
||||
.HAVE_SIGACTION = linux or macos or emscripten,
|
||||
|
|
@ -543,10 +573,11 @@ pub fn build(b: *std.Build) void {
|
|||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
.strip = strip,
|
||||
.sanitize_c = resolved_sanitize_c,
|
||||
.pic = pic,
|
||||
});
|
||||
const sdl_lib = b.addLibrary(.{
|
||||
.linkage = .dynamic, //if (emscripten) .static else preferred_linkage,
|
||||
.linkage = if (emscripten) .static else preferred_linkage,
|
||||
.name = "SDL3",
|
||||
.root_module = sdl_mod,
|
||||
.version = .{
|
||||
|
|
@ -556,7 +587,11 @@ pub fn build(b: *std.Build) void {
|
|||
},
|
||||
.use_llvm = if (emscripten) true else null,
|
||||
});
|
||||
sdl_lib.want_lto = lto;
|
||||
if (legacy_lto_field) {
|
||||
sdl_lib.want_lto = resolved_lto;
|
||||
} else {
|
||||
sdl_lib.lto = resolved_lto;
|
||||
}
|
||||
|
||||
sdl_mod.addCMacro("USING_GENERATED_CONFIG_H", "1");
|
||||
sdl_mod.addCMacro("SDL_BUILD_MAJOR_VERSION", std.fmt.comptimePrint("{}", .{version.major}));
|
||||
|
|
@ -583,25 +618,26 @@ pub fn build(b: *std.Build) void {
|
|||
if (linux_deps_values) |deps_values| {
|
||||
sdl_mod.addIncludePath(deps_values.dependency.path("src"));
|
||||
sdl_mod.addSystemIncludePath(deps_values.dependency.path("include"));
|
||||
if (target.result.cpu.arch == .x86_64 and target.result.abi.isGnu()) {
|
||||
// Currently, the only difference between these two sets of target-specific headers
|
||||
// is that the x86_64 one defines G_VA_COPY_AS_ARRAY and the aarch64 one doesn't.
|
||||
if (target.result.cpu.arch == .x86_64 and glibc) {
|
||||
sdl_mod.addSystemIncludePath(deps_values.dependency.path("include/x86_64-linux-gnu"));
|
||||
}
|
||||
if (target.result.cpu.arch == .aarch64 and target.result.abi.isGnu()) {
|
||||
// TODO: musl targets can piggyback off of the aarch64-linux-gnu headers for now because
|
||||
// they are identical to their x86_64-linux-musl and aarch64-linux-musl equivalents.
|
||||
if (target.result.cpu.arch == .aarch64 or target.result.cpu.arch == .x86_64 and musl) {
|
||||
sdl_mod.addSystemIncludePath(deps_values.dependency.path("include/aarch64-linux-gnu"));
|
||||
}
|
||||
}
|
||||
if (macos_system_include_path) |path| {
|
||||
if (system_include_path) |path| {
|
||||
sdl_mod.addSystemIncludePath(path);
|
||||
}
|
||||
if (macos_system_framework_path) |path| {
|
||||
if (system_framework_path) |path| {
|
||||
sdl_mod.addSystemFrameworkPath(path);
|
||||
}
|
||||
if (macos_library_path) |path| {
|
||||
if (library_path) |path| {
|
||||
sdl_mod.addLibraryPath(path);
|
||||
}
|
||||
if (emscripten_system_include_path) |path| {
|
||||
sdl_mod.addSystemIncludePath(path);
|
||||
}
|
||||
|
||||
var sdl_c_flags: std.BoundedArray([]const u8, common_c_flags.len + 3) = .{};
|
||||
sdl_c_flags.appendSliceAssumeCapacity(&common_c_flags);
|
||||
|
|
@ -804,6 +840,7 @@ pub fn build(b: *std.Build) void {
|
|||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
.strip = strip,
|
||||
.sanitize_c = resolved_sanitize_c,
|
||||
.pic = pic,
|
||||
});
|
||||
const sdl_uclibc_lib = b.addLibrary(.{
|
||||
|
|
@ -811,7 +848,11 @@ pub fn build(b: *std.Build) void {
|
|||
.name = "SDL_uclib",
|
||||
.root_module = sdl_uclibc_mod,
|
||||
});
|
||||
sdl_uclibc_lib.want_lto = lto;
|
||||
if (legacy_lto_field) {
|
||||
sdl_uclibc_lib.want_lto = resolved_lto;
|
||||
} else {
|
||||
sdl_uclibc_lib.lto = resolved_lto;
|
||||
}
|
||||
|
||||
sdl_uclibc_mod.addCMacro("USING_GENERATED_CONFIG_H", "1");
|
||||
|
||||
|
|
@ -1290,6 +1331,7 @@ pub fn build(b: *std.Build) void {
|
|||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
.strip = strip,
|
||||
.sanitize_c = resolved_sanitize_c,
|
||||
.pic = pic,
|
||||
});
|
||||
const sdl_test_lib = b.addLibrary(.{
|
||||
|
|
@ -1298,12 +1340,16 @@ pub fn build(b: *std.Build) void {
|
|||
.root_module = sdl_test_mod,
|
||||
.use_llvm = if (emscripten) true else null,
|
||||
});
|
||||
sdl_test_lib.want_lto = lto;
|
||||
if (legacy_lto_field) {
|
||||
sdl_test_lib.want_lto = resolved_lto;
|
||||
} else {
|
||||
sdl_test_lib.lto = resolved_lto;
|
||||
}
|
||||
|
||||
sdl_test_mod.addConfigHeader(build_config_h);
|
||||
sdl_test_mod.addConfigHeader(revision_h);
|
||||
sdl_test_mod.addIncludePath(b.path("include"));
|
||||
if (emscripten_system_include_path) |path| {
|
||||
if (system_include_path) |path| {
|
||||
sdl_test_mod.addSystemIncludePath(path);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
.{
|
||||
.name = .sdl,
|
||||
.version = "0.2.1+3.2.10",
|
||||
.version = "0.2.4+3.2.16",
|
||||
.fingerprint = 0xec638ccbf427e2ee,
|
||||
.minimum_zig_version = "0.14.0",
|
||||
.minimum_zig_version = "0.14.1",
|
||||
.dependencies = .{
|
||||
.sdl_linux_deps = .{
|
||||
.url = "git+https://github.com/castholm/SDL_linux_deps.git#085212f286621835f2638cb0cfff078fe515341a",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.2.10
|
||||
* Main include header for the SDL library, version 3.2.16
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
|
|
|||
|
|
@ -492,6 +492,8 @@ typedef struct SDL_MouseWheelEvent
|
|||
SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
|
||||
float mouse_x; /**< X coordinate, relative to window */
|
||||
float mouse_y; /**< Y coordinate, relative to window */
|
||||
Sint32 integer_x; /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
Sint32 integer_y; /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
} SDL_MouseWheelEvent;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2231,7 +2231,7 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGPUDriver(int index);
|
|||
|
||||
/**
|
||||
* Returns the name of the backend used to create this GPU context.
|
||||
|
||||
*
|
||||
* \param device a GPU context to query.
|
||||
* \returns the name of the device's driver, or NULL on error.
|
||||
*
|
||||
|
|
@ -2467,9 +2467,9 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader(
|
|||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only)
|
||||
* if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear
|
||||
* the texture to a depth of this value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12
|
||||
* only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
||||
* clear the texture to a stencil of this value. Defaults to zero.
|
||||
* clear the texture to a stencil of this Uint8 value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed
|
||||
* in debugging tools.
|
||||
*
|
||||
|
|
@ -2495,13 +2495,13 @@ extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture(
|
|||
SDL_GPUDevice *device,
|
||||
const SDL_GPUTextureCreateInfo *createinfo);
|
||||
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
|
||||
/**
|
||||
* Creates a buffer object to be used in graphics or compute workflows.
|
||||
|
|
@ -3775,7 +3775,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice(
|
|||
* supported via SDL_WindowSupportsGPUPresentMode /
|
||||
* SDL_WindowSupportsGPUSwapchainComposition prior to calling this function.
|
||||
*
|
||||
* SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* supported.
|
||||
*
|
||||
* \param device a GPU context.
|
||||
|
|
|
|||
|
|
@ -1074,8 +1074,8 @@ extern "C" {
|
|||
*
|
||||
* By default, SDL will try all available GPU backends in a reasonable order
|
||||
* until it finds one that can work, but this hint allows the app or user to
|
||||
* force a specific target, such as "direct3d11" if, say, your hardware
|
||||
* supports D3D12 but want to try using D3D11 instead.
|
||||
* force a specific target, such as "direct3d12" if, say, your hardware
|
||||
* supports Vulkan but you want to try using D3D12 instead.
|
||||
*
|
||||
* This hint should be set before any GPU functions are called.
|
||||
*
|
||||
|
|
@ -2026,8 +2026,8 @@ extern "C" {
|
|||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": RAWINPUT drivers are not used.
|
||||
* - "1": RAWINPUT drivers are used. (default)
|
||||
* - "0": RAWINPUT drivers are not used. (default)
|
||||
* - "1": RAWINPUT drivers are used.
|
||||
*
|
||||
* This hint should be set before SDL is initialized.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags;
|
|||
|
||||
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_HAPTIC 0x00001000u
|
||||
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
|
||||
#define SDL_INIT_EVENTS 0x00004000u
|
||||
|
|
|
|||
|
|
@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout
|
|||
* ABGR32, define a platform-independent encoding into bytes in the order
|
||||
* specified. For example, in RGB24 data, each pixel is encoded in 3 bytes
|
||||
* (red, green, blue) in that order, and in ABGR32 data, each pixel is
|
||||
* encoded in 4 bytes alpha, blue, green, red) in that order. Use these
|
||||
* encoded in 4 bytes (alpha, blue, green, red) in that order. Use these
|
||||
* names if the property of a format that is important to you is the order
|
||||
* of the bytes in memory or on disk.
|
||||
* - Names with a bit count per component, such as ARGB8888 and XRGB1555, are
|
||||
|
|
|
|||
|
|
@ -1607,8 +1607,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
|
|||
* Return whether an explicit rectangle was set as the viewport.
|
||||
*
|
||||
* This is useful if you're saving and restoring the viewport and want to know
|
||||
* whether you should restore a specific rectangle or NULL. Note that the
|
||||
* viewport is always reset when changing rendering targets.
|
||||
* whether you should restore a specific rectangle or NULL.
|
||||
*
|
||||
* Each render target has its own viewport. This function checks the viewport
|
||||
* for the current render target.
|
||||
|
|
|
|||
|
|
@ -4656,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x);
|
|||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on double-precision floating point values, use
|
||||
* SDL_atan2f for single-precision floats.
|
||||
|
|
@ -4692,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x);
|
|||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on single-precision floating point values, use
|
||||
* SDL_atan2 for double-precision floats.
|
||||
|
|
@ -5974,8 +5974,12 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
|
|||
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* strdup is not ANSI but POSIX, and its prototype might be hidden... */
|
||||
/* not for windows: might conflict with string.h where strdup may have
|
||||
* dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */
|
||||
char *strdup(const char *str);
|
||||
#endif
|
||||
|
||||
/* Starting LLVM 16, the analyser errors out if these functions do not have
|
||||
their prototype defined (clang-diagnostic-implicit-function-declaration) */
|
||||
|
|
|
|||
|
|
@ -1135,9 +1135,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
|
|||
* If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or
|
||||
* `dst`) is copied while ensuring clipping to `dst->clip_rect`.
|
||||
*
|
||||
* The final blit rectangles are saved in `srcrect` and `dstrect` after all
|
||||
* clipping is performed.
|
||||
*
|
||||
* The blit function should not be called on a locked surface.
|
||||
*
|
||||
* The blit semantics for surfaces with and without blending and colorkey are
|
||||
|
|
@ -1282,10 +1279,11 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src
|
|||
*
|
||||
* \param src the SDL_Surface structure to be copied from.
|
||||
* \param srcrect the SDL_Rect structure representing the rectangle to be
|
||||
* copied, may not be NULL.
|
||||
* copied, or NULL to copy the entire surface.
|
||||
* \param dst the SDL_Surface structure that is the blit target.
|
||||
* \param dstrect the SDL_Rect structure representing the target rectangle in
|
||||
* the destination surface, may not be NULL.
|
||||
* the destination surface, or NULL to fill the entire
|
||||
* destination surface.
|
||||
* \param scaleMode the SDL_ScaleMode to be used.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ extern "C" {
|
|||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MICRO_VERSION 10
|
||||
#define SDL_MICRO_VERSION 16
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
|
|
|||
|
|
@ -426,10 +426,10 @@ typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDi
|
|||
*/
|
||||
typedef enum SDL_GLAttr
|
||||
{
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */
|
||||
SDL_GL_DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */
|
||||
SDL_GL_DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */
|
||||
|
|
@ -1041,6 +1041,10 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count);
|
|||
/**
|
||||
* Create a window with the specified dimensions and flags.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* `flags` may be any of the following OR'd together:
|
||||
*
|
||||
* - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution
|
||||
|
|
@ -1127,6 +1131,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
|||
/**
|
||||
* Create a child popup window of the specified parent window.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* The flags parameter **must** contain at least one of the following:
|
||||
*
|
||||
* - `SDL_WINDOW_TOOLTIP`: The popup window is a tooltip and will not pass any
|
||||
|
|
@ -1189,6 +1197,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
|||
/**
|
||||
* Create a window with the specified properties.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN`: true if the window should
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
#include "SDL_hints_c.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "core/android/SDL_android.h"
|
||||
#endif
|
||||
|
||||
typedef struct SDL_HintWatch
|
||||
{
|
||||
SDL_HintCallback callback;
|
||||
|
|
@ -147,6 +151,13 @@ bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriori
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(value, false));
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
|
|
@ -185,6 +196,17 @@ bool SDL_ResetHint(const char *name)
|
|||
result = true;
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
|
|
@ -210,6 +232,17 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
|
|||
SDL_free(hint->value);
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
}
|
||||
|
||||
void SDL_ResetHints(void)
|
||||
|
|
|
|||
|
|
@ -265,6 +265,12 @@ extern "C" {
|
|||
#include "SDL_utils_c.h"
|
||||
#include "SDL_hashtable.h"
|
||||
|
||||
#define PUSH_SDL_ERROR() \
|
||||
{ char *_error = SDL_strdup(SDL_GetError());
|
||||
|
||||
#define POP_SDL_ERROR() \
|
||||
SDL_SetError("%s", _error); SDL_free(_error); }
|
||||
|
||||
// Do any initialization that needs to happen before threads are started
|
||||
extern void SDL_InitMainThread(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -403,6 +403,10 @@ const char *SDL_GetPersistentString(const char *string)
|
|||
static int PrefixMatch(const char *a, const char *b)
|
||||
{
|
||||
int matchlen = 0;
|
||||
// Fixes the "HORI HORl Taiko No Tatsujin Drum Controller"
|
||||
if (SDL_strncmp(a, "HORI ", 5) == 0 && SDL_strncmp(b, "HORl ", 5) == 0) {
|
||||
return 5;
|
||||
}
|
||||
while (*a && *b) {
|
||||
if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) {
|
||||
++matchlen;
|
||||
|
|
@ -424,8 +428,8 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
|
|||
{ "ASTRO Gaming", "ASTRO" },
|
||||
{ "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" },
|
||||
{ "Guangzhou Chicken Run Network Technology Co., Ltd.", "GameSir" },
|
||||
{ "HORI CO.,LTD", "HORI" },
|
||||
{ "HORI CO.,LTD.", "HORI" },
|
||||
{ "HORI CO.,LTD", "HORI" },
|
||||
{ "Mad Catz Inc.", "Mad Catz" },
|
||||
{ "Nintendo Co., Ltd.", "Nintendo" },
|
||||
{ "NVIDIA Corporation ", "" },
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
|
|||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
|
||||
if (logdev) {
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
device = logdev->physical_device;
|
||||
SDL_assert(device != NULL);
|
||||
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
|
||||
|
|
@ -459,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
|
|||
} else {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
|
||||
SDL_assert(device->instance_id == devid);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
if (!device) {
|
||||
|
|
@ -883,6 +885,7 @@ static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *tabl
|
|||
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
|
||||
data->highest = devid;
|
||||
data->result = (SDL_AudioDevice *) value;
|
||||
SDL_assert(data->result->instance_id == devid);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
|
@ -1051,7 +1054,10 @@ static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_Hash
|
|||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
|
||||
|
||||
SDL_assert(dev->instance_id == devid);
|
||||
DestroyPhysicalAudioDevice(dev);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
|
@ -1464,6 +1470,7 @@ static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTabl
|
|||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
SDL_assert(data->retval->instance_id == devid);
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
|
|
@ -1502,12 +1509,33 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
|
|||
|
||||
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool islogical = !(devid & (1<<1));
|
||||
const char *result = NULL;
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
|
||||
if (device) {
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
const void *vdev = NULL;
|
||||
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
SDL_SetError("Audio subsystem is not initialized");
|
||||
} else {
|
||||
// This does not call ObtainPhysicalAudioDevice() because the device's name never changes, so
|
||||
// it doesn't have to lock the whole device. However, just to make sure the device pointer itself
|
||||
// remains valid (in case the device is unplugged at the wrong moment), we hold the
|
||||
// device_hash_lock while we copy the string.
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
|
||||
if (!vdev) {
|
||||
SDL_SetError("Invalid audio device instance ID");
|
||||
} else if (islogical) {
|
||||
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
result = SDL_GetPersistentString(logdev->physical_device->name);
|
||||
} else {
|
||||
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
|
||||
SDL_assert(device->instance_id == devid);
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1715,13 +1743,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
|||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->recording, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
|
||||
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
|
||||
/* We impose a simple minimum on device formats. This prevents something low quality, like an old game using S8/8000Hz audio,
|
||||
from ruining a music thing playing at CD quality that tries to open later, or some VoIP library that opens for mono output
|
||||
ruining your surround-sound game because it got there first.
|
||||
These are just requests! The backend may change any of these values during OpenDevice method! */
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
|
||||
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
|
||||
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
|
||||
|
||||
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
|
||||
device->spec.channels = SDL_max(minimum_channels, spec.channels);
|
||||
device->spec.freq = SDL_max(minimum_freq, spec.freq);
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
|
|
|
|||
|
|
@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
|||
ctx.AAudioStreamBuilder_setFormat(builder, format);
|
||||
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
|
||||
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
|
||||
|
||||
// If no specific buffer size has been requested, the device will pick the optimal
|
||||
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
|
||||
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
|
||||
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
|
||||
}
|
||||
|
||||
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
|
|
@ -366,7 +372,7 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
|||
hidden->processed_bytes = 0;
|
||||
hidden->callback_bytes = 0;
|
||||
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers - 1);
|
||||
if (!hidden->semaphore) {
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
|
|||
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
|||
}
|
||||
|
||||
// limit to native freq
|
||||
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->spec.freq = MAIN_THREAD_EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq) * 2; // double the buffer size, some browsers need more, and we'll just have to live with the latency.
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
|
|
|||
|
|
@ -1118,7 +1118,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
|||
|
||||
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
||||
if (!stream_name || *stream_name == '\0') {
|
||||
stream_name = "Audio Stream";
|
||||
if (app_name) {
|
||||
stream_name = app_name;
|
||||
} else if (app_id) {
|
||||
stream_name = app_id;
|
||||
} else {
|
||||
stream_name = "SDL Audio Stream";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -672,7 +672,8 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
|||
paspec.rate = device->spec.freq;
|
||||
|
||||
// Reduced prebuffering compared to the defaults.
|
||||
paattr.fragsize = device->buffer_size; // despite the name, this is only used for recording devices, according to PulseAudio docs!
|
||||
|
||||
paattr.fragsize = device->buffer_size * 2; // despite the name, this is only used for recording devices, according to PulseAudio docs! (times 2 because we want _more_ than our buffer size sent from the server at a time, which helps some drivers).
|
||||
paattr.tlength = device->buffer_size;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
|||
|
||||
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
|
||||
// sceAudioOutOutput returns amount of samples queued or < 0 on error
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, S
|
|||
|
||||
SDL3.camera.ctx2d.drawImage(SDL3.camera.video, 0, 0, w, h);
|
||||
const imgrgba = SDL3.camera.ctx2d.getImageData(0, 0, w, h).data;
|
||||
Module.HEAPU8.set(imgrgba, rgba);
|
||||
HEAPU8.set(imgrgba, rgba);
|
||||
|
||||
return 1;
|
||||
}, device->actual_spec.width, device->actual_spec.height, rgba);
|
||||
|
|
|
|||
|
|
@ -371,6 +371,7 @@ static jmethodID midShowTextInput;
|
|||
static jmethodID midSupportsRelativeMouse;
|
||||
static jmethodID midOpenFileDescriptor;
|
||||
static jmethodID midShowFileDialog;
|
||||
static jmethodID midGetPreferredLocales;
|
||||
|
||||
// audio manager
|
||||
static jclass mAudioManagerClass;
|
||||
|
|
@ -660,6 +661,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
|||
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
|
||||
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
|
||||
midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
|
||||
|
||||
if (!midClipboardGetText ||
|
||||
!midClipboardHasText ||
|
||||
|
|
@ -691,7 +693,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
|||
!midShowTextInput ||
|
||||
!midSupportsRelativeMouse ||
|
||||
!midOpenFileDescriptor ||
|
||||
!midShowFileDialog) {
|
||||
!midShowFileDialog ||
|
||||
!midGetPreferredLocales) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
|
||||
}
|
||||
|
||||
|
|
@ -751,6 +754,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
|
|||
typedef int (*SDL_main_func)(int argc, char *argv[]);
|
||||
|
||||
static int run_count = 0;
|
||||
static bool allow_recreate_activity;
|
||||
static bool allow_recreate_activity_set;
|
||||
|
||||
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
|
||||
JNIEnv *env, jclass jcls)
|
||||
|
|
@ -760,10 +765,16 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
|
|||
return tmp;
|
||||
}
|
||||
|
||||
void Android_SetAllowRecreateActivity(bool enabled)
|
||||
{
|
||||
allow_recreate_activity = enabled;
|
||||
allow_recreate_activity_set = true;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
|
||||
JNIEnv *env, jclass jcls)
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY, false);
|
||||
return allow_recreate_activity;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitMainThread)(
|
||||
|
|
@ -1526,6 +1537,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
|
|||
// Note that we call setenv() directly to avoid affecting SDL environments
|
||||
setenv(utfname, utfvalue, 1); // This should NOT be SDL_setenv()
|
||||
|
||||
if (SDL_strcmp(utfname, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
// Only set this the first time we run, in case it's been set by the application via SDL_SetHint()
|
||||
if (!allow_recreate_activity_set) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(utfvalue, false));
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, name, utfname);
|
||||
(*env)->ReleaseStringUTFChars(env, value, utfvalue);
|
||||
}
|
||||
|
|
@ -2569,65 +2588,22 @@ bool Android_JNI_ShowToast(const char *message, int duration, int gravity, int x
|
|||
|
||||
bool Android_JNI_GetLocale(char *buf, size_t buflen)
|
||||
{
|
||||
AConfiguration *cfg;
|
||||
|
||||
SDL_assert(buflen > 6);
|
||||
|
||||
// Need to re-create the asset manager if locale has changed (SDL_EVENT_LOCALE_CHANGED)
|
||||
Internal_Android_Destroy_AssetManager();
|
||||
|
||||
if (!asset_manager) {
|
||||
Internal_Android_Create_AssetManager();
|
||||
}
|
||||
|
||||
if (!asset_manager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cfg = AConfiguration_new();
|
||||
if (!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
char language[2] = {};
|
||||
char country[2] = {};
|
||||
size_t id = 0;
|
||||
|
||||
AConfiguration_fromAssetManager(cfg, asset_manager);
|
||||
AConfiguration_getLanguage(cfg, language);
|
||||
AConfiguration_getCountry(cfg, country);
|
||||
|
||||
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
|
||||
if (language[0] == 'i' && language[1] == 'n') {
|
||||
language[1] = 'd';
|
||||
}
|
||||
|
||||
// copy language (not null terminated)
|
||||
if (language[0]) {
|
||||
buf[id++] = language[0];
|
||||
if (language[1]) {
|
||||
buf[id++] = language[1];
|
||||
bool result = false;
|
||||
if (buf && buflen > 0) {
|
||||
*buf = '\0';
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
jstring string = (jstring)(*env)->CallStaticObjectMethod(env, mActivityClass, midGetPreferredLocales);
|
||||
if (string) {
|
||||
const char *utf8string = (*env)->GetStringUTFChars(env, string, NULL);
|
||||
if (utf8string) {
|
||||
result = true;
|
||||
SDL_strlcpy(buf, utf8string, buflen);
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf8string);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
}
|
||||
|
||||
buf[id++] = '_';
|
||||
|
||||
// copy country (not null terminated)
|
||||
if (country[0]) {
|
||||
buf[id++] = country[0];
|
||||
if (country[1]) {
|
||||
buf[id++] = country[1];
|
||||
}
|
||||
}
|
||||
|
||||
buf[id++] = '\0';
|
||||
SDL_assert(id <= buflen);
|
||||
}
|
||||
|
||||
AConfiguration_delete(cfg);
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Android_JNI_OpenURL(const char *url)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeout
|
|||
void Android_LockActivityMutex(void);
|
||||
void Android_UnlockActivityMutex(void);
|
||||
|
||||
void Android_SetAllowRecreateActivity(bool enabled);
|
||||
|
||||
// Interface from the SDL library into the Android Java activity
|
||||
extern void Android_JNI_SetActivityTitle(const char *title);
|
||||
extern void Android_JNI_SetWindowStyle(bool fullscreen);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,10,0
|
||||
PRODUCTVERSION 3,2,10,0
|
||||
FILEVERSION 3,2,16,0
|
||||
PRODUCTVERSION 3,2,16,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
|
|
@ -23,12 +23,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL\0"
|
||||
VALUE "FileVersion", "3, 2, 10, 0\0"
|
||||
VALUE "FileVersion", "3, 2, 16, 0\0"
|
||||
VALUE "InternalName", "SDL\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
|
||||
VALUE "OriginalFilename", "SDL3.dll\0"
|
||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||
VALUE "ProductVersion", "3, 2, 10, 0\0"
|
||||
VALUE "ProductVersion", "3, 2, 16, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
|||
|
|
@ -115,7 +115,11 @@
|
|||
#define CPU_CFG2_LSX (1 << 6)
|
||||
#define CPU_CFG2_LASX (1 << 7)
|
||||
|
||||
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
|
||||
#if !defined(SDL_CPUINFO_DISABLED) && \
|
||||
!((defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))) && \
|
||||
!(defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)) && \
|
||||
!(defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)) && \
|
||||
defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
|
||||
/* This is the brute force way of detecting instruction sets...
|
||||
the idea is borrowed from the libmpeg2 library - thanks!
|
||||
*/
|
||||
|
|
@ -344,6 +348,8 @@ static int CPU_haveAltiVec(void)
|
|||
elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
|
||||
altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
|
||||
return altivec;
|
||||
#elif defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)
|
||||
altivec = getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC;
|
||||
#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
|
||||
void (*handler)(int sig);
|
||||
handler = signal(SIGILL, illegal_instruction);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,35 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <UniformTypeIdentifiers/UTType.h>
|
||||
|
||||
static void AddFileExtensionType(NSMutableArray *types, const char *pattern_ptr)
|
||||
{
|
||||
if (!*pattern_ptr) {
|
||||
return; // in case the string had an extra ';' at the end.
|
||||
}
|
||||
|
||||
// -[UTType typeWithFilenameExtension] will return nil if there's a period in the string. It's better to
|
||||
// allow too many files than not allow the one the user actually needs, so just take the part after the '.'
|
||||
const char *dot = SDL_strrchr(pattern_ptr, '.');
|
||||
NSString *extstr = [NSString stringWithFormat: @"%s", dot ? (dot + 1) : pattern_ptr];
|
||||
if (@available(macOS 11.0, *)) {
|
||||
UTType *uttype = [UTType typeWithFilenameExtension:extstr];
|
||||
if (uttype) { // still failed? Don't add the pattern. This is what the pre-macOS11 path does internally anyhow.
|
||||
[types addObject:uttype];
|
||||
}
|
||||
} else {
|
||||
[types addObject:extstr];
|
||||
}
|
||||
}
|
||||
|
||||
static void ReactivateAfterDialog(void)
|
||||
{
|
||||
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
|
||||
[i activateWithOptions:0];
|
||||
break;
|
||||
}
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
|
||||
{
|
||||
SDL_Window* window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL);
|
||||
|
|
@ -87,7 +116,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
|||
|
||||
if (filters) {
|
||||
// On macOS 11.0 and up, this is an array of UTType. Prior to that, it's an array of NSString
|
||||
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ];
|
||||
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters];
|
||||
|
||||
int has_all_files = 0;
|
||||
for (int i = 0; i < nfilters; i++) {
|
||||
|
|
@ -102,21 +131,14 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
|||
for (char *c = pattern; *c; c++) {
|
||||
if (*c == ';') {
|
||||
*c = '\0';
|
||||
if(@available(macOS 11.0, *)) {
|
||||
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
|
||||
} else {
|
||||
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
|
||||
}
|
||||
AddFileExtensionType(types, pattern_ptr);
|
||||
pattern_ptr = c + 1;
|
||||
} else if (*c == '*') {
|
||||
has_all_files = 1;
|
||||
}
|
||||
}
|
||||
if(@available(macOS 11.0, *)) {
|
||||
[types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]];
|
||||
} else {
|
||||
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
|
||||
}
|
||||
|
||||
AddFileExtensionType(types, pattern_ptr); // get the last piece of the string.
|
||||
|
||||
SDL_free(pattern);
|
||||
}
|
||||
|
|
@ -163,6 +185,8 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
|||
const char *files[1] = { NULL };
|
||||
callback(userdata, files, -1);
|
||||
}
|
||||
|
||||
ReactivateAfterDialog();
|
||||
}];
|
||||
} else {
|
||||
if ([dialog runModal] == NSModalResponseOK) {
|
||||
|
|
@ -182,6 +206,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
|||
const char *files[1] = { NULL };
|
||||
callback(userdata, files, -1);
|
||||
}
|
||||
ReactivateAfterDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||
|
||||
chosen_files_list[nfiles] = NULL;
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) >= MAX_PATH) {
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) == 0) {
|
||||
SDL_SetError("Path too long or invalid character in path");
|
||||
SDL_free(chosen_files_list);
|
||||
callback(userdata, NULL, -1);
|
||||
|
|
@ -273,7 +273,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||
SDL_strlcpy(chosen_file, chosen_folder, MAX_PATH);
|
||||
chosen_file[chosen_folder_size] = '\\';
|
||||
|
||||
file_ptr += SDL_strlen(chosen_folder) + 1;
|
||||
file_ptr += SDL_wcslen(file_ptr) + 1;
|
||||
|
||||
while (*file_ptr) {
|
||||
nfiles++;
|
||||
|
|
@ -295,7 +295,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||
|
||||
int diff = ((int) chosen_folder_size) + 1;
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) >= MAX_PATH - diff) {
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) == 0) {
|
||||
SDL_SetError("Path too long or invalid character in path");
|
||||
|
||||
for (size_t i = 0; i < nfiles - 1; i++) {
|
||||
|
|
@ -308,7 +308,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||
return;
|
||||
}
|
||||
|
||||
file_ptr += SDL_strlen(chosen_file) + 1 - diff;
|
||||
file_ptr += SDL_wcslen(file_ptr) + 1;
|
||||
|
||||
chosen_files_list[nfiles - 1] = SDL_strdup(chosen_file);
|
||||
|
||||
|
|
@ -516,6 +516,14 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
|
|||
|
||||
filters_str = win_get_filters(filters, nfilters);
|
||||
|
||||
DWORD flags = 0;
|
||||
if (allow_many) {
|
||||
flags |= OFN_ALLOWMULTISELECT;
|
||||
}
|
||||
if (is_save) {
|
||||
flags |= OFN_OVERWRITEPROMPT;
|
||||
}
|
||||
|
||||
if (!filters_str && filters) {
|
||||
callback(userdata, NULL, -1);
|
||||
SDL_free(args);
|
||||
|
|
@ -526,7 +534,7 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_
|
|||
args->filters_str = filters_str;
|
||||
args->default_file = default_location ? SDL_strdup(default_location) : NULL;
|
||||
args->parent = window;
|
||||
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
|
||||
args->flags = flags;
|
||||
args->callback = callback;
|
||||
args->userdata = userdata;
|
||||
args->title = title ? SDL_strdup(title) : NULL;
|
||||
|
|
|
|||
|
|
@ -633,9 +633,10 @@ static void SDL_LogEvent(const SDL_Event *event)
|
|||
#undef PRINT_MBUTTON_EVENT
|
||||
|
||||
SDL_EVENT_CASE(SDL_EVENT_MOUSE_WHEEL)
|
||||
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)",
|
||||
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g integer_x=%d integer_y=%d direction=%s)",
|
||||
(uint)event->wheel.timestamp, (uint)event->wheel.windowID,
|
||||
(uint)event->wheel.which, event->wheel.x, event->wheel.y,
|
||||
(int)event->wheel.integer_x, (int)event->wheel.integer_y,
|
||||
event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
|
||||
break;
|
||||
|
||||
|
|
@ -1076,16 +1077,11 @@ static void SDL_SendWakeupEvent(void)
|
|||
return;
|
||||
}
|
||||
|
||||
SDL_LockMutex(_this->wakeup_lock);
|
||||
{
|
||||
if (_this->wakeup_window) {
|
||||
_this->SendWakeupEvent(_this, _this->wakeup_window);
|
||||
|
||||
// No more wakeup events needed until we enter a new wait
|
||||
_this->wakeup_window = NULL;
|
||||
}
|
||||
// We only want to do this once while waiting for an event, so set it to NULL atomically here
|
||||
SDL_Window *wakeup_window = (SDL_Window *)SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
|
||||
if (wakeup_window) {
|
||||
_this->SendWakeupEvent(_this, wakeup_window);
|
||||
}
|
||||
SDL_UnlockMutex(_this->wakeup_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1379,9 +1375,7 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w
|
|||
return true;
|
||||
}
|
||||
|
||||
// Maximum wait of 30 seconds to prevent deadlocking forever
|
||||
const Sint32 MAX_CALLBACK_WAIT = 30 * 1000;
|
||||
SDL_WaitSemaphoreTimeout(entry->semaphore, MAX_CALLBACK_WAIT);
|
||||
SDL_WaitSemaphore(entry->semaphore);
|
||||
|
||||
switch (SDL_GetAtomicInt(&entry->state)) {
|
||||
case SDL_MAIN_CALLBACK_COMPLETE:
|
||||
|
|
@ -1525,18 +1519,7 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
|||
*/
|
||||
SDL_PumpEventsInternal(true);
|
||||
|
||||
SDL_LockMutex(_this->wakeup_lock);
|
||||
{
|
||||
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
// If status == 0 we are going to block so wakeup will be needed.
|
||||
if (status == 0) {
|
||||
_this->wakeup_window = wakeup_window;
|
||||
} else {
|
||||
_this->wakeup_window = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(_this->wakeup_lock);
|
||||
|
||||
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
if (status < 0) {
|
||||
// Got an error: return
|
||||
break;
|
||||
|
|
@ -1549,8 +1532,6 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
|||
if (timeoutNS > 0) {
|
||||
Sint64 elapsed = SDL_GetTicksNS() - start;
|
||||
if (elapsed >= timeoutNS) {
|
||||
// Set wakeup_window to NULL without holding the lock.
|
||||
_this->wakeup_window = NULL;
|
||||
return 0;
|
||||
}
|
||||
loop_timeoutNS = (timeoutNS - elapsed);
|
||||
|
|
@ -1563,9 +1544,9 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
|
|||
loop_timeoutNS = poll_intervalNS;
|
||||
}
|
||||
}
|
||||
SDL_SetAtomicPointer(&_this->wakeup_window, wakeup_window);
|
||||
status = _this->WaitEventTimeout(_this, loop_timeoutNS);
|
||||
// Set wakeup_window to NULL without holding the lock.
|
||||
_this->wakeup_window = NULL;
|
||||
SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
|
||||
if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
|
||||
// We may have woken up to poll. Try again
|
||||
continue;
|
||||
|
|
@ -1823,7 +1804,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
|||
Uint8 lo = (type & 0xff);
|
||||
|
||||
if (SDL_disabled_events[hi] &&
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
|
||||
current_state = false;
|
||||
} else {
|
||||
current_state = true;
|
||||
|
|
@ -1832,7 +1813,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
|||
if ((enabled != false) != current_state) {
|
||||
if (enabled) {
|
||||
SDL_assert(SDL_disabled_events[hi] != NULL);
|
||||
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31));
|
||||
SDL_disabled_events[hi]->bits[lo / 32] &= ~(1U << (lo & 31));
|
||||
|
||||
// Gamepad events depend on joystick events
|
||||
switch (type) {
|
||||
|
|
@ -1863,7 +1844,7 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
|
|||
}
|
||||
// Out of memory, nothing we can do...
|
||||
if (SDL_disabled_events[hi]) {
|
||||
SDL_disabled_events[hi]->bits[lo / 32] |= (1 << (lo & 31));
|
||||
SDL_disabled_events[hi]->bits[lo / 32] |= (1U << (lo & 31));
|
||||
SDL_FlushEvent(type);
|
||||
}
|
||||
}
|
||||
|
|
@ -1882,7 +1863,7 @@ bool SDL_EventEnabled(Uint32 type)
|
|||
Uint8 lo = (type & 0xff);
|
||||
|
||||
if (SDL_disabled_events[hi] &&
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
|
||||
(SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -138,21 +138,25 @@ static void SDLCALL SDL_TouchMouseEventsChanged(void *userdata, const char *name
|
|||
#ifdef SDL_PLATFORM_VITA
|
||||
static void SDLCALL SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
Uint8 vita_touch_mouse_device = 1;
|
||||
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
if (hint) {
|
||||
switch (*hint) {
|
||||
default:
|
||||
case '0':
|
||||
mouse->vita_touch_mouse_device = 1;
|
||||
vita_touch_mouse_device = 1;
|
||||
break;
|
||||
case '1':
|
||||
mouse->vita_touch_mouse_device = 2;
|
||||
vita_touch_mouse_device = 2;
|
||||
break;
|
||||
case '2':
|
||||
mouse->vita_touch_mouse_device = 3;
|
||||
vita_touch_mouse_device = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
mouse->vita_touch_mouse_device = vita_touch_mouse_device;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1022,18 +1026,14 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
|
|||
SDL_SetMouseFocus(window);
|
||||
}
|
||||
|
||||
// Accumulate fractional wheel motion if integer mode is enabled
|
||||
if (mouse->integer_mode_flags & 2) {
|
||||
mouse->integer_mode_residual_scroll_x = SDL_modff(mouse->integer_mode_residual_scroll_x + x, &x);
|
||||
mouse->integer_mode_residual_scroll_y = SDL_modff(mouse->integer_mode_residual_scroll_y + y, &y);
|
||||
}
|
||||
|
||||
if (x == 0.0f && y == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Post the event, if desired
|
||||
if (SDL_EventEnabled(SDL_EVENT_MOUSE_WHEEL)) {
|
||||
float integer_x, integer_y;
|
||||
|
||||
if (!mouse->relative_mode || mouse->warp_emulation_active) {
|
||||
// We're not in relative mode, so all mouse events are global mouse events
|
||||
mouseID = SDL_GLOBAL_MOUSE_ID;
|
||||
|
|
@ -1044,11 +1044,26 @@ void SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
|
|||
event.common.timestamp = timestamp;
|
||||
event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
|
||||
event.wheel.which = mouseID;
|
||||
event.wheel.x = x;
|
||||
event.wheel.y = y;
|
||||
event.wheel.direction = direction;
|
||||
event.wheel.mouse_x = mouse->x;
|
||||
event.wheel.mouse_y = mouse->y;
|
||||
|
||||
mouse->residual_scroll_x = SDL_modff(mouse->residual_scroll_x + x, &integer_x);
|
||||
event.wheel.integer_x = (Sint32)integer_x;
|
||||
|
||||
mouse->residual_scroll_y = SDL_modff(mouse->residual_scroll_y + y, &integer_y);
|
||||
event.wheel.integer_y = (Sint32)integer_y;
|
||||
|
||||
// Return the accumulated values in x/y when integer wheel mode is enabled.
|
||||
// This is necessary for compatibility with sdl2-compat 2.32.54.
|
||||
if (mouse->integer_mode_flags & 2) {
|
||||
event.wheel.x = integer_x;
|
||||
event.wheel.y = integer_y;
|
||||
} else {
|
||||
event.wheel.x = x;
|
||||
event.wheel.y = y;
|
||||
}
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ typedef struct
|
|||
Uint8 integer_mode_flags; // 1 to enable mouse quantization, 2 to enable wheel quantization
|
||||
float integer_mode_residual_motion_x;
|
||||
float integer_mode_residual_motion_y;
|
||||
float integer_mode_residual_scroll_x;
|
||||
float integer_mode_residual_scroll_y;
|
||||
|
||||
// Data common to all mice
|
||||
SDL_Window *focus;
|
||||
|
|
@ -105,6 +103,8 @@ typedef struct
|
|||
float x_accu;
|
||||
float y_accu;
|
||||
float last_x, last_y; // the last reported x and y coordinates
|
||||
float residual_scroll_x;
|
||||
float residual_scroll_y;
|
||||
double click_motion_x;
|
||||
double click_motion_y;
|
||||
bool has_position;
|
||||
|
|
|
|||
|
|
@ -565,10 +565,19 @@ void SDL_SendPenButton(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *wind
|
|||
event.pbutton.down = down;
|
||||
SDL_PushEvent(&event);
|
||||
|
||||
if (window && (pen_touching == instance_id)) {
|
||||
if (window && (!pen_touching || (pen_touching == instance_id))) {
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (mouse && mouse->pen_mouse_events) {
|
||||
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, button + 1, down);
|
||||
static const Uint8 mouse_buttons[] = {
|
||||
SDL_BUTTON_LEFT,
|
||||
SDL_BUTTON_RIGHT,
|
||||
SDL_BUTTON_MIDDLE,
|
||||
SDL_BUTTON_X1,
|
||||
SDL_BUTTON_X2
|
||||
};
|
||||
if (button < SDL_arraysize(mouse_buttons)) {
|
||||
SDL_SendMouseButton(timestamp, window, SDL_PEN_MOUSEID, mouse_buttons[button], down);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,15 +56,47 @@
|
|||
}
|
||||
|
||||
#define CHECK_RENDERPASS \
|
||||
if (!((Pass *)render_pass)->in_progress) { \
|
||||
if (!((RenderPass *)render_pass)->in_progress) { \
|
||||
SDL_assert_release(!"Render pass not in progress!"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
#define CHECK_SAMPLER_TEXTURES \
|
||||
RenderPass *rp = (RenderPass *)render_pass; \
|
||||
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->color_targets[color_target_index] == texture_sampler_bindings[texture_sampler_index].texture) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a sampler!"); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == texture_sampler_bindings[texture_sampler_index].texture) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a sampler!"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_STORAGE_TEXTURES \
|
||||
RenderPass *rp = (RenderPass *)render_pass; \
|
||||
for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->color_targets[color_target_index] == storage_textures[texture_sampler_index]) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a storage texture!"); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
|
||||
if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == storage_textures[texture_sampler_index]) { \
|
||||
SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a storage texture!"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((RenderPass *)render_pass)->graphics_pipeline) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_COMPUTEPASS \
|
||||
|
|
@ -74,7 +106,7 @@
|
|||
}
|
||||
|
||||
#define CHECK_COMPUTE_PIPELINE_BOUND \
|
||||
if (!((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->compute_pipeline_bound) { \
|
||||
if (!((ComputePass *)compute_pass)->compute_pipeline) { \
|
||||
SDL_assert_release(!"Compute pipeline not bound!"); \
|
||||
return; \
|
||||
}
|
||||
|
|
@ -137,23 +169,137 @@
|
|||
((CommandBufferCommonHeader *)command_buffer)->device
|
||||
|
||||
#define RENDERPASS_COMMAND_BUFFER \
|
||||
((Pass *)render_pass)->command_buffer
|
||||
((RenderPass *)render_pass)->command_buffer
|
||||
|
||||
#define RENDERPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device
|
||||
|
||||
#define RENDERPASS_BOUND_PIPELINE \
|
||||
((RenderPass *)render_pass)->graphics_pipeline
|
||||
|
||||
#define COMPUTEPASS_COMMAND_BUFFER \
|
||||
((Pass *)compute_pass)->command_buffer
|
||||
|
||||
#define COMPUTEPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device
|
||||
|
||||
#define COMPUTEPASS_BOUND_PIPELINE \
|
||||
((ComputePass *)compute_pass)->compute_pipeline
|
||||
|
||||
#define COPYPASS_COMMAND_BUFFER \
|
||||
((Pass *)copy_pass)->command_buffer
|
||||
|
||||
#define COPYPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
|
||||
|
||||
static bool TextureFormatIsComputeWritable[] = {
|
||||
false, // INVALID
|
||||
false, // A8_UNORM
|
||||
true, // R8_UNORM
|
||||
true, // R8G8_UNORM
|
||||
true, // R8G8B8A8_UNORM
|
||||
true, // R16_UNORM
|
||||
true, // R16G16_UNORM
|
||||
true, // R16G16B16A16_UNORM
|
||||
true, // R10G10B10A2_UNORM
|
||||
false, // B5G6R5_UNORM
|
||||
false, // B5G5R5A1_UNORM
|
||||
false, // B4G4R4A4_UNORM
|
||||
false, // B8G8R8A8_UNORM
|
||||
false, // BC1_UNORM
|
||||
false, // BC2_UNORM
|
||||
false, // BC3_UNORM
|
||||
false, // BC4_UNORM
|
||||
false, // BC5_UNORM
|
||||
false, // BC7_UNORM
|
||||
false, // BC6H_FLOAT
|
||||
false, // BC6H_UFLOAT
|
||||
true, // R8_SNORM
|
||||
true, // R8G8_SNORM
|
||||
true, // R8G8B8A8_SNORM
|
||||
true, // R16_SNORM
|
||||
true, // R16G16_SNORM
|
||||
true, // R16G16B16A16_SNORM
|
||||
true, // R16_FLOAT
|
||||
true, // R16G16_FLOAT
|
||||
true, // R16G16B16A16_FLOAT
|
||||
true, // R32_FLOAT
|
||||
true, // R32G32_FLOAT
|
||||
true, // R32G32B32A32_FLOAT
|
||||
true, // R11G11B10_UFLOAT
|
||||
true, // R8_UINT
|
||||
true, // R8G8_UINT
|
||||
true, // R8G8B8A8_UINT
|
||||
true, // R16_UINT
|
||||
true, // R16G16_UINT
|
||||
true, // R16G16B16A16_UINT
|
||||
true, // R32_UINT
|
||||
true, // R32G32_UINT
|
||||
true, // R32G32B32A32_UINT
|
||||
true, // R8_INT
|
||||
true, // R8G8_INT
|
||||
true, // R8G8B8A8_INT
|
||||
true, // R16_INT
|
||||
true, // R16G16_INT
|
||||
true, // R16G16B16A16_INT
|
||||
true, // R32_INT
|
||||
true, // R32G32_INT
|
||||
true, // R32G32B32A32_INT
|
||||
false, // R8G8B8A8_UNORM_SRGB
|
||||
false, // B8G8R8A8_UNORM_SRGB
|
||||
false, // BC1_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC7_UNORM_SRGB
|
||||
false, // D16_UNORM
|
||||
false, // D24_UNORM
|
||||
false, // D32_FLOAT
|
||||
false, // D24_UNORM_S8_UINT
|
||||
false, // D32_FLOAT_S8_UINT
|
||||
false, // ASTC_4x4_UNORM
|
||||
false, // ASTC_5x4_UNORM
|
||||
false, // ASTC_5x5_UNORM
|
||||
false, // ASTC_6x5_UNORM
|
||||
false, // ASTC_6x6_UNORM
|
||||
false, // ASTC_8x5_UNORM
|
||||
false, // ASTC_8x6_UNORM
|
||||
false, // ASTC_8x8_UNORM
|
||||
false, // ASTC_10x5_UNORM
|
||||
false, // ASTC_10x6_UNORM
|
||||
false, // ASTC_10x8_UNORM
|
||||
false, // ASTC_10x10_UNORM
|
||||
false, // ASTC_12x10_UNORM
|
||||
false, // ASTC_12x12_UNORM
|
||||
false, // ASTC_4x4_UNORM_SRGB
|
||||
false, // ASTC_5x4_UNORM_SRGB
|
||||
false, // ASTC_5x5_UNORM_SRGB
|
||||
false, // ASTC_6x5_UNORM_SRGB
|
||||
false, // ASTC_6x6_UNORM_SRGB
|
||||
false, // ASTC_8x5_UNORM_SRGB
|
||||
false, // ASTC_8x6_UNORM_SRGB
|
||||
false, // ASTC_8x8_UNORM_SRGB
|
||||
false, // ASTC_10x5_UNORM_SRGB
|
||||
false, // ASTC_10x6_UNORM_SRGB
|
||||
false, // ASTC_10x8_UNORM_SRGB
|
||||
false, // ASTC_10x10_UNORM_SRGB
|
||||
false, // ASTC_12x10_UNORM_SRGB
|
||||
false, // ASTC_12x12_UNORM_SRGB
|
||||
false, // ASTC_4x4_FLOAT
|
||||
false, // ASTC_5x4_FLOAT
|
||||
false, // ASTC_5x5_FLOAT
|
||||
false, // ASTC_6x5_FLOAT
|
||||
false, // ASTC_6x6_FLOAT
|
||||
false, // ASTC_8x5_FLOAT
|
||||
false, // ASTC_8x6_FLOAT
|
||||
false, // ASTC_8x8_FLOAT
|
||||
false, // ASTC_10x5_FLOAT
|
||||
false, // ASTC_10x6_FLOAT
|
||||
false, // ASTC_10x8_FLOAT
|
||||
false, // ASTC_10x10_FLOAT
|
||||
false, // ASTC_12x10_FLOAT
|
||||
false // ASTC_12x12_FLOAT
|
||||
};
|
||||
|
||||
// Drivers
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
|
|
@ -371,6 +517,73 @@ void SDL_GPU_BlitCommon(
|
|||
SDL_EndGPURenderPass(render_pass);
|
||||
}
|
||||
|
||||
static void SDL_GPU_CheckGraphicsBindings(SDL_GPURenderPass *render_pass)
|
||||
{
|
||||
RenderPass *rp = (RenderPass *)render_pass;
|
||||
GraphicsPipelineCommonHeader *pipeline = (GraphicsPipelineCommonHeader *)RENDERPASS_BOUND_PIPELINE;
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_samplers; i += 1) {
|
||||
if (!rp->vertex_sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_storage_textures; i += 1) {
|
||||
if (!rp->vertex_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_vertex_storage_buffers; i += 1) {
|
||||
if (!rp->vertex_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing vertex storage buffer binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_samplers; i += 1) {
|
||||
if (!rp->fragment_sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_storage_textures; i += 1) {
|
||||
if (!rp->fragment_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->num_fragment_storage_buffers; i += 1) {
|
||||
if (!rp->fragment_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing fragment storage buffer binding!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_GPU_CheckComputeBindings(SDL_GPUComputePass *compute_pass)
|
||||
{
|
||||
ComputePass *cp = (ComputePass *)compute_pass;
|
||||
ComputePipelineCommonHeader *pipeline = (ComputePipelineCommonHeader *)COMPUTEPASS_BOUND_PIPELINE;
|
||||
for (Uint32 i = 0; i < pipeline->numSamplers; i += 1) {
|
||||
if (!cp->sampler_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute sampler binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadonlyStorageTextures; i += 1) {
|
||||
if (!cp->read_only_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute readonly storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadonlyStorageBuffers; i += 1) {
|
||||
if (!cp->read_only_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute readonly storage buffer binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageTextures; i += 1) {
|
||||
if (!cp->read_write_storage_texture_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute read-write storage texture binding!");
|
||||
}
|
||||
}
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageBuffers; i += 1) {
|
||||
if (!cp->read_write_storage_buffer_bound[i]) {
|
||||
SDL_assert_release(!"Missing compute read-write storage buffer bbinding!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Functions
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
|
|
@ -532,7 +745,6 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
|
|||
result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props);
|
||||
if (result != NULL) {
|
||||
result->backend = selectedBackend->name;
|
||||
result->shader_formats = selectedBackend->shader_formats;
|
||||
result->debug_mode = debug_mode;
|
||||
}
|
||||
}
|
||||
|
|
@ -721,6 +933,13 @@ bool SDL_GPUTextureSupportsFormat(
|
|||
CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false)
|
||||
}
|
||||
|
||||
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
|
||||
(usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
|
||||
if (!TextureFormatIsComputeWritable[format]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return device->SupportsTextureFormat(
|
||||
device->driverData,
|
||||
format,
|
||||
|
|
@ -1343,15 +1562,29 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
|
|||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->device = device;
|
||||
commandBufferHeader->render_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->graphics_pipeline_bound = false;
|
||||
commandBufferHeader->compute_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pipeline_bound = false;
|
||||
commandBufferHeader->copy_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
|
||||
if (device->debug_mode) {
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->render_pass.graphics_pipeline = NULL;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pass.compute_pipeline = NULL;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
|
||||
return command_buffer;
|
||||
}
|
||||
|
|
@ -1469,30 +1702,47 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
|
||||
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
|
||||
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
if (color_target_infos[i].resolve_texture == NULL) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
|
||||
return NULL;
|
||||
} else {
|
||||
TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
|
||||
if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Resolve texture must have a sample count of 1!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.format != textureHeader->info.format) {
|
||||
SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
|
||||
return NULL;
|
||||
}
|
||||
if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
|
||||
SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
|
||||
SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
|
|
@ -1500,10 +1750,12 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
|
||||
if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
|
||||
SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
|
||||
SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
|
||||
|
|
@ -1511,6 +1763,7 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
|
||||
depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1522,7 +1775,18 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
depth_stencil_target_info);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->render_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->render_pass.in_progress = true;
|
||||
for (Uint32 i = 0; i < num_color_targets; i += 1) {
|
||||
commandBufferHeader->render_pass.color_targets[i] = color_target_infos[i].texture;
|
||||
}
|
||||
commandBufferHeader->render_pass.num_color_targets = num_color_targets;
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
commandBufferHeader->render_pass.depth_stencil_target = depth_stencil_target_info->texture;
|
||||
}
|
||||
}
|
||||
|
||||
return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass);
|
||||
}
|
||||
|
||||
|
|
@ -1530,8 +1794,6 @@ void SDL_BindGPUGraphicsPipeline(
|
|||
SDL_GPURenderPass *render_pass,
|
||||
SDL_GPUGraphicsPipeline *graphics_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
return;
|
||||
|
|
@ -1545,8 +1807,10 @@ void SDL_BindGPUGraphicsPipeline(
|
|||
RENDERPASS_COMMAND_BUFFER,
|
||||
graphics_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->graphics_pipeline_bound = true;
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
RENDERPASS_BOUND_PIPELINE = graphics_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_SetGPUViewport(
|
||||
|
|
@ -1696,6 +1960,15 @@ void SDL_BindGPUVertexSamplers(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
|
||||
{
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexSamplers(
|
||||
|
|
@ -1722,6 +1995,11 @@ void SDL_BindGPUVertexStorageTextures(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_STORAGE_TEXTURES
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexStorageTextures(
|
||||
|
|
@ -1748,6 +2026,10 @@ void SDL_BindGPUVertexStorageBuffers(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexStorageBuffers(
|
||||
|
|
@ -1774,6 +2056,14 @@ void SDL_BindGPUFragmentSamplers(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation) {
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentSamplers(
|
||||
|
|
@ -1800,6 +2090,11 @@ void SDL_BindGPUFragmentStorageTextures(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_STORAGE_TEXTURES
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentStorageTextures(
|
||||
|
|
@ -1826,6 +2121,10 @@ void SDL_BindGPUFragmentStorageBuffers(
|
|||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentStorageBuffers(
|
||||
|
|
@ -1851,6 +2150,7 @@ void SDL_DrawGPUIndexedPrimitives(
|
|||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitives(
|
||||
|
|
@ -1877,6 +2177,7 @@ void SDL_DrawGPUPrimitives(
|
|||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitives(
|
||||
|
|
@ -1905,6 +2206,7 @@ void SDL_DrawGPUPrimitivesIndirect(
|
|||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitivesIndirect(
|
||||
|
|
@ -1932,6 +2234,7 @@ void SDL_DrawGPUIndexedPrimitivesIndirect(
|
|||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
|
||||
|
|
@ -1945,6 +2248,7 @@ void SDL_EndGPURenderPass(
|
|||
SDL_GPURenderPass *render_pass)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferCommonHeader;
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
|
|
@ -1958,9 +2262,22 @@ void SDL_EndGPURenderPass(
|
|||
RENDERPASS_DEVICE->EndRenderPass(
|
||||
RENDERPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->render_pass.in_progress = false;
|
||||
commandBufferCommonHeader->graphics_pipeline_bound = false;
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
commandBufferCommonHeader->render_pass.in_progress = false;
|
||||
for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
|
||||
{
|
||||
commandBufferCommonHeader->render_pass.color_targets[i] = NULL;
|
||||
}
|
||||
commandBufferCommonHeader->render_pass.num_color_targets = 0;
|
||||
commandBufferCommonHeader->render_pass.depth_stencil_target = NULL;
|
||||
commandBufferCommonHeader->render_pass.graphics_pipeline = NULL;
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_buffer_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute Pass
|
||||
|
|
@ -2004,6 +2321,16 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
|||
SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
|
||||
SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate buffer usage?
|
||||
|
|
@ -2017,7 +2344,19 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
|||
num_storage_buffer_bindings);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_texture_bound[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_buffer_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_buffer_bound[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
|
||||
}
|
||||
|
||||
|
|
@ -2025,8 +2364,6 @@ void SDL_BindGPUComputePipeline(
|
|||
SDL_GPUComputePass *compute_pass,
|
||||
SDL_GPUComputePipeline *compute_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (compute_pass == NULL) {
|
||||
SDL_InvalidParamError("compute_pass");
|
||||
return;
|
||||
|
|
@ -2044,8 +2381,10 @@ void SDL_BindGPUComputePipeline(
|
|||
COMPUTEPASS_COMMAND_BUFFER,
|
||||
compute_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->compute_pipeline_bound = true;
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
COMPUTEPASS_BOUND_PIPELINE = compute_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BindGPUComputeSamplers(
|
||||
|
|
@ -2065,6 +2404,10 @@ void SDL_BindGPUComputeSamplers(
|
|||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeSamplers(
|
||||
|
|
@ -2091,6 +2434,10 @@ void SDL_BindGPUComputeStorageTextures(
|
|||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageTextures(
|
||||
|
|
@ -2117,6 +2464,10 @@ void SDL_BindGPUComputeStorageBuffers(
|
|||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
|
||||
|
|
@ -2140,6 +2491,7 @@ void SDL_DispatchGPUCompute(
|
|||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchCompute(
|
||||
|
|
@ -2162,6 +2514,7 @@ void SDL_DispatchGPUComputeIndirect(
|
|||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchComputeIndirect(
|
||||
|
|
@ -2187,9 +2540,16 @@ void SDL_EndGPUComputePass(
|
|||
COMPUTEPASS_DEVICE->EndComputePass(
|
||||
COMPUTEPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pipeline_bound = false;
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pass.compute_pipeline = false;
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// TransferBuffer Data
|
||||
|
|
@ -2247,7 +2607,11 @@ SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
|
|||
command_buffer);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
}
|
||||
|
||||
return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
|
||||
}
|
||||
|
||||
|
|
@ -2498,7 +2862,9 @@ void SDL_EndGPUCopyPass(
|
|||
COPYPASS_DEVICE->EndCopyPass(
|
||||
COPYPASS_COMMAND_BUFFER);
|
||||
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
if (COPYPASS_DEVICE->debug_mode) {
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_GenerateMipmapsForGPUTexture(
|
||||
|
|
@ -2528,11 +2894,19 @@ void SDL_GenerateMipmapsForGPUTexture(
|
|||
SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = true;
|
||||
}
|
||||
|
||||
COMMAND_BUFFER_DEVICE->GenerateMipmaps(
|
||||
command_buffer,
|
||||
texture);
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BlitGPUTexture(
|
||||
|
|
|
|||
|
|
@ -24,6 +24,21 @@
|
|||
#ifndef SDL_GPU_DRIVER_H
|
||||
#define SDL_GPU_DRIVER_H
|
||||
|
||||
// GraphicsDevice Limits
|
||||
|
||||
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
|
||||
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
|
||||
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
|
||||
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
|
||||
#define MAX_COMPUTE_WRITE_TEXTURES 8
|
||||
#define MAX_COMPUTE_WRITE_BUFFERS 8
|
||||
#define UNIFORM_BUFFER_SIZE 32768
|
||||
#define MAX_VERTEX_BUFFERS 16
|
||||
#define MAX_VERTEX_ATTRIBUTES 16
|
||||
#define MAX_COLOR_TARGET_BINDINGS 4
|
||||
#define MAX_PRESENT_COUNT 16
|
||||
#define MAX_FRAMES_IN_FLIGHT 3
|
||||
|
||||
// Common Structs
|
||||
|
||||
typedef struct Pass
|
||||
|
|
@ -32,16 +47,51 @@ typedef struct Pass
|
|||
bool in_progress;
|
||||
} Pass;
|
||||
|
||||
typedef struct ComputePass
|
||||
{
|
||||
SDL_GPUCommandBuffer *command_buffer;
|
||||
bool in_progress;
|
||||
|
||||
SDL_GPUComputePipeline *compute_pipeline;
|
||||
|
||||
bool sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool read_only_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool read_only_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
bool read_write_storage_texture_bound[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
bool read_write_storage_buffer_bound[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
} ComputePass;
|
||||
|
||||
typedef struct RenderPass
|
||||
{
|
||||
SDL_GPUCommandBuffer *command_buffer;
|
||||
bool in_progress;
|
||||
SDL_GPUTexture *color_targets[MAX_COLOR_TARGET_BINDINGS];
|
||||
Uint32 num_color_targets;
|
||||
SDL_GPUTexture *depth_stencil_target;
|
||||
|
||||
SDL_GPUGraphicsPipeline *graphics_pipeline;
|
||||
|
||||
bool vertex_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool vertex_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool vertex_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
bool fragment_sampler_bound[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
bool fragment_storage_texture_bound[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
bool fragment_storage_buffer_bound[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
} RenderPass;
|
||||
|
||||
typedef struct CommandBufferCommonHeader
|
||||
{
|
||||
SDL_GPUDevice *device;
|
||||
Pass render_pass;
|
||||
bool graphics_pipeline_bound;
|
||||
Pass compute_pass;
|
||||
bool compute_pipeline_bound;
|
||||
|
||||
RenderPass render_pass;
|
||||
ComputePass compute_pass;
|
||||
|
||||
Pass copy_pass;
|
||||
bool swapchain_texture_acquired;
|
||||
bool submitted;
|
||||
// used to avoid tripping assert on GenerateMipmaps
|
||||
bool ignore_render_pass_texture_validation;
|
||||
} CommandBufferCommonHeader;
|
||||
|
||||
typedef struct TextureCommonHeader
|
||||
|
|
@ -49,6 +99,29 @@ typedef struct TextureCommonHeader
|
|||
SDL_GPUTextureCreateInfo info;
|
||||
} TextureCommonHeader;
|
||||
|
||||
typedef struct GraphicsPipelineCommonHeader
|
||||
{
|
||||
Uint32 num_vertex_samplers;
|
||||
Uint32 num_vertex_storage_textures;
|
||||
Uint32 num_vertex_storage_buffers;
|
||||
Uint32 num_vertex_uniform_buffers;
|
||||
|
||||
Uint32 num_fragment_samplers;
|
||||
Uint32 num_fragment_storage_textures;
|
||||
Uint32 num_fragment_storage_buffers;
|
||||
Uint32 num_fragment_uniform_buffers;
|
||||
} GraphicsPipelineCommonHeader;
|
||||
|
||||
typedef struct ComputePipelineCommonHeader
|
||||
{
|
||||
Uint32 numSamplers;
|
||||
Uint32 numReadonlyStorageTextures;
|
||||
Uint32 numReadonlyStorageBuffers;
|
||||
Uint32 numReadWriteStorageTextures;
|
||||
Uint32 numReadWriteStorageBuffers;
|
||||
Uint32 numUniformBuffers;
|
||||
} ComputePipelineCommonHeader;
|
||||
|
||||
typedef struct BlitFragmentUniforms
|
||||
{
|
||||
// texcoord space
|
||||
|
|
@ -136,6 +209,7 @@ static inline Sint32 Texture_GetBlockWidth(
|
|||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM:
|
||||
|
|
@ -253,6 +327,7 @@ static inline Sint32 Texture_GetBlockHeight(
|
|||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
|
||||
case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM:
|
||||
|
|
@ -385,21 +460,6 @@ static inline Uint32 BytesPerRow(
|
|||
return blocksPerRow * SDL_GPUTextureFormatTexelBlockSize(format);
|
||||
}
|
||||
|
||||
// GraphicsDevice Limits
|
||||
|
||||
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
|
||||
#define MAX_STORAGE_TEXTURES_PER_STAGE 8
|
||||
#define MAX_STORAGE_BUFFERS_PER_STAGE 8
|
||||
#define MAX_UNIFORM_BUFFERS_PER_STAGE 4
|
||||
#define MAX_COMPUTE_WRITE_TEXTURES 8
|
||||
#define MAX_COMPUTE_WRITE_BUFFERS 8
|
||||
#define UNIFORM_BUFFER_SIZE 32768
|
||||
#define MAX_VERTEX_BUFFERS 16
|
||||
#define MAX_VERTEX_ATTRIBUTES 16
|
||||
#define MAX_COLOR_TARGET_BINDINGS 4
|
||||
#define MAX_PRESENT_COUNT 16
|
||||
#define MAX_FRAMES_IN_FLIGHT 3
|
||||
|
||||
// Internal Macros
|
||||
|
||||
#define EXPAND_ARRAY_IF_NEEDED(arr, elementType, newCount, capacity, newCapacity) \
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -476,33 +476,21 @@ typedef struct MetalShader
|
|||
|
||||
typedef struct MetalGraphicsPipeline
|
||||
{
|
||||
GraphicsPipelineCommonHeader header;
|
||||
|
||||
id<MTLRenderPipelineState> handle;
|
||||
|
||||
SDL_GPURasterizerState rasterizerState;
|
||||
SDL_GPUPrimitiveType primitiveType;
|
||||
|
||||
id<MTLDepthStencilState> depth_stencil_state;
|
||||
|
||||
Uint32 vertexSamplerCount;
|
||||
Uint32 vertexUniformBufferCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexStorageTextureCount;
|
||||
|
||||
Uint32 fragmentSamplerCount;
|
||||
Uint32 fragmentUniformBufferCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentStorageTextureCount;
|
||||
} MetalGraphicsPipeline;
|
||||
|
||||
typedef struct MetalComputePipeline
|
||||
{
|
||||
ComputePipelineCommonHeader header;
|
||||
|
||||
id<MTLComputePipelineState> handle;
|
||||
Uint32 numSamplers;
|
||||
Uint32 numReadonlyStorageTextures;
|
||||
Uint32 numReadWriteStorageTextures;
|
||||
Uint32 numReadonlyStorageBuffers;
|
||||
Uint32 numReadWriteStorageBuffers;
|
||||
Uint32 numUniformBuffers;
|
||||
Uint32 threadcountX;
|
||||
Uint32 threadcountY;
|
||||
Uint32 threadcountZ;
|
||||
|
|
@ -840,6 +828,10 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader(
|
|||
dispatch_data_t data;
|
||||
id<MTLFunction> function;
|
||||
|
||||
if (!entrypoint) {
|
||||
entrypoint = "main0";
|
||||
}
|
||||
|
||||
if (format == SDL_GPU_SHADERFORMAT_MSL) {
|
||||
NSString *codeString = [[NSString alloc]
|
||||
initWithBytes:code
|
||||
|
|
@ -1055,12 +1047,12 @@ static SDL_GPUComputePipeline *METAL_CreateComputePipeline(
|
|||
|
||||
pipeline = SDL_calloc(1, sizeof(MetalComputePipeline));
|
||||
pipeline->handle = handle;
|
||||
pipeline->numSamplers = createinfo->num_samplers;
|
||||
pipeline->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
pipeline->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
pipeline->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
pipeline->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
pipeline->numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
pipeline->header.numSamplers = createinfo->num_samplers;
|
||||
pipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
pipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
pipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
pipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
pipeline->header.numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
pipeline->threadcountX = createinfo->threadcount_x;
|
||||
pipeline->threadcountY = createinfo->threadcount_y;
|
||||
pipeline->threadcountZ = createinfo->threadcount_z;
|
||||
|
|
@ -1203,14 +1195,14 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
|
|||
result->depth_stencil_state = depthStencilState;
|
||||
result->rasterizerState = createinfo->rasterizer_state;
|
||||
result->primitiveType = createinfo->primitive_type;
|
||||
result->vertexSamplerCount = vertexShader->numSamplers;
|
||||
result->vertexUniformBufferCount = vertexShader->numUniformBuffers;
|
||||
result->vertexStorageBufferCount = vertexShader->numStorageBuffers;
|
||||
result->vertexStorageTextureCount = vertexShader->numStorageTextures;
|
||||
result->fragmentSamplerCount = fragmentShader->numSamplers;
|
||||
result->fragmentUniformBufferCount = fragmentShader->numUniformBuffers;
|
||||
result->fragmentStorageBufferCount = fragmentShader->numStorageBuffers;
|
||||
result->fragmentStorageTextureCount = fragmentShader->numStorageTextures;
|
||||
result->header.num_vertex_samplers = vertexShader->numSamplers;
|
||||
result->header.num_vertex_uniform_buffers = vertexShader->numUniformBuffers;
|
||||
result->header.num_vertex_storage_buffers = vertexShader->numStorageBuffers;
|
||||
result->header.num_vertex_storage_textures = vertexShader->numStorageTextures;
|
||||
result->header.num_fragment_samplers = fragmentShader->numSamplers;
|
||||
result->header.num_fragment_uniform_buffers = fragmentShader->numUniformBuffers;
|
||||
result->header.num_fragment_storage_buffers = fragmentShader->numStorageBuffers;
|
||||
result->header.num_fragment_storage_textures = fragmentShader->numStorageTextures;
|
||||
return (SDL_GPUGraphicsPipeline *)result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1494,7 +1486,9 @@ static SDL_GPUTexture *METAL_CreateTexture(
|
|||
// Copy properties so we don't lose information when the client destroys them
|
||||
container->header.info = *createinfo;
|
||||
container->header.info.props = SDL_CreateProperties();
|
||||
SDL_CopyProperties(createinfo->props, container->header.info.props);
|
||||
if (createinfo->props) {
|
||||
SDL_CopyProperties(createinfo->props, container->header.info.props);
|
||||
}
|
||||
|
||||
container->activeTexture = texture;
|
||||
container->textureCapacity = 1;
|
||||
|
|
@ -2406,14 +2400,14 @@ static void METAL_BindGraphicsPipeline(
|
|||
metalCommandBuffer->needFragmentUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->vertexUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) {
|
||||
if (metalCommandBuffer->vertexUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->vertexUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->fragmentUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) {
|
||||
if (metalCommandBuffer->fragmentUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->fragmentUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
|
|
@ -2644,11 +2638,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Vertex Samplers+Textures
|
||||
|
||||
if (commandBuffer->needVertexSamplerBind) {
|
||||
if (graphicsPipeline->vertexSamplerCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_samplers > 0) {
|
||||
[commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers
|
||||
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
|
||||
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures
|
||||
withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_vertex_samplers)];
|
||||
}
|
||||
commandBuffer->needVertexSamplerBind = false;
|
||||
}
|
||||
|
|
@ -2656,10 +2650,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Vertex Storage Textures
|
||||
|
||||
if (commandBuffer->needVertexStorageTextureBind) {
|
||||
if (graphicsPipeline->vertexStorageTextureCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_storage_textures > 0) {
|
||||
[commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures
|
||||
withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount,
|
||||
graphicsPipeline->vertexStorageTextureCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_samplers,
|
||||
graphicsPipeline->header.num_vertex_storage_textures)];
|
||||
}
|
||||
commandBuffer->needVertexStorageTextureBind = false;
|
||||
}
|
||||
|
|
@ -2667,20 +2661,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Vertex Storage Buffers
|
||||
|
||||
if (commandBuffer->needVertexStorageBufferBind) {
|
||||
if (graphicsPipeline->vertexStorageBufferCount > 0) {
|
||||
if (graphicsPipeline->header.num_vertex_storage_buffers > 0) {
|
||||
[commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount,
|
||||
graphicsPipeline->vertexStorageBufferCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_vertex_uniform_buffers,
|
||||
graphicsPipeline->header.num_vertex_storage_buffers)];
|
||||
}
|
||||
commandBuffer->needVertexStorageBufferBind = false;
|
||||
}
|
||||
|
||||
// Vertex Uniform Buffers
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_uniform_buffers; i += 1) {
|
||||
if (commandBuffer->needVertexUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->vertexUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_vertex_uniform_buffers > i) {
|
||||
[commandBuffer->renderEncoder
|
||||
setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle
|
||||
offset:commandBuffer->vertexUniformBuffers[i]->drawOffset
|
||||
|
|
@ -2693,11 +2687,11 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Fragment Samplers+Textures
|
||||
|
||||
if (commandBuffer->needFragmentSamplerBind) {
|
||||
if (graphicsPipeline->fragmentSamplerCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_samplers > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers
|
||||
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
|
||||
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures
|
||||
withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
|
||||
withRange:NSMakeRange(0, graphicsPipeline->header.num_fragment_samplers)];
|
||||
}
|
||||
commandBuffer->needFragmentSamplerBind = false;
|
||||
}
|
||||
|
|
@ -2705,10 +2699,10 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Fragment Storage Textures
|
||||
|
||||
if (commandBuffer->needFragmentStorageTextureBind) {
|
||||
if (graphicsPipeline->fragmentStorageTextureCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_storage_textures > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures
|
||||
withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount,
|
||||
graphicsPipeline->fragmentStorageTextureCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_samplers,
|
||||
graphicsPipeline->header.num_fragment_storage_textures)];
|
||||
}
|
||||
commandBuffer->needFragmentStorageTextureBind = false;
|
||||
}
|
||||
|
|
@ -2716,20 +2710,20 @@ static void METAL_INTERNAL_BindGraphicsResources(
|
|||
// Fragment Storage Buffers
|
||||
|
||||
if (commandBuffer->needFragmentStorageBufferBind) {
|
||||
if (graphicsPipeline->fragmentStorageBufferCount > 0) {
|
||||
if (graphicsPipeline->header.num_fragment_storage_buffers > 0) {
|
||||
[commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount,
|
||||
graphicsPipeline->fragmentStorageBufferCount)];
|
||||
withRange:NSMakeRange(graphicsPipeline->header.num_fragment_uniform_buffers,
|
||||
graphicsPipeline->header.num_fragment_storage_buffers)];
|
||||
}
|
||||
commandBuffer->needFragmentStorageBufferBind = false;
|
||||
}
|
||||
|
||||
// Fragment Uniform Buffers
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_uniform_buffers; i += 1) {
|
||||
if (commandBuffer->needFragmentUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->fragmentUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_fragment_uniform_buffers > i) {
|
||||
[commandBuffer->renderEncoder
|
||||
setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle
|
||||
offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset
|
||||
|
|
@ -2748,38 +2742,38 @@ static void METAL_INTERNAL_BindComputeResources(
|
|||
NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 };
|
||||
|
||||
if (commandBuffer->needComputeSamplerBind) {
|
||||
if (computePipeline->numSamplers > 0) {
|
||||
if (computePipeline->header.numSamplers > 0) {
|
||||
[commandBuffer->computeEncoder setTextures:commandBuffer->computeSamplerTextures
|
||||
withRange:NSMakeRange(0, computePipeline->numSamplers)];
|
||||
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
|
||||
[commandBuffer->computeEncoder setSamplerStates:commandBuffer->computeSamplers
|
||||
withRange:NSMakeRange(0, computePipeline->numSamplers)];
|
||||
withRange:NSMakeRange(0, computePipeline->header.numSamplers)];
|
||||
}
|
||||
commandBuffer->needComputeSamplerBind = false;
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageTextureBind) {
|
||||
if (computePipeline->numReadonlyStorageTextures > 0) {
|
||||
if (computePipeline->header.numReadonlyStorageTextures > 0) {
|
||||
[commandBuffer->computeEncoder setTextures:commandBuffer->computeReadOnlyTextures
|
||||
withRange:NSMakeRange(
|
||||
computePipeline->numSamplers,
|
||||
computePipeline->numReadonlyStorageTextures)];
|
||||
computePipeline->header.numSamplers,
|
||||
computePipeline->header.numReadonlyStorageTextures)];
|
||||
}
|
||||
commandBuffer->needComputeReadOnlyStorageTextureBind = false;
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageBufferBind) {
|
||||
if (computePipeline->numReadonlyStorageBuffers > 0) {
|
||||
if (computePipeline->header.numReadonlyStorageBuffers > 0) {
|
||||
[commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadOnlyBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(computePipeline->numUniformBuffers,
|
||||
computePipeline->numReadonlyStorageBuffers)];
|
||||
withRange:NSMakeRange(computePipeline->header.numUniformBuffers,
|
||||
computePipeline->header.numReadonlyStorageBuffers)];
|
||||
}
|
||||
commandBuffer->needComputeReadOnlyStorageBufferBind = false;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
|
||||
if (commandBuffer->needComputeUniformBufferBind[i]) {
|
||||
if (computePipeline->numUniformBuffers > i) {
|
||||
if (computePipeline->header.numUniformBuffers > i) {
|
||||
[commandBuffer->computeEncoder
|
||||
setBuffer:commandBuffer->computeUniformBuffers[i]->handle
|
||||
offset:commandBuffer->computeUniformBuffers[i]->drawOffset
|
||||
|
|
@ -3127,7 +3121,7 @@ static void METAL_BindComputePipeline(
|
|||
metalCommandBuffer->needComputeUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < pipeline->numUniformBuffers; i += 1) {
|
||||
for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) {
|
||||
if (metalCommandBuffer->computeUniformBuffers[i] == NULL) {
|
||||
metalCommandBuffer->computeUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
|
||||
metalCommandBuffer);
|
||||
|
|
@ -3135,22 +3129,22 @@ static void METAL_BindComputePipeline(
|
|||
}
|
||||
|
||||
// Bind write-only resources
|
||||
if (pipeline->numReadWriteStorageTextures > 0) {
|
||||
if (pipeline->header.numReadWriteStorageTextures > 0) {
|
||||
[metalCommandBuffer->computeEncoder setTextures:metalCommandBuffer->computeReadWriteTextures
|
||||
withRange:NSMakeRange(
|
||||
pipeline->numSamplers +
|
||||
pipeline->numReadonlyStorageTextures,
|
||||
pipeline->numReadWriteStorageTextures)];
|
||||
pipeline->header.numSamplers +
|
||||
pipeline->header.numReadonlyStorageTextures,
|
||||
pipeline->header.numReadWriteStorageTextures)];
|
||||
}
|
||||
|
||||
NSUInteger offsets[MAX_COMPUTE_WRITE_BUFFERS] = { 0 };
|
||||
if (pipeline->numReadWriteStorageBuffers > 0) {
|
||||
if (pipeline->header.numReadWriteStorageBuffers > 0) {
|
||||
[metalCommandBuffer->computeEncoder setBuffers:metalCommandBuffer->computeReadWriteBuffers
|
||||
offsets:offsets
|
||||
withRange:NSMakeRange(
|
||||
pipeline->numUniformBuffers +
|
||||
pipeline->numReadonlyStorageBuffers,
|
||||
pipeline->numReadWriteStorageBuffers)];
|
||||
pipeline->header.numUniformBuffers +
|
||||
pipeline->header.numReadonlyStorageBuffers,
|
||||
pipeline->header.numReadWriteStorageBuffers)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4564,6 +4558,7 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD
|
|||
SDL_GPUDevice *result = SDL_calloc(1, sizeof(SDL_GPUDevice));
|
||||
ASSIGN_DRIVER(METAL)
|
||||
result->driverData = (SDL_GPURenderer *)renderer;
|
||||
result->shader_formats = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
|
||||
renderer->sdlGPUDevice = result;
|
||||
|
||||
return result;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -807,6 +807,8 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
|
|||
#define hid_send_feature_report LIBUSB_hid_send_feature_report
|
||||
#define hid_set_nonblocking LIBUSB_hid_set_nonblocking
|
||||
#define hid_write LIBUSB_hid_write
|
||||
#define hid_version LIBUSB_hid_version
|
||||
#define hid_version_str LIBUSB_hid_version_str
|
||||
#define input_report LIBUSB_input_report
|
||||
#define make_path LIBUSB_make_path
|
||||
#define new_hid_device LIBUSB_new_hid_device
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@
|
|||
#define wcsstr SDL_wcsstr
|
||||
#define wcstol SDL_wcstol
|
||||
|
||||
// These functions conflict when linking both SDL and hidapi statically
|
||||
#define hid_winapi_descriptor_reconstruct_pp_data SDL_hid_winapi_descriptor_reconstruct_pp_data
|
||||
#define hid_winapi_get_container_id SDL_hid_winapi_get_container_id
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "windows/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
|
|
|
|||
|
|
@ -1238,6 +1238,7 @@ static void init_xbox360(libusb_device_handle *device_handle, unsigned short idV
|
|||
(void)conf_desc;
|
||||
|
||||
if ((idVendor == 0x05ac && idProduct == 0x055b) /* Gamesir-G3w */ ||
|
||||
(idVendor == 0x20d6 && idProduct == 0x4010) /* PowerA Battle Dragon Advanced Wireless Controller */ ||
|
||||
idVendor == 0x0f0d /* Hori Xbox controllers */) {
|
||||
unsigned char data[20];
|
||||
|
||||
|
|
|
|||
|
|
@ -775,13 +775,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||
// All other gamepads have the standard set of 19 buttons and 6 axes
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
|
||||
|
||||
if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
|
||||
// XBox Series X Controllers have a share button under the guide button
|
||||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickXboxOneElite(vendor, product)) {
|
||||
// XBox One Elite Controllers have 4 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickSteamController(vendor, product)) {
|
||||
if (SDL_IsJoystickSteamController(vendor, product)) {
|
||||
// Steam controllers have 2 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickNintendoSwitchPro(vendor, product) ||
|
||||
|
|
@ -822,6 +816,15 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||
SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,paddle3:b14,paddle4:b13,", sizeof(mapping_string));
|
||||
}
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||
if (SDL_IsJoystickXboxOneElite(vendor, product)) {
|
||||
// XBox One Elite Controllers have 4 back paddle buttons
|
||||
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickXboxSeriesX(vendor, product)) {
|
||||
// XBox Series X Controllers have a share button under the guide button
|
||||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (vendor == 0 && product == 0) {
|
||||
// This is a Bluetooth Nintendo Switch Pro controller
|
||||
|
|
@ -2751,6 +2754,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
|||
|
||||
gamepad->joystick = SDL_OpenJoystick(instance_id);
|
||||
if (!gamepad->joystick) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
|
|
@ -2759,6 +2763,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
|||
if (gamepad->joystick->naxes) {
|
||||
gamepad->last_match_axis = (SDL_GamepadBinding **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis));
|
||||
if (!gamepad->last_match_axis) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
|
|
@ -2768,6 +2773,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
|||
if (gamepad->joystick->nhats) {
|
||||
gamepad->last_hat_mask = (Uint8 *)SDL_calloc(gamepad->joystick->nhats, sizeof(*gamepad->last_hat_mask));
|
||||
if (!gamepad->last_hat_mask) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad->last_match_axis);
|
||||
SDL_free(gamepad);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ static const char *s_GamepadMappings[] = {
|
|||
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
|
||||
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
|
||||
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,righttrigger:-a5,start:b11,x:b3,y:b4,",
|
||||
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
|
|
@ -421,7 +421,7 @@ static const char *s_GamepadMappings[] = {
|
|||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,righttrigger:a5,start:b11,x:b3,y:b4,",
|
||||
"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
|
|
@ -553,6 +553,7 @@ static const char *s_GamepadMappings[] = {
|
|||
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000049190000020400001b010000,GameSir T4 Pro,crc:8283,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b23,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000373500009710000001020000,GameSir-K1 FLUX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"03000000c01100000140000011010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
|
|
@ -867,7 +868,9 @@ static const char *s_GamepadMappings[] = {
|
|||
"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
|
||||
"05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000fd216d04,8BitDo Pro 2,crc:ac95,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,crc:3e00,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,crc:40d6,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
|
|
@ -904,7 +907,7 @@ static const char *s_GamepadMappings[] = {
|
|||
"0000000050535669746120436f6e7400,PSVita Controller,crc:d598,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_N3DS
|
||||
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b0,b:b1,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b10,y:b11,",
|
||||
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b1,b:b0,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b11,y:b10,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ static Uint32 initial_blacklist_devices[] = {
|
|||
MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device
|
||||
MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller
|
||||
MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only)
|
||||
MAKE_VIDPID(0x3434, 0x0211), // Keychron K1 Pro System Control
|
||||
};
|
||||
static SDL_vidpid_list blacklist_devices = {
|
||||
SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL,
|
||||
|
|
@ -289,7 +290,17 @@ static Uint32 initial_flightstick_devices[] = {
|
|||
MAKE_VIDPID(0x044f, 0x0402), // HOTAS Warthog Joystick
|
||||
MAKE_VIDPID(0x044f, 0xb10a), // ThrustMaster, Inc. T.16000M Joystick
|
||||
MAKE_VIDPID(0x046d, 0xc215), // Logitech Extreme 3D
|
||||
MAKE_VIDPID(0x0583, 0x6258), // Padix USB joystick with viewfinder
|
||||
MAKE_VIDPID(0x0583, 0x688f), // Padix QF-688uv Windstorm Pro
|
||||
MAKE_VIDPID(0x0583, 0x7070), // Padix QF-707u Bazooka
|
||||
MAKE_VIDPID(0x0583, 0xa019), // Padix USB vibration joystick with viewfinder
|
||||
MAKE_VIDPID(0x0583, 0xa131), // Padix USB Wireless 2.4GHz
|
||||
MAKE_VIDPID(0x0583, 0xa209), // Padix MetalStrike ForceFeedback
|
||||
MAKE_VIDPID(0x0583, 0xb010), // Padix MetalStrike Pro
|
||||
MAKE_VIDPID(0x0583, 0xb012), // Padix Wireless MetalStrike
|
||||
MAKE_VIDPID(0x0583, 0xb013), // Padix USB Wireless 2.4GHZ
|
||||
MAKE_VIDPID(0x0738, 0x2221), // Saitek Pro Flight X-56 Rhino Stick
|
||||
MAKE_VIDPID(0x10f5, 0x7084), // Turtle Beach VelocityOne
|
||||
MAKE_VIDPID(0x231d, 0x0126), // Gunfighter Mk.III 'Space Combat Edition' (right)
|
||||
MAKE_VIDPID(0x231d, 0x0127), // Gunfighter Mk.III 'Space Combat Edition' (left)
|
||||
MAKE_VIDPID(0x362c, 0x0001), // Yawman Arrow
|
||||
|
|
@ -331,6 +342,7 @@ static SDL_vidpid_list rog_gamepad_mice = {
|
|||
static Uint32 initial_throttle_devices[] = {
|
||||
MAKE_VIDPID(0x044f, 0x0404), // HOTAS Warthog Throttle
|
||||
MAKE_VIDPID(0x0738, 0xa221), // Saitek Pro Flight X-56 Rhino Throttle
|
||||
MAKE_VIDPID(0x10f5, 0x7085), // Turtle Beach VelocityOne Throttle
|
||||
};
|
||||
static SDL_vidpid_list throttle_devices = {
|
||||
SDL_HINT_JOYSTICK_THROTTLE_DEVICES, 0, 0, NULL,
|
||||
|
|
@ -374,6 +386,14 @@ static Uint32 initial_wheel_devices[] = {
|
|||
MAKE_VIDPID(0x046d, 0xca03), // Logitech Momo Racing
|
||||
MAKE_VIDPID(0x0483, 0x0522), // Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U)
|
||||
MAKE_VIDPID(0x0483, 0xa355), // VRS DirectForce Pro Wheel Base
|
||||
MAKE_VIDPID(0x0583, 0xa132), // Padix USB Wireless 2.4GHz Wheelpad
|
||||
MAKE_VIDPID(0x0583, 0xa133), // Padix USB Wireless 2.4GHz Wheel
|
||||
MAKE_VIDPID(0x0583, 0xa202), // Padix Force Feedback Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb002), // Padix Vibration USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb005), // Padix USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb008), // Padix USB Wireless 2.4GHz Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb009), // Padix USB Wheel
|
||||
MAKE_VIDPID(0x0583, 0xb018), // Padix TW6 Wheel
|
||||
MAKE_VIDPID(0x0eb7, 0x0001), // Fanatec ClubSport Wheel Base V2
|
||||
MAKE_VIDPID(0x0eb7, 0x0004), // Fanatec ClubSport Wheel Base V2.5
|
||||
MAKE_VIDPID(0x0eb7, 0x0005), // Fanatec CSL Elite Wheel Base+ (PS4)
|
||||
|
|
@ -1122,7 +1142,11 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
|||
joystick->attached = true;
|
||||
joystick->led_expiration = SDL_GetTicks();
|
||||
joystick->battery_percent = -1;
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver);
|
||||
#else
|
||||
joystick->is_virtual = false;
|
||||
#endif
|
||||
|
||||
if (!driver->Open(joystick, device_index)) {
|
||||
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);
|
||||
|
|
@ -1166,9 +1190,35 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
|||
|
||||
// If this joystick is known to have all zero centered axes, skip the auto-centering code
|
||||
if (SDL_JoystickAxesCenteredAtZero(joystick)) {
|
||||
int i;
|
||||
for (int i = 0; i < joystick->naxes; ++i) {
|
||||
joystick->axes[i].has_initial_value = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < joystick->naxes; ++i) {
|
||||
// We know the initial values for HIDAPI and XInput joysticks
|
||||
if ((SDL_IsJoystickHIDAPI(joystick->guid) ||
|
||||
SDL_IsJoystickXInput(joystick->guid) ||
|
||||
SDL_IsJoystickRAWINPUT(joystick->guid) ||
|
||||
SDL_IsJoystickWGI(joystick->guid)) &&
|
||||
joystick->naxes >= SDL_GAMEPAD_AXIS_COUNT) {
|
||||
int left_trigger, right_trigger;
|
||||
if (SDL_IsJoystickXInput(joystick->guid)) {
|
||||
left_trigger = 2;
|
||||
right_trigger = 5;
|
||||
} else {
|
||||
left_trigger = SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
|
||||
right_trigger = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER;
|
||||
}
|
||||
for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) {
|
||||
int initial_value;
|
||||
if (i == left_trigger || i == right_trigger) {
|
||||
initial_value = SDL_MIN_SINT16;
|
||||
} else {
|
||||
initial_value = 0;
|
||||
}
|
||||
joystick->axes[i].value = initial_value;
|
||||
joystick->axes[i].zero = initial_value;
|
||||
joystick->axes[i].initial_value = initial_value;
|
||||
joystick->axes[i].has_initial_value = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1814,6 +1864,14 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
|
|||
result = true;
|
||||
} else {
|
||||
result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
|
||||
if (result) {
|
||||
joystick->trigger_rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS;
|
||||
if (joystick->trigger_rumble_resend == 0) {
|
||||
joystick->trigger_rumble_resend = 1;
|
||||
}
|
||||
} else {
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
|
|
@ -1824,6 +1882,7 @@ bool SDL_RumbleJoystickTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
|
|||
joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
|
||||
} else {
|
||||
joystick->trigger_rumble_expiration = 0;
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2478,6 +2537,15 @@ void SDL_UpdateJoysticks(void)
|
|||
|
||||
if (joystick->trigger_rumble_expiration && now >= joystick->trigger_rumble_expiration) {
|
||||
SDL_RumbleJoystickTriggers(joystick, 0, 0, 0);
|
||||
joystick->trigger_rumble_resend = 0;
|
||||
}
|
||||
|
||||
if (joystick->trigger_rumble_resend && now >= joystick->trigger_rumble_resend) {
|
||||
joystick->driver->RumbleTriggers(joystick, joystick->left_trigger_rumble, joystick->right_trigger_rumble);
|
||||
joystick->trigger_rumble_resend = now + SDL_RUMBLE_RESEND_MS;
|
||||
if (joystick->trigger_rumble_resend == 0) {
|
||||
joystick->trigger_rumble_resend = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2858,7 +2926,8 @@ bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
|
|||
}
|
||||
if (vendor_id == USB_VENDOR_HORI) {
|
||||
if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X) {
|
||||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ struct SDL_Joystick
|
|||
Uint16 left_trigger_rumble _guarded;
|
||||
Uint16 right_trigger_rumble _guarded;
|
||||
Uint64 trigger_rumble_expiration _guarded;
|
||||
Uint64 trigger_rumble_resend _guarded;
|
||||
|
||||
Uint8 led_red _guarded;
|
||||
Uint8 led_green _guarded;
|
||||
|
|
|
|||
|
|
@ -751,11 +751,12 @@ bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoysti
|
|||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
if (pJoystickID) {
|
||||
*pJoystickID = joystickID;
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1051,6 +1052,11 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
|
|||
info.usage = USB_USAGE_GENERIC_GAMEPAD;
|
||||
info.manufacturer_string = L"Nintendo";
|
||||
info.product_string = L"Switch Joy-Con (L/R)";
|
||||
if (children[0]->is_bluetooth || children[1]->is_bluetooth) {
|
||||
info.bus_type = SDL_HID_API_BUS_BLUETOOTH;
|
||||
} else {
|
||||
info.bus_type = SDL_HID_API_BUS_USB;
|
||||
}
|
||||
|
||||
combined = HIDAPI_AddDevice(&info, 2, children);
|
||||
if (combined && combined->driver) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER 0x01AB
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER_BT 0x0196
|
||||
#define USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER 0x01b2
|
||||
#define USB_PRODUCT_LOGITECH_F310 0xc216
|
||||
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
|
||||
#define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ struct joystick_hwdata
|
|||
Uint8 wgi_correlation_count;
|
||||
Uint8 wgi_uncorrelate_count;
|
||||
WindowsGamingInputGamepadState *wgi_slot;
|
||||
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
|
||||
#endif
|
||||
|
||||
bool triggers_rumbling;
|
||||
|
|
@ -449,7 +450,6 @@ typedef struct WindowsGamingInputGamepadState
|
|||
bool used; // Is currently mapped to an SDL device
|
||||
bool connected; // Just used during update to track disconnected
|
||||
Uint8 correlation_id;
|
||||
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
|
||||
} WindowsGamingInputGamepadState;
|
||||
|
||||
static struct
|
||||
|
|
@ -1030,7 +1030,7 @@ static bool RAWINPUT_JoystickInit(void)
|
|||
{
|
||||
SDL_assert(!SDL_RAWINPUT_inited);
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, true)) {
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1482,12 +1482,11 @@ static bool RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency
|
|||
|
||||
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
|
||||
// Save off the motor state in case trigger rumble is started
|
||||
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
|
||||
HRESULT hr;
|
||||
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
|
||||
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
|
||||
ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
|
||||
ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
|
||||
if (!rumbled && ctx->wgi_correlated) {
|
||||
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
|
||||
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
|
||||
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
|
||||
if (SUCCEEDED(hr)) {
|
||||
rumbled = true;
|
||||
}
|
||||
|
|
@ -1509,12 +1508,11 @@ static bool RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_
|
|||
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
|
||||
RAWINPUT_DeviceContext *ctx = joystick->hwdata;
|
||||
|
||||
ctx->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
|
||||
ctx->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
|
||||
if (ctx->wgi_correlated) {
|
||||
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
|
||||
HRESULT hr;
|
||||
gamepad_state->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
|
||||
gamepad_state->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
|
||||
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
|
||||
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
return SDL_SetError("Setting vibration failed: 0x%lx", hr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,6 +304,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||
if (stderr_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||
stderr_option = SDL_PROCESS_STDIO_NULL;
|
||||
}
|
||||
creation_flags |= CREATE_NO_WINDOW;
|
||||
}
|
||||
|
||||
switch (stdin_option) {
|
||||
|
|
@ -329,7 +330,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||
startup_info.hStdInput = stdin_pipe[READ_END];
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_NULL:
|
||||
startup_info.hStdInput = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
startup_info.hStdInput = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_INHERITED:
|
||||
default:
|
||||
|
|
@ -366,7 +367,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||
startup_info.hStdOutput = stdout_pipe[WRITE_END];
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_NULL:
|
||||
startup_info.hStdOutput = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
startup_info.hStdOutput = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_INHERITED:
|
||||
default:
|
||||
|
|
@ -412,7 +413,7 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||
startup_info.hStdError = stderr_pipe[WRITE_END];
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_NULL:
|
||||
startup_info.hStdError = CreateFile(TEXT("\\\\.\\NUL"), GENERIC_ALL, 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
startup_info.hStdError = CreateFile(TEXT("\\\\.\\NUL"), (GENERIC_READ | GENERIC_WRITE), 0, &security_attributes, OPEN_EXISTING, 0, NULL);
|
||||
break;
|
||||
case SDL_PROCESS_STDIO_INHERITED:
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -1658,8 +1658,6 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
|
|||
}
|
||||
}
|
||||
|
||||
surface_colorspace = SDL_GetSurfaceColorspace(surface);
|
||||
|
||||
// Try to have the best pixel format for the texture
|
||||
// No alpha, but a colorkey => promote to alpha
|
||||
if (!SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) {
|
||||
|
|
@ -1721,6 +1719,9 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
|
|||
}
|
||||
}
|
||||
|
||||
surface_colorspace = SDL_GetSurfaceColorspace(surface);
|
||||
texture_colorspace = surface_colorspace;
|
||||
|
||||
if (surface_colorspace == SDL_COLORSPACE_SRGB_LINEAR ||
|
||||
SDL_COLORSPACETRANSFER(surface_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
|
||||
if (SDL_ISPIXELFORMAT_FLOAT(format)) {
|
||||
|
|
@ -2572,7 +2573,7 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
|
|||
const float logical_h = view->logical_h;
|
||||
int iwidth, iheight;
|
||||
|
||||
if (renderer->target) {
|
||||
if (!is_main_view && renderer->target) {
|
||||
iwidth = (int)renderer->target->w;
|
||||
iheight = (int)renderer->target->h;
|
||||
} else {
|
||||
|
|
@ -3930,8 +3931,7 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F
|
|||
real_srcrect.w = (float)texture->w;
|
||||
real_srcrect.h = (float)texture->h;
|
||||
if (srcrect) {
|
||||
if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect) ||
|
||||
real_srcrect.w == 0.0f || real_srcrect.h == 0.0f) {
|
||||
if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,7 +445,6 @@ static void GPU_InvalidateCachedState(SDL_Renderer *renderer)
|
|||
{
|
||||
GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
|
||||
|
||||
data->state.render_target = NULL;
|
||||
data->state.scissor_enabled = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,15 +79,10 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16,
|
|||
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4);
|
||||
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4;
|
||||
|
||||
// Sampler types
|
||||
typedef enum
|
||||
{
|
||||
SDL_METAL_SAMPLER_NEAREST_CLAMP,
|
||||
SDL_METAL_SAMPLER_NEAREST_WRAP,
|
||||
SDL_METAL_SAMPLER_LINEAR_CLAMP,
|
||||
SDL_METAL_SAMPLER_LINEAR_WRAP,
|
||||
SDL_NUM_METAL_SAMPLERS
|
||||
} SDL_METAL_sampler_type;
|
||||
#define RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v) \
|
||||
(((scale_mode == SDL_SCALEMODE_NEAREST) << 0) | \
|
||||
((address_u == SDL_TEXTURE_ADDRESS_WRAP) << 1) | \
|
||||
((address_v == SDL_TEXTURE_ADDRESS_WRAP) << 2))
|
||||
|
||||
typedef enum SDL_MetalVertexFunction
|
||||
{
|
||||
|
|
@ -139,7 +134,7 @@ typedef struct METAL_ShaderPipelines
|
|||
@property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
||||
@property(nonatomic, retain) id<MTLLibrary> mtllibrary;
|
||||
@property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
||||
@property(nonatomic, retain) NSMutableArray<id<MTLSamplerState>> *mtlsamplers;
|
||||
@property(nonatomic, retain) NSMutableDictionary<NSNumber *, id<MTLSamplerState>> *mtlsamplers;
|
||||
@property(nonatomic, retain) id<MTLBuffer> mtlbufconstants;
|
||||
@property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
|
||||
@property(nonatomic, assign) SDL_MetalView mtlview;
|
||||
|
|
@ -1295,6 +1290,9 @@ typedef struct
|
|||
__unsafe_unretained id<MTLBuffer> vertex_buffer;
|
||||
size_t constants_offset;
|
||||
SDL_Texture *texture;
|
||||
SDL_ScaleMode texture_scale_mode;
|
||||
SDL_TextureAddressMode texture_address_mode_u;
|
||||
SDL_TextureAddressMode texture_address_mode_v;
|
||||
bool cliprect_dirty;
|
||||
bool cliprect_enabled;
|
||||
SDL_Rect cliprect;
|
||||
|
|
@ -1452,6 +1450,58 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
return true;
|
||||
}
|
||||
|
||||
static id<MTLSamplerState> GetSampler(SDL3METAL_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v)
|
||||
{
|
||||
NSNumber *key = [NSNumber numberWithInteger:RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v)];
|
||||
id<MTLSamplerState> mtlsampler = data.mtlsamplers[key];
|
||||
if (mtlsampler == nil) {
|
||||
MTLSamplerDescriptor *samplerdesc;
|
||||
samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
||||
switch (scale_mode) {
|
||||
case SDL_SCALEMODE_NEAREST:
|
||||
samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
|
||||
samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
case SDL_SCALEMODE_LINEAR:
|
||||
samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown scale mode: %d", scale_mode);
|
||||
return nil;
|
||||
}
|
||||
switch (address_u) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
samplerdesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
samplerdesc.sAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown texture address mode: %d", address_u);
|
||||
return nil;
|
||||
}
|
||||
switch (address_v) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
samplerdesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
samplerdesc.tAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown texture address mode: %d", address_v);
|
||||
return nil;
|
||||
}
|
||||
mtlsampler = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
||||
if (mtlsampler == nil) {
|
||||
SDL_SetError("Couldn't create sampler");
|
||||
return nil;
|
||||
}
|
||||
data.mtlsamplers[key] = mtlsampler;
|
||||
}
|
||||
return mtlsampler;
|
||||
}
|
||||
|
||||
static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
|
||||
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
||||
{
|
||||
|
|
@ -1467,33 +1517,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
}
|
||||
|
||||
if (texture != statecache->texture) {
|
||||
id<MTLSamplerState> mtlsampler;
|
||||
|
||||
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_NEAREST) {
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_CLAMP];
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP];
|
||||
break;
|
||||
default:
|
||||
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
|
||||
}
|
||||
} else {
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_CLAMP];
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP];
|
||||
break;
|
||||
default:
|
||||
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
|
||||
}
|
||||
}
|
||||
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
|
||||
|
||||
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
|
||||
#ifdef SDL_HAVE_YUV
|
||||
if (texturedata.yuv || texturedata.nv12) {
|
||||
|
|
@ -1503,6 +1526,20 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
#endif
|
||||
statecache->texture = texture;
|
||||
}
|
||||
|
||||
if (cmd->data.draw.texture_scale_mode != statecache->texture_scale_mode ||
|
||||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_u ||
|
||||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_v) {
|
||||
id<MTLSamplerState> mtlsampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_address_mode);
|
||||
if (mtlsampler == nil) {
|
||||
return false;
|
||||
}
|
||||
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
|
||||
|
||||
statecache->texture_scale_mode = cmd->data.draw.texture_scale_mode;
|
||||
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode;
|
||||
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1523,6 +1560,9 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
|
|||
statecache.vertex_buffer = nil;
|
||||
statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
|
||||
statecache.texture = NULL;
|
||||
statecache.texture_scale_mode = SDL_SCALEMODE_INVALID;
|
||||
statecache.texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID;
|
||||
statecache.texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID;
|
||||
statecache.shader_constants_dirty = true;
|
||||
statecache.cliprect_dirty = true;
|
||||
statecache.viewport_dirty = true;
|
||||
|
|
@ -1883,7 +1923,6 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
|||
int maxtexsize, quadcount = UINT16_MAX / 4;
|
||||
UInt16 *indexdata;
|
||||
size_t indicessize = sizeof(UInt16) * quadcount * 6;
|
||||
MTLSamplerDescriptor *samplerdesc;
|
||||
id<MTLCommandQueue> mtlcmdqueue;
|
||||
id<MTLLibrary> mtllibrary;
|
||||
id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
|
||||
|
|
@ -2043,27 +2082,7 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
|||
data.allpipelines = NULL;
|
||||
ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
|
||||
|
||||
static struct
|
||||
{
|
||||
MTLSamplerMinMagFilter filter;
|
||||
MTLSamplerAddressMode address;
|
||||
} samplerParams[] = {
|
||||
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeClampToEdge },
|
||||
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeRepeat },
|
||||
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeClampToEdge },
|
||||
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeRepeat },
|
||||
};
|
||||
SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_METAL_SAMPLERS);
|
||||
|
||||
data.mtlsamplers = [[NSMutableArray<id<MTLSamplerState>> alloc] init];
|
||||
samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
||||
for (int i = 0; i < SDL_arraysize(samplerParams); ++i) {
|
||||
samplerdesc.minFilter = samplerParams[i].filter;
|
||||
samplerdesc.magFilter = samplerParams[i].filter;
|
||||
samplerdesc.sAddressMode = samplerParams[i].address;
|
||||
samplerdesc.tAddressMode = samplerParams[i].address;
|
||||
[data.mtlsamplers addObject:[data.mtldevice newSamplerStateWithDescriptor:samplerdesc]];
|
||||
}
|
||||
data.mtlsamplers = [[NSMutableDictionary<NSNumber *, id<MTLSamplerState>> alloc] init];
|
||||
|
||||
mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ typedef struct
|
|||
static int vsync_sema_id = 0;
|
||||
|
||||
// PRIVATE METHODS
|
||||
static int vsync_handler(void)
|
||||
static int vsync_handler(int reason)
|
||||
{
|
||||
iSignalSema(vsync_sema_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ static TitleStorageBootStrap *titlebootstrap[] = {
|
|||
static UserStorageBootStrap *userbootstrap[] = {
|
||||
#ifdef SDL_STORAGE_STEAM
|
||||
&STEAM_userbootstrap,
|
||||
#endif
|
||||
#ifdef SDL_STORAGE_PRIVATE
|
||||
&PRIVATE_userbootstrap,
|
||||
#endif
|
||||
&GENERIC_userbootstrap,
|
||||
NULL
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ extern TitleStorageBootStrap GENERIC_titlebootstrap;
|
|||
// Steam does not have title storage APIs
|
||||
|
||||
extern UserStorageBootStrap GENERIC_userbootstrap;
|
||||
extern UserStorageBootStrap PRIVATE_userbootstrap;
|
||||
extern UserStorageBootStrap STEAM_userbootstrap;
|
||||
|
||||
extern SDL_Storage *GENERIC_OpenFileStorage(const char *path);
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ typedef enum
|
|||
static gulong (*g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
|
||||
static void (*g_object_unref)(gpointer object);
|
||||
static gchar *(*g_mkdtemp)(gchar *template);
|
||||
gpointer (*g_object_ref_sink)(gpointer object);
|
||||
gpointer (*g_object_ref)(gpointer object);
|
||||
static gpointer (*g_object_ref_sink)(gpointer object);
|
||||
static gpointer (*g_object_ref)(gpointer object);
|
||||
|
||||
// glib_typeof requires compiler-specific code and includes that are too complex
|
||||
// to be worth copy-pasting here
|
||||
|
|
@ -541,7 +541,7 @@ SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
entry->submenu->menu = (GtkMenuShell *)gtk_menu_new();
|
||||
entry->submenu->menu = g_object_ref_sink(gtk_menu_new());
|
||||
entry->submenu->parent_tray = NULL;
|
||||
entry->submenu->parent_entry = entry;
|
||||
entry->submenu->nEntries = 0;
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
|||
mii.dwTypeData = label_w;
|
||||
mii.cch = (UINT) SDL_wcslen(label_w);
|
||||
|
||||
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, TRUE, &mii)) {
|
||||
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, FALSE, &mii)) {
|
||||
SDL_SetError("Couldn't update tray entry label");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_blit.h"
|
||||
|
||||
#ifdef SDL_HAVE_BLIT_AUTO
|
||||
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
|
||||
#include "SDL_blit.h"
|
||||
|
||||
extern SDL_BlitFuncEntry SDL_GeneratedBlitFuncTable[];
|
||||
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
|
|
|||
|
|
@ -1101,9 +1101,9 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
|
|||
int dst_w, dst_h;
|
||||
|
||||
// Make sure the surfaces aren't locked
|
||||
if (!SDL_SurfaceValid(src)) {
|
||||
if (!SDL_SurfaceValid(src) || !src->pixels) {
|
||||
return SDL_InvalidParamError("src");
|
||||
} else if (!SDL_SurfaceValid(dst)) {
|
||||
} else if (!SDL_SurfaceValid(dst) || !dst->pixels) {
|
||||
return SDL_InvalidParamError("dst");
|
||||
} else if ((src->flags & SDL_SURFACE_LOCKED) || (dst->flags & SDL_SURFACE_LOCKED)) {
|
||||
return SDL_SetError("Surfaces must not be locked during blit");
|
||||
|
|
@ -1133,6 +1133,13 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
|
|||
return SDL_BlitSurface(src, srcrect, dst, dstrect);
|
||||
}
|
||||
|
||||
if (src_w == 0) {
|
||||
src_w = 1;
|
||||
}
|
||||
if (src_h == 0) {
|
||||
src_h = 1;
|
||||
}
|
||||
|
||||
scaling_w = (double)dst_w / src_w;
|
||||
scaling_h = (double)dst_h / src_h;
|
||||
|
||||
|
|
|
|||
|
|
@ -396,8 +396,7 @@ struct SDL_VideoDevice
|
|||
bool checked_texture_framebuffer;
|
||||
bool is_dummy;
|
||||
bool suspend_screensaver;
|
||||
SDL_Window *wakeup_window;
|
||||
SDL_Mutex *wakeup_lock; // Initialized only if WaitEventTimeout/SendWakeupEvent are supported
|
||||
void *wakeup_window;
|
||||
int num_displays;
|
||||
SDL_VideoDisplay **displays;
|
||||
SDL_Rect desktop_bounds;
|
||||
|
|
|
|||
|
|
@ -1731,12 +1731,25 @@ SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window)
|
|||
return SDL_GetVideoDisplay(displayID);
|
||||
}
|
||||
|
||||
#define SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY "sdl2-compat.window.preferred_fullscreen_display"
|
||||
|
||||
SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window)
|
||||
{
|
||||
SDL_DisplayID displayID = 0;
|
||||
|
||||
CHECK_WINDOW_MAGIC(window, 0);
|
||||
|
||||
/* sdl2-compat calls this function to get a display on which to make the window fullscreen,
|
||||
* so pass it the preferred fullscreen display ID in a property.
|
||||
*/
|
||||
SDL_PropertiesID window_props = SDL_GetWindowProperties(window);
|
||||
SDL_VideoDisplay *fs_display = SDL_GetVideoDisplayForFullscreenWindow(window);
|
||||
if (fs_display) {
|
||||
SDL_SetNumberProperty(window_props, SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY, fs_display->id);
|
||||
} else {
|
||||
SDL_ClearProperty(window_props, SDL_PROP_SDL2_COMPAT_WINDOW_PREFERRED_FULLSCREEN_DISPLAY);
|
||||
}
|
||||
|
||||
// An explicit fullscreen display overrides all
|
||||
if (window->flags & SDL_WINDOW_FULLSCREEN) {
|
||||
displayID = window->current_fullscreen_mode.displayID;
|
||||
|
|
@ -2500,7 +2513,9 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
|||
SDL_UpdateWindowHierarchy(window, parent);
|
||||
|
||||
if (_this->CreateSDLWindow && !_this->CreateSDLWindow(_this, window, props)) {
|
||||
PUSH_SDL_ERROR()
|
||||
SDL_DestroyWindow(window);
|
||||
POP_SDL_ERROR()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2748,7 +2763,7 @@ SDL_Window *SDL_GetWindowFromID(SDL_WindowID id)
|
|||
}
|
||||
}
|
||||
}
|
||||
SDL_SetError("Invalid window ID"); \
|
||||
SDL_SetError("Invalid window ID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -4266,9 +4281,7 @@ void SDL_DestroyWindow(SDL_Window *window)
|
|||
_this->current_glwin = NULL;
|
||||
}
|
||||
|
||||
if (_this->wakeup_window == window) {
|
||||
_this->wakeup_window = NULL;
|
||||
}
|
||||
SDL_CompareAndSwapAtomicPointer(&_this->wakeup_window, window, NULL);
|
||||
|
||||
// Now invalidate magic
|
||||
SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, false);
|
||||
|
|
@ -5021,8 +5034,7 @@ bool SDL_GL_GetAttribute(SDL_GLAttr attr, int *value)
|
|||
}
|
||||
if (fbo_type != GL_NONE) {
|
||||
glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *)value);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
if (glBindFramebufferFunc && (current_fbo != 0)) {
|
||||
|
|
@ -5253,7 +5265,7 @@ bool SDL_GL_SwapWindow(SDL_Window *window)
|
|||
bool SDL_GL_DestroyContext(SDL_GLContext context)
|
||||
{
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo(); \
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
if (!context) {
|
||||
return SDL_InvalidParamError("context");
|
||||
|
|
|
|||
|
|
@ -158,6 +158,17 @@ bool Cocoa_SetClipboardData(SDL_VideoDevice *_this)
|
|||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
|
||||
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
||||
|
||||
// SetClipboardText specialization so text is available after the app quits
|
||||
if (_this->clipboard_callback && _this->num_clipboard_mime_types == 1) {
|
||||
if (SDL_strncmp(_this->clipboard_mime_types[0], "text/plain;charset=utf-8", 24) == 0) {
|
||||
[pasteboard declareTypes:@[ NSPasteboardTypeString ] owner:nil];
|
||||
[pasteboard setString:@((char *)_this->clipboard_userdata) forType:NSPasteboardTypeString];
|
||||
data.clipboard_count = [pasteboard changeCount];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
NSPasteboardItem *newItem = [NSPasteboardItem new];
|
||||
NSMutableArray *utiTypes = [NSMutableArray new];
|
||||
Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
|
||||
|
|
|
|||
|
|
@ -450,12 +450,18 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
|
|||
// All events except NSEventTypeMouseExited can only happen if the window
|
||||
// has mouse focus, so we'll always set the focus even if we happen to miss
|
||||
// NSEventTypeMouseEntered, which apparently happens if the window is
|
||||
// created under the mouse on macOS 12.7
|
||||
// created under the mouse on macOS 12.7. But, only set the focus if
|
||||
// the event acutally has a non-NULL window, otherwise what would happen
|
||||
// is that after an NSEventTypeMouseEntered there would sometimes be
|
||||
// NSEventTypeMouseMoved without a window causing us to suppress subsequent
|
||||
// mouse move events.
|
||||
NSEventType event_type = [event type];
|
||||
if (event_type == NSEventTypeMouseExited) {
|
||||
Cocoa_MouseFocus = NULL;
|
||||
} else {
|
||||
Cocoa_MouseFocus = [event window];
|
||||
if ([event window] != NULL) {
|
||||
Cocoa_MouseFocus = [event window];
|
||||
}
|
||||
}
|
||||
|
||||
switch (event_type) {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,6 @@ static void Cocoa_VideoQuit(SDL_VideoDevice *_this);
|
|||
static void Cocoa_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (device->wakeup_lock) {
|
||||
SDL_DestroyMutex(device->wakeup_lock);
|
||||
}
|
||||
CFBridgingRelease(device->internal);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
|
@ -81,7 +78,6 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
|
|||
return NULL;
|
||||
}
|
||||
device->internal = (SDL_VideoData *)CFBridgingRetain(data);
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
device->system_theme = Cocoa_GetSystemTheme();
|
||||
|
||||
// Set the function pointers
|
||||
|
|
|
|||
|
|
@ -2022,6 +2022,7 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
|
|||
@interface SDL3View : NSView
|
||||
{
|
||||
SDL_Window *_sdlWindow;
|
||||
NSTrackingArea *_trackingArea; // only used on macOS <= 11.0
|
||||
}
|
||||
|
||||
- (void)setSDLWindow:(SDL_Window *)window;
|
||||
|
|
@ -2033,6 +2034,7 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
|
|||
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent;
|
||||
- (BOOL)wantsUpdateLayer;
|
||||
- (void)updateLayer;
|
||||
- (void)updateTrackingAreas;
|
||||
@end
|
||||
|
||||
@implementation SDL3View
|
||||
|
|
@ -2104,15 +2106,62 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
|
|||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
|
||||
{
|
||||
if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) {
|
||||
if (_sdlWindow->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
return YES;
|
||||
} else if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) {
|
||||
return SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, false);
|
||||
} else {
|
||||
return SDL_GetHintBoolean("SDL_MAC_MOUSE_FOCUS_CLICKTHROUGH", false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
[super updateTrackingAreas];
|
||||
|
||||
if (@available(macOS 12.0, *)) {
|
||||
// we (currently) use the tracking areas as a workaround for older macOSes, but we might be safe everywhere...
|
||||
} else {
|
||||
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)_sdlWindow->internal;
|
||||
if (_trackingArea) {
|
||||
[self removeTrackingArea:_trackingArea];
|
||||
}
|
||||
_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways owner:windata.listener userInfo:nil];
|
||||
[self addTrackingArea:_trackingArea];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
static void Cocoa_UpdateMouseFocus()
|
||||
{
|
||||
const NSPoint mouseLocation = [NSEvent mouseLocation];
|
||||
|
||||
// Find the topmost window under the pointer and send a motion event if it is an SDL window.
|
||||
[NSApp enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
|
||||
usingBlock:^(NSWindow *nswin, BOOL *stop) {
|
||||
NSRect r = [nswin contentRectForFrameRect:[nswin frame]];
|
||||
if (NSPointInRect(mouseLocation, r)) {
|
||||
SDL_VideoDevice *vid = SDL_GetVideoDevice();
|
||||
SDL_Window *sdlwindow;
|
||||
for (sdlwindow = vid->windows; sdlwindow; sdlwindow = sdlwindow->next) {
|
||||
if (nswin == ((__bridge SDL_CocoaWindowData *)sdlwindow->internal).nswindow) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*stop = YES;
|
||||
if (sdlwindow) {
|
||||
int wx, wy;
|
||||
SDL_RelativeToGlobalForWindow(sdlwindow, sdlwindow->x, sdlwindow->y, &wx, &wy);
|
||||
|
||||
// Calculate the cursor coordinates relative to the window.
|
||||
const float dx = mouseLocation.x - wx;
|
||||
const float dy = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - mouseLocation.y) - wy;
|
||||
SDL_SendMouseMotion(0, sdlwindow, SDL_GLOBAL_MOUSE_ID, false, dx, dy);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow *nswindow, NSView *nsview)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
|
@ -2210,8 +2259,10 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
|
|||
} else {
|
||||
if (window->flags & SDL_WINDOW_TOOLTIP) {
|
||||
[nswindow setIgnoresMouseEvents:YES];
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
[nswindow setAcceptsMouseMovedEvents:NO];
|
||||
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
Cocoa_UpdateMouseFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2531,8 +2582,8 @@ void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal;
|
||||
|
||||
NSSize maxSize;
|
||||
maxSize.width = window->max_w;
|
||||
maxSize.height = window->max_h;
|
||||
maxSize.width = window->max_w ? window->max_w : CGFLOAT_MAX;
|
||||
maxSize.height = window->max_h ? window->max_h : CGFLOAT_MAX;
|
||||
|
||||
[windata.nswindow setContentMaxSize:maxSize];
|
||||
}
|
||||
|
|
@ -2596,6 +2647,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
[nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]];
|
||||
}
|
||||
}
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
Cocoa_UpdateMouseFocus();
|
||||
}
|
||||
}
|
||||
[nswindow setIsVisible:YES];
|
||||
|
|
@ -2643,6 +2697,7 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
}
|
||||
|
||||
Cocoa_SetKeyboardFocus(new_focus, set_focus);
|
||||
Cocoa_UpdateMouseFocus();
|
||||
} else if (window->parent && waskey) {
|
||||
/* Key status is not automatically set on the parent when a child is hidden. Check if the
|
||||
* child window was key, and set the first visible parent to be key if so.
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ bool Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *wind
|
|||
if (!Module['SDL3']) Module['SDL3'] = {};
|
||||
var SDL3 = Module['SDL3'];
|
||||
if (SDL3.ctxCanvas !== canvas) {
|
||||
SDL3.ctx = Module['createContext'](canvas, false, true);
|
||||
SDL3.ctx = Browser.createContext(canvas, false, true);
|
||||
SDL3.ctxCanvas = canvas;
|
||||
}
|
||||
if (SDL3.w !== w || SDL3.h !== h || SDL3.imageCtx !== SDL3.ctx) {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ SDL_GLContext Emscripten_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *
|
|||
|
||||
context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
|
||||
|
||||
if (context < 0) {
|
||||
if (!context) {
|
||||
SDL_SetError("Could not create webgl context");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static SDL_SystemTheme Emscripten_GetSystemTheme(void)
|
|||
/* Technically, light theme can mean explicit light theme or no preference.
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme#syntax */
|
||||
|
||||
int theme_code = EM_ASM_INT({
|
||||
int theme_code = MAIN_THREAD_EM_ASM_INT({
|
||||
if (!window.matchMedia) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1368,9 +1368,14 @@ bool KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
|
||||
dispdata->mode.hdisplay, dispdata->mode.vdisplay,
|
||||
surface_fmt, surface_flags);
|
||||
|
||||
if (!windata->gs && errno == ENOSYS) {
|
||||
// Try again without the scanout flags, needed on NVIDIA drivers
|
||||
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
|
||||
dispdata->mode.hdisplay, dispdata->mode.vdisplay,
|
||||
surface_fmt, 0);
|
||||
}
|
||||
if (!windata->gs) {
|
||||
return SDL_SetError("Could not create GBM surface");
|
||||
return SDL_SetError("Could not create GBM surface: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* We can't get the EGL context yet because SDL_CreateRenderer has not been called,
|
||||
|
|
@ -1729,9 +1734,9 @@ bool KMSDRM_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
|||
}
|
||||
|
||||
/* Create the window surfaces with the size we have just chosen.
|
||||
Needs the window diverdata in place. */
|
||||
Needs the window driverdata in place. */
|
||||
if (!KMSDRM_CreateSurfaces(_this, window)) {
|
||||
return SDL_SetError("Can't window GBM/EGL surfaces on window creation.");
|
||||
return false;
|
||||
}
|
||||
} // NON-Vulkan block ends.
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ static SDL_VideoDevice *PSP_Create(void)
|
|||
|
||||
device->PumpEvents = PSP_PumpEvents;
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ RECENT REVISION HISTORY:
|
|||
Bug & warning fixes
|
||||
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
|
||||
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
|
||||
Phil Jordan Dave Moore Roy Eltham
|
||||
Phil Jordan Henner Zeller Dave Moore Roy Eltham
|
||||
Hayaki Saito Nathan Reed Won Chun
|
||||
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
|
||||
Thomas Ruf Ronny Chevalier github:rlyeh
|
||||
|
|
@ -1914,6 +1914,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
|
|||
int i,j;
|
||||
unsigned char *good;
|
||||
|
||||
if (data == NULL) return data;
|
||||
if (req_comp == img_n) return data;
|
||||
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
|
||||
|
||||
|
|
|
|||
|
|
@ -124,31 +124,30 @@ static BOOL UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messag
|
|||
return YES;
|
||||
}
|
||||
|
||||
static void UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID, int *result)
|
||||
typedef struct UIKit_ShowMessageBoxData
|
||||
{
|
||||
const SDL_MessageBoxData *messageboxdata;
|
||||
int *buttonID;
|
||||
bool result;
|
||||
} UIKit_ShowMessageBoxData;
|
||||
|
||||
static void SDLCALL UIKit_ShowMessageBoxMainThreadCallback(void *userdata)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (UIKit_ShowMessageBoxAlertController(messageboxdata, buttonID)) {
|
||||
*result = true;
|
||||
} else {
|
||||
*result = SDL_SetError("Could not show message box.");
|
||||
}
|
||||
UIKit_ShowMessageBoxData *data = (UIKit_ShowMessageBoxData *) userdata;
|
||||
data->result = UIKit_ShowMessageBoxAlertController(data->messageboxdata, data->buttonID);
|
||||
}
|
||||
}
|
||||
|
||||
bool UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
|
||||
{
|
||||
@autoreleasepool {
|
||||
__block int result = true;
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
UIKit_ShowMessageBoxImpl(messageboxdata, buttonID, &result);
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
UIKit_ShowMessageBoxImpl(messageboxdata, buttonID, &result);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
UIKit_ShowMessageBoxData data = { messageboxdata, buttonID, false };
|
||||
if (!SDL_RunOnMainThread(UIKit_ShowMessageBoxMainThreadCallback, &data, true)) {
|
||||
return false;
|
||||
} else if (!data.result) {
|
||||
return SDL_SetError("Could not show message box.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_UIKIT
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
|
|||
int i;
|
||||
SDL_MouseButtonFlags buttons = SDL_GetMouseState(NULL, NULL);
|
||||
|
||||
for (i = 0; i < MAX_MOUSE_BUTTONS; ++i) {
|
||||
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
|
||||
if (buttons & SDL_BUTTON_MASK(i)) {
|
||||
SDL_SendMouseButton(UIKit_GetEventTimestamp([touch timestamp]), sdlwindow, SDL_GLOBAL_MOUSE_ID, (Uint8)i, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ static SDL_VideoDevice *VITA_Create(void)
|
|||
|
||||
device->PumpEvents = VITA_PumpEvents;
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@ extern SDL_Window *Vita_Window;
|
|||
// Display and window functions
|
||||
extern bool VITA_VideoInit(SDL_VideoDevice *_this);
|
||||
extern void VITA_VideoQuit(SDL_VideoDevice *_this);
|
||||
extern bool VITA_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
|
||||
extern bool VITA_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
extern bool VITA_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
extern void VITA_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool VITA_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
|
|
|||
|
|
@ -163,16 +163,9 @@ static bool Wayland_SurfaceHasActiveTouches(struct wl_surface *surface)
|
|||
|
||||
static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
|
||||
{
|
||||
static Uint64 last;
|
||||
static Uint64 timestamp_offset;
|
||||
static Uint64 timestamp_offset = 0;
|
||||
const Uint64 now = SDL_GetTicksNS();
|
||||
|
||||
if (nsTimestamp < last) {
|
||||
// 32-bit timer rollover, bump the offset
|
||||
timestamp_offset += SDL_MS_TO_NS(0x100000000LLU);
|
||||
}
|
||||
last = nsTimestamp;
|
||||
|
||||
if (!timestamp_offset) {
|
||||
timestamp_offset = (now - nsTimestamp);
|
||||
}
|
||||
|
|
@ -196,19 +189,24 @@ static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
|
|||
Wayland_input_timestamp_listener
|
||||
};
|
||||
|
||||
static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
|
||||
{
|
||||
static Uint64 timestamp_offset = 0;
|
||||
static Uint32 last = 0;
|
||||
|
||||
// Handle 32-bit timer rollover.
|
||||
if (wl_timestamp_ms < last) {
|
||||
timestamp_offset += SDL_MS_TO_NS(SDL_UINT64_C(0x100000000));
|
||||
}
|
||||
last = wl_timestamp_ms;
|
||||
|
||||
return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset;
|
||||
}
|
||||
|
||||
static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
if (wl_timestamp_ms) {
|
||||
return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
if (wl_timestamp_ms) {
|
||||
return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms);
|
||||
return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -217,7 +215,7 @@ static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Ui
|
|||
static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
if (wl_timestamp_ms) {
|
||||
return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
||||
return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -226,7 +224,7 @@ static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32
|
|||
Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
if (wl_timestamp_ms) {
|
||||
return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
||||
return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -269,10 +267,11 @@ void Wayland_CreateCursorShapeDevice(struct SDL_WaylandInput *input)
|
|||
static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
while (elapsed >= repeat_info->next_repeat_ns) {
|
||||
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
|
||||
const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
|
||||
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
|
||||
const Uint64 timestamp = repeat_info->base_time_ns + repeat_info->next_repeat_ns;
|
||||
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
|
||||
}
|
||||
if (repeat_info->text[0]) {
|
||||
SDL_SendKeyboardText(repeat_info->text);
|
||||
|
|
@ -291,8 +290,8 @@ static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info)
|
|||
repeat_info->is_key_down = false;
|
||||
}
|
||||
|
||||
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint64 wl_press_time_ns,
|
||||
uint32_t scancode, bool has_text, char text[8])
|
||||
static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 keyboard_id, uint32_t key, Uint32 wl_press_time_ms,
|
||||
Uint64 base_time_ns, uint32_t scancode, bool has_text, char text[8])
|
||||
{
|
||||
if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
|
||||
return;
|
||||
|
|
@ -300,12 +299,13 @@ static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, Uint32 k
|
|||
repeat_info->is_key_down = true;
|
||||
repeat_info->keyboard_id = keyboard_id;
|
||||
repeat_info->key = key;
|
||||
repeat_info->wl_press_time_ns = wl_press_time_ns;
|
||||
repeat_info->wl_press_time_ms = wl_press_time_ms;
|
||||
repeat_info->base_time_ns = base_time_ns;
|
||||
repeat_info->sdl_press_time_ns = SDL_GetTicksNS();
|
||||
repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms);
|
||||
repeat_info->scancode = scancode;
|
||||
if (has_text) {
|
||||
SDL_copyp(repeat_info->text, text);
|
||||
SDL_memcpy(repeat_info->text, text, sizeof(repeat_info->text));
|
||||
} else {
|
||||
repeat_info->text[0] = '\0';
|
||||
}
|
||||
|
|
@ -598,11 +598,11 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|||
wind->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
||||
|
||||
input->buttons_pressed = 0;
|
||||
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_LEFT, false);
|
||||
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_RIGHT, false);
|
||||
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_MIDDLE, false);
|
||||
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X1, false);
|
||||
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X2, false);
|
||||
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_LEFT, false);
|
||||
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_RIGHT, false);
|
||||
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_MIDDLE, false);
|
||||
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_X1, false);
|
||||
SDL_SendMouseButton(0, wind->sdlwindow, input->pointer_id, SDL_BUTTON_X2, false);
|
||||
}
|
||||
|
||||
/* A pointer leave event may be emitted if the compositor hides the pointer in response to receiving a touch event.
|
||||
|
|
@ -1199,7 +1199,7 @@ static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t ti
|
|||
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
|
||||
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
|
||||
|
||||
SDL_SendTouchMotion(Wayland_GetPointerTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
||||
SDL_SendTouchMotion(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
||||
(SDL_FingerID)(id + 1), window_data->sdlwindow, x, y, 1.0f);
|
||||
}
|
||||
}
|
||||
|
|
@ -1855,7 +1855,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|||
char text[8];
|
||||
bool has_text = false;
|
||||
bool handled_by_ime = false;
|
||||
const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time);
|
||||
const Uint64 timestamp_ns = Wayland_GetKeyboardTimestamp(input, time);
|
||||
|
||||
Wayland_UpdateImplicitGrabSerial(input, serial);
|
||||
|
||||
|
|
@ -1871,7 +1871,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|||
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
|
||||
* which may be off if the application hasn't pumped events for a while.
|
||||
*/
|
||||
keyboard_repeat_handle(&input->keyboard_repeat, timestamp_raw_ns - input->keyboard_repeat.wl_press_time_ns);
|
||||
const Uint64 elapsed = SDL_MS_TO_NS(time - input->keyboard_repeat.wl_press_time_ms);
|
||||
keyboard_repeat_handle(&input->keyboard_repeat, elapsed);
|
||||
keyboard_repeat_clear(&input->keyboard_repeat);
|
||||
}
|
||||
keyboard_input_get_text(text, input, key, false, &handled_by_ime);
|
||||
|
|
@ -1879,9 +1880,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|||
|
||||
const SDL_Scancode scancode = Wayland_GetScancodeForKey(input, key);
|
||||
Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
||||
Uint64 timestamp = Wayland_GetKeyboardTimestamp(input, time);
|
||||
|
||||
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
||||
SDL_SendKeyboardKeyIgnoreModifiers(timestamp_ns, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
|
||||
|
|
@ -1890,7 +1890,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|||
}
|
||||
}
|
||||
if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) {
|
||||
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, timestamp_raw_ns, scancode, has_text, text);
|
||||
keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, time, timestamp_ns, scancode, has_text, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2951,7 +2951,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool
|
|||
return; // Not a pen we report on.
|
||||
}
|
||||
|
||||
const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_MS_TO_NS(time));
|
||||
const Uint64 timestamp = Wayland_GetEventTimestamp(Wayland_EventTimestampMSToNS(time));
|
||||
const SDL_PenID instance_id = sdltool->instance_id;
|
||||
SDL_Window *window = sdltool->tool_focus;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,17 +49,18 @@ typedef struct SDL_WaylandTabletInput
|
|||
|
||||
typedef struct
|
||||
{
|
||||
int32_t repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
|
||||
int32_t repeat_delay_ms; // Time to first repeat event in milliseconds
|
||||
Uint32 keyboard_id; // ID of the source keyboard.
|
||||
Sint32 repeat_rate; // Repeat rate in range of [1, 1000] character(s) per second
|
||||
Sint32 repeat_delay_ms; // Time to first repeat event in milliseconds
|
||||
Uint32 keyboard_id; // ID of the source keyboard.
|
||||
bool is_initialized;
|
||||
|
||||
bool is_key_down;
|
||||
uint32_t key;
|
||||
Uint64 wl_press_time_ns; // Key press time as reported by the Wayland API
|
||||
Uint32 key;
|
||||
Uint32 wl_press_time_ms; // Key press time as reported by the Wayland API in milliseconds
|
||||
Uint64 base_time_ns; // Key press time as reported by the Wayland API in nanoseconds
|
||||
Uint64 sdl_press_time_ns; // Key press time expressed in SDL ticks
|
||||
Uint64 next_repeat_ns; // Next repeat event in nanoseconds
|
||||
uint32_t scancode;
|
||||
Uint32 scancode;
|
||||
char text[8];
|
||||
} SDL_WaylandKeyboardRepeat;
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
|
|||
|
||||
if (internal->text_input_manager) {
|
||||
if (input && input->text_input) {
|
||||
const SDL_Rect *rect = &input->text_input->cursor_rect;
|
||||
const SDL_Rect *rect = &input->text_input->text_input_rect;
|
||||
enum zwp_text_input_v3_content_hint hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
|
||||
enum zwp_text_input_v3_content_purpose purpose;
|
||||
|
||||
|
|
@ -125,12 +125,21 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
|
|||
// Now that it's enabled, set the input properties
|
||||
zwp_text_input_v3_set_content_type(input->text_input->text_input, hint, purpose);
|
||||
if (!SDL_RectEmpty(rect)) {
|
||||
// This gets reset on enable so we have to cache it
|
||||
SDL_WindowData *wind = window->internal;
|
||||
const SDL_Rect scaled_rect = {
|
||||
(int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
|
||||
(int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
|
||||
(int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
|
||||
(int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
|
||||
};
|
||||
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
|
||||
|
||||
// Clamp the x value so it doesn't run too far past the end of the text input area.
|
||||
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
|
||||
rect->x,
|
||||
rect->y,
|
||||
rect->w,
|
||||
rect->h);
|
||||
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
|
||||
scaled_rect.y,
|
||||
1,
|
||||
scaled_rect.h);
|
||||
}
|
||||
zwp_text_input_v3_commit(input->text_input->text_input);
|
||||
}
|
||||
|
|
@ -174,13 +183,24 @@ bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
if (internal->text_input_manager) {
|
||||
struct SDL_WaylandInput *input = internal->input;
|
||||
if (input && input->text_input) {
|
||||
if (!SDL_RectsEqual(&window->text_input_rect, &input->text_input->cursor_rect)) {
|
||||
SDL_copyp(&input->text_input->cursor_rect, &window->text_input_rect);
|
||||
SDL_WindowData *wind = window->internal;
|
||||
const SDL_Rect scaled_rect = {
|
||||
(int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
|
||||
(int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
|
||||
(int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
|
||||
(int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
|
||||
};
|
||||
const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
|
||||
if (!SDL_RectsEqual(&scaled_rect, &input->text_input->text_input_rect) || scaled_cursor != input->text_input->text_input_cursor) {
|
||||
SDL_copyp(&input->text_input->text_input_rect, &scaled_rect);
|
||||
input->text_input->text_input_cursor = scaled_cursor;
|
||||
|
||||
// Clamp the x value so it doesn't run too far past the end of the text input area.
|
||||
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
|
||||
window->text_input_rect.x,
|
||||
window->text_input_rect.y,
|
||||
window->text_input_rect.w,
|
||||
window->text_input_rect.h);
|
||||
SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
|
||||
scaled_rect.y,
|
||||
1,
|
||||
scaled_rect.h);
|
||||
zwp_text_input_v3_commit(input->text_input->text_input);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
typedef struct SDL_WaylandTextInput
|
||||
{
|
||||
struct zwp_text_input_v3 *text_input;
|
||||
SDL_Rect cursor_rect;
|
||||
SDL_Rect text_input_rect;
|
||||
int text_input_cursor;
|
||||
bool has_preedit;
|
||||
} SDL_WaylandTextInput;
|
||||
|
||||
|
|
|
|||
|
|
@ -446,9 +446,6 @@ static void Wayland_DeleteDevice(SDL_VideoDevice *device)
|
|||
WAYLAND_wl_display_disconnect(data->display);
|
||||
SDL_ClearProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER);
|
||||
}
|
||||
if (device->wakeup_lock) {
|
||||
SDL_DestroyMutex(device->wakeup_lock);
|
||||
}
|
||||
SDL_free(data);
|
||||
SDL_free(device);
|
||||
SDL_WAYLAND_UnloadSymbols();
|
||||
|
|
@ -589,7 +586,6 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
|||
}
|
||||
|
||||
device->internal = data;
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
|
||||
// Set the function pointers
|
||||
device->VideoInit = Wayland_VideoInit;
|
||||
|
|
|
|||
|
|
@ -2055,6 +2055,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
struct wl_callback *cb = wl_display_sync(_this->internal->display);
|
||||
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
|
||||
|
||||
data->showing_window = true;
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
|
||||
data->showing_window = false;
|
||||
|
||||
// Send an exposure event to signal that the client should draw.
|
||||
if (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
|
||||
|
|
@ -2277,6 +2281,11 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
|
|||
return SDL_FULLSCREEN_FAILED;
|
||||
}
|
||||
|
||||
// Drop fullscreen leave requests when showing the window.
|
||||
if (wind->showing_window && fullscreen == SDL_FULLSCREEN_OP_LEAVE) {
|
||||
return SDL_FULLSCREEN_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (wind->show_hide_sync_required) {
|
||||
WAYLAND_wl_display_roundtrip(_this->internal->display);
|
||||
}
|
||||
|
|
@ -2331,6 +2340,11 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
{
|
||||
SDL_WindowData *wind = window->internal;
|
||||
|
||||
// Drop restore requests when showing the window.
|
||||
if (wind->showing_window) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not currently fullscreen or maximized, and no state pending; nothing to do.
|
||||
if (!(window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) &&
|
||||
!wind->fullscreen_deadline_count && !wind->maximized_restored_deadline_count) {
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ struct SDL_WindowData
|
|||
bool is_fullscreen;
|
||||
bool fullscreen_exclusive;
|
||||
bool drop_fullscreen_requests;
|
||||
bool showing_window;
|
||||
bool fullscreen_was_positioned;
|
||||
bool show_hide_sync_required;
|
||||
bool scale_to_display;
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ static void WIN_UpdateMouseCapture(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)
|
||||
static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus, DWORD pos)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
HWND hwnd = data->hwnd;
|
||||
|
|
@ -389,7 +389,8 @@ static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)
|
|||
|
||||
// In relative mode we are guaranteed to have mouse focus if we have keyboard focus
|
||||
if (!SDL_GetMouse()->relative_mode) {
|
||||
GetCursorPos(&cursorPos);
|
||||
cursorPos.x = (LONG)GET_X_LPARAM(pos);
|
||||
cursorPos.y = (LONG)GET_Y_LPARAM(pos);
|
||||
ScreenToClient(hwnd, &cursorPos);
|
||||
SDL_SendMouseMotion(WIN_GetEventTimestamp(), window, SDL_GLOBAL_MOUSE_ID, false, (float)cursorPos.x, (float)cursorPos.y);
|
||||
}
|
||||
|
|
@ -472,11 +473,6 @@ static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource(ULONG extrainfo)
|
|||
return SDL_MOUSE_EVENT_SOURCE_PEN;
|
||||
}
|
||||
}
|
||||
/* Sometimes WM_INPUT events won't have the correct touch signature,
|
||||
so we have to rely purely on the touch bit being set. */
|
||||
if (SDL_TouchDevicesAvailable() && extrainfo & 0x80) {
|
||||
return SDL_MOUSE_EVENT_SOURCE_TOUCH;
|
||||
}
|
||||
return SDL_MOUSE_EVENT_SOURCE_MOUSE;
|
||||
}
|
||||
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
|
@ -614,7 +610,8 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
|
|||
return;
|
||||
}
|
||||
|
||||
if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE) {
|
||||
if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE ||
|
||||
(SDL_TouchDevicesAvailable() && (rawmouse->ulExtraInformation & 0x80) == 0x80)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1235,22 +1232,19 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
case WM_NCACTIVATE:
|
||||
{
|
||||
// Don't immediately clip the cursor in case we're clicking minimize/maximize buttons
|
||||
// This is the only place that this flag is set. This causes all subsequent calls to
|
||||
// WIN_UpdateClipCursor for this window to be no-ops in this frame's message-pumping.
|
||||
// This flag is unset at the end of message pumping each frame for every window, and
|
||||
// should never be carried over between frames.
|
||||
data->skip_update_clipcursor = true;
|
||||
data->postpone_clipcursor = true;
|
||||
data->clipcursor_queued = true;
|
||||
|
||||
/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
|
||||
actually being the foreground window, but this appears to get called in all cases where
|
||||
the global foreground window changes to and from this window. */
|
||||
WIN_UpdateFocus(data->window, !!wParam);
|
||||
WIN_UpdateFocus(data->window, !!wParam, GetMessagePos());
|
||||
} break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
{
|
||||
// Update the focus in case we changed focus to a child window and then away from the application
|
||||
WIN_UpdateFocus(data->window, !!LOWORD(wParam));
|
||||
WIN_UpdateFocus(data->window, !!LOWORD(wParam), GetMessagePos());
|
||||
} break;
|
||||
|
||||
case WM_MOUSEACTIVATE:
|
||||
|
|
@ -1273,14 +1267,14 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
case WM_SETFOCUS:
|
||||
{
|
||||
// Update the focus in case it's changing between top-level windows in the same application
|
||||
WIN_UpdateFocus(data->window, true);
|
||||
WIN_UpdateFocus(data->window, true, GetMessagePos());
|
||||
} break;
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
case WM_ENTERIDLE:
|
||||
{
|
||||
// Update the focus in case it's changing between top-level windows in the same application
|
||||
WIN_UpdateFocus(data->window, false);
|
||||
WIN_UpdateFocus(data->window, false, GetMessagePos());
|
||||
} break;
|
||||
|
||||
case WM_POINTERENTER:
|
||||
|
|
@ -1361,8 +1355,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
const Uint64 timestamp = WIN_GetEventTimestamp();
|
||||
SDL_Window *window = data->window;
|
||||
|
||||
const bool istouching = IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam);
|
||||
|
||||
// if lifting off, do it first, so any motion changes don't cause app issues.
|
||||
if (msg == WM_POINTERUP) {
|
||||
if (!istouching) {
|
||||
SDL_SendPenTouch(timestamp, pen, window, (pen_info.penFlags & PEN_FLAG_INVERTED) != 0, false);
|
||||
}
|
||||
|
||||
|
|
@ -1392,7 +1388,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
}
|
||||
|
||||
// if setting down, do it last, so the pen is positioned correctly from the first contact.
|
||||
if (msg == WM_POINTERDOWN) {
|
||||
if (istouching) {
|
||||
SDL_SendPenTouch(timestamp, pen, window, (pen_info.penFlags & PEN_FLAG_INVERTED) != 0, true);
|
||||
}
|
||||
|
||||
|
|
@ -1408,9 +1404,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
window->flags & (SDL_WINDOW_MOUSE_RELATIVE_MODE | SDL_WINDOW_MOUSE_GRABBED) ||
|
||||
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)
|
||||
);
|
||||
if (wish_clip_cursor) {
|
||||
data->skip_update_clipcursor = false;
|
||||
WIN_UpdateClipCursor(window);
|
||||
if (wish_clip_cursor) { // queue clipcursor refresh on pump finish
|
||||
data->clipcursor_queued = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1435,6 +1430,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
SDL_SendMouseMotion(WIN_GetEventTimestamp(), window, SDL_GLOBAL_MOUSE_ID, false, (float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
|
|
@ -1498,8 +1494,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !IsIconic(hwnd)) {
|
||||
SDL_Mouse *mouse;
|
||||
DWORD pos = GetMessagePos();
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
cursorPos.x = GET_X_LPARAM(pos);
|
||||
cursorPos.y = GET_Y_LPARAM(pos);
|
||||
ScreenToClient(hwnd, &cursorPos);
|
||||
mouse = SDL_GetMouse();
|
||||
if (!mouse->was_touch_mouse_events) { // we're not a touch handler causing a mouse leave?
|
||||
|
|
@ -1638,7 +1636,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
// Reference: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
|
||||
if (SendMessage(hwnd, WM_NCHITTEST, wParam, lParam) == HTCAPTION) {
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
GetCursorPos(&cursorPos); // want the most current pos so as to not cause position change
|
||||
ScreenToClient(hwnd, &cursorPos);
|
||||
PostMessage(hwnd, WM_MOUSEMOVE, 0, cursorPos.x | (((Uint32)((Sint16)cursorPos.y)) << 16));
|
||||
}
|
||||
|
|
@ -1852,6 +1850,9 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
data->initial_size_rect.bottom = data->window->y + data->window->h;
|
||||
|
||||
SetTimer(hwnd, (UINT_PTR)SDL_IterateMainCallbacks, USER_TIMER_MINIMUM, NULL);
|
||||
|
||||
// Reset the keyboard, as we won't get any key up events during the modal loop
|
||||
SDL_ResetKeyboard();
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
@ -2590,13 +2591,27 @@ void WIN_PumpEvents(SDL_VideoDevice *_this)
|
|||
}
|
||||
}
|
||||
|
||||
// Update the clipping rect in case someone else has stolen it
|
||||
// fire queued clipcursor refreshes
|
||||
if (_this) {
|
||||
SDL_Window *window = _this->windows;
|
||||
while (window) {
|
||||
bool refresh_clipcursor = false;
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (data && data->skip_update_clipcursor) {
|
||||
data->skip_update_clipcursor = false;
|
||||
if (data) {
|
||||
refresh_clipcursor = data->clipcursor_queued;
|
||||
data->clipcursor_queued = false; // Must be cleared unconditionally.
|
||||
data->postpone_clipcursor = false; // Must be cleared unconditionally.
|
||||
// Must happen before UpdateClipCursor.
|
||||
// Although its occurrence currently
|
||||
// always coincides with the queuing of
|
||||
// clipcursor, it is logically distinct
|
||||
// and this coincidence might no longer
|
||||
// be true in the future.
|
||||
// Ergo this placement concordantly
|
||||
// conveys its unconditionality
|
||||
// vis-a-vis the queuing of clipcursor.
|
||||
}
|
||||
if (refresh_clipcursor) {
|
||||
WIN_UpdateClipCursor(window);
|
||||
}
|
||||
window = window->next;
|
||||
|
|
|
|||
|
|
@ -120,9 +120,6 @@ static void WIN_DeleteDevice(SDL_VideoDevice *device)
|
|||
SDL_UnloadObject(data->dxgiDLL);
|
||||
}
|
||||
#endif
|
||||
if (device->wakeup_lock) {
|
||||
SDL_DestroyMutex(device->wakeup_lock);
|
||||
}
|
||||
SDL_free(device->internal->rawinput);
|
||||
SDL_free(device->internal);
|
||||
SDL_free(device);
|
||||
|
|
@ -148,7 +145,6 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
|
|||
return NULL;
|
||||
}
|
||||
device->internal = data;
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
device->system_theme = WIN_GetSystemTheme();
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
|
|
|||
|
|
@ -348,6 +348,10 @@ bool WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags, SDL_WindowRec
|
|||
|
||||
// Update any child windows
|
||||
for (child_window = window->first_child; child_window; child_window = child_window->next_sibling) {
|
||||
if (!child_window->internal) {
|
||||
// This child window is not yet fully initialized.
|
||||
continue;
|
||||
}
|
||||
if (!WIN_SetWindowPositionInternal(child_window, flags, SDL_WINDOWRECT_CURRENT)) {
|
||||
result = false;
|
||||
}
|
||||
|
|
@ -1028,8 +1032,9 @@ void WIN_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *
|
|||
|
||||
void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
HWND hwnd = data->hwnd;
|
||||
DWORD style;
|
||||
HWND hwnd;
|
||||
|
||||
bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, true);
|
||||
|
||||
|
|
@ -1038,17 +1043,30 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
WIN_SetWindowPosition(_this, window);
|
||||
}
|
||||
|
||||
hwnd = window->internal->hwnd;
|
||||
// If the window isn't borderless and will be fullscreen, use the borderless style to hide the initial borders.
|
||||
if (window->pending_flags & SDL_WINDOW_FULLSCREEN) {
|
||||
if (!(window->flags & SDL_WINDOW_BORDERLESS)) {
|
||||
window->flags |= SDL_WINDOW_BORDERLESS;
|
||||
style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
style &= ~STYLE_MASK;
|
||||
style |= GetWindowStyle(window);
|
||||
SetWindowLong(hwnd, GWL_STYLE, style);
|
||||
window->flags &= ~SDL_WINDOW_BORDERLESS;
|
||||
}
|
||||
}
|
||||
style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if (style & WS_EX_NOACTIVATE) {
|
||||
bActivate = false;
|
||||
}
|
||||
|
||||
data->showing_window = true;
|
||||
if (bActivate) {
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
} else {
|
||||
// Use SetWindowPos instead of ShowWindow to avoid activating the parent window if this is a child window
|
||||
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, window->internal->copybits_flag | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
}
|
||||
data->showing_window = false;
|
||||
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU && bActivate) {
|
||||
WIN_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
|
|
@ -1207,10 +1225,12 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
|
||||
HWND hwnd = data->hwnd;
|
||||
data->expected_resize = true;
|
||||
ShowWindow(hwnd, SW_RESTORE);
|
||||
data->expected_resize = false;
|
||||
if (!data->showing_window || window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED)) {
|
||||
HWND hwnd = data->hwnd;
|
||||
data->expected_resize = true;
|
||||
ShowWindow(hwnd, SW_RESTORE);
|
||||
data->expected_resize = false;
|
||||
}
|
||||
} else {
|
||||
data->windowed_mode_was_maximized = false;
|
||||
}
|
||||
|
|
@ -1218,18 +1238,22 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
|
||||
static void WIN_UpdateCornerRoundingForHWND(SDL_VideoDevice *_this, HWND hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPref)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
if (videodata->DwmSetWindowAttribute) {
|
||||
videodata->DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void WIN_UpdateBorderColorForHWND(SDL_VideoDevice *_this, HWND hwnd, COLORREF colorRef)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
if (videodata->DwmSetWindowAttribute) {
|
||||
videodata->DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &colorRef, sizeof(colorRef));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1591,7 +1615,7 @@ void WIN_UnclipCursorForWindow(SDL_Window *window) {
|
|||
void WIN_UpdateClipCursor(SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (data->in_title_click || data->focus_click_pending || data->skip_update_clipcursor) {
|
||||
if (data->in_title_click || data->focus_click_pending || data->postpone_clipcursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,11 +78,13 @@ struct SDL_WindowData
|
|||
bool in_border_change;
|
||||
bool in_title_click;
|
||||
Uint8 focus_click_pending;
|
||||
bool skip_update_clipcursor;
|
||||
bool postpone_clipcursor;
|
||||
bool clipcursor_queued;
|
||||
bool windowed_mode_was_maximized;
|
||||
bool in_window_deactivation;
|
||||
bool force_ws_maximizebox;
|
||||
bool disable_move_size_events;
|
||||
bool showing_window;
|
||||
int in_modal_loop;
|
||||
RECT initial_size_rect;
|
||||
RECT cursor_clipped_rect; // last successfully committed clipping rect for this window
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@
|
|||
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
|
||||
#include <X11/extensions/XTest.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -506,17 +506,32 @@ static void X11_DispatchFocusOut(SDL_VideoDevice *_this, SDL_WindowData *data)
|
|||
static void X11_DispatchMapNotify(SDL_WindowData *data)
|
||||
{
|
||||
SDL_Window *window = data->window;
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
|
||||
if (!(window->flags & SDL_WINDOW_HIDDEN) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
data->was_shown = true;
|
||||
|
||||
// This may be sent when restoring a minimized window.
|
||||
if (window->flags & SDL_WINDOW_MINIMIZED) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
|
||||
SDL_UpdateWindowGrab(window);
|
||||
}
|
||||
}
|
||||
|
||||
static void X11_DispatchUnmapNotify(SDL_WindowData *data)
|
||||
{
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
|
||||
SDL_Window *window = data->window;
|
||||
|
||||
// This may be sent when minimizing a window.
|
||||
if (!window->is_hiding) {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
|
||||
} else {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void DispatchWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *data, const SDL_Point *point)
|
||||
|
|
@ -1096,6 +1111,41 @@ void X11_GetBorderValues(SDL_WindowData *data)
|
|||
}
|
||||
}
|
||||
|
||||
void X11_EmitConfigureNotifyEvents(SDL_WindowData *data, XConfigureEvent *xevent)
|
||||
{
|
||||
if (xevent->x != data->last_xconfigure.x ||
|
||||
xevent->y != data->last_xconfigure.y) {
|
||||
if (!data->size_move_event_flags) {
|
||||
SDL_Window *w;
|
||||
int x = xevent->x;
|
||||
int y = xevent->y;
|
||||
|
||||
data->pending_operation &= ~X11_PENDING_OP_MOVE;
|
||||
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
|
||||
|
||||
for (w = data->window->first_child; w; w = w->next_sibling) {
|
||||
// Don't update hidden child popup windows, their relative position doesn't change
|
||||
if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) {
|
||||
X11_UpdateWindowPosition(w, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xevent->width != data->last_xconfigure.width ||
|
||||
xevent->height != data->last_xconfigure.height) {
|
||||
if (!data->size_move_event_flags) {
|
||||
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
|
||||
xevent->width,
|
||||
xevent->height);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_copyp(&data->last_xconfigure, xevent);
|
||||
}
|
||||
|
||||
static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
|
|
@ -1291,8 +1341,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
SDL_SendMouseMotion(0, data->window, SDL_GLOBAL_MOUSE_ID, false, (float)xevent->xcrossing.x, (float)xevent->xcrossing.y);
|
||||
}
|
||||
|
||||
// We ungrab in LeaveNotify, so we may need to grab again here
|
||||
SDL_UpdateWindowGrab(data->window);
|
||||
// We ungrab in LeaveNotify, so we may need to grab again here, but not if captured, as the capture can be lost.
|
||||
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
SDL_UpdateWindowGrab(data->window);
|
||||
}
|
||||
|
||||
X11_ProcessHitTest(_this, data, mouse->last_x, mouse->last_y, true);
|
||||
} break;
|
||||
|
|
@ -1320,7 +1372,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
xevent->xcrossing.detail != NotifyInferior) {
|
||||
|
||||
/* In order for interaction with the window decorations and menu to work properly
|
||||
on Mutter, we need to ungrab the keyboard when the the mouse leaves. */
|
||||
on Mutter, we need to ungrab the keyboard when the mouse leaves. */
|
||||
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN)) {
|
||||
X11_SetWindowKeyboardGrab(_this, data->window, false);
|
||||
}
|
||||
|
|
@ -1447,9 +1499,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
xevent->xconfigure.x, xevent->xconfigure.y,
|
||||
xevent->xconfigure.width, xevent->xconfigure.height);
|
||||
#endif
|
||||
// Real configure notify events are relative to the parent, synthetic events are absolute.
|
||||
if (!xevent->xconfigure.send_event)
|
||||
{
|
||||
// Real configure notify events are relative to the parent, synthetic events are absolute.
|
||||
if (!xevent->xconfigure.send_event) {
|
||||
unsigned int NumChildren;
|
||||
Window ChildReturn, Root, Parent;
|
||||
Window *Children;
|
||||
|
|
@ -1462,41 +1513,23 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
&ChildReturn);
|
||||
}
|
||||
|
||||
if (xevent->xconfigure.x != data->last_xconfigure.x ||
|
||||
xevent->xconfigure.y != data->last_xconfigure.y) {
|
||||
if (!data->size_move_event_flags) {
|
||||
SDL_Window *w;
|
||||
int x = xevent->xconfigure.x;
|
||||
int y = xevent->xconfigure.y;
|
||||
/* Xfce sends ConfigureNotify before PropertyNotify when toggling fullscreen and maximized, which
|
||||
* is backwards from every other window manager, as well as what is expected by SDL and its clients.
|
||||
* Defer emitting the size/move events until the corresponding PropertyNotify arrives.
|
||||
*/
|
||||
const Uint32 changed = X11_GetNetWMState(_this, data->window, xevent->xproperty.window) ^ data->window->flags;
|
||||
if (changed & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) {
|
||||
SDL_copyp(&data->pending_xconfigure, &xevent->xconfigure);
|
||||
data->emit_size_move_after_property_notify = true;
|
||||
}
|
||||
|
||||
data->pending_operation &= ~X11_PENDING_OP_MOVE;
|
||||
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
|
||||
|
||||
for (w = data->window->first_child; w; w = w->next_sibling) {
|
||||
// Don't update hidden child popup windows, their relative position doesn't change
|
||||
if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) {
|
||||
X11_UpdateWindowPosition(w, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!data->emit_size_move_after_property_notify) {
|
||||
X11_EmitConfigureNotifyEvents(data, &xevent->xconfigure);
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
X11_HandleConfigure(data->window, &xevent->xconfigure);
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
if (xevent->xconfigure.width != data->last_xconfigure.width ||
|
||||
xevent->xconfigure.height != data->last_xconfigure.height) {
|
||||
if (!data->size_move_event_flags) {
|
||||
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
|
||||
xevent->xconfigure.width,
|
||||
xevent->xconfigure.height);
|
||||
}
|
||||
}
|
||||
|
||||
data->last_xconfigure = xevent->xconfigure;
|
||||
} break;
|
||||
|
||||
// Have we been requested to quit (or another client message?)
|
||||
|
|
@ -1782,19 +1815,15 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
|
||||
if (xevent->xproperty.atom == data->videodata->atoms._NET_WM_STATE) {
|
||||
/* Get the new state from the window manager.
|
||||
Compositing window managers can alter visibility of windows
|
||||
without ever mapping / unmapping them, so we handle that here,
|
||||
because they use the NETWM protocol to notify us of changes.
|
||||
* Compositing window managers can alter visibility of windows
|
||||
* without ever mapping / unmapping them, so we handle that here,
|
||||
* because they use the NETWM protocol to notify us of changes.
|
||||
*/
|
||||
const SDL_WindowFlags flags = X11_GetNetWMState(_this, data->window, xevent->xproperty.window);
|
||||
const SDL_WindowFlags changed = flags ^ data->window->flags;
|
||||
|
||||
if ((changed & (SDL_WINDOW_HIDDEN | SDL_WINDOW_FULLSCREEN)) != 0) {
|
||||
if (flags & SDL_WINDOW_HIDDEN) {
|
||||
X11_DispatchUnmapNotify(data);
|
||||
} else {
|
||||
X11_DispatchMapNotify(data);
|
||||
}
|
||||
if ((changed & SDL_WINDOW_HIDDEN) && !(flags & SDL_WINDOW_HIDDEN)) {
|
||||
X11_DispatchMapNotify(data);
|
||||
}
|
||||
|
||||
if (!SDL_WINDOW_IS_POPUP(data->window)) {
|
||||
|
|
@ -1805,6 +1834,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
if (!(flags & SDL_WINDOW_MINIMIZED)) {
|
||||
const bool commit = SDL_memcmp(&data->window->current_fullscreen_mode, &data->requested_fullscreen_mode, sizeof(SDL_DisplayMode)) != 0;
|
||||
|
||||
// Ensure the maximized flag is cleared before entering fullscreen.
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0);
|
||||
if (commit) {
|
||||
/* This was initiated by the compositor, or the mode was changed between the request and the window
|
||||
|
|
@ -1896,6 +1927,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (data->emit_size_move_after_property_notify) {
|
||||
X11_EmitConfigureNotifyEvents(data, &data->pending_xconfigure);
|
||||
data->emit_size_move_after_property_notify = false;
|
||||
}
|
||||
if ((flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
if (data->pending_move) {
|
||||
DispatchWindowMove(_this, data, &data->pending_move_point);
|
||||
|
|
|
|||
|
|
@ -762,7 +762,9 @@ void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
|
|||
break;
|
||||
}
|
||||
(void)SDL_snprintf(deeplink, sizeof(deeplink),
|
||||
"steam://open/keyboard?XPosition=0&YPosition=0&Width=0&Height=0&Mode=%d",
|
||||
"steam://open/keyboard?XPosition=%i&YPosition=%i&Width=%i&Height=%i&Mode=%d",
|
||||
window->text_input_rect.x, window->text_input_rect.y,
|
||||
window->text_input_rect.w, window->text_input_rect.h,
|
||||
mode);
|
||||
SDL_OpenURL(deeplink);
|
||||
videodata->steam_keyboard_open = true;
|
||||
|
|
|
|||
|
|
@ -425,6 +425,13 @@ static bool X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
|
|||
Display *display = data->display;
|
||||
SDL_WindowData *windowdata = NULL;
|
||||
const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
#ifdef XRANDR_DISABLED_BY_DEFAULT
|
||||
const bool use_xrandr_by_default = false;
|
||||
#else
|
||||
const bool use_xrandr_by_default = true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (messageboxdata->window) {
|
||||
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(messageboxdata->window);
|
||||
|
|
@ -497,7 +504,17 @@ static bool X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
|
|||
const SDL_DisplayData *dpydata = dpy->internal;
|
||||
x = dpydata->x + ((dpy->current_mode->w - data->dialog_width) / 2);
|
||||
y = dpydata->y + ((dpy->current_mode->h - data->dialog_height) / 3);
|
||||
} else { // oh well. This will misposition on a multi-head setup. Init first next time.
|
||||
}
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
else if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, use_xrandr_by_default)) {
|
||||
XRRScreenResources *screen = X11_XRRGetScreenResourcesCurrent(display, DefaultRootWindow(display));
|
||||
XRRCrtcInfo *crtc_info = X11_XRRGetCrtcInfo(display, screen, screen->crtcs[0]);
|
||||
x = (crtc_info->width - data->dialog_width) / 2;
|
||||
y = (crtc_info->height - data->dialog_height) / 3;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// oh well. This will misposition on a multi-head setup. Init first next time.
|
||||
x = (DisplayWidth(display, data->screen) - data->dialog_width) / 2;
|
||||
y = (DisplayHeight(display, data->screen) - data->dialog_height) / 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,14 +283,16 @@ static X11_PenHandle *X11_MaybeAddPen(SDL_VideoDevice *_this, const XIDeviceInfo
|
|||
|
||||
X11_PenHandle *X11_MaybeAddPenByDeviceID(SDL_VideoDevice *_this, int deviceid)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
int num_device_info = 0;
|
||||
XIDeviceInfo *device_info = X11_XIQueryDevice(data->display, deviceid, &num_device_info);
|
||||
if (device_info) {
|
||||
SDL_assert(num_device_info == 1);
|
||||
X11_PenHandle *handle = X11_MaybeAddPen(_this, device_info);
|
||||
X11_XIFreeDeviceInfo(device_info);
|
||||
return handle;
|
||||
if (X11_Xinput2IsInitialized()) {
|
||||
SDL_VideoData *data = _this->internal;
|
||||
int num_device_info = 0;
|
||||
XIDeviceInfo *device_info = X11_XIQueryDevice(data->display, deviceid, &num_device_info);
|
||||
if (device_info) {
|
||||
SDL_assert(num_device_info == 1);
|
||||
X11_PenHandle *handle = X11_MaybeAddPen(_this, device_info);
|
||||
X11_XIFreeDeviceInfo(device_info);
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -306,6 +308,10 @@ void X11_RemovePenByDeviceID(int deviceid)
|
|||
|
||||
void X11_InitPen(SDL_VideoDevice *_this)
|
||||
{
|
||||
if (!X11_Xinput2IsInitialized()) {
|
||||
return; // we need XIQueryDevice() for this.
|
||||
}
|
||||
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
#define LOOKUP_PEN_ATOM(X) X11_XInternAtom(data->display, X, False)
|
||||
|
|
|
|||
|
|
@ -63,9 +63,6 @@ static void X11_DeleteDevice(SDL_VideoDevice *device)
|
|||
X11_XCloseDisplay(data->request_display);
|
||||
}
|
||||
SDL_free(data->windowlist);
|
||||
if (device->wakeup_lock) {
|
||||
SDL_DestroyMutex(device->wakeup_lock);
|
||||
}
|
||||
SDL_free(device->internal);
|
||||
SDL_free(device);
|
||||
|
||||
|
|
@ -78,23 +75,6 @@ static bool X11_IsXWayland(Display *d)
|
|||
return X11_XQueryExtension(d, "XWAYLAND", &opcode, &event, &error) == True;
|
||||
}
|
||||
|
||||
static bool X11_CheckCurrentDesktop(const char *name)
|
||||
{
|
||||
SDL_Environment *env = SDL_GetEnvironment();
|
||||
|
||||
const char *desktopVar = SDL_GetEnvironmentVariable(env, "DESKTOP_SESSION");
|
||||
if (desktopVar && SDL_strcasecmp(desktopVar, name) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
desktopVar = SDL_GetEnvironmentVariable(env, "XDG_CURRENT_DESKTOP");
|
||||
if (desktopVar && SDL_strcasestr(desktopVar, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *X11_CreateDevice(void)
|
||||
{
|
||||
SDL_VideoDevice *device;
|
||||
|
|
@ -146,8 +126,6 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
|
||||
#ifdef X11_DEBUG
|
||||
X11_XSynchronize(data->display, True);
|
||||
#endif
|
||||
|
|
@ -275,17 +253,11 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
|||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT;
|
||||
|
||||
/* Openbox doesn't send the new window dimensions when entering fullscreen, so the events must be synthesized.
|
||||
* This is otherwise not wanted, as it can break fullscreen window positioning on multi-monitor configurations.
|
||||
*/
|
||||
if (!X11_CheckCurrentDesktop("openbox")) {
|
||||
device->device_caps |= VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES;
|
||||
}
|
||||
|
||||
data->is_xwayland = X11_IsXWayland(x11_display);
|
||||
if (data->is_xwayland) {
|
||||
device->device_caps |= VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |
|
||||
VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS;
|
||||
VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS |
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
|
||||
}
|
||||
|
||||
return device;
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
|
|||
}
|
||||
|
||||
const bool force_override_redirect = SDL_GetHintBoolean(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, false);
|
||||
const bool use_resize_sync = !(window->flags & SDL_WINDOW_VULKAN); /* doesn't work well with Vulkan */
|
||||
const bool use_resize_sync = !!(window->flags & SDL_WINDOW_OPENGL); // Doesn't work well with Vulkan
|
||||
SDL_WindowData *windowdata;
|
||||
Display *display = data->display;
|
||||
int screen = displaydata->screen;
|
||||
|
|
@ -934,6 +934,75 @@ static int X11_CatchAnyError(Display *d, XErrorEvent *e)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void X11_ExternalResizeMoveSync(SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
Display *display = data->videodata->display;
|
||||
int (*prev_handler)(Display *, XErrorEvent *);
|
||||
unsigned int childCount;
|
||||
Window childReturn, root, parent;
|
||||
Window *children;
|
||||
XWindowAttributes attrs;
|
||||
Uint64 timeout = 0;
|
||||
int x, y;
|
||||
const bool send_move = !!(data->pending_operation & X11_PENDING_OP_MOVE);
|
||||
const bool send_resize = !!(data->pending_operation & X11_PENDING_OP_RESIZE);
|
||||
|
||||
X11_XSync(display, False);
|
||||
X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount);
|
||||
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
|
||||
|
||||
/* Wait a brief time to see if the window manager decided to let the move or resize happen.
|
||||
* If the window changes at all, even to an unexpected value, we break out.
|
||||
*/
|
||||
timeout = SDL_GetTicksNS() + SDL_MS_TO_NS(100);
|
||||
while (true) {
|
||||
caught_x11_error = false;
|
||||
X11_XSync(display, False);
|
||||
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
|
||||
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
|
||||
attrs.x, attrs.y, &x, &y, &childReturn);
|
||||
SDL_GlobalToRelativeForWindow(window, x, y, &x, &y);
|
||||
|
||||
if (!caught_x11_error) {
|
||||
if ((data->pending_operation & X11_PENDING_OP_MOVE) && (x == data->expected.x + data->border_left && y == data->expected.y + data->border_top)) {
|
||||
data->pending_operation &= ~X11_PENDING_OP_MOVE;
|
||||
}
|
||||
if ((data->pending_operation & X11_PENDING_OP_RESIZE) && (attrs.width == data->expected.w && attrs.height == data->expected.h)) {
|
||||
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
|
||||
}
|
||||
|
||||
if (data->pending_operation == X11_PENDING_OP_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GetTicksNS() >= timeout) {
|
||||
// Timed out without the expected values. Update the requested data so future sync calls won't block.
|
||||
data->pending_operation &= ~(X11_PENDING_OP_MOVE | X11_PENDING_OP_RESIZE);
|
||||
data->expected.x = x;
|
||||
data->expected.y = y;
|
||||
data->expected.w = attrs.width;
|
||||
data->expected.h = attrs.height;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
if (!caught_x11_error) {
|
||||
if (send_move) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, x, y);
|
||||
}
|
||||
if (send_resize) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, attrs.width, attrs.height);
|
||||
}
|
||||
}
|
||||
|
||||
X11_XSetErrorHandler(prev_handler);
|
||||
caught_x11_error = false;
|
||||
}
|
||||
|
||||
/* Wait a brief time, or not, to see if the window manager decided to move/resize the window.
|
||||
* Send MOVED and RESIZED window events */
|
||||
static bool X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, Uint64 param_timeout)
|
||||
|
|
@ -1214,9 +1283,10 @@ void X11_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
|
||||
X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
|
||||
|
||||
sizehints->min_width = sizehints->max_width = window->pending.w;
|
||||
sizehints->min_height = sizehints->max_height = window->pending.h;
|
||||
data->expected.w = sizehints->min_width = sizehints->max_width = window->pending.w;
|
||||
data->expected.h = sizehints->min_height = sizehints->max_height = window->pending.h;
|
||||
sizehints->flags |= PMinSize | PMaxSize;
|
||||
data->pending_operation |= X11_PENDING_OP_RESIZE;
|
||||
|
||||
X11_XSetWMNormalHints(display, data->xwindow, sizehints);
|
||||
|
||||
|
|
@ -1504,6 +1574,12 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
X11_PumpEvents(_this);
|
||||
data->size_move_event_flags = 0;
|
||||
|
||||
/* A MapNotify or PropertyNotify may not have arrived, so ensure that the shown event is dispatched
|
||||
* to apply pending state before clearing the flag.
|
||||
*/
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
|
||||
data->was_shown = true;
|
||||
|
||||
// If a configure event was received (type is non-zero), send the final window size and coordinates.
|
||||
if (data->last_xconfigure.type) {
|
||||
int x, y;
|
||||
|
|
@ -1695,6 +1771,11 @@ void X11_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
|
||||
void X11_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
// Don't restore the window the first time it is being shown.
|
||||
if (!window->internal->was_shown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->internal->pending_operation & (X11_PENDING_OP_FULLSCREEN | X11_PENDING_OP_MAXIMIZE | X11_PENDING_OP_MINIMIZE)) {
|
||||
SDL_SyncWindow(window);
|
||||
}
|
||||
|
|
@ -1729,6 +1810,10 @@ static SDL_FullscreenResult X11_SetWindowFullscreenViaWM(SDL_VideoDevice *_this,
|
|||
Atom _NET_WM_STATE = data->videodata->atoms._NET_WM_STATE;
|
||||
Atom _NET_WM_STATE_FULLSCREEN = data->videodata->atoms._NET_WM_STATE_FULLSCREEN;
|
||||
|
||||
if (!data->was_shown && fullscreen == SDL_FULLSCREEN_OP_LEAVE) {
|
||||
return SDL_FULLSCREEN_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (X11_IsWindowMapped(_this, window)) {
|
||||
XEvent e;
|
||||
|
||||
|
|
@ -2223,6 +2308,15 @@ void X11_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
|
|||
|
||||
bool X11_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
// If the window is external and has only a pending resize or move event, use the special external sync path to avoid processing events.
|
||||
if ((window->flags & SDL_WINDOW_EXTERNAL) &&
|
||||
(data->pending_operation & ~(X11_PENDING_OP_RESIZE | X11_PENDING_OP_MOVE)) == X11_PENDING_OP_NONE) {
|
||||
X11_ExternalResizeMoveSync(window);
|
||||
return true;
|
||||
}
|
||||
|
||||
const Uint64 current_time = SDL_GetTicksNS();
|
||||
Uint64 timeout = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct SDL_WindowData
|
|||
bool pending_move;
|
||||
SDL_Point pending_move_point;
|
||||
XConfigureEvent last_xconfigure;
|
||||
XConfigureEvent pending_xconfigure;
|
||||
struct SDL_VideoData *videodata;
|
||||
unsigned long user_time;
|
||||
Atom xdnd_req;
|
||||
|
|
@ -115,6 +116,8 @@ struct SDL_WindowData
|
|||
bool previous_borders_nonzero;
|
||||
bool toggle_borders;
|
||||
bool fullscreen_borders_forced_on;
|
||||
bool was_shown;
|
||||
bool emit_size_move_after_property_notify;
|
||||
SDL_HitTestResult hit_test_result;
|
||||
|
||||
XPoint xim_spot;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ const std = @import("std");
|
|||
pub fn addShaderDefinition(
|
||||
b: *std.Build,
|
||||
comptime sdl3Path: []const u8,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
shaderName: []const u8,
|
||||
jsonPath: std.Build.LazyPath,
|
||||
|
|
@ -16,7 +17,7 @@ pub fn addShaderDefinition(
|
|||
const module = b.createModule(.{ .root_source_file = reflectedZigOut, .optimize = optimize });
|
||||
|
||||
const dep = b.dependency("shaderTypes", .{
|
||||
.target = b.graph.host,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
module.addImport("shaderTypes", dep.module("shaderTypes"));
|
||||
|
|
@ -28,11 +29,12 @@ pub fn shaderDefintion(
|
|||
b: *std.Build,
|
||||
module: *std.Build.Module,
|
||||
comptime sdl3Path: []const u8,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
shaderName: []const u8,
|
||||
jsonPath: std.Build.LazyPath,
|
||||
) void {
|
||||
const mod = addShaderDefinition(b, sdl3Path, optimize, shaderName, jsonPath);
|
||||
const mod = addShaderDefinition(b, sdl3Path, target, optimize, shaderName, jsonPath);
|
||||
module.addImport(shaderName, mod);
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +69,7 @@ pub fn build(b: *std.Build) void {
|
|||
mod.addImport("shaderTypes", shaderTypes.module("shaderTypes"));
|
||||
|
||||
mod.addIncludePath(b.path("SDL/include"));
|
||||
// mod.linkLibrary(sdl3_lib);
|
||||
mod.linkLibrary(sdl3_lib);
|
||||
|
||||
const test_step = b.step("test", "run unit tests for sdl3");
|
||||
const tests = b.addExecutable(.{
|
||||
|
|
@ -80,11 +82,12 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
tests.root_module.addImport("sdl3", mod);
|
||||
|
||||
const vertexDefinitions = addShaderDefinition(b, ".", optimize, "hello-triangle.vert", b.path("content/hello-triangle.vert.json"));
|
||||
const vertexDefinitions = addShaderDefinition(b, ".", target, optimize, "hello-triangle.vert", b.path("content/hello-triangle.vert.json"));
|
||||
tests.root_module.addImport("hello-triangle.vert", vertexDefinitions);
|
||||
|
||||
const runArtifact = b.addRunArtifact(tests);
|
||||
test_step.dependOn(&runArtifact.step);
|
||||
|
||||
b.installArtifact(sdl3_lib);
|
||||
b.installArtifact(tests);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -3,14 +3,6 @@
|
|||
|
||||
using namespace metal;
|
||||
|
||||
struct type_TransformBuffer
|
||||
{
|
||||
float4x4 modelMatrix;
|
||||
float4x4 viewMatrix;
|
||||
float4x4 projectionMatrix;
|
||||
float time;
|
||||
};
|
||||
|
||||
struct Scene
|
||||
{
|
||||
float4 color;
|
||||
|
|
@ -21,19 +13,8 @@ struct type_StructuredBuffer_Scene
|
|||
Scene _m0[1];
|
||||
};
|
||||
|
||||
struct Scene2
|
||||
{
|
||||
float4 color;
|
||||
float4 lmfao;
|
||||
};
|
||||
|
||||
struct type_StructuredBuffer_Scene2
|
||||
{
|
||||
Scene2 _m0[1];
|
||||
};
|
||||
|
||||
constant float2 _40 = {};
|
||||
constant float4 _41 = {};
|
||||
constant float2 _30 = {};
|
||||
constant float4 _31 = {};
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
|
|
@ -41,45 +22,45 @@ struct main0_out
|
|||
float4 gl_Position [[position]];
|
||||
};
|
||||
|
||||
vertex main0_out main0(constant type_TransformBuffer& TransformBuffer [[buffer(0)]], const device type_StructuredBuffer_Scene& test [[buffer(1)]], const device type_StructuredBuffer_Scene2& test2 [[buffer(2)]], uint gl_VertexIndex [[vertex_id]])
|
||||
vertex main0_out main0(const device type_StructuredBuffer_Scene& test [[buffer(0)]], uint gl_VertexIndex [[vertex_id]])
|
||||
{
|
||||
main0_out out = {};
|
||||
float4 _68;
|
||||
float2 _69;
|
||||
float4 _58;
|
||||
float2 _59;
|
||||
if (gl_VertexIndex == 0u)
|
||||
{
|
||||
_68 = test._m0[0u].color;
|
||||
_69 = float2(-1.0);
|
||||
_58 = test._m0[0u].color;
|
||||
_59 = float2(-1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float4 _66;
|
||||
float2 _67;
|
||||
float4 _56;
|
||||
float2 _57;
|
||||
if (gl_VertexIndex == 1u)
|
||||
{
|
||||
_66 = test2._m0[1u].color;
|
||||
_67 = float2(1.0, -1.0);
|
||||
_56 = test._m0[1u].color;
|
||||
_57 = float2(1.0, -1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool _58 = gl_VertexIndex == 2u;
|
||||
float4 _63;
|
||||
if (_58)
|
||||
bool _48 = gl_VertexIndex == 2u;
|
||||
float4 _53;
|
||||
if (_48)
|
||||
{
|
||||
_63 = test._m0[2u].color;
|
||||
_53 = test._m0[2u].color;
|
||||
}
|
||||
else
|
||||
{
|
||||
_63 = _41;
|
||||
_53 = _31;
|
||||
}
|
||||
_66 = _63;
|
||||
_67 = select(_40, float2(0.0, 1.0), bool2(_58));
|
||||
_56 = _53;
|
||||
_57 = select(_30, float2(0.0, 1.0), bool2(_48));
|
||||
}
|
||||
_68 = _66;
|
||||
_69 = _67;
|
||||
_58 = _56;
|
||||
_59 = _57;
|
||||
}
|
||||
out.out_var_TEXCOORD0 = _68;
|
||||
out.gl_Position = TransformBuffer.modelMatrix * float4(_69, 0.0, 1.0);
|
||||
out.out_var_TEXCOORD0 = _58;
|
||||
out.gl_Position = float4(_59, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue