Compare commits
147
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68bfcb6c54 | ||
|
|
0d01efca52 | ||
|
|
0e65e04ce1 | ||
|
|
58d351fe98 | ||
|
|
9b71f18141 | ||
|
|
554f08bac3 | ||
|
|
913813a933 | ||
|
|
4e34c771e4 | ||
|
|
9995174e68 | ||
|
|
5a0197d430 | ||
|
|
4a55143e15 | ||
|
|
87c9bc1b1f | ||
|
|
16a57b70f7 | ||
|
|
69564cd0b1 | ||
|
|
da648b00e7 | ||
|
|
5886d90308 | ||
|
|
e84df0cad1 | ||
|
|
e482904111 | ||
|
|
b8ee44ca6a | ||
|
|
4a4abe4240 | ||
|
|
fe47f5cc30 | ||
|
|
5b64be0810 | ||
|
|
17656d051b | ||
|
|
233fce456a | ||
|
|
5290bb036c | ||
|
|
2bff72b4f6 | ||
|
|
08ebeaee5c | ||
|
|
12b56f5447 | ||
|
|
165b86e7b7 | ||
|
|
608101a185 | ||
|
|
554bee6aae | ||
|
|
3e0ce51067 | ||
|
|
7261c43342 | ||
|
|
ad57c6ea37 | ||
|
|
caecff650d | ||
|
|
f6300be4b2 | ||
|
|
bde5687a3c | ||
|
|
0f3504f78d | ||
|
|
0aaa0321cc | ||
|
|
caaaf52583 | ||
|
|
56449f167d | ||
|
|
c7325228dc | ||
|
|
079967afa5 | ||
|
|
2ed55b614c | ||
|
|
28721e3cd2 | ||
|
|
9d9845d063 | ||
|
|
a96dc76831 | ||
|
|
ad8e517227 | ||
|
|
8d578d590f | ||
|
|
6b4a211374 | ||
|
|
55b023c961 | ||
|
|
e2d0fe3e2f | ||
|
|
6b56ff7a97 | ||
|
|
67f796ebde | ||
|
|
06da7490fc | ||
|
|
af83c442d3 | ||
|
|
d726e98596 | ||
|
|
c9a6709bd2 | ||
|
|
25816bea41 | ||
|
|
e0f6e96da0 | ||
|
|
57de46ae7e | ||
|
|
59693c8996 | ||
|
|
f0efffc093 | ||
|
|
1b41cd759c | ||
|
|
d42a1402e8 | ||
|
|
5c44678d55 | ||
|
|
0638fd58ce | ||
|
|
cb662b6730 | ||
|
|
e874c7515e | ||
|
|
2ba797576b | ||
|
|
180b454d61 | ||
|
|
6ce7ae77b1 | ||
|
|
abbaf95cf0 | ||
|
|
1081b70951 | ||
|
|
4f51f956ad | ||
|
|
b076f4b590 | ||
|
|
91180f8cb4 | ||
|
|
99aa859362 | ||
|
|
31267feb03 | ||
|
|
6a5bac72cb | ||
|
|
2ed5062950 | ||
|
|
0b0b02c5a1 | ||
|
|
28c71368a1 | ||
|
|
25bd4285ab | ||
|
|
180171cad6 | ||
|
|
bc3eeecf7f | ||
|
|
9178d14519 | ||
|
|
6cd35f5b72 | ||
|
|
72d5eb0ecb | ||
|
|
5cf924420d | ||
|
|
290574e6f6 | ||
|
|
d9db975b4b | ||
|
|
e5c0e5efa7 | ||
|
|
26a1aae098 | ||
|
|
ab114490fc | ||
|
|
9546c54286 | ||
|
|
4d3cdb70b5 | ||
|
|
a66816a72f | ||
|
|
c925f72562 | ||
|
|
ef97329f41 | ||
|
|
195f709eda | ||
|
|
eb57d94ec5 | ||
|
|
d6212ae839 | ||
|
|
b494897b3d | ||
|
|
559d4415eb | ||
|
|
49e9134774 | ||
|
|
9571b0ece8 | ||
|
|
b55cfaf90b | ||
|
|
509168856f | ||
|
|
24fa2722c3 | ||
|
|
142700f909 | ||
|
|
f3611681df | ||
|
|
7f0a5d6a10 | ||
|
|
2001cc15d5 | ||
|
|
8d604353a5 | ||
|
|
8410e11ecb | ||
|
|
9f8161bf4a | ||
|
|
c038d6f7f8 | ||
|
|
2fff37fffc | ||
|
|
6feb86be71 | ||
|
|
ed22220bc6 | ||
|
|
219cb1a59d | ||
|
|
71bd25a893 | ||
|
|
01ef4c46a1 | ||
|
|
64f728ec48 | ||
|
|
ba10adf1fb | ||
|
|
c18aa99358 | ||
|
|
3498412611 | ||
|
|
8c1b3ff210 | ||
|
|
1870052af6 | ||
|
|
3b1e3d5176 | ||
|
|
cdf26c6e97 | ||
|
|
9f1a1405a6 | ||
|
|
6e97d8d1b3 | ||
|
|
9d9a24d325 | ||
|
|
0897f4a7d1 | ||
|
|
5aec645191 | ||
|
|
07c33068f3 | ||
|
|
d684e5d57e | ||
|
|
219500d95c | ||
|
|
810addf7ae | ||
|
|
4ef077ca52 | ||
|
|
7d2275c4dc | ||
|
|
cbd8917047 | ||
|
|
c98a19401c | ||
|
|
434836c480 | ||
|
|
50d02ad732 |
No files matched your search
@@ -256,7 +256,7 @@ jobs:
|
||||
|
||||
msvc:
|
||||
needs: [src]
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2025
|
||||
outputs:
|
||||
VC-x86: ${{ steps.releaser.outputs.VC-x86 }}
|
||||
VC-x64: ${{ steps.releaser.outputs.VC-x64 }}
|
||||
|
||||
+11
-5
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# See docs/release_checklist.md
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.12")
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.18")
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(SDL3_MAINPROJECT ON)
|
||||
@@ -188,9 +188,12 @@ if(MSVC)
|
||||
# Make sure /RTC1 is disabled, otherwise it will use functions from the CRT
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
set(CMAKE_MSVC_RUNTIME_CHECKS "")
|
||||
endif()
|
||||
|
||||
if(MSVC_CLANG)
|
||||
@@ -634,6 +637,11 @@ if(MSVC)
|
||||
# Mark SDL3.dll as compatible with Control-flow Enforcement Technology (CET)
|
||||
sdl_shared_link_options("-CETCOMPAT")
|
||||
endif()
|
||||
|
||||
# for VS >= 17.14 targeting ARM64: inline the Interlocked funcs
|
||||
if(MSVC_VERSION GREATER 1943 AND SDL_CPU_ARM64 AND NOT SDL_LIBC)
|
||||
sdl_compile_options(PRIVATE "/forceInterlockedFunctions-")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
@@ -1336,9 +1344,7 @@ if(ANDROID)
|
||||
set(HAVE_SDL_HAPTIC TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_HIDAPI)
|
||||
CheckHIDAPI()
|
||||
endif()
|
||||
CheckHIDAPI()
|
||||
|
||||
if(SDL_JOYSTICK)
|
||||
set(SDL_JOYSTICK_ANDROID 1)
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.12</string>
|
||||
<string>3.2.18</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>SDLX</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.2.12</string>
|
||||
<string>3.2.18</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -3086,7 +3086,7 @@
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.12.0;
|
||||
DYLIB_CURRENT_VERSION = 201.18.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||
@@ -3121,7 +3121,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.12;
|
||||
MARKETING_VERSION = 3.2.18;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
PRODUCT_NAME = SDL3;
|
||||
@@ -3150,7 +3150,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.12.0;
|
||||
DYLIB_CURRENT_VERSION = 201.18.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -3182,7 +3182,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.12;
|
||||
MARKETING_VERSION = 3.2.18;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Title SDL 3.2.12
|
||||
Title SDL 3.2.18
|
||||
Version 1
|
||||
Description SDL Library for macOS (http://www.libsdl.org)
|
||||
DefaultLocation /Library/Frameworks
|
||||
|
||||
@@ -92,7 +92,7 @@ if(NOT TARGET SDL3::Headers)
|
||||
add_library(SDL3::Headers INTERFACE IMPORTED)
|
||||
set_target_properties(SDL3::Headers
|
||||
PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
|
||||
INTERFACE_COMPILE_OPTIONS "-F${_sdl3_framework_parent_path}"
|
||||
)
|
||||
endif()
|
||||
set(SDL3_Headers_FOUND TRUE)
|
||||
|
||||
+2
@@ -51,6 +51,8 @@
|
||||
boolean supportsRelativeMouse();
|
||||
int openFileDescriptor(java.lang.String, java.lang.String);
|
||||
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
|
||||
java.lang.String getPreferredLocales();
|
||||
java.lang.String formatLocale(java.util.Locale);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.LocaleList;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -60,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 3;
|
||||
private static final int SDL_MINOR_VERSION = 2;
|
||||
private static final int SDL_MICRO_VERSION = 12;
|
||||
private static final int SDL_MICRO_VERSION = 18;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
@@ -2116,6 +2117,44 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
int requestCode;
|
||||
boolean multipleChoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static String getPreferredLocales() {
|
||||
String result = "";
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
|
||||
LocaleList locales = LocaleList.getAdjustedDefault();
|
||||
for (int i = 0; i < locales.size(); i++) {
|
||||
if (i != 0) result += ",";
|
||||
result += formatLocale(locales.get(i));
|
||||
}
|
||||
} else if (mCurrentLocale != null) {
|
||||
result = formatLocale(mCurrentLocale);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String formatLocale(Locale locale) {
|
||||
String result = "";
|
||||
String lang = "";
|
||||
if (locale.getLanguage() == "in") {
|
||||
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
|
||||
lang = "id";
|
||||
} else if (locale.getLanguage() == "") {
|
||||
// Make sure language is never empty
|
||||
lang = "und";
|
||||
} else {
|
||||
lang = locale.getLanguage();
|
||||
}
|
||||
|
||||
if (locale.getCountry() == "") {
|
||||
result = lang;
|
||||
} else {
|
||||
result = lang + "_" + locale.getCountry();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -424,7 +424,11 @@ sub dewikify_chunk {
|
||||
$str .= "\n```$codelang\n$code\n```\n";
|
||||
}
|
||||
} elsif ($dewikify_mode eq 'manpage') {
|
||||
$str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
|
||||
# make sure these can't become part of roff syntax.
|
||||
$str =~ s/\./\\[char46]/gms;
|
||||
$str =~ s/"/\\(dq/gms;
|
||||
$str =~ s/'/\\(aq/gms;
|
||||
|
||||
if ($wikitype eq 'mediawiki') {
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
@@ -449,33 +453,52 @@ sub dewikify_chunk {
|
||||
# bullets
|
||||
$str =~ s/^\* /\n\\\(bu /gm;
|
||||
} elsif ($wikitype eq 'md') {
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\(bu /gm;
|
||||
# merge paragraphs
|
||||
$str =~ s/^[ \t]+//gm;
|
||||
$str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
|
||||
$str =~ s/\n\n/\n.PP\n/g;
|
||||
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
$str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
|
||||
my $apr = $apiprefixregex;
|
||||
if(!($apr =~ /\A\(.*\)\Z/s)) {
|
||||
# we're relying on the apiprefixregex having a capturing group.
|
||||
$apr = "(" . $apr . ")";
|
||||
}
|
||||
$str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
|
||||
# handle cases like "[x](x), [y](y), [z](z)" being separated.
|
||||
while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
|
||||
}
|
||||
|
||||
# links
|
||||
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
|
||||
|
||||
# <code></code> is also popular. :/
|
||||
$str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold+italic (this looks bad, just make it bold).
|
||||
$str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold
|
||||
$str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# italic
|
||||
$str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
|
||||
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\\(bu /gm;
|
||||
$str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
|
||||
}
|
||||
|
||||
# cleanup unnecessary quotes
|
||||
$str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
|
||||
$str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
|
||||
$str =~ s/"(\S+)"/$1/gm;
|
||||
# cleanup unnecessary whitespace
|
||||
$str =~ s/ +\n/\n/gm;
|
||||
|
||||
if (defined $code) {
|
||||
$code =~ s/\A\n+//gms;
|
||||
$code =~ s/\n+\Z//gms;
|
||||
$code =~ s/\\/\\(rs/gms;
|
||||
if ($dewikify_manpage_code_indent) {
|
||||
$str .= "\n.IP\n"
|
||||
} else {
|
||||
@@ -580,7 +603,7 @@ sub dewikify {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
} elsif ($wikitype eq 'md') {
|
||||
while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
|
||||
while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
}
|
||||
@@ -2765,7 +2788,6 @@ __EOF__
|
||||
my $wikitype = $wikitypes{$sym};
|
||||
my $sectionsref = $wikisyms{$sym};
|
||||
my $remarks = $sectionsref->{'Remarks'};
|
||||
my $params = $sectionsref->{'Function Parameters'};
|
||||
my $returns = $sectionsref->{'Return Value'};
|
||||
my $version = $sectionsref->{'Version'};
|
||||
my $threadsafety = $sectionsref->{'Thread Safety'};
|
||||
@@ -2773,6 +2795,23 @@ __EOF__
|
||||
my $examples = $sectionsref->{'Code Examples'};
|
||||
my $deprecated = $sectionsref->{'Deprecated'};
|
||||
my $headerfile = $manpageheaderfiletext;
|
||||
|
||||
my $params = undef;
|
||||
|
||||
if ($symtype == -1) { # category documentation block.
|
||||
# nothing to be done here.
|
||||
} elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
|
||||
$params = $sectionsref->{'Function Parameters'};
|
||||
} elsif ($symtype == 2) {
|
||||
$params = $sectionsref->{'Macro Parameters'};
|
||||
} elsif ($symtype == 3) {
|
||||
$params = $sectionsref->{'Fields'};
|
||||
} elsif ($symtype == 4) {
|
||||
$params = $sectionsref->{'Values'};
|
||||
} else {
|
||||
die("Unexpected symtype $symtype");
|
||||
}
|
||||
|
||||
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
|
||||
$headerfile .= "\n";
|
||||
|
||||
@@ -2839,18 +2878,22 @@ __EOF__
|
||||
$str .= dewikify($wikitype, $deprecated) . "\n";
|
||||
}
|
||||
|
||||
my $incfile = $mainincludefname;
|
||||
if (defined $headerfile) {
|
||||
$str .= ".SH HEADER FILE\n";
|
||||
$str .= dewikify($wikitype, $headerfile) . "\n";
|
||||
if($headerfile =~ /Defined in (.*)/) {
|
||||
$incfile = $1;
|
||||
}
|
||||
}
|
||||
|
||||
$str .= ".SH SYNOPSIS\n";
|
||||
$str .= ".nf\n";
|
||||
$str .= ".B #include \\(dq$mainincludefname\\(dq\n";
|
||||
$str .= ".B #include <$incfile>\n";
|
||||
$str .= ".PP\n";
|
||||
|
||||
my @decllines = split /\n/, $decl;
|
||||
foreach (@decllines) {
|
||||
$_ =~ s/\\/\\(rs/g; # fix multiline macro defs
|
||||
$_ =~ s/"/\\(dq/g;
|
||||
$str .= ".BI \"$_\n";
|
||||
}
|
||||
$str .= ".fi\n";
|
||||
@@ -2938,8 +2981,11 @@ __EOF__
|
||||
}
|
||||
|
||||
if (defined $returns) {
|
||||
# Chop datatype in parentheses off the front.
|
||||
if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
|
||||
$returns =~ s/\A\([^\)]*\) //ms;
|
||||
}
|
||||
$returns = dewikify($wikitype, $returns);
|
||||
$returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
|
||||
$str .= ".SH RETURN VALUE\n";
|
||||
$str .= "$returns\n";
|
||||
}
|
||||
@@ -2975,6 +3021,8 @@ __EOF__
|
||||
s/\A\/*//;
|
||||
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
|
||||
s/\\\(bu//; # dewikify added this, but we want to handle it.
|
||||
s/\A\s*[\:\*\-]\s*//;
|
||||
s/\A\s+//;
|
||||
s/\s+\Z//;
|
||||
|
||||
@@ -1077,6 +1077,14 @@ endmacro()
|
||||
|
||||
# Check for HIDAPI support
|
||||
macro(CheckHIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
if(SDL_HIDAPI)
|
||||
set(HAVE_HIDAPI ON)
|
||||
if(SDL_HIDAPI_LIBUSB)
|
||||
@@ -1109,14 +1117,6 @@ macro(CheckHIDAPI)
|
||||
endif()
|
||||
|
||||
if(HAVE_HIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
set(HAVE_SDL_HIDAPI TRUE)
|
||||
|
||||
if(SDL_JOYSTICK AND SDL_HIDAPI_JOYSTICK)
|
||||
|
||||
@@ -49,7 +49,7 @@ NSApplicationDelegate implementation:
|
||||
```objc
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_QUIT) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_QUIT)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_QUIT;
|
||||
@@ -61,7 +61,7 @@ NSApplicationDelegate implementation:
|
||||
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_DROP_FILE) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_DROP_FILE)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_DROP_FILE;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
- [macOS](README-macos.md)
|
||||
- [NetBSD](README-bsd.md)
|
||||
- [Nintendo Switch](README-switch.md)
|
||||
- [Nintendo 3DS](README-3ds.md)
|
||||
- [Nintendo 3DS](README-n3ds.md)
|
||||
- [OpenBSD](README-bsd.md)
|
||||
- [PlayStation 2](README-ps2.md)
|
||||
- [PlayStation 4](README-ps4.md)
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.2.12
|
||||
* Main include header for the SDL library, version 3.2.18
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
||||
@@ -1021,7 +1021,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream);
|
||||
/**
|
||||
* Query an audio stream for its currently-bound device.
|
||||
*
|
||||
* This reports the audio device that an audio stream is currently bound to.
|
||||
* This reports the logical audio device that an audio stream is currently bound to.
|
||||
*
|
||||
* If not bound, or invalid, this returns zero, which is not a valid device
|
||||
* ID.
|
||||
|
||||
@@ -486,7 +486,7 @@ SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Swap a 16-bit value from littleendian to native byte order.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1279,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 12
|
||||
#define SDL_MICRO_VERSION 18
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
||||
@@ -1167,6 +1167,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
||||
* Popup windows implicitly do not have a border/decorations and do not appear
|
||||
* on the taskbar/dock or in lists of windows such as alt-tab menus.
|
||||
*
|
||||
* By default, popup window positions will automatically be constrained to keep
|
||||
* the entire window within display bounds. This can be overridden with the
|
||||
* `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN` property.
|
||||
*
|
||||
* By default, popup menus will automatically grab keyboard focus from the parent
|
||||
* when shown. This behavior can be overridden by setting the `SDL_WINDOW_NOT_FOCUSABLE`
|
||||
* flag, setting the `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN` property to false, or
|
||||
* toggling it after creation via the `SDL_SetWindowFocusable()` function.
|
||||
*
|
||||
* If a parent window is hidden or destroyed, any child popup windows will be
|
||||
* recursively hidden or destroyed as well. Child popup windows not explicitly
|
||||
* hidden will be restored when the parent is shown.
|
||||
@@ -1207,6 +1216,9 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
||||
* be always on top
|
||||
* - `SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN`: true if the window has no
|
||||
* window decoration
|
||||
* - `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN`: true if the "tooltip" and
|
||||
* "menu" window types should be automatically constrained to be entirely within
|
||||
* display bounds (default), false if no constraints on the position are desired.
|
||||
* - `SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN`: true if the
|
||||
* window will be used with an externally managed graphics context.
|
||||
* - `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN`: true if the window should
|
||||
@@ -1321,6 +1333,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop
|
||||
|
||||
#define SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN "SDL.window.create.always_on_top"
|
||||
#define SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN "SDL.window.create.borderless"
|
||||
#define SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN "SDL.window.create.constrain_popup"
|
||||
#define SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN "SDL.window.create.focusable"
|
||||
#define SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN "SDL.window.create.external_graphics_context"
|
||||
#define SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER "SDL.window.create.flags"
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Avoid including vulkan.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_H_
|
||||
/* Avoid including vulkan_core.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_CORE_H_
|
||||
#define NO_SDL_VULKAN_TYPEDEFS
|
||||
#endif
|
||||
#ifndef NO_SDL_VULKAN_TYPEDEFS
|
||||
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
|
||||
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64)
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
|
||||
#else
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// Initialization/Cleanup routines
|
||||
#include "timer/SDL_timer_c.h"
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
extern bool SDL_HelperWindowCreate(void);
|
||||
extern void SDL_HelperWindowDestroy(void);
|
||||
#endif
|
||||
@@ -317,7 +317,7 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_DBus_Init();
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) {
|
||||
if (!SDL_HelperWindowCreate()) {
|
||||
goto quit_and_error;
|
||||
@@ -653,7 +653,7 @@ void SDL_Quit(void)
|
||||
SDL_bInMainQuit = true;
|
||||
|
||||
// Quit all subsystems
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
SDL_HelperWindowDestroy();
|
||||
#endif
|
||||
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+45
-15
@@ -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.
|
||||
}
|
||||
@@ -1385,6 +1391,7 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
typedef struct CountAudioDevicesData
|
||||
{
|
||||
int devs_seen;
|
||||
int devs_skipped;
|
||||
const int num_devices;
|
||||
SDL_AudioDeviceID *result;
|
||||
const bool recording;
|
||||
@@ -1400,7 +1407,13 @@ static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == data->recording)) {
|
||||
SDL_assert(data->devs_seen < data->num_devices);
|
||||
data->result[data->devs_seen++] = devid;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value; // this is normally risky, but we hold the device_hash_lock here.
|
||||
const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
|
||||
if (zombie) {
|
||||
data->devs_skipped++;
|
||||
} else {
|
||||
data->result[data->devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
@@ -1416,10 +1429,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
num_devices = SDL_GetAtomicInt(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count);
|
||||
result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
|
||||
if (result) {
|
||||
CountAudioDevicesData data = { 0, num_devices, result, recording };
|
||||
CountAudioDevicesData data = { 0, 0, num_devices, result, recording };
|
||||
SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
|
||||
SDL_assert(data.devs_seen == num_devices);
|
||||
result[data.devs_seen] = 0; // null-terminated.
|
||||
SDL_assert((data.devs_seen + data.devs_skipped) == num_devices);
|
||||
num_devices = data.devs_seen; // might be less if we skipped any.
|
||||
result[num_devices] = 0; // null-terminated.
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -1464,6 +1478,7 @@ static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTabl
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
SDL_assert(data->retval->instance_id == devid);
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
@@ -1502,8 +1517,10 @@ 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 = NULL;
|
||||
const void *vdev = NULL;
|
||||
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
SDL_SetError("Audio subsystem is not initialized");
|
||||
@@ -1513,10 +1530,16 @@ const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
// 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, (const void **) &device);
|
||||
if (!device) {
|
||||
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);
|
||||
@@ -1552,7 +1575,9 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
|
||||
if (device) {
|
||||
channels = device->spec.channels;
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
if (channels > 0 && device->chmap) {
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
}
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
@@ -1728,13 +1753,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->recording, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
|
||||
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
|
||||
/* We impose a simple minimum on device formats. This prevents something low quality, like an old game using S8/8000Hz audio,
|
||||
from ruining a music thing playing at CD quality that tries to open later, or some VoIP library that opens for mono output
|
||||
ruining your surround-sound game because it got there first.
|
||||
These are just requests! The backend may change any of these values during OpenDevice method! */
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
|
||||
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
|
||||
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
|
||||
|
||||
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
|
||||
device->spec.channels = SDL_max(minimum_channels, spec.channels);
|
||||
device->spec.freq = SDL_max(minimum_freq, spec.freq);
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
|
||||
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
|
||||
|
||||
@@ -1156,7 +1156,7 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
#if SDL_ALSA_DEBUG
|
||||
snd_pcm_uframes_t bufsize;
|
||||
ALSA_snd_pcm_hw_params_get_buffer_size(cfg_ctx.hwparams, &bufsize);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO,
|
||||
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
|
||||
cfg_ctx.persize, cfg_ctx.periods, bufsize);
|
||||
#endif
|
||||
|
||||
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
|
||||
{
|
||||
#ifdef HAVE_MMDEVICEAPI_H
|
||||
if (SupportsIMMDevice) {
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
@@ -189,7 +189,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// limit to native freq
|
||||
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->spec.freq = MAIN_THREAD_EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq) * 2; // double the buffer size, some browsers need more, and we'll just have to live with the latency.
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
@@ -269,19 +269,9 @@ static const char *getAppName(void)
|
||||
return SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING);
|
||||
}
|
||||
|
||||
static void ThreadedMainloopSignal(void)
|
||||
{
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // alert waiting threads to unblock.
|
||||
|
||||
// we need to kill any SDL_SetError state; we didn't create this thread
|
||||
// so its SDL TLS slot will leak otherwise, so we do this every time
|
||||
// we're (presumably) losing control of the thread.
|
||||
SDL_CleanupTLS();
|
||||
}
|
||||
|
||||
static void OperationStateChangeCallback(pa_operation *o, void *userdata)
|
||||
{
|
||||
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
|
||||
}
|
||||
|
||||
/* This function assume you are holding `mainloop`'s lock. The operation is unref'd in here, assuming
|
||||
@@ -323,7 +313,7 @@ static void DisconnectFromPulseServer(void)
|
||||
|
||||
static void PulseContextStateChangeCallback(pa_context *context, void *userdata)
|
||||
{
|
||||
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
|
||||
}
|
||||
|
||||
static bool ConnectToPulseServer(void)
|
||||
@@ -410,7 +400,7 @@ static void WriteCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||
struct SDL_PrivateAudioData *h = (struct SDL_PrivateAudioData *)userdata;
|
||||
//SDL_Log("PULSEAUDIO WRITE CALLBACK! nbytes=%u", (unsigned int) nbytes);
|
||||
h->bytes_requested += nbytes;
|
||||
ThreadedMainloopSignal();
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
@@ -481,7 +471,7 @@ static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
static void ReadCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||
{
|
||||
//SDL_Log("PULSEAUDIO READ CALLBACK! nbytes=%u", (unsigned int) nbytes);
|
||||
ThreadedMainloopSignal(); // the recording code queries what it needs, we just need to signal to end any wait
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // the recording code queries what it needs, we just need to signal to end any wait
|
||||
}
|
||||
|
||||
static bool PULSEAUDIO_WaitRecordingDevice(SDL_AudioDevice *device)
|
||||
@@ -602,7 +592,7 @@ static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
|
||||
static void PulseStreamStateChangeCallback(pa_stream *stream, void *userdata)
|
||||
{
|
||||
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
|
||||
}
|
||||
|
||||
static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
@@ -682,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;
|
||||
@@ -803,7 +794,7 @@ static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last,
|
||||
if (i) {
|
||||
AddPulseAudioDevice(false, i->description, i->name, i->index, &i->sample_spec);
|
||||
}
|
||||
ThreadedMainloopSignal();
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
// This is called when PulseAudio adds a recording ("source") device.
|
||||
@@ -813,7 +804,7 @@ static void SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_la
|
||||
if (i && (include_monitors || (i->monitor_of_sink == PA_INVALID_INDEX))) {
|
||||
AddPulseAudioDevice(true, i->description, i->name, i->index, &i->sample_spec);
|
||||
}
|
||||
ThreadedMainloopSignal();
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
static void ServerInfoCallback(pa_context *c, const pa_server_info *i, void *data)
|
||||
@@ -838,7 +829,7 @@ static void ServerInfoCallback(pa_context *c, const pa_server_info *i, void *dat
|
||||
}
|
||||
}
|
||||
|
||||
ThreadedMainloopSignal();
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
static bool FindAudioDeviceByIndex(SDL_AudioDevice *device, void *userdata)
|
||||
@@ -882,7 +873,7 @@ static void HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint3
|
||||
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByIndex, (void *)(uintptr_t)idx));
|
||||
}
|
||||
}
|
||||
ThreadedMainloopSignal();
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
static bool CheckDefaultDevice(const bool changed, char *device_path)
|
||||
|
||||
@@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
|
||||
// sceAudioOutOutput returns amount of samples queued or < 0 on error
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
|
||||
@@ -337,7 +337,7 @@ typedef struct
|
||||
static bool mgmtthrtask_DetectDevices(void *userdata)
|
||||
{
|
||||
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, S
|
||||
|
||||
SDL3.camera.ctx2d.drawImage(SDL3.camera.video, 0, 0, w, h);
|
||||
const imgrgba = SDL3.camera.ctx2d.getImageData(0, 0, w, h).data;
|
||||
Module.HEAPU8.set(imgrgba, rgba);
|
||||
HEAPU8.set(imgrgba, rgba);
|
||||
|
||||
return 1;
|
||||
}, device->actual_spec.width, device->actual_spec.height, rgba);
|
||||
|
||||
@@ -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?");
|
||||
}
|
||||
|
||||
@@ -2585,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)
|
||||
|
||||
@@ -105,7 +105,7 @@ bool GDK_RegisterChangeNotifications(void)
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppConstrainedChangeNotification handler");
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this) {
|
||||
if (constrained) {
|
||||
if (constrained && !((_this->windows) && _this->windows->text_input_active)) {
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
} else {
|
||||
SDL_SetKeyboardFocus(_this->windows);
|
||||
|
||||
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format)
|
||||
{
|
||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||
@@ -162,7 +162,7 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devn
|
||||
SDL_zero(spec);
|
||||
spec.channels = (Uint8)fmt->Format.nChannels;
|
||||
spec.freq = fmt->Format.nSamplesPerSec;
|
||||
spec.format = SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
spec.format = (force_format != SDL_AUDIO_UNKNOWN) ? force_format : SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
|
||||
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
|
||||
if (!device) {
|
||||
@@ -183,6 +183,7 @@ typedef struct SDLMMNotificationClient
|
||||
{
|
||||
const IMMNotificationClientVtbl *lpVtbl;
|
||||
SDL_AtomicInt refcount;
|
||||
SDL_AudioFormat force_format;
|
||||
} SDLMMNotificationClient;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
|
||||
@@ -241,6 +242,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceRemoved(IMMNoti
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId, DWORD dwNewState)
|
||||
{
|
||||
SDLMMNotificationClient *client = (SDLMMNotificationClient *)iclient;
|
||||
IMMDevice *device = NULL;
|
||||
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
|
||||
@@ -255,7 +257,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
|
||||
GUID dsoundguid;
|
||||
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
|
||||
if (utf8dev) {
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
@@ -286,7 +288,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
|
||||
SDLMMNotificationClient_OnPropertyValueChanged
|
||||
};
|
||||
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN };
|
||||
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
|
||||
{
|
||||
@@ -363,7 +365,7 @@ bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool reco
|
||||
return true;
|
||||
}
|
||||
|
||||
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device)
|
||||
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format)
|
||||
{
|
||||
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
|
||||
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
|
||||
@@ -405,7 +407,7 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
|
||||
SDL_zero(dsoundguid);
|
||||
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
|
||||
if (devname) {
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid);
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format);
|
||||
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
|
||||
*default_device = sdldevice;
|
||||
}
|
||||
@@ -422,10 +424,12 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format)
|
||||
{
|
||||
EnumerateEndpointsForFlow(false, default_playback);
|
||||
EnumerateEndpointsForFlow(true, default_recording);
|
||||
EnumerateEndpointsForFlow(false, default_playback, force_format);
|
||||
EnumerateEndpointsForFlow(true, default_recording, force_format);
|
||||
|
||||
notification_client.force_format = force_format;
|
||||
|
||||
// if this fails, we just won't get hotplug events. Carry on anyhow.
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)¬ification_client);
|
||||
|
||||
@@ -37,7 +37,7 @@ typedef struct SDL_IMMDevice_callbacks
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
|
||||
void SDL_IMMDevice_Quit(void);
|
||||
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format);
|
||||
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
|
||||
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
|
||||
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);
|
||||
|
||||
@@ -53,6 +53,78 @@ typedef enum RO_INIT_TYPE
|
||||
#define WC_ERR_INVALID_CHARS 0x00000080
|
||||
#endif
|
||||
|
||||
// Fake window to help with DirectInput events.
|
||||
HWND SDL_HelperWindow = NULL;
|
||||
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
|
||||
static const TCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
|
||||
static ATOM SDL_HelperWindowClass = 0;
|
||||
|
||||
/*
|
||||
* Creates a HelperWindow used for DirectInput.
|
||||
*/
|
||||
bool SDL_HelperWindowCreate(void)
|
||||
{
|
||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
WNDCLASS wce;
|
||||
|
||||
// Make sure window isn't created twice.
|
||||
if (SDL_HelperWindow != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create the class.
|
||||
SDL_zero(wce);
|
||||
wce.lpfnWndProc = DefWindowProc;
|
||||
wce.lpszClassName = SDL_HelperWindowClassName;
|
||||
wce.hInstance = hInstance;
|
||||
|
||||
// Register the class.
|
||||
SDL_HelperWindowClass = RegisterClass(&wce);
|
||||
if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
|
||||
return WIN_SetError("Unable to create Helper Window Class");
|
||||
}
|
||||
|
||||
// Create the window.
|
||||
SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
|
||||
SDL_HelperWindowName,
|
||||
WS_OVERLAPPED, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, HWND_MESSAGE, NULL,
|
||||
hInstance, NULL);
|
||||
if (!SDL_HelperWindow) {
|
||||
UnregisterClass(SDL_HelperWindowClassName, hInstance);
|
||||
return WIN_SetError("Unable to create Helper Window");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
|
||||
*/
|
||||
void SDL_HelperWindowDestroy(void)
|
||||
{
|
||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
|
||||
// Destroy the window.
|
||||
if (SDL_HelperWindow != NULL) {
|
||||
if (DestroyWindow(SDL_HelperWindow) == 0) {
|
||||
WIN_SetError("Unable to destroy Helper Window");
|
||||
return;
|
||||
}
|
||||
SDL_HelperWindow = NULL;
|
||||
}
|
||||
|
||||
// Unregister the class.
|
||||
if (SDL_HelperWindowClass != 0) {
|
||||
if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
|
||||
WIN_SetError("Unable to destroy Helper Window Class");
|
||||
return;
|
||||
}
|
||||
SDL_HelperWindowClass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets an error message based on an HRESULT
|
||||
bool WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
|
||||
{
|
||||
|
||||
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,12,0
|
||||
PRODUCTVERSION 3,2,12,0
|
||||
FILEVERSION 3,2,18,0
|
||||
PRODUCTVERSION 3,2,18,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
@@ -23,12 +23,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL\0"
|
||||
VALUE "FileVersion", "3, 2, 12, 0\0"
|
||||
VALUE "FileVersion", "3, 2, 18, 0\0"
|
||||
VALUE "InternalName", "SDL\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
|
||||
VALUE "OriginalFilename", "SDL3.dll\0"
|
||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||
VALUE "ProductVersion", "3, 2, 12, 0\0"
|
||||
VALUE "ProductVersion", "3, 2, 18, 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,8 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <UniformTypeIdentifiers/UTType.h>
|
||||
|
||||
extern void Cocoa_SetWindowHasModalDialog(SDL_Window *window, bool has_modal);
|
||||
|
||||
static void AddFileExtensionType(NSMutableArray *types, const char *pattern_ptr)
|
||||
{
|
||||
if (!*pattern_ptr) {
|
||||
@@ -163,6 +165,9 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
|
||||
if (window) {
|
||||
w = (__bridge NSWindow *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
||||
if (w) {
|
||||
Cocoa_SetWindowHasModalDialog(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (w) {
|
||||
@@ -186,6 +191,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
||||
callback(userdata, files, -1);
|
||||
}
|
||||
|
||||
Cocoa_SetWindowHasModalDialog(window, false);
|
||||
ReactivateAfterDialog();
|
||||
}];
|
||||
} else {
|
||||
@@ -206,6 +212,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);
|
||||
|
||||
|
||||
+7
-25
@@ -1077,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
|
||||
}
|
||||
|
||||
@@ -1524,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;
|
||||
@@ -1548,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);
|
||||
@@ -1562,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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -371,10 +371,10 @@ static const SDL_Scancode xfree86_scancode_table2[] = {
|
||||
/* 188, 0x0bc */ SDL_SCANCODE_F18, // XF86Launch9
|
||||
/* 189, 0x0bd */ SDL_SCANCODE_F19, // NoSymbol
|
||||
/* 190, 0x0be */ SDL_SCANCODE_F20, // XF86AudioMicMute
|
||||
/* 191, 0x0bf */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadToggle
|
||||
/* 192, 0x0c0 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOn
|
||||
/* 193, 0x0c1 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOff
|
||||
/* 194, 0x0c2 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
/* 191, 0x0bf */ SDL_SCANCODE_F21, // XF86TouchpadToggle
|
||||
/* 192, 0x0c0 */ SDL_SCANCODE_F22, // XF86TouchpadOn
|
||||
/* 193, 0x0c1 */ SDL_SCANCODE_F23, // XF86TouchpadOff
|
||||
/* 194, 0x0c2 */ SDL_SCANCODE_F24, // NoSymbol
|
||||
/* 195, 0x0c3 */ SDL_SCANCODE_MODE, // Mode_switch
|
||||
/* 196, 0x0c4 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
/* 197, 0x0c5 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
|
||||
|
||||
+370
-44
@@ -93,10 +93,10 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
#define CHECK_GRAPHICS_PIPELINE_BOUND \
|
||||
if (!((RenderPass *)render_pass)->graphics_pipeline) { \
|
||||
SDL_assert_release(!"Graphics pipeline not bound!"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_COMPUTEPASS \
|
||||
@@ -106,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; \
|
||||
}
|
||||
@@ -174,18 +174,132 @@
|
||||
#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
|
||||
@@ -403,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
|
||||
@@ -564,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;
|
||||
}
|
||||
}
|
||||
@@ -753,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,
|
||||
@@ -1375,15 +1562,30 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->device = device;
|
||||
commandBufferHeader->render_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->graphics_pipeline_bound = false;
|
||||
commandBufferHeader->compute_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pipeline_bound = false;
|
||||
commandBufferHeader->copy_pass.command_buffer = command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
|
||||
if (device->debug_mode) {
|
||||
commandBufferHeader->render_pass.in_progress = false;
|
||||
commandBufferHeader->render_pass.graphics_pipeline = NULL;
|
||||
commandBufferHeader->compute_pass.in_progress = false;
|
||||
commandBufferHeader->compute_pass.compute_pipeline = NULL;
|
||||
commandBufferHeader->copy_pass.in_progress = false;
|
||||
commandBufferHeader->swapchain_texture_acquired = false;
|
||||
commandBufferHeader->submitted = false;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = false;
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
|
||||
return command_buffer;
|
||||
}
|
||||
@@ -1501,30 +1703,47 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
|
||||
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
|
||||
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
if (color_target_infos[i].resolve_texture == NULL) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
|
||||
return NULL;
|
||||
} else {
|
||||
TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
|
||||
if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Resolve texture must have a sample count of 1!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.format != textureHeader->info.format) {
|
||||
SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
|
||||
return NULL;
|
||||
}
|
||||
if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
|
||||
SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
|
||||
SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
@@ -1532,10 +1751,12 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
|
||||
if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
|
||||
SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
|
||||
SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
|
||||
@@ -1543,6 +1764,7 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
|
||||
depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1554,14 +1776,18 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
||||
depth_stencil_target_info);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1569,8 +1795,6 @@ void SDL_BindGPUGraphicsPipeline(
|
||||
SDL_GPURenderPass *render_pass,
|
||||
SDL_GPUGraphicsPipeline *graphics_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
return;
|
||||
@@ -1584,8 +1808,10 @@ void SDL_BindGPUGraphicsPipeline(
|
||||
RENDERPASS_COMMAND_BUFFER,
|
||||
graphics_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->graphics_pipeline_bound = true;
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
RENDERPASS_BOUND_PIPELINE = graphics_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_SetGPUViewport(
|
||||
@@ -1735,7 +1961,15 @@ void SDL_BindGPUVertexSamplers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
|
||||
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(
|
||||
@@ -1763,6 +1997,10 @@ 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(
|
||||
@@ -1789,6 +2027,10 @@ void SDL_BindGPUVertexStorageBuffers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->vertex_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindVertexStorageBuffers(
|
||||
@@ -1815,7 +2057,14 @@ void SDL_BindGPUFragmentSamplers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_SAMPLER_TEXTURES
|
||||
|
||||
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(
|
||||
@@ -1843,6 +2092,10 @@ 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(
|
||||
@@ -1869,6 +2122,10 @@ void SDL_BindGPUFragmentStorageBuffers(
|
||||
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((RenderPass *)render_pass)->fragment_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->BindFragmentStorageBuffers(
|
||||
@@ -1894,6 +2151,7 @@ void SDL_DrawGPUIndexedPrimitives(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitives(
|
||||
@@ -1920,6 +2178,7 @@ void SDL_DrawGPUPrimitives(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitives(
|
||||
@@ -1948,6 +2207,7 @@ void SDL_DrawGPUPrimitivesIndirect(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawPrimitivesIndirect(
|
||||
@@ -1975,6 +2235,7 @@ void SDL_DrawGPUIndexedPrimitivesIndirect(
|
||||
if (RENDERPASS_DEVICE->debug_mode) {
|
||||
CHECK_RENDERPASS
|
||||
CHECK_GRAPHICS_PIPELINE_BOUND
|
||||
SDL_GPU_CheckGraphicsBindings(render_pass);
|
||||
}
|
||||
|
||||
RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
|
||||
@@ -1988,6 +2249,7 @@ void SDL_EndGPURenderPass(
|
||||
SDL_GPURenderPass *render_pass)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferCommonHeader;
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
|
||||
if (render_pass == NULL) {
|
||||
SDL_InvalidParamError("render_pass");
|
||||
@@ -2001,15 +2263,22 @@ void SDL_EndGPURenderPass(
|
||||
RENDERPASS_DEVICE->EndRenderPass(
|
||||
RENDERPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->render_pass.in_progress = false;
|
||||
for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
|
||||
{
|
||||
commandBufferCommonHeader->render_pass.color_targets[i] = NULL;
|
||||
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);
|
||||
}
|
||||
commandBufferCommonHeader->render_pass.num_color_targets = 0;
|
||||
commandBufferCommonHeader->render_pass.depth_stencil_target = NULL;
|
||||
commandBufferCommonHeader->graphics_pipeline_bound = false;
|
||||
}
|
||||
|
||||
// Compute Pass
|
||||
@@ -2053,6 +2322,16 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
||||
SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
|
||||
SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate buffer usage?
|
||||
@@ -2066,7 +2345,19 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
||||
num_storage_buffer_bindings);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->compute_pass.in_progress = true;
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_texture_bound[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < num_storage_buffer_bindings; i += 1) {
|
||||
commandBufferHeader->compute_pass.read_write_storage_buffer_bound[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
|
||||
}
|
||||
|
||||
@@ -2074,8 +2365,6 @@ void SDL_BindGPUComputePipeline(
|
||||
SDL_GPUComputePass *compute_pass,
|
||||
SDL_GPUComputePipeline *compute_pipeline)
|
||||
{
|
||||
CommandBufferCommonHeader *commandBufferHeader;
|
||||
|
||||
if (compute_pass == NULL) {
|
||||
SDL_InvalidParamError("compute_pass");
|
||||
return;
|
||||
@@ -2093,8 +2382,10 @@ void SDL_BindGPUComputePipeline(
|
||||
COMPUTEPASS_COMMAND_BUFFER,
|
||||
compute_pipeline);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferHeader->compute_pipeline_bound = true;
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
COMPUTEPASS_BOUND_PIPELINE = compute_pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BindGPUComputeSamplers(
|
||||
@@ -2114,6 +2405,10 @@ void SDL_BindGPUComputeSamplers(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->sampler_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeSamplers(
|
||||
@@ -2140,6 +2435,10 @@ void SDL_BindGPUComputeStorageTextures(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_texture_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageTextures(
|
||||
@@ -2166,6 +2465,10 @@ void SDL_BindGPUComputeStorageBuffers(
|
||||
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
|
||||
for (Uint32 i = 0; i < num_bindings; i += 1) {
|
||||
((ComputePass *)compute_pass)->read_only_storage_buffer_bound[first_slot + i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
|
||||
@@ -2189,6 +2492,7 @@ void SDL_DispatchGPUCompute(
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchCompute(
|
||||
@@ -2211,6 +2515,7 @@ void SDL_DispatchGPUComputeIndirect(
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
CHECK_COMPUTEPASS
|
||||
CHECK_COMPUTE_PIPELINE_BOUND
|
||||
SDL_GPU_CheckComputeBindings(compute_pass);
|
||||
}
|
||||
|
||||
COMPUTEPASS_DEVICE->DispatchComputeIndirect(
|
||||
@@ -2236,9 +2541,16 @@ void SDL_EndGPUComputePass(
|
||||
COMPUTEPASS_DEVICE->EndComputePass(
|
||||
COMPUTEPASS_COMMAND_BUFFER);
|
||||
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pipeline_bound = false;
|
||||
if (COMPUTEPASS_DEVICE->debug_mode) {
|
||||
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
|
||||
commandBufferCommonHeader->compute_pass.in_progress = false;
|
||||
commandBufferCommonHeader->compute_pass.compute_pipeline = NULL;
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_texture_bound);
|
||||
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_buffer_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// TransferBuffer Data
|
||||
@@ -2296,7 +2608,11 @@ SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
|
||||
command_buffer);
|
||||
|
||||
commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
commandBufferHeader->copy_pass.in_progress = true;
|
||||
}
|
||||
|
||||
return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
|
||||
}
|
||||
|
||||
@@ -2547,7 +2863,9 @@ void SDL_EndGPUCopyPass(
|
||||
COPYPASS_DEVICE->EndCopyPass(
|
||||
COPYPASS_COMMAND_BUFFER);
|
||||
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
if (COPYPASS_DEVICE->debug_mode) {
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_GenerateMipmapsForGPUTexture(
|
||||
@@ -2577,11 +2895,19 @@ void SDL_GenerateMipmapsForGPUTexture(
|
||||
SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = true;
|
||||
}
|
||||
|
||||
COMMAND_BUFFER_DEVICE->GenerateMipmaps(
|
||||
command_buffer,
|
||||
texture);
|
||||
|
||||
if (COMMAND_BUFFER_DEVICE->debug_mode) {
|
||||
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
|
||||
commandBufferHeader->ignore_render_pass_texture_validation = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_BlitGPUTexture(
|
||||
|
||||
+54
-3
@@ -47,6 +47,20 @@ 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;
|
||||
@@ -54,18 +68,30 @@ typedef struct RenderPass
|
||||
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;
|
||||
|
||||
RenderPass render_pass;
|
||||
bool graphics_pipeline_bound;
|
||||
Pass compute_pass;
|
||||
bool compute_pipeline_bound;
|
||||
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
|
||||
@@ -73,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
|
||||
@@ -160,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:
|
||||
@@ -277,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:
|
||||
|
||||
+183
-147
@@ -1015,26 +1015,38 @@ struct D3D12CommandBuffer
|
||||
Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS];
|
||||
Uint32 vertexBufferCount;
|
||||
|
||||
D3D12Texture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12Sampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12Texture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12Buffer *vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
D3D12UniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
|
||||
|
||||
D3D12Texture *fragmentSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12Sampler *fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12Texture *fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12Buffer *fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
D3D12UniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
|
||||
|
||||
D3D12Texture *computeSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12Sampler *computeSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
// Track these separately because barriers can happen mid compute pass
|
||||
D3D12Texture *computeReadOnlyStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
D3D12Buffer *computeReadOnlyStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageTextureDescriptorHandles[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageBufferDescriptorHandles[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
|
||||
// Track these separately because they are bound when the compute pass begins
|
||||
D3D12TextureSubresource *computeReadWriteStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
Uint32 computeReadWriteStorageTextureSubresourceCount;
|
||||
D3D12Buffer *computeReadWriteStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
Uint32 computeReadWriteStorageBufferCount;
|
||||
|
||||
D3D12UniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
|
||||
|
||||
// Resource tracking
|
||||
@@ -1098,22 +1110,14 @@ typedef struct D3D12GraphicsRootSignature
|
||||
|
||||
struct D3D12GraphicsPipeline
|
||||
{
|
||||
GraphicsPipelineCommonHeader header;
|
||||
|
||||
ID3D12PipelineState *pipelineState;
|
||||
D3D12GraphicsRootSignature *rootSignature;
|
||||
SDL_GPUPrimitiveType primitiveType;
|
||||
|
||||
Uint32 vertexStrides[MAX_VERTEX_BUFFERS];
|
||||
|
||||
Uint32 vertexSamplerCount;
|
||||
Uint32 vertexUniformBufferCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexStorageTextureCount;
|
||||
|
||||
Uint32 fragmentSamplerCount;
|
||||
Uint32 fragmentUniformBufferCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentStorageTextureCount;
|
||||
|
||||
SDL_AtomicInt referenceCount;
|
||||
};
|
||||
|
||||
@@ -1132,16 +1136,11 @@ typedef struct D3D12ComputeRootSignature
|
||||
|
||||
struct D3D12ComputePipeline
|
||||
{
|
||||
ComputePipelineCommonHeader header;
|
||||
|
||||
ID3D12PipelineState *pipelineState;
|
||||
D3D12ComputeRootSignature *rootSignature;
|
||||
|
||||
Uint32 numSamplers;
|
||||
Uint32 numReadOnlyStorageTextures;
|
||||
Uint32 numReadOnlyStorageBuffers;
|
||||
Uint32 numReadWriteStorageTextures;
|
||||
Uint32 numReadWriteStorageBuffers;
|
||||
Uint32 numUniformBuffers;
|
||||
|
||||
SDL_AtomicInt referenceCount;
|
||||
};
|
||||
|
||||
@@ -2886,12 +2885,12 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline(
|
||||
|
||||
computePipeline->pipelineState = pipelineState;
|
||||
computePipeline->rootSignature = rootSignature;
|
||||
computePipeline->numSamplers = createinfo->num_samplers;
|
||||
computePipeline->numReadOnlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
computePipeline->numReadOnlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
computePipeline->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
computePipeline->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
computePipeline->numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
computePipeline->header.numSamplers = createinfo->num_samplers;
|
||||
computePipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
|
||||
computePipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
|
||||
computePipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
|
||||
computePipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
|
||||
computePipeline->header.numUniformBuffers = createinfo->num_uniform_buffers;
|
||||
SDL_SetAtomicInt(&computePipeline->referenceCount, 0);
|
||||
|
||||
if (renderer->debug_mode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) {
|
||||
@@ -3172,15 +3171,15 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
|
||||
|
||||
pipeline->primitiveType = createinfo->primitive_type;
|
||||
|
||||
pipeline->vertexSamplerCount = vertShader->num_samplers;
|
||||
pipeline->vertexStorageTextureCount = vertShader->numStorageTextures;
|
||||
pipeline->vertexStorageBufferCount = vertShader->numStorageBuffers;
|
||||
pipeline->vertexUniformBufferCount = vertShader->numUniformBuffers;
|
||||
pipeline->header.num_vertex_samplers = vertShader->num_samplers;
|
||||
pipeline->header.num_vertex_storage_textures = vertShader->numStorageTextures;
|
||||
pipeline->header.num_vertex_storage_buffers = vertShader->numStorageBuffers;
|
||||
pipeline->header.num_vertex_uniform_buffers = vertShader->numUniformBuffers;
|
||||
|
||||
pipeline->fragmentSamplerCount = fragShader->num_samplers;
|
||||
pipeline->fragmentStorageTextureCount = fragShader->numStorageTextures;
|
||||
pipeline->fragmentStorageBufferCount = fragShader->numStorageBuffers;
|
||||
pipeline->fragmentUniformBufferCount = fragShader->numUniformBuffers;
|
||||
pipeline->header.num_fragment_samplers = fragShader->num_samplers;
|
||||
pipeline->header.num_fragment_storage_textures = fragShader->numStorageTextures;
|
||||
pipeline->header.num_fragment_storage_buffers = fragShader->numStorageBuffers;
|
||||
pipeline->header.num_fragment_uniform_buffers = fragShader->numUniformBuffers;
|
||||
|
||||
SDL_SetAtomicInt(&pipeline->referenceCount, 0);
|
||||
|
||||
@@ -3350,7 +3349,7 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture(
|
||||
|
||||
if (createinfo->type != SDL_GPU_TEXTURETYPE_3D) {
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.Alignment = isSwapchainTexture ? 0 : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||
desc.Alignment = isSwapchainTexture ? 0 : isMultisample ? D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||
desc.Width = createinfo->width;
|
||||
desc.Height = createinfo->height;
|
||||
desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth;
|
||||
@@ -4637,14 +4636,14 @@ static void D3D12_BindGraphicsPipeline(
|
||||
d3d12CommandBuffer->needFragmentUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->vertexUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) {
|
||||
if (d3d12CommandBuffer->vertexUniformBuffers[i] == NULL) {
|
||||
d3d12CommandBuffer->vertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
|
||||
d3d12CommandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pipeline->fragmentUniformBufferCount; i += 1) {
|
||||
for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) {
|
||||
if (d3d12CommandBuffer->fragmentUniformBuffers[i] == NULL) {
|
||||
d3d12CommandBuffer->fragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
|
||||
d3d12CommandBuffer);
|
||||
@@ -4711,21 +4710,21 @@ static void D3D12_BindVertexSamplers(
|
||||
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
|
||||
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (d3d12CommandBuffer->vertexSamplers[firstSlot + i] != sampler) {
|
||||
if (d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackSampler(
|
||||
d3d12CommandBuffer,
|
||||
sampler);
|
||||
|
||||
d3d12CommandBuffer->vertexSamplers[firstSlot + i] = sampler;
|
||||
d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
|
||||
d3d12CommandBuffer->needVertexSamplerBind = true;
|
||||
}
|
||||
|
||||
if (d3d12CommandBuffer->vertexSamplerTextures[firstSlot + i] != container->activeTexture) {
|
||||
if (d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackTexture(
|
||||
d3d12CommandBuffer,
|
||||
container->activeTexture);
|
||||
|
||||
d3d12CommandBuffer->vertexSamplerTextures[firstSlot + i] = container->activeTexture;
|
||||
d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needVertexSamplerBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4743,10 +4742,10 @@ static void D3D12_BindVertexStorageTextures(
|
||||
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i];
|
||||
D3D12Texture *texture = container->activeTexture;
|
||||
|
||||
if (d3d12CommandBuffer->vertexStorageTextures[firstSlot + i] != texture) {
|
||||
if (d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture);
|
||||
|
||||
d3d12CommandBuffer->vertexStorageTextures[firstSlot + i] = texture;
|
||||
d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needVertexStorageTextureBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4762,12 +4761,12 @@ static void D3D12_BindVertexStorageBuffers(
|
||||
|
||||
for (Uint32 i = 0; i < numBindings; i += 1) {
|
||||
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i];
|
||||
if (d3d12CommandBuffer->vertexStorageBuffers[firstSlot + i] != container->activeBuffer) {
|
||||
if (d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackBuffer(
|
||||
d3d12CommandBuffer,
|
||||
container->activeBuffer);
|
||||
|
||||
d3d12CommandBuffer->vertexStorageBuffers[firstSlot + i] = container->activeBuffer;
|
||||
d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle;
|
||||
d3d12CommandBuffer->needVertexStorageBufferBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4785,21 +4784,21 @@ static void D3D12_BindFragmentSamplers(
|
||||
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
|
||||
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (d3d12CommandBuffer->fragmentSamplers[firstSlot + i] != sampler) {
|
||||
if (d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackSampler(
|
||||
d3d12CommandBuffer,
|
||||
sampler);
|
||||
|
||||
d3d12CommandBuffer->fragmentSamplers[firstSlot + i] = sampler;
|
||||
d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
|
||||
d3d12CommandBuffer->needFragmentSamplerBind = true;
|
||||
}
|
||||
|
||||
if (d3d12CommandBuffer->fragmentSamplerTextures[firstSlot + i] != container->activeTexture) {
|
||||
if (d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackTexture(
|
||||
d3d12CommandBuffer,
|
||||
container->activeTexture);
|
||||
|
||||
d3d12CommandBuffer->fragmentSamplerTextures[firstSlot + i] = container->activeTexture;
|
||||
d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needFragmentSamplerBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4817,10 +4816,10 @@ static void D3D12_BindFragmentStorageTextures(
|
||||
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i];
|
||||
D3D12Texture *texture = container->activeTexture;
|
||||
|
||||
if (d3d12CommandBuffer->fragmentStorageTextures[firstSlot + i] != texture) {
|
||||
if (d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture);
|
||||
|
||||
d3d12CommandBuffer->fragmentStorageTextures[firstSlot + i] = texture;
|
||||
d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needFragmentStorageTextureBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4837,12 +4836,12 @@ static void D3D12_BindFragmentStorageBuffers(
|
||||
for (Uint32 i = 0; i < numBindings; i += 1) {
|
||||
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i];
|
||||
|
||||
if (d3d12CommandBuffer->fragmentStorageBuffers[firstSlot + i] != container->activeBuffer) {
|
||||
if (d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackBuffer(
|
||||
d3d12CommandBuffer,
|
||||
container->activeBuffer);
|
||||
|
||||
d3d12CommandBuffer->fragmentStorageBuffers[firstSlot + i] = container->activeBuffer;
|
||||
d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle;
|
||||
d3d12CommandBuffer->needFragmentStorageBufferBind = true;
|
||||
}
|
||||
}
|
||||
@@ -4923,15 +4922,19 @@ static void D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
gpuBaseDescriptor->ptr = heap->descriptorHeapGPUStart.ptr + (heap->currentDescriptorIndex * heap->descriptorSize);
|
||||
|
||||
for (Uint32 i = 0; i < resourceHandleCount; i += 1) {
|
||||
ID3D12Device_CopyDescriptorsSimple(
|
||||
commandBuffer->renderer->device,
|
||||
1,
|
||||
gpuHeapCpuHandle,
|
||||
resourceDescriptorHandles[i],
|
||||
heapType);
|
||||
// This will crash the driver if it gets a null handle! Cool!
|
||||
if (resourceDescriptorHandles[i].ptr != 0)
|
||||
{
|
||||
ID3D12Device_CopyDescriptorsSimple(
|
||||
commandBuffer->renderer->device,
|
||||
1,
|
||||
gpuHeapCpuHandle,
|
||||
resourceDescriptorHandles[i],
|
||||
heapType);
|
||||
|
||||
heap->currentDescriptorIndex += 1;
|
||||
gpuHeapCpuHandle.ptr += heap->descriptorSize;
|
||||
heap->currentDescriptorIndex += 1;
|
||||
gpuHeapCpuHandle.ptr += heap->descriptorSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4961,19 +4964,21 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
0,
|
||||
commandBuffer->vertexBufferCount,
|
||||
vertexBufferViews);
|
||||
|
||||
commandBuffer->needVertexBufferBind = false;
|
||||
}
|
||||
|
||||
if (commandBuffer->needVertexSamplerBind) {
|
||||
if (graphicsPipeline->vertexSamplerCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexSamplerCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexSamplers[i]->handle.cpuHandle;
|
||||
if (graphicsPipeline->header.num_vertex_samplers > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexSamplerDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
cpuHandles,
|
||||
graphicsPipeline->vertexSamplerCount,
|
||||
graphicsPipeline->header.num_vertex_samplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -4981,15 +4986,15 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
graphicsPipeline->rootSignature->vertexSamplerRootIndex,
|
||||
gpuDescriptorHandle);
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexSamplerCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexSamplerTextures[i]->srvHandle.cpuHandle;
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexSamplerTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->vertexSamplerCount,
|
||||
graphicsPipeline->header.num_vertex_samplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5001,16 +5006,16 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needVertexStorageTextureBind) {
|
||||
if (graphicsPipeline->vertexStorageTextureCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexStorageTextureCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexStorageTextures[i]->srvHandle.cpuHandle;
|
||||
if (graphicsPipeline->header.num_vertex_storage_textures > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_textures; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexStorageTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->vertexStorageTextureCount,
|
||||
graphicsPipeline->header.num_vertex_storage_textures,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5022,16 +5027,16 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needVertexStorageBufferBind) {
|
||||
if (graphicsPipeline->vertexStorageBufferCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->vertexStorageBufferCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexStorageBuffers[i]->srvDescriptor.cpuHandle;
|
||||
if (graphicsPipeline->header.num_vertex_storage_buffers > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_buffers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->vertexStorageBufferDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->vertexStorageBufferCount,
|
||||
graphicsPipeline->header.num_vertex_storage_buffers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5044,7 +5049,7 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
|
||||
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
|
||||
if (commandBuffer->needVertexUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->vertexUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_vertex_uniform_buffers > i) {
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(
|
||||
commandBuffer->graphicsCommandList,
|
||||
graphicsPipeline->rootSignature->vertexUniformBufferRootIndex[i],
|
||||
@@ -5055,16 +5060,16 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needFragmentSamplerBind) {
|
||||
if (graphicsPipeline->fragmentSamplerCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentSamplerCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentSamplers[i]->handle.cpuHandle;
|
||||
if (graphicsPipeline->header.num_fragment_samplers > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentSamplerDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
cpuHandles,
|
||||
graphicsPipeline->fragmentSamplerCount,
|
||||
graphicsPipeline->header.num_fragment_samplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5072,15 +5077,15 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
graphicsPipeline->rootSignature->fragmentSamplerRootIndex,
|
||||
gpuDescriptorHandle);
|
||||
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentSamplerCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentSamplerTextures[i]->srvHandle.cpuHandle;
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentSamplerTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->fragmentSamplerCount,
|
||||
graphicsPipeline->header.num_fragment_samplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5092,16 +5097,16 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needFragmentStorageTextureBind) {
|
||||
if (graphicsPipeline->fragmentStorageTextureCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentStorageTextureCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentStorageTextures[i]->srvHandle.cpuHandle;
|
||||
if (graphicsPipeline->header.num_fragment_storage_textures > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_textures; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentStorageTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->fragmentStorageTextureCount,
|
||||
graphicsPipeline->header.num_fragment_storage_textures,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5113,16 +5118,16 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needFragmentStorageBufferBind) {
|
||||
if (graphicsPipeline->fragmentStorageBufferCount > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->fragmentStorageBufferCount; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentStorageBuffers[i]->srvDescriptor.cpuHandle;
|
||||
if (graphicsPipeline->header.num_fragment_storage_buffers > 0) {
|
||||
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_buffers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->fragmentStorageBufferDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
graphicsPipeline->fragmentStorageBufferCount,
|
||||
graphicsPipeline->header.num_fragment_storage_buffers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
|
||||
@@ -5135,7 +5140,7 @@ static void D3D12_INTERNAL_BindGraphicsResources(
|
||||
|
||||
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
|
||||
if (commandBuffer->needFragmentUniformBufferBind[i]) {
|
||||
if (graphicsPipeline->fragmentUniformBufferCount > i) {
|
||||
if (graphicsPipeline->header.num_fragment_uniform_buffers > i) {
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(
|
||||
commandBuffer->graphicsCommandList,
|
||||
graphicsPipeline->rootSignature->fragmentUniformBufferRootIndex[i],
|
||||
@@ -5300,15 +5305,15 @@ static void D3D12_EndRenderPass(
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexBufferOffsets);
|
||||
d3d12CommandBuffer->vertexBufferCount = 0;
|
||||
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexSamplerTextures);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexSamplers);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexStorageTextures);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexStorageBuffers);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexSamplerDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->vertexStorageBufferDescriptorHandles);
|
||||
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentSamplerTextures);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentSamplers);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentStorageTextures);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentStorageBuffers);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentSamplerDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles);
|
||||
}
|
||||
|
||||
// Compute Pass
|
||||
@@ -5342,6 +5347,7 @@ static void D3D12_BeginComputePass(
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i] = subresource;
|
||||
d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i] = subresource->uavHandle.cpuHandle;
|
||||
|
||||
D3D12_INTERNAL_TrackTexture(
|
||||
d3d12CommandBuffer,
|
||||
@@ -5360,6 +5366,7 @@ static void D3D12_BeginComputePass(
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
d3d12CommandBuffer->computeReadWriteStorageBuffers[i] = buffer;
|
||||
d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i] = buffer->uavDescriptor.cpuHandle;
|
||||
|
||||
D3D12_INTERNAL_TrackBuffer(
|
||||
d3d12CommandBuffer,
|
||||
@@ -5401,7 +5408,7 @@ static void D3D12_BindComputePipeline(
|
||||
d3d12CommandBuffer->needComputeUniformBufferBind[i] = true;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < pipeline->numUniformBuffers; i += 1) {
|
||||
for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) {
|
||||
if (d3d12CommandBuffer->computeUniformBuffers[i] == NULL) {
|
||||
d3d12CommandBuffer->computeUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
|
||||
d3d12CommandBuffer);
|
||||
@@ -5411,9 +5418,9 @@ static void D3D12_BindComputePipeline(
|
||||
D3D12_INTERNAL_TrackComputePipeline(d3d12CommandBuffer, pipeline);
|
||||
|
||||
// Bind write-only resources after setting root signature
|
||||
if (pipeline->numReadWriteStorageTextures > 0) {
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageTextures; i += 1) {
|
||||
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i]->uavHandle.cpuHandle;
|
||||
if (pipeline->header.numReadWriteStorageTextures > 0) {
|
||||
for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageTextures; i += 1) {
|
||||
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
@@ -5429,9 +5436,9 @@ static void D3D12_BindComputePipeline(
|
||||
gpuDescriptorHandle);
|
||||
}
|
||||
|
||||
if (pipeline->numReadWriteStorageBuffers > 0) {
|
||||
for (Uint32 i = 0; i < pipeline->numReadWriteStorageBuffers; i += 1) {
|
||||
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageBuffers[i]->uavDescriptor.cpuHandle;
|
||||
if (pipeline->header.numReadWriteStorageBuffers > 0) {
|
||||
for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageBuffers; i += 1) {
|
||||
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
@@ -5460,21 +5467,21 @@ static void D3D12_BindComputeSamplers(
|
||||
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
|
||||
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (d3d12CommandBuffer->computeSamplers[firstSlot + i] != sampler) {
|
||||
if (d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackSampler(
|
||||
d3d12CommandBuffer,
|
||||
(D3D12Sampler *)textureSamplerBindings[i].sampler);
|
||||
|
||||
d3d12CommandBuffer->computeSamplers[firstSlot + i] = (D3D12Sampler *)textureSamplerBindings[i].sampler;
|
||||
d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
|
||||
d3d12CommandBuffer->needComputeSamplerBind = true;
|
||||
}
|
||||
|
||||
if (d3d12CommandBuffer->computeSamplerTextures[firstSlot + i] != container->activeTexture) {
|
||||
if (d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
|
||||
D3D12_INTERNAL_TrackTexture(
|
||||
d3d12CommandBuffer,
|
||||
container->activeTexture);
|
||||
|
||||
d3d12CommandBuffer->computeSamplerTextures[firstSlot + i] = container->activeTexture;
|
||||
d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needComputeSamplerBind = true;
|
||||
}
|
||||
}
|
||||
@@ -5511,6 +5518,7 @@ static void D3D12_BindComputeStorageTextures(
|
||||
container->activeTexture);
|
||||
|
||||
d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] = container->activeTexture;
|
||||
d3d12CommandBuffer->computeReadOnlyStorageTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
|
||||
d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true;
|
||||
}
|
||||
}
|
||||
@@ -5548,6 +5556,7 @@ static void D3D12_BindComputeStorageBuffers(
|
||||
buffer);
|
||||
|
||||
d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] = buffer;
|
||||
d3d12CommandBuffer->computeReadOnlyStorageBufferDescriptorHandles[firstSlot + i] = buffer->srvDescriptor.cpuHandle;
|
||||
d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true;
|
||||
}
|
||||
}
|
||||
@@ -5583,16 +5592,16 @@ static void D3D12_INTERNAL_BindComputeResources(
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle;
|
||||
|
||||
if (commandBuffer->needComputeSamplerBind) {
|
||||
if (computePipeline->numSamplers > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->numSamplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeSamplers[i]->handle.cpuHandle;
|
||||
if (computePipeline->header.numSamplers > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeSamplerDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
cpuHandles,
|
||||
computePipeline->numSamplers,
|
||||
computePipeline->header.numSamplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
|
||||
@@ -5600,15 +5609,15 @@ static void D3D12_INTERNAL_BindComputeResources(
|
||||
computePipeline->rootSignature->samplerRootIndex,
|
||||
gpuDescriptorHandle);
|
||||
|
||||
for (Uint32 i = 0; i < computePipeline->numSamplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeSamplerTextures[i]->srvHandle.cpuHandle;
|
||||
for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeSamplerTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
computePipeline->numSamplers,
|
||||
computePipeline->header.numSamplers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
|
||||
@@ -5620,16 +5629,16 @@ static void D3D12_INTERNAL_BindComputeResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageTextureBind) {
|
||||
if (computePipeline->numReadOnlyStorageTextures > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->numReadOnlyStorageTextures; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeReadOnlyStorageTextures[i]->srvHandle.cpuHandle;
|
||||
if (computePipeline->header.numReadonlyStorageTextures > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageTextures; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeReadOnlyStorageTextureDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
computePipeline->numReadOnlyStorageTextures,
|
||||
computePipeline->header.numReadonlyStorageTextures,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
|
||||
@@ -5641,16 +5650,16 @@ static void D3D12_INTERNAL_BindComputeResources(
|
||||
}
|
||||
|
||||
if (commandBuffer->needComputeReadOnlyStorageBufferBind) {
|
||||
if (computePipeline->numReadOnlyStorageBuffers > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->numReadOnlyStorageBuffers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeReadOnlyStorageBuffers[i]->srvDescriptor.cpuHandle;
|
||||
if (computePipeline->header.numReadonlyStorageBuffers > 0) {
|
||||
for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageBuffers; i += 1) {
|
||||
cpuHandles[i] = commandBuffer->computeReadOnlyStorageBufferDescriptorHandles[i];
|
||||
}
|
||||
|
||||
D3D12_INTERNAL_WriteGPUDescriptors(
|
||||
commandBuffer,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
cpuHandles,
|
||||
computePipeline->numReadOnlyStorageBuffers,
|
||||
computePipeline->header.numReadonlyStorageBuffers,
|
||||
&gpuDescriptorHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
|
||||
@@ -5663,7 +5672,7 @@ static void D3D12_INTERNAL_BindComputeResources(
|
||||
|
||||
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) {
|
||||
ID3D12GraphicsCommandList_SetComputeRootConstantBufferView(
|
||||
commandBuffer->graphicsCommandList,
|
||||
computePipeline->rootSignature->uniformBufferRootIndex[i],
|
||||
@@ -5762,8 +5771,11 @@ static void D3D12_EndComputePass(
|
||||
}
|
||||
}
|
||||
|
||||
SDL_zeroa(d3d12CommandBuffer->computeSamplerTextures);
|
||||
SDL_zeroa(d3d12CommandBuffer->computeSamplers);
|
||||
SDL_zeroa(d3d12CommandBuffer->computeSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->computeSamplerDescriptorHandles);
|
||||
|
||||
SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles);
|
||||
|
||||
d3d12CommandBuffer->currentComputePipeline = NULL;
|
||||
}
|
||||
@@ -7352,20 +7364,22 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
|
||||
SDL_zeroa(commandBuffer->vertexBufferOffsets);
|
||||
commandBuffer->vertexBufferCount = 0;
|
||||
|
||||
SDL_zeroa(commandBuffer->vertexSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->vertexSamplers);
|
||||
SDL_zeroa(commandBuffer->vertexStorageTextures);
|
||||
SDL_zeroa(commandBuffer->vertexStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->vertexSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->vertexSamplerDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->vertexStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->vertexStorageBufferDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->vertexUniformBuffers);
|
||||
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplers);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageTextures);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageBufferDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->fragmentUniformBuffers);
|
||||
|
||||
SDL_zeroa(commandBuffer->computeSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->computeSamplers);
|
||||
SDL_zeroa(commandBuffer->computeSamplerTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->computeSamplerDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->computeReadOnlyStorageTextureDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->computeReadOnlyStorageBufferDescriptorHandles);
|
||||
SDL_zeroa(commandBuffer->computeReadOnlyStorageTextures);
|
||||
SDL_zeroa(commandBuffer->computeReadOnlyStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->computeReadWriteStorageTextureSubresources);
|
||||
@@ -8819,6 +8833,12 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
|
||||
// Initialize the D3D12 debug layer, if applicable
|
||||
if (debugMode) {
|
||||
bool hasD3d12Debug = D3D12_INTERNAL_TryInitializeD3D12Debug(renderer);
|
||||
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
|
||||
if (hasD3d12Debug) {
|
||||
SDL_LogInfo(
|
||||
SDL_LOG_CATEGORY_GPU,
|
||||
"Validation layers enabled, expect debug level performance!");
|
||||
#else
|
||||
if (hasDxgiDebug && hasD3d12Debug) {
|
||||
SDL_LogInfo(
|
||||
SDL_LOG_CATEGORY_GPU,
|
||||
@@ -8827,6 +8847,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
|
||||
SDL_LogWarn(
|
||||
SDL_LOG_CATEGORY_GPU,
|
||||
"Validation layers partially enabled, some warnings may not be available");
|
||||
#endif
|
||||
} else {
|
||||
SDL_LogWarn(
|
||||
SDL_LOG_CATEGORY_GPU,
|
||||
@@ -9159,8 +9180,23 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_GPUShaderFormat shaderFormats = SDL_GPU_SHADERFORMAT_DXBC;
|
||||
|
||||
D3D12_FEATURE_DATA_SHADER_MODEL shaderModel;
|
||||
shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0;
|
||||
|
||||
res = ID3D12Device_CheckFeatureSupport(
|
||||
renderer->device,
|
||||
D3D12_FEATURE_SHADER_MODEL,
|
||||
&shaderModel,
|
||||
sizeof(shaderModel));
|
||||
if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) {
|
||||
shaderFormats |= SDL_GPU_SHADERFORMAT_DXIL;
|
||||
}
|
||||
|
||||
ASSIGN_DRIVER(D3D12)
|
||||
result->driverData = (SDL_GPURenderer *)renderer;
|
||||
result->shader_formats = shaderFormats;
|
||||
result->debug_mode = debugMode;
|
||||
renderer->sdlGPUDevice = result;
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -1059,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;
|
||||
@@ -1207,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;
|
||||
}
|
||||
}
|
||||
@@ -2412,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);
|
||||
@@ -2650,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;
|
||||
}
|
||||
@@ -2662,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;
|
||||
}
|
||||
@@ -2673,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
|
||||
@@ -2699,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;
|
||||
}
|
||||
@@ -2711,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;
|
||||
}
|
||||
@@ -2722,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
|
||||
@@ -2754,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
|
||||
@@ -3133,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);
|
||||
@@ -3141,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)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4570,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;
|
||||
|
||||
+143
-91
@@ -732,7 +732,7 @@ typedef struct WindowData
|
||||
|
||||
// Synchronization primitives
|
||||
VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT];
|
||||
VkSemaphore renderFinishedSemaphore[MAX_FRAMES_IN_FLIGHT];
|
||||
VkSemaphore *renderFinishedSemaphore;
|
||||
SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT];
|
||||
|
||||
Uint32 frameCounter;
|
||||
@@ -822,13 +822,13 @@ typedef struct DescriptorSetLayout
|
||||
typedef struct GraphicsPipelineResourceLayoutHashTableKey
|
||||
{
|
||||
Uint32 vertexSamplerCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexStorageTextureCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexUniformBufferCount;
|
||||
|
||||
Uint32 fragmentSamplerCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentStorageTextureCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentUniformBufferCount;
|
||||
} GraphicsPipelineResourceLayoutHashTableKey;
|
||||
|
||||
@@ -846,18 +846,20 @@ typedef struct VulkanGraphicsPipelineResourceLayout
|
||||
DescriptorSetLayout *descriptorSetLayouts[4];
|
||||
|
||||
Uint32 vertexSamplerCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexStorageTextureCount;
|
||||
Uint32 vertexStorageBufferCount;
|
||||
Uint32 vertexUniformBufferCount;
|
||||
|
||||
Uint32 fragmentSamplerCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentStorageTextureCount;
|
||||
Uint32 fragmentStorageBufferCount;
|
||||
Uint32 fragmentUniformBufferCount;
|
||||
} VulkanGraphicsPipelineResourceLayout;
|
||||
|
||||
typedef struct VulkanGraphicsPipeline
|
||||
{
|
||||
GraphicsPipelineCommonHeader header;
|
||||
|
||||
VkPipeline pipeline;
|
||||
SDL_GPUPrimitiveType primitiveType;
|
||||
|
||||
@@ -901,6 +903,8 @@ typedef struct VulkanComputePipelineResourceLayout
|
||||
|
||||
typedef struct VulkanComputePipeline
|
||||
{
|
||||
ComputePipelineCommonHeader header;
|
||||
|
||||
VkShaderModule shaderModule;
|
||||
VkPipeline pipeline;
|
||||
VulkanComputePipelineResourceLayout *resourceLayout;
|
||||
@@ -1038,25 +1042,33 @@ typedef struct VulkanCommandBuffer
|
||||
Uint32 vertexBufferCount;
|
||||
bool needVertexBufferBind;
|
||||
|
||||
VulkanTexture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanSampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanTexture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VulkanBuffer *vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
VkImageView vertexSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkSampler vertexSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkImageView vertexStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VkBuffer vertexStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
VulkanTexture *fragmentSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanSampler *fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanTexture *fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VulkanBuffer *fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
VkImageView fragmentSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkSampler fragmentSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkImageView fragmentStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VkBuffer fragmentStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
VkImageView computeSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkSampler computeSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VkImageView readOnlyComputeStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VkBuffer readOnlyComputeStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
// Track these separately because barriers can happen mid compute pass
|
||||
VulkanTexture *readOnlyComputeStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VulkanBuffer *readOnlyComputeStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
VkImageView readWriteComputeStorageTextureViewBindings[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
VkBuffer readWriteComputeStorageBufferBindings[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
|
||||
// Track these separately because they are barriered when the compute pass begins
|
||||
VulkanTextureSubresource *readWriteComputeStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES];
|
||||
Uint32 readWriteComputeStorageTextureSubresourceCount;
|
||||
VulkanBuffer *readWriteComputeStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS];
|
||||
|
||||
VulkanTexture *computeSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanSampler *computeSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
|
||||
VulkanTexture *readOnlyComputeStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
|
||||
VulkanBuffer *readOnlyComputeStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
|
||||
|
||||
// Uniform buffers
|
||||
|
||||
VulkanUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
|
||||
@@ -3217,7 +3229,6 @@ static void VULKAN_INTERNAL_DestroySwapchain(
|
||||
SDL_free(windowData->textureContainers[i].activeTexture->subresources);
|
||||
SDL_free(windowData->textureContainers[i].activeTexture);
|
||||
}
|
||||
windowData->imageCount = 0;
|
||||
|
||||
SDL_free(windowData->textureContainers);
|
||||
windowData->textureContainers = NULL;
|
||||
@@ -3246,7 +3257,8 @@ static void VULKAN_INTERNAL_DestroySwapchain(
|
||||
NULL);
|
||||
windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
}
|
||||
for (i = 0; i < windowData->imageCount; i += 1) {
|
||||
if (windowData->renderFinishedSemaphore[i]) {
|
||||
renderer->vkDestroySemaphore(
|
||||
renderer->logicalDevice,
|
||||
@@ -3255,6 +3267,10 @@ static void VULKAN_INTERNAL_DestroySwapchain(
|
||||
windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
SDL_free(windowData->renderFinishedSemaphore);
|
||||
windowData->renderFinishedSemaphore = NULL;
|
||||
|
||||
windowData->imageCount = 0;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(
|
||||
@@ -4812,6 +4828,12 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
|
||||
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
|
||||
}
|
||||
|
||||
windowData->inFlightFences[i] = NULL;
|
||||
}
|
||||
|
||||
windowData->renderFinishedSemaphore = SDL_malloc(
|
||||
sizeof(VkSemaphore) * windowData->imageCount);
|
||||
for (i = 0; i < windowData->imageCount; i += 1) {
|
||||
vulkanResult = renderer->vkCreateSemaphore(
|
||||
renderer->logicalDevice,
|
||||
&semaphoreCreateInfo,
|
||||
@@ -4831,8 +4853,6 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
|
||||
windowData->swapchain = VK_NULL_HANDLE;
|
||||
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
|
||||
}
|
||||
|
||||
windowData->inFlightFences[i] = NULL;
|
||||
}
|
||||
|
||||
windowData->needsSwapchainRecreate = false;
|
||||
@@ -5118,8 +5138,8 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplers[i]->sampler;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplerBindings[i];
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -5142,7 +5162,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -5164,7 +5184,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pImageInfo = NULL;
|
||||
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBuffers[i]->buffer;
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBufferBindings[i];
|
||||
bufferInfos[bufferInfoCount].offset = 0;
|
||||
bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
|
||||
|
||||
@@ -5237,8 +5257,8 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplers[i]->sampler;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplerBindings[i];
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -5261,7 +5281,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -5283,7 +5303,7 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pImageInfo = NULL;
|
||||
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBuffers[i]->buffer;
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBufferBindings[i];
|
||||
bufferInfos[bufferInfoCount].offset = 0;
|
||||
bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
|
||||
|
||||
@@ -6557,6 +6577,16 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
|
||||
&nameInfo);
|
||||
}
|
||||
|
||||
// Put this data in the pipeline we can do validation in gpu.c
|
||||
graphicsPipeline->header.num_vertex_samplers = graphicsPipeline->resourceLayout->vertexSamplerCount;
|
||||
graphicsPipeline->header.num_vertex_storage_buffers = graphicsPipeline->resourceLayout->vertexStorageBufferCount;
|
||||
graphicsPipeline->header.num_vertex_storage_textures = graphicsPipeline->resourceLayout->vertexStorageTextureCount;
|
||||
graphicsPipeline->header.num_vertex_uniform_buffers = graphicsPipeline->resourceLayout->vertexUniformBufferCount;
|
||||
graphicsPipeline->header.num_fragment_samplers = graphicsPipeline->resourceLayout->fragmentSamplerCount;
|
||||
graphicsPipeline->header.num_fragment_storage_buffers = graphicsPipeline->resourceLayout->fragmentStorageBufferCount;
|
||||
graphicsPipeline->header.num_fragment_storage_textures = graphicsPipeline->resourceLayout->fragmentStorageTextureCount;
|
||||
graphicsPipeline->header.num_fragment_uniform_buffers = graphicsPipeline->resourceLayout->fragmentUniformBufferCount;
|
||||
|
||||
return (SDL_GPUGraphicsPipeline *)graphicsPipeline;
|
||||
}
|
||||
|
||||
@@ -6651,6 +6681,14 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
|
||||
&nameInfo);
|
||||
}
|
||||
|
||||
// Track these here for debug layer
|
||||
vulkanComputePipeline->header.numSamplers = vulkanComputePipeline->resourceLayout->numSamplers;
|
||||
vulkanComputePipeline->header.numReadonlyStorageTextures = vulkanComputePipeline->resourceLayout->numReadonlyStorageTextures;
|
||||
vulkanComputePipeline->header.numReadonlyStorageBuffers = vulkanComputePipeline->resourceLayout->numReadonlyStorageBuffers;
|
||||
vulkanComputePipeline->header.numReadWriteStorageTextures = vulkanComputePipeline->resourceLayout->numReadWriteStorageTextures;
|
||||
vulkanComputePipeline->header.numReadWriteStorageBuffers = vulkanComputePipeline->resourceLayout->numReadWriteStorageBuffers;
|
||||
vulkanComputePipeline->header.numUniformBuffers = vulkanComputePipeline->resourceLayout->numUniformBuffers;
|
||||
|
||||
return (SDL_GPUComputePipeline *)vulkanComputePipeline;
|
||||
}
|
||||
|
||||
@@ -7449,21 +7487,21 @@ static void VULKAN_BindVertexSamplers(
|
||||
VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
|
||||
VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (vulkanCommandBuffer->vertexSamplers[firstSlot + i] != sampler) {
|
||||
if (vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] != sampler->sampler) {
|
||||
VULKAN_INTERNAL_TrackSampler(
|
||||
vulkanCommandBuffer,
|
||||
(VulkanSampler *)textureSamplerBindings[i].sampler);
|
||||
|
||||
vulkanCommandBuffer->vertexSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler;
|
||||
vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] = sampler->sampler;
|
||||
vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
|
||||
}
|
||||
|
||||
if (vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] != textureContainer->activeTexture) {
|
||||
if (vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -7480,12 +7518,12 @@ static void VULKAN_BindVertexStorageTextures(
|
||||
for (Uint32 i = 0; i < numBindings; i += 1) {
|
||||
VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i];
|
||||
|
||||
if (vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] != textureContainer->activeTexture) {
|
||||
if (vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -7502,12 +7540,12 @@ static void VULKAN_BindVertexStorageBuffers(
|
||||
for (Uint32 i = 0; i < numBindings; i += 1) {
|
||||
VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i];
|
||||
|
||||
if (vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) {
|
||||
if (vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) {
|
||||
VULKAN_INTERNAL_TrackBuffer(
|
||||
vulkanCommandBuffer,
|
||||
bufferContainer->activeBuffer);
|
||||
|
||||
vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer;
|
||||
vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
|
||||
vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -7525,21 +7563,21 @@ static void VULKAN_BindFragmentSamplers(
|
||||
VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
|
||||
VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (vulkanCommandBuffer->fragmentSamplers[firstSlot + i] != sampler) {
|
||||
if (vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] != sampler->sampler) {
|
||||
VULKAN_INTERNAL_TrackSampler(
|
||||
vulkanCommandBuffer,
|
||||
(VulkanSampler *)textureSamplerBindings[i].sampler);
|
||||
|
||||
vulkanCommandBuffer->fragmentSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler;
|
||||
vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] = sampler->sampler;
|
||||
vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
|
||||
}
|
||||
|
||||
if (vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] != textureContainer->activeTexture) {
|
||||
if (vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -7556,12 +7594,12 @@ static void VULKAN_BindFragmentStorageTextures(
|
||||
for (Uint32 i = 0; i < numBindings; i += 1) {
|
||||
VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i];
|
||||
|
||||
if (vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] != textureContainer->activeTexture) {
|
||||
if (vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -7580,12 +7618,12 @@ static void VULKAN_BindFragmentStorageBuffers(
|
||||
for (i = 0; i < numBindings; i += 1) {
|
||||
bufferContainer = (VulkanBufferContainer *)storageBuffers[i];
|
||||
|
||||
if (vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) {
|
||||
if (vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) {
|
||||
VULKAN_INTERNAL_TrackBuffer(
|
||||
vulkanCommandBuffer,
|
||||
bufferContainer->activeBuffer);
|
||||
|
||||
vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer;
|
||||
vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
|
||||
vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -8099,15 +8137,15 @@ static void VULKAN_EndRenderPass(
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets);
|
||||
vulkanCommandBuffer->vertexBufferCount = 0;
|
||||
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexSamplers);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextures);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexStorageTextures);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexStorageBuffers);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexSamplerBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexStorageTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->vertexStorageBufferBindings);
|
||||
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentSamplers);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextures);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextures);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentStorageBuffers);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentSamplerBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->fragmentStorageBufferBindings);
|
||||
}
|
||||
|
||||
static void VULKAN_BeginComputePass(
|
||||
@@ -8137,6 +8175,7 @@ static void VULKAN_BeginComputePass(
|
||||
VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE);
|
||||
|
||||
vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = subresource;
|
||||
vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings[i] = subresource->computeWriteView;
|
||||
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
@@ -8150,9 +8189,10 @@ static void VULKAN_BeginComputePass(
|
||||
vulkanCommandBuffer,
|
||||
bufferContainer,
|
||||
storageBufferBindings[i].cycle,
|
||||
VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ);
|
||||
VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE);
|
||||
|
||||
vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer;
|
||||
vulkanCommandBuffer->readWriteComputeStorageBufferBindings[i] = buffer->buffer;
|
||||
|
||||
VULKAN_INTERNAL_TrackBuffer(
|
||||
vulkanCommandBuffer,
|
||||
@@ -8204,21 +8244,21 @@ static void VULKAN_BindComputeSamplers(
|
||||
VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
|
||||
VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
|
||||
|
||||
if (vulkanCommandBuffer->computeSamplers[firstSlot + i] != sampler) {
|
||||
if (vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] != sampler->sampler) {
|
||||
VULKAN_INTERNAL_TrackSampler(
|
||||
vulkanCommandBuffer,
|
||||
sampler);
|
||||
|
||||
vulkanCommandBuffer->computeSamplers[firstSlot + i] = sampler;
|
||||
vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] = sampler->sampler;
|
||||
vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
|
||||
}
|
||||
|
||||
if (vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] != textureContainer->activeTexture) {
|
||||
if (vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -8259,6 +8299,7 @@ static void VULKAN_BindComputeStorageTextures(
|
||||
textureContainer->activeTexture);
|
||||
|
||||
vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture;
|
||||
vulkanCommandBuffer->readOnlyComputeStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
|
||||
vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -8298,6 +8339,7 @@ static void VULKAN_BindComputeStorageBuffers(
|
||||
bufferContainer->activeBuffer);
|
||||
|
||||
vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer;
|
||||
vulkanCommandBuffer->readOnlyComputeStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
|
||||
vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
|
||||
}
|
||||
}
|
||||
@@ -8372,8 +8414,8 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplers[i]->sampler;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplerBindings[i];
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -8396,7 +8438,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextures[i]->fullView;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -8418,7 +8460,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pImageInfo = NULL;
|
||||
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBuffers[i]->buffer;
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBufferBindings[i];
|
||||
bufferInfos[bufferInfoCount].offset = 0;
|
||||
bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
|
||||
|
||||
@@ -8453,7 +8495,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
|
||||
currentWriteDescriptorSet->pBufferInfo = NULL;
|
||||
|
||||
imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureSubresources[i]->computeWriteView;
|
||||
imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureViewBindings[i];
|
||||
imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
|
||||
@@ -8475,7 +8517,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
|
||||
currentWriteDescriptorSet->pTexelBufferView = NULL;
|
||||
currentWriteDescriptorSet->pImageInfo = NULL;
|
||||
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBuffers[i]->buffer;
|
||||
bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBufferBindings[i];
|
||||
bufferInfos[bufferInfoCount].offset = 0;
|
||||
bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
|
||||
|
||||
@@ -8642,9 +8684,12 @@ static void VULKAN_EndComputePass(
|
||||
}
|
||||
}
|
||||
|
||||
// we don't need a barrier because sampler state is always the default if sampler bit is set
|
||||
SDL_zeroa(vulkanCommandBuffer->computeSamplerTextures);
|
||||
SDL_zeroa(vulkanCommandBuffer->computeSamplers);
|
||||
// we don't need a barrier for sampler resources because sampler state is always the default if sampler bit is set
|
||||
SDL_zeroa(vulkanCommandBuffer->computeSamplerTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->computeSamplerBindings);
|
||||
|
||||
SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings);
|
||||
SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageBufferBindings);
|
||||
|
||||
vulkanCommandBuffer->currentComputePipeline = NULL;
|
||||
|
||||
@@ -9510,21 +9555,23 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(
|
||||
SDL_zeroa(commandBuffer->vertexBufferOffsets);
|
||||
commandBuffer->vertexBufferCount = 0;
|
||||
|
||||
SDL_zeroa(commandBuffer->vertexSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->vertexSamplers);
|
||||
SDL_zeroa(commandBuffer->vertexStorageTextures);
|
||||
SDL_zeroa(commandBuffer->vertexStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->vertexSamplerTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->vertexSamplerBindings);
|
||||
SDL_zeroa(commandBuffer->vertexStorageTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->vertexStorageBufferBindings);
|
||||
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplers);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageTextures);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->fragmentSamplerBindings);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->fragmentStorageBufferBindings);
|
||||
|
||||
SDL_zeroa(commandBuffer->readWriteComputeStorageTextureSubresources);
|
||||
commandBuffer->readWriteComputeStorageTextureSubresourceCount = 0;
|
||||
SDL_zeroa(commandBuffer->readWriteComputeStorageBuffers);
|
||||
SDL_zeroa(commandBuffer->computeSamplerTextures);
|
||||
SDL_zeroa(commandBuffer->computeSamplers);
|
||||
SDL_zeroa(commandBuffer->computeSamplerTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->computeSamplerBindings);
|
||||
SDL_zeroa(commandBuffer->readOnlyComputeStorageTextureViewBindings);
|
||||
SDL_zeroa(commandBuffer->readOnlyComputeStorageBufferBindings);
|
||||
SDL_zeroa(commandBuffer->readOnlyComputeStorageTextures);
|
||||
SDL_zeroa(commandBuffer->readOnlyComputeStorageBuffers);
|
||||
|
||||
@@ -10021,7 +10068,7 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
|
||||
}
|
||||
|
||||
vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] =
|
||||
windowData->renderFinishedSemaphore[windowData->frameCounter];
|
||||
windowData->renderFinishedSemaphore[swapchainImageIndex];
|
||||
vulkanCommandBuffer->signalSemaphoreCount += 1;
|
||||
|
||||
*swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer;
|
||||
@@ -10562,7 +10609,7 @@ static bool VULKAN_Submit(
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pNext = NULL;
|
||||
presentInfo.pWaitSemaphores =
|
||||
&presentData->windowData->renderFinishedSemaphore[presentData->windowData->frameCounter];
|
||||
&presentData->windowData->renderFinishedSemaphore[presentData->swapchainImageIndex];
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pSwapchains = &presentData->windowData->swapchain;
|
||||
presentInfo.swapchainCount = 1;
|
||||
@@ -11601,7 +11648,7 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
|
||||
{
|
||||
// Set up dummy VulkanRenderer
|
||||
VulkanRenderer *renderer;
|
||||
Uint8 result;
|
||||
bool result = false;
|
||||
|
||||
if (_this->Vulkan_CreateSurface == NULL) {
|
||||
return false;
|
||||
@@ -11611,16 +11658,16 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
|
||||
return false;
|
||||
}
|
||||
|
||||
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
|
||||
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
|
||||
|
||||
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
|
||||
|
||||
if (result) {
|
||||
renderer->vkDestroyInstance(renderer->instance, NULL);
|
||||
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
|
||||
if (renderer) {
|
||||
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
|
||||
if (result) {
|
||||
renderer->vkDestroyInstance(renderer->instance, NULL);
|
||||
}
|
||||
SDL_free(renderer);
|
||||
}
|
||||
SDL_free(renderer);
|
||||
SDL_Vulkan_UnloadLibrary();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -11636,8 +11683,12 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
|
||||
return NULL;
|
||||
}
|
||||
|
||||
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
|
||||
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
|
||||
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
|
||||
if (!renderer) {
|
||||
SDL_Vulkan_UnloadLibrary();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
renderer->debugMode = debugMode;
|
||||
renderer->preferLowPower = preferLowPower;
|
||||
renderer->allowedFramesInFlight = 2;
|
||||
@@ -11681,6 +11732,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
|
||||
ASSIGN_DRIVER(VULKAN)
|
||||
|
||||
result->driverData = (SDL_GPURenderer *)renderer;
|
||||
result->shader_formats = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||
|
||||
/*
|
||||
* Create initial swapchain array
|
||||
|
||||
@@ -31,11 +31,7 @@
|
||||
/*
|
||||
* External stuff.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
extern HWND SDL_HelperWindow;
|
||||
#else
|
||||
static const HWND SDL_HelperWindow = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal stuff.
|
||||
|
||||
@@ -807,6 +807,8 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
|
||||
#define hid_send_feature_report LIBUSB_hid_send_feature_report
|
||||
#define hid_set_nonblocking LIBUSB_hid_set_nonblocking
|
||||
#define hid_write LIBUSB_hid_write
|
||||
#define hid_version LIBUSB_hid_version
|
||||
#define hid_version_str LIBUSB_hid_version_str
|
||||
#define input_report LIBUSB_input_report
|
||||
#define make_path LIBUSB_make_path
|
||||
#define new_hid_device LIBUSB_new_hid_device
|
||||
|
||||
+27
-1
@@ -71,6 +71,11 @@ extern "C" {
|
||||
#define DETACH_KERNEL_DRIVER
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:5287) /* operands are different enum types */
|
||||
#endif
|
||||
|
||||
/* Uncomment to enable the retrieval of Usage and Usage Page in
|
||||
hid_enumerate(). Warning, on platforms different from FreeBSD
|
||||
this is very invasive as it requires the detach
|
||||
@@ -918,6 +923,22 @@ static int should_enumerate_interface(unsigned short vendor_id, const struct lib
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libusb_blacklist(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
size_t i;
|
||||
static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
|
||||
{ 0x1532, 0x0227 } /* Razer Huntsman Gaming keyboard - long delay asking for device details */
|
||||
};
|
||||
|
||||
for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
|
||||
if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
libusb_device **devs;
|
||||
@@ -948,7 +969,8 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
unsigned short dev_pid = desc.idProduct;
|
||||
|
||||
if ((vendor_id != 0x0 && vendor_id != dev_vid) ||
|
||||
(product_id != 0x0 && product_id != dev_pid)) {
|
||||
(product_id != 0x0 && product_id != dev_pid) ||
|
||||
libusb_blacklist(dev_vid, dev_pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2140,6 +2162,10 @@ uint16_t get_usb_code_for_current_locale(void)
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -949,6 +949,7 @@ static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
|
||||
{ 0x0D8C, 0x0014 }, /* Sharkoon Skiller SGH2 headset - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x0109 }, /* Razer Lycosa Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x010B }, /* Razer Arctosa Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1532, 0x0227 }, /* Razer Huntsman Gaming keyboard - long delay asking for device details */
|
||||
{ 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard - causes deadlock asking for device details */
|
||||
{ 0x1CCF, 0x0000 } /* All Konami Amusement Devices - causes deadlock asking for device details */
|
||||
};
|
||||
|
||||
@@ -913,7 +913,7 @@ static GamepadMapping_t *SDL_PrivateMatchGamepadMappingForGUID(SDL_GUID guid, bo
|
||||
// An exact match, including CRC
|
||||
return mapping;
|
||||
} else if (crc && exact_match_crc) {
|
||||
return NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!best_match) {
|
||||
@@ -1786,6 +1786,11 @@ static GamepadMapping_t *SDL_PrivateGenerateAutomaticGamepadMapping(const char *
|
||||
char name_string[128];
|
||||
char mapping[1024];
|
||||
|
||||
// Remove the CRC from the GUID
|
||||
// We already know that this GUID doesn't have a mapping without the CRC, and we want newly
|
||||
// added mappings without a CRC to override this mapping.
|
||||
SDL_SetJoystickGUIDCRC(&guid, 0);
|
||||
|
||||
// Remove any commas in the name
|
||||
SDL_strlcpy(name_string, name, sizeof(name_string));
|
||||
{
|
||||
@@ -2754,6 +2759,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
|
||||
gamepad->joystick = SDL_OpenJoystick(instance_id);
|
||||
if (!gamepad->joystick) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
@@ -2762,6 +2768,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
if (gamepad->joystick->naxes) {
|
||||
gamepad->last_match_axis = (SDL_GamepadBinding **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis));
|
||||
if (!gamepad->last_match_axis) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad);
|
||||
SDL_UnlockJoysticks();
|
||||
@@ -2771,6 +2778,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
|
||||
if (gamepad->joystick->nhats) {
|
||||
gamepad->last_hat_mask = (Uint8 *)SDL_calloc(gamepad->joystick->nhats, sizeof(*gamepad->last_hat_mask));
|
||||
if (!gamepad->last_hat_mask) {
|
||||
SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, false);
|
||||
SDL_CloseJoystick(gamepad->joystick);
|
||||
SDL_free(gamepad->last_match_axis);
|
||||
SDL_free(gamepad);
|
||||
|
||||
@@ -215,7 +215,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
|
||||
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
|
||||
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
@@ -416,12 +416,13 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
|
||||
"03000000853200008906000000010000,NACON Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
|
||||
"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
|
||||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,start:b11,x:b3,y:b4,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
@@ -796,6 +797,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
|
||||
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000182e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -868,7 +870,9 @@ static const char *s_GamepadMappings[] = {
|
||||
"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
|
||||
"05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000fd216d04,8BitDo Pro 2,crc:ac95,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,crc:3e00,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,crc:40d6,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
|
||||
@@ -1142,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);
|
||||
@@ -1186,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x2e18 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x020a ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS PS4/PS5 (PS4 mode)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "SDL_iokitjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
#include "../../haptic/darwin/SDL_syshaptic_c.h" // For haptic hot plugging
|
||||
#include "../usb_ids.h"
|
||||
|
||||
#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
|
||||
|
||||
@@ -213,6 +214,29 @@ static bool GetHIDScaledCalibratedState(recDevice *pDevice, recElement *pElement
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(recDevice *pDevice, recElement *pElement, SInt32 min, SInt32 max, SInt32 *pValue)
|
||||
{
|
||||
if (pElement->minReport == 0 && pElement->maxReport == 255) {
|
||||
return GetHIDScaledCalibratedState(pDevice, pElement, min, max, pValue);
|
||||
}
|
||||
|
||||
// This device thumbstick axes have an unusual axis range that
|
||||
// doesn't work with GetHIDScaledCalibratedState() above.
|
||||
//
|
||||
// See https://github.com/libsdl-org/SDL/issues/13143 for details
|
||||
if (GetHIDElementState(pDevice, pElement, pValue)) {
|
||||
if (*pValue >= 0) {
|
||||
// Negative axis values range from 32767 (at rest) to 0 (minimum)
|
||||
*pValue = -32767 + *pValue;
|
||||
} else if (*pValue < 0) {
|
||||
// Positive axis values range from -32768 (at rest) to 0 (maximum)
|
||||
*pValue = 32768 + *pValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
|
||||
{
|
||||
recDevice *device = (recDevice *)ctx;
|
||||
@@ -506,6 +530,11 @@ static bool GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
|
||||
pDevice->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, (Uint16)vendor, (Uint16)product, (Uint16)version, manufacturer_string, product_string, 0, 0);
|
||||
pDevice->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot((Uint16)vendor, (Uint16)product, product_string);
|
||||
|
||||
if (vendor == USB_VENDOR_NACON_ALT &&
|
||||
product == USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT) {
|
||||
pDevice->nacon_revolution_x_unlimited = true;
|
||||
}
|
||||
|
||||
array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
|
||||
if (array) {
|
||||
AddHIDElements(array, pDevice);
|
||||
@@ -957,7 +986,11 @@ static void DARWIN_JoystickUpdate(SDL_Joystick *joystick)
|
||||
i = 0;
|
||||
|
||||
while (element) {
|
||||
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
|
||||
if (device->nacon_revolution_x_unlimited) {
|
||||
goodRead = GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(device, element, -32768, 32767, &value);
|
||||
} else {
|
||||
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
|
||||
}
|
||||
if (goodRead) {
|
||||
SDL_SendJoystickAxis(timestamp, joystick, i, value);
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ struct joystick_hwdata
|
||||
int instance_id;
|
||||
SDL_GUID guid;
|
||||
int steam_virtual_gamepad_slot;
|
||||
bool nacon_revolution_x_unlimited;
|
||||
|
||||
struct joystick_hwdata *pNext; // next device
|
||||
};
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_GAMECUBE_PROTOCOL
|
||||
#if 0
|
||||
#define DEBUG_GAMECUBE_PROTOCOL
|
||||
#endif
|
||||
|
||||
#define MAX_CONTROLLERS 4
|
||||
|
||||
@@ -119,22 +121,15 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
ctx->joysticks[0] = 0;
|
||||
ctx->joysticks[1] = 0;
|
||||
ctx->joysticks[2] = 0;
|
||||
ctx->joysticks[3] = 0;
|
||||
ctx->rumble[0] = rumbleMagic;
|
||||
ctx->useRumbleBrake = false;
|
||||
|
||||
if (device->vendor_id != USB_VENDOR_NINTENDO) {
|
||||
ctx->pc_mode = true;
|
||||
}
|
||||
|
||||
if (ctx->pc_mode) {
|
||||
for (i = 0; i < MAX_CONTROLLERS; ++i) {
|
||||
ResetAxisRange(ctx, i);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
|
||||
}
|
||||
ResetAxisRange(ctx, 0);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
|
||||
} else {
|
||||
// This is all that's needed to initialize the device. Really!
|
||||
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
|
||||
@@ -204,69 +199,61 @@ static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device
|
||||
{
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, int size)
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, bool invert_c_stick)
|
||||
{
|
||||
SDL_Joystick *joystick;
|
||||
Uint8 i, v;
|
||||
const Uint8 i = 0; // We have a separate context for each connected controller in PC mode, just use the first index
|
||||
Uint8 v;
|
||||
Sint16 axis_value;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (size != 10) {
|
||||
return; // How do we handle this packet?
|
||||
}
|
||||
|
||||
i = packet[0] - 1;
|
||||
if (i >= MAX_CONTROLLERS) {
|
||||
return; // How do we handle this packet?
|
||||
}
|
||||
|
||||
joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
|
||||
if (!joystick) {
|
||||
// Hasn't been opened yet, skip
|
||||
return;
|
||||
}
|
||||
|
||||
#define READ_BUTTON(off, flag, button) \
|
||||
SDL_SendJoystickButton( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
button, \
|
||||
#define READ_BUTTON(off, flag, button) \
|
||||
SDL_SendJoystickButton( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
button, \
|
||||
((packet[off] & flag) != 0));
|
||||
READ_BUTTON(1, 0x02, 0) // A
|
||||
READ_BUTTON(1, 0x04, 1) // B
|
||||
READ_BUTTON(1, 0x08, 3) // Y
|
||||
READ_BUTTON(1, 0x01, 2) // X
|
||||
READ_BUTTON(2, 0x80, 4) // DPAD_LEFT
|
||||
READ_BUTTON(2, 0x20, 5) // DPAD_RIGHT
|
||||
READ_BUTTON(2, 0x40, 6) // DPAD_DOWN
|
||||
READ_BUTTON(2, 0x10, 7) // DPAD_UP
|
||||
READ_BUTTON(2, 0x02, 8) // START
|
||||
READ_BUTTON(1, 0x80, 9) // RIGHTSHOULDER
|
||||
READ_BUTTON(0, 0x02, 0) // A
|
||||
READ_BUTTON(0, 0x04, 1) // B
|
||||
READ_BUTTON(0, 0x08, 3) // Y
|
||||
READ_BUTTON(0, 0x01, 2) // X
|
||||
READ_BUTTON(1, 0x80, 4) // DPAD_LEFT
|
||||
READ_BUTTON(1, 0x20, 5) // DPAD_RIGHT
|
||||
READ_BUTTON(1, 0x40, 6) // DPAD_DOWN
|
||||
READ_BUTTON(1, 0x10, 7) // DPAD_UP
|
||||
READ_BUTTON(1, 0x02, 8) // START
|
||||
READ_BUTTON(0, 0x80, 9) // RIGHTSHOULDER
|
||||
/* These two buttons are for the bottoms of the analog triggers.
|
||||
* More than likely, you're going to want to read the axes instead!
|
||||
* -flibit
|
||||
*/
|
||||
READ_BUTTON(1, 0x20, 10) // TRIGGERRIGHT
|
||||
READ_BUTTON(1, 0x10, 11) // TRIGGERLEFT
|
||||
READ_BUTTON(0, 0x20, 10) // TRIGGERRIGHT
|
||||
READ_BUTTON(0, 0x10, 11) // TRIGGERLEFT
|
||||
#undef READ_BUTTON
|
||||
|
||||
#define READ_AXIS(off, axis, invert) \
|
||||
v = invert ? (0xff - packet[off]) : packet[off]; \
|
||||
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
#define READ_AXIS(off, axis, invert) \
|
||||
v = (invert) ? (0xff - packet[off]) : packet[off]; \
|
||||
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
|
||||
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
|
||||
axis_value = (Sint16)HIDAPI_RemapVal(v, ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \
|
||||
SDL_SendJoystickAxis( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
SDL_SendJoystickAxis( \
|
||||
timestamp, \
|
||||
joystick, \
|
||||
axis, axis_value);
|
||||
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX, 0)
|
||||
READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY, 1)
|
||||
READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTX, 0)
|
||||
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTY, 1)
|
||||
READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
|
||||
READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
|
||||
READ_AXIS(2, SDL_GAMEPAD_AXIS_LEFTX, 0)
|
||||
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTY, 1)
|
||||
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX, invert_c_stick ? 1 : 0)
|
||||
READ_AXIS(4, SDL_GAMEPAD_AXIS_RIGHTY, invert_c_stick ? 0 : 1)
|
||||
READ_AXIS(6, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
|
||||
READ_AXIS(7, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
|
||||
#undef READ_AXIS
|
||||
}
|
||||
|
||||
@@ -365,7 +352,18 @@ static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
|
||||
#endif
|
||||
if (ctx->pc_mode) {
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, size);
|
||||
if (size == 10) {
|
||||
// This is the older firmware
|
||||
// The first byte is the index of the connected controller
|
||||
// The C stick has an inverted value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, &packet[1], true);
|
||||
} else if (size == 9) {
|
||||
// This is the newer firmware (version 0x7)
|
||||
// The C stick has the same value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, false);
|
||||
} else {
|
||||
// How do we handle this packet?
|
||||
}
|
||||
} else {
|
||||
HIDAPI_DriverGameCube_HandleNintendoPacket(device, ctx, packet, size);
|
||||
}
|
||||
|
||||
@@ -1003,8 +1003,8 @@ static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
|
||||
|
||||
static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet, int size)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 920; // This is noted as being 944 resolution, but 920 feels better
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 1.08695652e-3f; // 1.0f / 920 // This is noted as being 944 resolution, but 920 feels better
|
||||
Sint16 axis;
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
@@ -812,14 +812,19 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
|
||||
}
|
||||
|
||||
if (ctx->sensors_supported) {
|
||||
// Standard DualSense sensor update rate is 250 Hz over USB
|
||||
float update_rate = 250.0f;
|
||||
|
||||
if (ctx->device->is_bluetooth) {
|
||||
// Bluetooth sensor update rate appears to be 1000 Hz
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 1000.0f);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 1000.0f);
|
||||
} else {
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 250.0f);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 250.0f);
|
||||
update_rate = 1000.0f;
|
||||
} else if (SDL_IsJoystickDualSenseEdge(ctx->device->vendor_id, ctx->device->product_id)) {
|
||||
// DualSense Edge sensor update rate is 1000 Hz over USB
|
||||
update_rate = 1000.0f;
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, update_rate);
|
||||
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
|
||||
}
|
||||
|
||||
ctx->report_battery = true;
|
||||
@@ -1355,8 +1360,8 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
@@ -1406,8 +1411,8 @@ static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
|
||||
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
|
||||
bool touchpad_down;
|
||||
int touchpad_x, touchpad_y;
|
||||
|
||||
|
||||
@@ -58,9 +58,7 @@
|
||||
#define SWITCH_GYRO_SCALE 14.2842f
|
||||
#define SWITCH_ACCEL_SCALE 4096.f
|
||||
|
||||
#define SWITCH_GYRO_SCALE_OFFSET 13371.0f
|
||||
#define SWITCH_GYRO_SCALE_MULT 936.0f
|
||||
#define SWITCH_ACCEL_SCALE_OFFSET 16384.0f
|
||||
#define SWITCH_ACCEL_SCALE_MULT 4.0f
|
||||
|
||||
enum
|
||||
@@ -930,13 +928,14 @@ static bool SetIMUEnabled(SDL_DriverSwitch_Context *ctx, bool enabled)
|
||||
|
||||
static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
Uint8 *pLeftStickCal;
|
||||
Uint8 *pRightStickCal;
|
||||
Uint8 *pLeftStickCal = NULL;
|
||||
Uint8 *pRightStickCal = NULL;
|
||||
size_t stick, axis;
|
||||
SwitchSubcommandInputPacket_t *user_reply = NULL;
|
||||
SwitchSubcommandInputPacket_t *factory_reply = NULL;
|
||||
SwitchSPIOpData_t readUserParams;
|
||||
SwitchSPIOpData_t readFactoryParams;
|
||||
Uint8 userParamsReadSuccessCount = 0;
|
||||
|
||||
// Read User Calibration Info
|
||||
readUserParams.unAddress = k_unSPIStickUserCalibrationStartOffset;
|
||||
@@ -949,33 +948,46 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
|
||||
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
|
||||
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
for (int attempt = 0; ; ++attempt) {
|
||||
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
|
||||
// We successfully read the calibration data
|
||||
break;
|
||||
}
|
||||
|
||||
if (attempt == MAX_ATTEMPTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically select the user calibration if magic bytes are set
|
||||
if (user_reply && user_reply->stickUserCalibration.rgucLeftMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucLeftMagic[1] == 0xA1) {
|
||||
userParamsReadSuccessCount += 1;
|
||||
pLeftStickCal = user_reply->stickUserCalibration.rgucLeftCalibration;
|
||||
} else {
|
||||
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
|
||||
}
|
||||
|
||||
if (user_reply && user_reply->stickUserCalibration.rgucRightMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucRightMagic[1] == 0xA1) {
|
||||
userParamsReadSuccessCount += 1;
|
||||
pRightStickCal = user_reply->stickUserCalibration.rgucRightCalibration;
|
||||
} else {
|
||||
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
|
||||
}
|
||||
|
||||
// Only read the factory calibration info if we failed to receive the correct magic bytes
|
||||
if (userParamsReadSuccessCount < 2) {
|
||||
// Read Factory Calibration Info
|
||||
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
|
||||
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
|
||||
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
for (int attempt = 0;; ++attempt) {
|
||||
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
|
||||
// We successfully read the calibration data
|
||||
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
|
||||
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
|
||||
break;
|
||||
}
|
||||
|
||||
if (attempt == MAX_ATTEMPTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have calibration data, return false
|
||||
if (pLeftStickCal == NULL || pRightStickCal == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stick calibration values are 12-bits each and are packed by bit
|
||||
@@ -1044,6 +1056,8 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
|
||||
Uint8 *pIMUScale;
|
||||
Sint16 sAccelRawX, sAccelRawY, sAccelRawZ, sGyroRawX, sGyroRawY, sGyroRawZ;
|
||||
Sint16 sAccelSensCoeffX, sAccelSensCoeffY, sAccelSensCoeffZ;
|
||||
Sint16 sGyroSensCoeffX, sGyroSensCoeffY, sGyroSensCoeffZ;
|
||||
|
||||
// IMU scale gives us multipliers for converting raw values to real world values
|
||||
pIMUScale = reply->spiReadData.rgucReadData;
|
||||
@@ -1052,10 +1066,18 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
sAccelRawY = (pIMUScale[3] << 8) | pIMUScale[2];
|
||||
sAccelRawZ = (pIMUScale[5] << 8) | pIMUScale[4];
|
||||
|
||||
sAccelSensCoeffX = (pIMUScale[7] << 8) | pIMUScale[6];
|
||||
sAccelSensCoeffY = (pIMUScale[9] << 8) | pIMUScale[8];
|
||||
sAccelSensCoeffZ = (pIMUScale[11] << 8) | pIMUScale[10];
|
||||
|
||||
sGyroRawX = (pIMUScale[13] << 8) | pIMUScale[12];
|
||||
sGyroRawY = (pIMUScale[15] << 8) | pIMUScale[14];
|
||||
sGyroRawZ = (pIMUScale[17] << 8) | pIMUScale[16];
|
||||
|
||||
sGyroSensCoeffX = (pIMUScale[19] << 8) | pIMUScale[18];
|
||||
sGyroSensCoeffY = (pIMUScale[21] << 8) | pIMUScale[20];
|
||||
sGyroSensCoeffZ = (pIMUScale[23] << 8) | pIMUScale[22];
|
||||
|
||||
// Check for user calibration data. If it's present and set, it'll override the factory settings
|
||||
readParams.unAddress = k_unSPIIMUUserScaleStartOffset;
|
||||
readParams.ucLength = k_unSPIIMUUserScaleLength;
|
||||
@@ -1072,14 +1094,14 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
}
|
||||
|
||||
// Accelerometer scale
|
||||
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffX - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffY - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
|
||||
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffZ - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
|
||||
|
||||
// Gyro scale
|
||||
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawX) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawY) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffX - (float)sGyroRawX) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffY - (float)sGyroRawY) * SDL_PI_F / 180.0f;
|
||||
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffZ - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
|
||||
|
||||
} else {
|
||||
// Use default values
|
||||
@@ -1101,14 +1123,17 @@ static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, i
|
||||
{
|
||||
sRawValue -= ctx->m_StickCalData[nStick].axis[nAxis].sCenter;
|
||||
|
||||
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
if (sRawValue >= 0) {
|
||||
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
|
||||
} else {
|
||||
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
|
||||
}
|
||||
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, ctx->m_StickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
}
|
||||
|
||||
static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
|
||||
@@ -1118,14 +1143,17 @@ static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nSt
|
||||
|
||||
sRawValue -= usJoystickCenter;
|
||||
|
||||
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
if (sRawValue >= 0) {
|
||||
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
|
||||
} else {
|
||||
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
|
||||
}
|
||||
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
|
||||
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
}
|
||||
|
||||
static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
|
||||
|
||||
@@ -751,11 +751,12 @@ bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoysti
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
if (pJoystickID) {
|
||||
*pJoystickID = joystickID;
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(joystickID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRED 0x0d17
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS 0x0d18
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED 0x0d19
|
||||
#define USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT 0x0689
|
||||
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
|
||||
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
|
||||
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e
|
||||
|
||||
@@ -40,11 +40,7 @@
|
||||
#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
|
||||
|
||||
// external variables referenced.
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
extern HWND SDL_HelperWindow;
|
||||
#else
|
||||
static const HWND SDL_HelperWindow = NULL;
|
||||
#endif
|
||||
|
||||
// local variables
|
||||
static bool coinitialized = false;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2573,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 {
|
||||
@@ -2685,6 +2685,8 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
|
||||
view->pixel_h = (int) view->logical_dst_rect.h;
|
||||
UpdatePixelViewport(renderer, view);
|
||||
UpdatePixelClipRect(renderer, view);
|
||||
QueueCmdSetViewport(renderer);
|
||||
QueueCmdSetClipRect(renderer);
|
||||
}
|
||||
|
||||
bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode)
|
||||
@@ -3605,7 +3607,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
|
||||
#endif
|
||||
|
||||
SDL_RenderViewState *view = renderer->view;
|
||||
const bool islogical = ((view == &renderer->main_view) && (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED));
|
||||
const bool islogical = (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED);
|
||||
|
||||
if (islogical || (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY)) {
|
||||
const float scale_x = view->current_scale.x;
|
||||
@@ -3624,7 +3626,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
|
||||
int num_indices = 0;
|
||||
const int size_indices = 4;
|
||||
int cur_index = -4;
|
||||
const int is_looping = (points[0].x == points[count - 1].x && points[0].y == points[count - 1].y);
|
||||
const bool is_looping = (points[0].x == points[count - 1].x && points[0].y == points[count - 1].y);
|
||||
SDL_FPoint p; // previous point
|
||||
p.x = p.y = 0.0f;
|
||||
/* p q
|
||||
@@ -3656,7 +3658,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
|
||||
num_indices += 3;
|
||||
|
||||
// closed polyline, don´t draw twice the point
|
||||
if (i || is_looping == 0) {
|
||||
if (i || !is_looping) {
|
||||
ADD_TRIANGLE(4, 5, 6)
|
||||
ADD_TRIANGLE(4, 6, 7)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -3763,7 +3763,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
|
||||
VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants);
|
||||
|
||||
switch (cmd->data.draw.texture_scale_mode) {
|
||||
case VK_FILTER_NEAREST:
|
||||
case SDL_SCALEMODE_NEAREST:
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_CLAMP];
|
||||
@@ -3775,7 +3775,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
|
||||
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
|
||||
}
|
||||
break;
|
||||
case VK_FILTER_LINEAR:
|
||||
case SDL_SCALEMODE_LINEAR:
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_CLAMP];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <pspkerneltypes.h>
|
||||
#include <pspthreadman.h>
|
||||
|
||||
#define PSP_THREAD_NAME_MAX 32
|
||||
|
||||
static int ThreadEntry(SceSize args, void *argp)
|
||||
{
|
||||
SDL_RunThread(*(SDL_Thread **)argp);
|
||||
@@ -44,6 +46,7 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread,
|
||||
{
|
||||
SceKernelThreadInfo status;
|
||||
int priority = 32;
|
||||
char thread_name[PSP_THREAD_NAME_MAX];
|
||||
|
||||
// Set priority of new thread to the same as the current thread
|
||||
status.size = sizeof(SceKernelThreadInfo);
|
||||
@@ -51,7 +54,12 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread,
|
||||
priority = status.currentPriority;
|
||||
}
|
||||
|
||||
thread->handle = sceKernelCreateThread(thread->name, ThreadEntry,
|
||||
SDL_strlcpy(thread_name, "SDL thread", PSP_THREAD_NAME_MAX);
|
||||
if (thread->name) {
|
||||
SDL_strlcpy(thread_name, thread->name, PSP_THREAD_NAME_MAX);
|
||||
}
|
||||
|
||||
thread->handle = sceKernelCreateThread(thread_name, ThreadEntry,
|
||||
priority, thread->stacksize ? ((int)thread->stacksize) : 0x8000,
|
||||
PSP_THREAD_ATTR_VFPU, NULL);
|
||||
if (thread->handle < 0) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ struct SDL_Window
|
||||
bool restore_on_show; // Child was hidden recursively by the parent, restore when shown.
|
||||
bool last_position_pending; // This should NOT be cleared by the backend, as it is used for fullscreen positioning.
|
||||
bool last_size_pending; // This should be cleared by the backend if the new size cannot be applied.
|
||||
bool constrain_popup;
|
||||
bool is_destroying;
|
||||
bool is_dropping; // drag/drop in progress, expecting SDL_SendDropComplete().
|
||||
|
||||
@@ -129,6 +130,9 @@ struct SDL_Window
|
||||
|
||||
SDL_WindowData *internal;
|
||||
|
||||
// If a toplevel window, holds the current keyboard focus for grabbing popups.
|
||||
SDL_Window *keyboard_focus;
|
||||
|
||||
SDL_Window *prev;
|
||||
SDL_Window *next;
|
||||
|
||||
@@ -396,8 +400,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;
|
||||
@@ -566,6 +569,8 @@ extern bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags);
|
||||
extern bool SDL_HasWindows(void);
|
||||
extern void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int *abs_x, int *abs_y);
|
||||
extern void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y);
|
||||
extern bool SDL_ShouldFocusPopup(SDL_Window *window);
|
||||
extern bool SDL_ShouldRelinquishPopupFocus(SDL_Window *window, SDL_Window **new_focus);
|
||||
|
||||
extern void SDL_OnDisplayAdded(SDL_VideoDisplay *display);
|
||||
extern void SDL_OnDisplayMoved(SDL_VideoDisplay *display);
|
||||
|
||||
+58
-9
@@ -171,9 +171,10 @@ static VideoBootStrap *bootstrap[] = {
|
||||
}
|
||||
|
||||
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
|
||||
// Support for macOS fullscreen spaces
|
||||
// Support for macOS fullscreen spaces, etc.
|
||||
extern bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window);
|
||||
extern bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking);
|
||||
extern bool Cocoa_IsShowingModalDialog(SDL_Window *window);
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_UIKIT
|
||||
@@ -2503,6 +2504,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||
window->is_destroying = false;
|
||||
window->last_displayID = SDL_GetDisplayForWindow(window);
|
||||
window->external_graphics_context = external_graphics_context;
|
||||
window->constrain_popup = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, true);
|
||||
|
||||
if (_this->windows) {
|
||||
_this->windows->prev = window;
|
||||
@@ -2513,7 +2515,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;
|
||||
}
|
||||
|
||||
@@ -2761,7 +2765,7 @@ SDL_Window *SDL_GetWindowFromID(SDL_WindowID id)
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_SetError("Invalid window ID"); \
|
||||
SDL_SetError("Invalid window ID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3659,6 +3663,10 @@ bool SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent)
|
||||
CHECK_WINDOW_NOT_POPUP(parent, false);
|
||||
}
|
||||
|
||||
if (window == parent) {
|
||||
return SDL_SetError("Cannot set the parent of a window to itself.");
|
||||
}
|
||||
|
||||
if (!_this->SetWindowParent) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
@@ -3704,6 +3712,48 @@ bool SDL_SetWindowModal(SDL_Window *window, bool modal)
|
||||
return _this->SetWindowModal(_this, window, modal);
|
||||
}
|
||||
|
||||
bool SDL_ShouldRelinquishPopupFocus(SDL_Window *window, SDL_Window **new_focus)
|
||||
{
|
||||
SDL_Window *focus = window->parent;
|
||||
bool set_focus = !!(window->flags & SDL_WINDOW_INPUT_FOCUS);
|
||||
|
||||
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed, and can grab the keyboard focus.
|
||||
while (SDL_WINDOW_IS_POPUP(focus) && ((focus->flags & SDL_WINDOW_NOT_FOCUSABLE) || focus->is_hiding || focus->is_destroying)) {
|
||||
focus = focus->parent;
|
||||
|
||||
// If some window in the chain currently had focus, set it to the new lowest-level window.
|
||||
if (!set_focus) {
|
||||
set_focus = !!(focus->flags & SDL_WINDOW_INPUT_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
*new_focus = focus;
|
||||
return set_focus;
|
||||
}
|
||||
|
||||
bool SDL_ShouldFocusPopup(SDL_Window *window)
|
||||
{
|
||||
SDL_Window *toplevel_parent;
|
||||
for (toplevel_parent = window->parent; SDL_WINDOW_IS_POPUP(toplevel_parent); toplevel_parent = toplevel_parent->parent) {
|
||||
}
|
||||
|
||||
SDL_Window *current_focus = toplevel_parent->keyboard_focus;
|
||||
bool found_higher_focus = false;
|
||||
|
||||
/* Traverse the window tree from the currently focused window to the toplevel parent and see if we encounter
|
||||
* the new focus request. If the new window is found, a higher-level window already has focus.
|
||||
*/
|
||||
SDL_Window *w;
|
||||
for (w = current_focus; w != toplevel_parent; w = w->parent) {
|
||||
if (w == window) {
|
||||
found_higher_focus = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !found_higher_focus || w == toplevel_parent;
|
||||
}
|
||||
|
||||
bool SDL_SetWindowFocusable(SDL_Window *window, bool focusable)
|
||||
{
|
||||
CHECK_WINDOW_MAGIC(window, false);
|
||||
@@ -4122,7 +4172,9 @@ static bool SDL_ShouldMinimizeOnFocusLoss(SDL_Window *window)
|
||||
|
||||
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
|
||||
if (SDL_strcmp(_this->name, "cocoa") == 0) { // don't do this for X11, etc
|
||||
if (Cocoa_IsWindowInFullscreenSpace(window)) {
|
||||
if (Cocoa_IsShowingModalDialog(window)) {
|
||||
return false; // modal system dialogs can live over fullscreen windows, don't minimize.
|
||||
} else if (Cocoa_IsWindowInFullscreenSpace(window)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4279,9 +4331,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);
|
||||
@@ -5034,8 +5084,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)) {
|
||||
@@ -5266,7 +5315,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];
|
||||
|
||||
@@ -311,15 +311,26 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
if (!SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true))
|
||||
if (!SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The menu bar of SDL apps which don't have the typical .app bundle
|
||||
* structure fails to work the first time a window is created (until it's
|
||||
* de-focused and re-focused), if this call is in Cocoa_RegisterApp instead
|
||||
* of here. https://bugzilla.libsdl.org/show_bug.cgi?id=3051
|
||||
* of here. https://github.com/libsdl-org/SDL/issues/1913
|
||||
*/
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, false)) {
|
||||
|
||||
/* this apparently became unnecessary on macOS 14.0, and will addition pop up a
|
||||
hidden dock if you're moving the mouse during launch, so change the default
|
||||
behaviour there. https://github.com/libsdl-org/SDL/issues/10340
|
||||
(13.6 still needs it, presumably 13.7 does, too.) */
|
||||
bool background_app_default = false;
|
||||
if (@available(macOS 14.0, *)) {
|
||||
background_app_default = true; /* by default, don't explicitly activate the dock and then us again to force to foreground */
|
||||
}
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, background_app_default)) {
|
||||
// Get more aggressive for Catalina: activate the Dock first so we definitely reset all activation state.
|
||||
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
|
||||
[i activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -146,13 +146,13 @@ typedef enum
|
||||
@property(nonatomic) BOOL was_zoomed;
|
||||
@property(nonatomic) NSInteger window_number;
|
||||
@property(nonatomic) NSInteger flash_request;
|
||||
@property(nonatomic) SDL_Window *keyboard_focus;
|
||||
@property(nonatomic) SDL3Cocoa_WindowListener *listener;
|
||||
@property(nonatomic) NSModalSession modal_session;
|
||||
@property(nonatomic) SDL_CocoaVideoData *videodata;
|
||||
@property(nonatomic) bool pending_size;
|
||||
@property(nonatomic) bool pending_position;
|
||||
@property(nonatomic) bool border_toggled;
|
||||
@property(nonatomic) bool has_modal_dialog;
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
@property(nonatomic) EGLSurface egl_surface;
|
||||
|
||||
@@ -432,6 +432,18 @@ bool Cocoa_IsWindowZoomed(SDL_Window *window)
|
||||
return zoomed;
|
||||
}
|
||||
|
||||
bool Cocoa_IsShowingModalDialog(SDL_Window *window)
|
||||
{
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
|
||||
return data.has_modal_dialog;
|
||||
}
|
||||
|
||||
void Cocoa_SetWindowHasModalDialog(SDL_Window *window, bool has_modal)
|
||||
{
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
|
||||
data.has_modal_dialog = has_modal;
|
||||
}
|
||||
|
||||
typedef enum CocoaMenuVisibility
|
||||
{
|
||||
COCOA_MENU_VISIBILITY_AUTO = 0,
|
||||
@@ -707,10 +719,7 @@ static SDL_Window *GetParentToplevelWindow(SDL_Window *window)
|
||||
static void Cocoa_SetKeyboardFocus(SDL_Window *window, bool set_active_focus)
|
||||
{
|
||||
SDL_Window *toplevel = GetParentToplevelWindow(window);
|
||||
SDL_CocoaWindowData *toplevel_data;
|
||||
|
||||
toplevel_data = (__bridge SDL_CocoaWindowData *)toplevel->internal;
|
||||
toplevel_data.keyboard_focus = window;
|
||||
toplevel->keyboard_focus = window;
|
||||
|
||||
if (set_active_focus && !window->is_hiding && !window->is_destroying) {
|
||||
SDL_SetKeyboardFocus(window);
|
||||
@@ -1252,7 +1261,7 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
|
||||
|
||||
// We're going to get keyboard events, since we're key.
|
||||
// This needs to be done before restoring the relative mouse mode.
|
||||
Cocoa_SetKeyboardFocus(_data.keyboard_focus ? _data.keyboard_focus : window, true);
|
||||
Cocoa_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window, true);
|
||||
|
||||
// If we just gained focus we need the updated mouse position
|
||||
if (!(window->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE)) {
|
||||
@@ -2022,6 +2031,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 +2043,7 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent;
|
||||
- (BOOL)wantsUpdateLayer;
|
||||
- (void)updateLayer;
|
||||
- (void)updateTrackingAreas;
|
||||
@end
|
||||
|
||||
@implementation SDL3View
|
||||
@@ -2113,6 +2124,21 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
|
||||
}
|
||||
}
|
||||
|
||||
- (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()
|
||||
@@ -2244,7 +2270,9 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
|
||||
[nswindow setIgnoresMouseEvents:YES];
|
||||
[nswindow setAcceptsMouseMovedEvents:NO];
|
||||
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
if (!(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
Cocoa_SetKeyboardFocus(window, true);
|
||||
}
|
||||
Cocoa_UpdateMouseFocus();
|
||||
}
|
||||
}
|
||||
@@ -2334,7 +2362,7 @@ bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
|
||||
rect.origin.y -= screenRect.origin.y;
|
||||
|
||||
// Constrain the popup
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (SDL_WINDOW_IS_POPUP(window) && window->constrain_popup) {
|
||||
if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) {
|
||||
rect.origin.x -= (rect.origin.x + rect.size.width) - (screenRect.origin.x + screenRect.size.width);
|
||||
}
|
||||
@@ -2490,7 +2518,7 @@ bool Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
ConvertNSRect(&rect);
|
||||
|
||||
// Position and constrain the popup
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (SDL_WINDOW_IS_POPUP(window) && window->constrain_popup) {
|
||||
NSRect screenRect = [ScreenForRect(&rect) frame];
|
||||
|
||||
if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) {
|
||||
@@ -2631,7 +2659,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
}
|
||||
}
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
if (!(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
Cocoa_SetKeyboardFocus(window, true);
|
||||
}
|
||||
Cocoa_UpdateMouseFocus();
|
||||
}
|
||||
}
|
||||
@@ -2665,20 +2695,9 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
Cocoa_SetWindowModal(_this, window, false);
|
||||
|
||||
// Transfer keyboard focus back to the parent when closing a popup menu
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
SDL_Window *new_focus = window->parent;
|
||||
bool set_focus = window == SDL_GetKeyboardFocus();
|
||||
|
||||
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
|
||||
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
new_focus = new_focus->parent;
|
||||
|
||||
// If some window in the chain currently had focus, set it to the new lowest-level window.
|
||||
if (!set_focus) {
|
||||
set_focus = new_focus == SDL_GetKeyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
SDL_Window *new_focus;
|
||||
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
|
||||
Cocoa_SetKeyboardFocus(new_focus, set_focus);
|
||||
Cocoa_UpdateMouseFocus();
|
||||
} else if (window->parent && waskey) {
|
||||
@@ -3105,20 +3124,19 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
|
||||
#endif // SDL_VIDEO_OPENGL
|
||||
SDL_Window *topmost = GetParentToplevelWindow(window);
|
||||
SDL_CocoaWindowData *topmost_data = (__bridge SDL_CocoaWindowData *)topmost->internal;
|
||||
|
||||
/* Reset the input focus of the root window if this window is still set as keyboard focus.
|
||||
* SDL_DestroyWindow will have already taken care of reassigning focus if this is the SDL
|
||||
* keyboard focus, this ensures that an inactive window with this window set as input focus
|
||||
* does not try to reference it the next time it gains focus.
|
||||
*/
|
||||
if (topmost_data.keyboard_focus == window) {
|
||||
if (topmost->keyboard_focus == window) {
|
||||
SDL_Window *new_focus = window;
|
||||
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
new_focus = new_focus->parent;
|
||||
}
|
||||
|
||||
topmost_data.keyboard_focus = new_focus;
|
||||
topmost->keyboard_focus = new_focus;
|
||||
}
|
||||
|
||||
if ([data.listener isInFullscreenSpace]) {
|
||||
@@ -3283,6 +3301,20 @@ bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOper
|
||||
|
||||
bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
|
||||
{
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
SDL_Window *new_focus;
|
||||
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
|
||||
Cocoa_SetKeyboardFocus(new_focus, set_focus);
|
||||
} else if (focusable) {
|
||||
if (SDL_ShouldFocusPopup(window)) {
|
||||
Cocoa_SetKeyboardFocus(window, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // just succeed, the real work is done elsewhere.
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -199,7 +199,6 @@ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
|
||||
timestamp_offset += SDL_MS_TO_NS(SDL_UINT64_C(0x100000000));
|
||||
}
|
||||
last = wl_timestamp_ms;
|
||||
wl_timestamp_ms += timestamp_offset;
|
||||
|
||||
return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset;
|
||||
}
|
||||
@@ -213,11 +212,6 @@ static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint3
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms);
|
||||
}
|
||||
|
||||
static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
||||
{
|
||||
if (wl_timestamp_ms) {
|
||||
@@ -273,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);
|
||||
@@ -295,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;
|
||||
@@ -304,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';
|
||||
}
|
||||
@@ -1721,7 +1717,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
||||
window->keyboard_device = input;
|
||||
|
||||
// Restore the keyboard focus to the child popup that was holding it
|
||||
SDL_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window->sdlwindow);
|
||||
SDL_SetKeyboardFocus(window->sdlwindow->keyboard_focus ? window->sdlwindow->keyboard_focus : window->sdlwindow);
|
||||
|
||||
#ifdef SDL_USE_IME
|
||||
if (!input->text_input) {
|
||||
@@ -1859,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);
|
||||
|
||||
@@ -1875,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);
|
||||
@@ -1883,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))) {
|
||||
@@ -1894,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -646,6 +642,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
||||
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
|
||||
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
|
||||
device->SyncWindow = Wayland_SyncWindow;
|
||||
device->SetWindowFocusable = Wayland_SetWindowFocusable;
|
||||
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
if (SDL_SystemTheme_Init())
|
||||
|
||||
@@ -181,7 +181,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
||||
if (!wind->shell_surface.libdecor.initial_configure_seen || !wind->shell_surface.libdecor.frame) {
|
||||
if (!wind->shell_surface.libdecor.frame) {
|
||||
return; // Can't do anything yet, wait for ShowWindow
|
||||
}
|
||||
/* No need to change these values if the window is non-resizable,
|
||||
@@ -198,7 +198,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
|
||||
} else
|
||||
#endif
|
||||
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
||||
if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) {
|
||||
if (!wind->shell_surface.xdg.toplevel.xdg_toplevel) {
|
||||
return; // Can't do anything yet, wait for ShowWindow
|
||||
}
|
||||
xdg_toplevel_set_min_size(wind->shell_surface.xdg.toplevel.xdg_toplevel,
|
||||
@@ -753,7 +753,9 @@ static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *x
|
||||
xdg_surface_ack_configure(xdg, serial);
|
||||
}
|
||||
|
||||
wind->shell_surface.xdg.initial_configure_seen = true;
|
||||
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener shell_surface_listener_xdg = {
|
||||
@@ -970,10 +972,6 @@ static void handle_configure_xdg_toplevel(void *data,
|
||||
wind->active = active;
|
||||
window->tiled = tiled;
|
||||
wind->resizing = resizing;
|
||||
|
||||
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
|
||||
@@ -1122,9 +1120,7 @@ static void handle_configure_zxdg_decoration(void *data,
|
||||
WAYLAND_wl_display_roundtrip(internal->waylandData->display);
|
||||
|
||||
Wayland_HideWindow(device, window);
|
||||
SDL_zero(internal->shell_surface);
|
||||
internal->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR;
|
||||
|
||||
Wayland_ShowWindow(device, window);
|
||||
}
|
||||
}
|
||||
@@ -1406,11 +1402,8 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
||||
libdecor_state_free(state);
|
||||
}
|
||||
|
||||
if (!wind->shell_surface.libdecor.initial_configure_seen) {
|
||||
LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
|
||||
wind->shell_surface.libdecor.initial_configure_seen = true;
|
||||
}
|
||||
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
|
||||
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
|
||||
}
|
||||
|
||||
@@ -1666,7 +1659,7 @@ static const struct wp_color_management_surface_feedback_v1_listener color_manag
|
||||
feedback_surface_preferred_changed
|
||||
};
|
||||
|
||||
static void SetKeyboardFocus(SDL_Window *window, bool set_focus)
|
||||
static void Wayland_SetKeyboardFocus(SDL_Window *window, bool set_focus)
|
||||
{
|
||||
SDL_Window *toplevel = window;
|
||||
|
||||
@@ -1675,7 +1668,7 @@ static void SetKeyboardFocus(SDL_Window *window, bool set_focus)
|
||||
toplevel = toplevel->parent;
|
||||
}
|
||||
|
||||
toplevel->internal->keyboard_focus = window;
|
||||
toplevel->keyboard_focus = window;
|
||||
|
||||
if (set_focus && !window->is_hiding && !window->is_destroying) {
|
||||
SDL_SetKeyboardFocus(window);
|
||||
@@ -1819,12 +1812,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
}
|
||||
}
|
||||
|
||||
/* The window was hidden, but the sync point hasn't yet been reached.
|
||||
* Pump events to avoid a possible protocol violation.
|
||||
*/
|
||||
if (data->show_hide_sync_required) {
|
||||
// Always roundtrip to ensure there are no pending buffer attachments.
|
||||
do {
|
||||
WAYLAND_wl_display_roundtrip(c->display);
|
||||
}
|
||||
} while (data->show_hide_sync_required);
|
||||
|
||||
data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE;
|
||||
|
||||
@@ -1905,8 +1896,9 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
data->shell_surface.xdg.popup.xdg_positioner = xdg_wm_base_create_positioner(c->shell.xdg);
|
||||
xdg_positioner_set_anchor(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT);
|
||||
xdg_positioner_set_anchor_rect(data->shell_surface.xdg.popup.xdg_positioner, 0, 0, parent->internal->current.logical_width, parent->internal->current.logical_width);
|
||||
xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.popup.xdg_positioner,
|
||||
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
|
||||
|
||||
const Uint32 constraint = window->constrain_popup ? (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) : XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE;
|
||||
xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.popup.xdg_positioner, constraint);
|
||||
xdg_positioner_set_gravity(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
|
||||
xdg_positioner_set_size(data->shell_surface.xdg.popup.xdg_positioner, data->current.logical_width, data->current.logical_height);
|
||||
|
||||
@@ -1935,8 +1927,8 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
wl_region_add(region, 0, 0, 0, 0);
|
||||
wl_surface_set_input_region(data->surface, region);
|
||||
wl_region_destroy(region);
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
|
||||
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
Wayland_SetKeyboardFocus(window, true);
|
||||
}
|
||||
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER, data->shell_surface.xdg.popup.xdg_popup);
|
||||
@@ -1984,7 +1976,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
||||
if (data->shell_surface.libdecor.frame) {
|
||||
while (!data->shell_surface.libdecor.initial_configure_seen) {
|
||||
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
WAYLAND_wl_display_flush(c->display);
|
||||
WAYLAND_wl_display_dispatch(c->display);
|
||||
}
|
||||
@@ -1998,7 +1990,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
*/
|
||||
wl_surface_commit(data->surface);
|
||||
if (data->shell_surface.xdg.surface) {
|
||||
while (!data->shell_surface.xdg.initial_configure_seen) {
|
||||
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
WAYLAND_wl_display_flush(c->display);
|
||||
WAYLAND_wl_display_dispatch(c->display);
|
||||
}
|
||||
@@ -2083,21 +2075,10 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *popup)
|
||||
return;
|
||||
}
|
||||
|
||||
if (popup->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
SDL_Window *new_focus = popup->parent;
|
||||
bool set_focus = popup == SDL_GetKeyboardFocus();
|
||||
|
||||
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
|
||||
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
new_focus = new_focus->parent;
|
||||
|
||||
// If some window in the chain currently had focus, set it to the new lowest-level window.
|
||||
if (!set_focus) {
|
||||
set_focus = new_focus == SDL_GetKeyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
SetKeyboardFocus(new_focus, set_focus);
|
||||
if ((popup->flags & SDL_WINDOW_POPUP_MENU) && !(popup->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
SDL_Window *new_focus;
|
||||
const bool set_focus = SDL_ShouldRelinquishPopupFocus(popup, &new_focus);
|
||||
Wayland_SetKeyboardFocus(new_focus, set_focus);
|
||||
}
|
||||
|
||||
xdg_popup_destroy(popupdata->shell_surface.xdg.popup.xdg_popup);
|
||||
@@ -2158,26 +2139,27 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
||||
if (wind->shell_surface.libdecor.frame) {
|
||||
libdecor_frame_unref(wind->shell_surface.libdecor.frame);
|
||||
wind->shell_surface.libdecor.frame = NULL;
|
||||
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
|
||||
Wayland_ReleasePopup(_this, window);
|
||||
} else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
|
||||
xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
|
||||
wind->shell_surface.xdg.toplevel.xdg_toplevel = NULL;
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
|
||||
}
|
||||
if (wind->shell_surface.xdg.surface) {
|
||||
xdg_surface_destroy(wind->shell_surface.xdg.surface);
|
||||
wind->shell_surface.xdg.surface = NULL;
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
|
||||
Wayland_ReleasePopup(_this, window);
|
||||
} else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
|
||||
xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
|
||||
}
|
||||
|
||||
if (wind->shell_surface.xdg.surface) {
|
||||
xdg_surface_destroy(wind->shell_surface.xdg.surface);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_zero(wind->shell_surface);
|
||||
wind->show_hide_sync_required = true;
|
||||
struct wl_callback *cb = wl_display_sync(_this->internal->display);
|
||||
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
|
||||
@@ -2991,6 +2973,27 @@ bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
|
||||
{
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
SDL_Window *new_focus;
|
||||
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
|
||||
Wayland_SetKeyboardFocus(new_focus, set_focus);
|
||||
} else if (focusable) {
|
||||
if (SDL_ShouldFocusPopup(window)) {
|
||||
Wayland_SetKeyboardFocus(window, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return SDL_SetError("wayland: focus can only be toggled on popup menu windows");
|
||||
}
|
||||
|
||||
void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
|
||||
{
|
||||
SDL_WindowData *wind = window->internal;
|
||||
|
||||
@@ -48,7 +48,6 @@ struct SDL_WindowData
|
||||
struct
|
||||
{
|
||||
struct libdecor_frame *frame;
|
||||
bool initial_configure_seen;
|
||||
} libdecor;
|
||||
#endif
|
||||
struct
|
||||
@@ -66,7 +65,6 @@ struct SDL_WindowData
|
||||
struct xdg_positioner *xdg_positioner;
|
||||
} popup;
|
||||
};
|
||||
bool initial_configure_seen;
|
||||
} xdg;
|
||||
} shell_surface;
|
||||
enum
|
||||
@@ -125,8 +123,6 @@ struct SDL_WindowData
|
||||
SDL_DisplayData **outputs;
|
||||
int num_outputs;
|
||||
|
||||
SDL_Window *keyboard_focus;
|
||||
|
||||
char *app_id;
|
||||
double scale_factor;
|
||||
|
||||
@@ -237,6 +233,7 @@ extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);
|
||||
extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
extern bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
extern float Wayland_GetWindowContentScale(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
|
||||
|
||||
|
||||
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user