Compare commits

..
46 Commits
Author SHA1 Message Date
Cameron Gutman ee7cb5123d Add NVDEC to list of supported video acceleration APIs 2019-08-05 18:31:38 -07:00
Cameron Gutman 77e1d6ab8a Version 1.1 2019-08-05 18:28:26 -07:00
Cameron Gutman 1640bed7a5 Improve reliability of mDNS discovery 2019-08-04 18:04:33 -07:00
Cameron Gutman c6fd5cbbce Update common-c to fix high quality surround sound over the Internet 2019-08-04 15:15:51 -07:00
Cameron Gutman 5288041da5 Prevent us from consuming more than 4 samples per write callback to bound latency 2019-08-03 12:47:44 -07:00
Cameron Gutman a848fb1dd1 Add Steam Link to Travis CI 2019-08-02 21:31:07 -07:00
Cameron Gutman 172945434c Build the full DMG on Travis CI 2019-08-02 20:52:23 -07:00
Cameron Gutman a0967e0281 Fix building a dmg with no code signing identities 2019-08-02 20:40:20 -07:00
Cameron Gutman deab717c73 Remove AppVeyor OpenSSL hack 2019-08-02 20:21:10 -07:00
Cameron Gutman 5db5a088ea Fix NVDEC artifacts if the renderer is delayed for a bit 2019-08-01 20:25:58 -07:00
Cameron Gutman 5e106d2f19 Only store the local address from mDNS if it actually worked 2019-07-31 22:16:11 -07:00
Cameron Gutman 940da6bc73 Fix discovery of IPv6-only hosts 2019-07-31 22:07:20 -07:00
Cameron Gutman d110bff253 Update qmdnsengine to improve reliability of mDNS on multi-homed systems 2019-07-31 22:03:27 -07:00
Cameron Gutman 4caa329c36 Update Windows to SDL 2.0.10 with USE_D3D9EX 2019-07-28 12:01:12 -07:00
Cameron Gutman 7c7d279337 Update SDL_GameControllerDB to dca1a629d9e094baa17fff8ba1642cabc6125eed 2019-07-26 16:43:20 -04:00
Cameron Gutman 831e6ee76d Update moonlight-common-c to fix termination error code on GFE 3.19.0.107 2019-07-26 16:43:20 -04:00
Cameron Gutman b01842ad02 Update macOS to SDL 2.0.10 2019-07-26 16:43:20 -04:00
Cameron Gutman 7acf91883a Rework audio renderer selection to fall back and treat ML_AUDIO as a hard selection 2019-07-26 12:50:45 -04:00
Cameron Gutman 897f6fdd3e Improve handling of IPv6-only cases 2019-07-15 01:07:31 -07:00
Cameron Gutman 6f9c3fbc38 Add support for zero configuration IPv6 streaming 2019-07-14 17:56:57 -07:00
Cameron Gutman bcbd1a5b4b Fix subsystem print in VAAPI 2019-07-07 15:41:26 -07:00
Cameron Gutman 6468efd7e4 Add VAAPI DRM support 2019-07-07 15:32:38 -07:00
Cameron Gutman 66863789c7 Update common-c for compatibility with legacy servers 2019-07-05 22:52:42 -07:00
Cameron Gutman b30058fc29 Fix pairing to Gen 3-5 servers 2019-07-05 21:04:04 -07:00
Cameron Gutman a41cd0b070 Generate SHA-256 client certificates instead of SHA-1 2019-07-05 20:57:21 -07:00
Cameron Gutman ea8b905f02 Missed a call to SDL_SetRelativeMouseMode 2019-07-02 22:39:09 -07:00
Cameron Gutman 16b301236b Add a mouse capture fallback if SDL_SetRelativeMouseMode() fails 2019-07-02 22:17:38 -07:00
Cameron Gutman 22162dda83 Fix runtime SDL version report 2019-06-30 18:48:11 -07:00
Cameron Gutman 024af89be3 Add an option to disable the gamepad mouse button toggle 2019-06-29 18:24:59 -07:00
Cameron Gutman e1a697658e Add Discord Rich Presence for macOS 2019-06-29 17:55:21 -07:00
Cameron Gutman 0a5051f959 Add Discord Rich Presence integration for Windows 2019-06-29 17:40:30 -07:00
Cameron Gutman 82b6b60b31 Take advantage of SDL 2.0.10 bugfixes and new APIs. Fixes #133 2019-06-29 16:08:04 -07:00
Cameron Gutman 06b3c3636a Print compile-time and run-time SDL versions 2019-06-29 15:43:45 -07:00
Cameron Gutman e5712a9474 Move dylibs into the Frameworks folder in the app bundle 2019-06-29 15:39:20 -07:00
Cameron Gutman 6ff845c53b Use borderless windowed mode as the default on macOS. Fixes #246 2019-06-29 14:58:27 -07:00
Cameron Gutman 1c225ed04d Use CUDA acceleration if other hwaccels are unavailable 2019-06-26 21:54:29 -07:00
Cameron Gutman 612b738968 Use the preferred sw_format when reading frames back 2019-06-26 21:25:41 -07:00
Cameron Gutman 87356ef594 Add CUDA acceleration support 2019-06-26 21:02:33 -07:00
Cameron Gutman 20a4dfa6d6 Update bug report template 2019-06-25 21:41:02 -07:00
Cameron Gutman 524cc97f51 Use borderless windowed mode when toggling to full-screen from an initially windowed stream. Fixes #248 2019-06-23 13:29:57 -07:00
Cameron Gutman fc849fb51a Switch back to SDL for audio on Linux. Fixes #245 2019-06-23 13:16:00 -07:00
Cameron Gutman c88651939a Re-add latency bounding on the SDL audio renderer 2019-06-23 13:14:55 -07:00
Cameron Gutman 01254f67f0 Allow audio renderers to specify capabilities 2019-06-23 12:49:37 -07:00
Cameron Gutman 212ed33b21 Block Optimus from using the dGPU due to driver bugs. Fixes #240. Fixes #235 2019-06-22 19:49:05 -07:00
Cameron Gutman bd3f8aef21 Remove OpenSSL 1.0.2 for Qt 5.12.4/5.13 2019-06-18 19:54:35 -07:00
Cameron Gutman 3785acea29 Update to OpenSSL 1.1.1c in preparation for Qt 5.12.4/5.13 2019-06-16 15:20:04 -07:00
286 changed files with 9688 additions and 4940 deletions

No files matched your search

+6 -1
View File
@@ -1,8 +1,10 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us address broken functionality about: Create a report to help us address issues in Moonlight
--- ---
**READ ME FIRST!**
This issue tracker is not the right place to ask for troubleshooting help if you're not able to connect or stream at all. For those requests, please use the #pc-help channel on our Discord server where there are many more people who can help (or direct you back here if it looks like a Moonlight bug after all). https://discord.gg/MySTSdq
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is.
@@ -16,6 +18,9 @@ If applicable, add screenshots to help explain your problem. If the issue is rel
**Affected games** **Affected games**
List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there. List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
**Other Moonlight clients**
- Does the issue occur when using Moonlight on iOS or Android?
**Moonlight settings (please complete the following information)** **Moonlight settings (please complete the following information)**
- Have any settings been adjusted from defaults? - Have any settings been adjusted from defaults?
- If so, which settings have been changed? - If so, which settings have been changed?
+33 -15
View File
@@ -3,17 +3,31 @@ language: cpp
git: git:
depth: 1 depth: 1
env:
- NJOBS=2
matrix: matrix:
include: include:
- os: osx - os: osx
osx_image: xcode10.2
compiler: clang compiler: clang
env: TRAVIS_TARGET=osx
addons:
homebrew:
packages:
- qt
- os: linux - os: linux
sudo: required sudo: required
dist: xenial dist: xenial
compiler: gcc compiler: gcc
env: TRAVIS_TARGET=steamlink
addons:
apt:
packages:
- libc6:i386
- libstdc++6:i386
- os: linux
sudo: required
dist: xenial
compiler: gcc
env: TRAVIS_TARGET=linux
addons: addons:
apt: apt:
sources: sources:
@@ -35,19 +49,23 @@ matrix:
- libvdpau-dev - libvdpau-dev
install: install:
- '[ "$TRAVIS_OS_NAME" != osx ] || brew install qt5' - '[ "$TRAVIS_TARGET" != osx ] || brew link --force qt'
- '[ "$TRAVIS_OS_NAME" != osx ] || brew link --force qt5' - if [[ "$TRAVIS_TARGET" = "osx" ]]; then nvm use node && npm install --global create-dmg; fi
- if [[ "$TRAVIS_OS_NAME" = "linux" ]]; then export SDL2_VER=2.0.9 && wget https://www.libsdl.org/release/SDL2-$SDL2_VER.tar.gz && tar -xvf SDL2-$SDL2_VER.tar.gz && cd SDL2-$SDL2_VER && ./configure && make -j$NJOBS && sudo make install && cd ..; fi - if [[ "$TRAVIS_TARGET" = "linux" ]]; then export SDL2_VER=2.0.9 && wget https://www.libsdl.org/release/SDL2-$SDL2_VER.tar.gz && tar -xvf SDL2-$SDL2_VER.tar.gz && cd SDL2-$SDL2_VER && ./configure && make -j$(nproc) && sudo make install && cd ..; fi
- if [[ "$TRAVIS_OS_NAME" = "linux" ]]; then export SDL2_TTF_VER=2.0.15 && wget https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-$SDL2_TTF_VER.tar.gz && tar -xvf SDL2_ttf-$SDL2_TTF_VER.tar.gz && cd SDL2_ttf-$SDL2_TTF_VER && ./configure && make -j$NJOBS && sudo make install && cd ..; fi - if [[ "$TRAVIS_TARGET" = "linux" ]]; then export SDL2_TTF_VER=2.0.15 && wget https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-$SDL2_TTF_VER.tar.gz && tar -xvf SDL2_ttf-$SDL2_TTF_VER.tar.gz && cd SDL2_ttf-$SDL2_TTF_VER && ./configure && make -j$(nproc) && sudo make install && cd ..; fi
- if [[ "$TRAVIS_TARGET" = "steamlink" ]]; then git clone --depth=1 https://github.com/ValveSoftware/steamlink-sdk.git $HOME/steamlink-sdk; fi
before_script: before_script:
- '[ "$TRAVIS_OS_NAME" != "linux" ] || source /opt/qt59/bin/qt59-env.sh' - '[ "$TRAVIS_TARGET" != "linux" ] || source /opt/qt59/bin/qt59-env.sh'
- qmake -v - '[ "$TRAVIS_TARGET" = "steamlink" ] || qmake -v'
- '[[ "$TRAVIS_OS_NAME" != linux || "$CXX" != clang++ ]] || export QMAKESPEC=linux-clang' - '[[ "$TRAVIS_TARGET" != linux || "$CXX" != clang++ ]] || export QMAKESPEC=linux-clang'
- '[[ "$TRAVIS_OS_NAME" != linux || "$CXX" != g++ ]] || export QMAKESPEC=linux-g++' - '[[ "$TRAVIS_TARGET" != linux || "$CXX" != g++ ]] || export QMAKESPEC=linux-g++'
- '[ "$TRAVIS_OS_NAME" != osx ] || export QMAKESPEC=macx-clang' - '[ "$TRAVIS_TARGET" != osx ] || export QMAKESPEC=macx-clang'
- '[ "$TRAVIS_TARGET" != "steamlink" ] || export STEAMLINK_SDK_PATH=$HOME/steamlink-sdk'
script: script:
- qmake moonlight-qt.pro -spec $QMAKESPEC - '[ "$TRAVIS_TARGET" != "linux" ] || qmake moonlight-qt.pro -spec $QMAKESPEC'
- make -j$NJOBS debug - '[ "$TRAVIS_TARGET" != "linux" ] || make -j$(nproc) debug'
- make -j$NJOBS release - '[ "$TRAVIS_TARGET" != "linux" ] || make -j$(nproc) release'
- '[ "$TRAVIS_TARGET" != "osx" ] || scripts/generate-dmg.sh Release'
- '[ "$TRAVIS_TARGET" != "steamlink" ] || scripts/build-steamlink-app.sh'
+12
View File
@@ -135,10 +135,22 @@ private:
// D3D9 exclusive fullscreen in a way that causes CreateDeviceEx() // D3D9 exclusive fullscreen in a way that causes CreateDeviceEx()
// to deadlock. https://github.com/moonlight-stream/moonlight-qt/issues/102 // to deadlock. https://github.com/moonlight-stream/moonlight-qt/issues/102
L"NahimicOSD.dll", L"NahimicOSD.dll",
// This DLL has been seen in several crash reports. Some Googling // This DLL has been seen in several crash reports. Some Googling
// suggests it's highly unstable and causes issues in many games. // suggests it's highly unstable and causes issues in many games.
L"EZFRD32.dll", L"EZFRD32.dll",
L"EZFRD64.dll", L"EZFRD64.dll",
// These are the dList DLLs for Optimus hybrid graphics DDI.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/hybrid-system-ddi
//
// We forcefully block them from loading because Optimus has a bug that
// deadlocks DXVA2 when we present with D3DPRESENT_DONOTWAIT. This will prevent
// Optimus from ever using the dGPU even if the user has requested it.
// https://github.com/moonlight-stream/moonlight-qt/issues/240
// https://github.com/moonlight-stream/moonlight-qt/issues/235
L"nvdlist.dll",
L"nvdlistx.dll",
}; };
}; };
+22 -3
View File
@@ -84,6 +84,9 @@ unix:!macx {
packagesExist(libva-wayland) { packagesExist(libva-wayland) {
CONFIG += libva-wayland CONFIG += libva-wayland
} }
packagesExist(libva-drm) {
CONFIG += libva-drm
}
CONFIG += libva CONFIG += libva
} }
@@ -107,7 +110,7 @@ win32 {
CONFIG += ffmpeg CONFIG += ffmpeg
} }
win32:!winrt { win32:!winrt {
CONFIG += soundio CONFIG += soundio discord-rpc
} }
macx { macx {
LIBS += -lssl -lcrypto -lavcodec.58 -lavutil.56 -lopus -framework SDL2 -framework SDL2_ttf LIBS += -lssl -lcrypto -lavcodec.58 -lavutil.56 -lopus -framework SDL2 -framework SDL2_ttf
@@ -116,7 +119,7 @@ macx {
# For libsoundio # For libsoundio
LIBS += -framework CoreAudio -framework AudioUnit LIBS += -framework CoreAudio -framework AudioUnit
CONFIG += ffmpeg soundio CONFIG += ffmpeg soundio discord-rpc
} }
SOURCES += \ SOURCES += \
@@ -128,6 +131,7 @@ SOURCES += \
backend/nvpairingmanager.cpp \ backend/nvpairingmanager.cpp \
backend/computermanager.cpp \ backend/computermanager.cpp \
backend/boxartmanager.cpp \ backend/boxartmanager.cpp \
backend/richpresencemanager.cpp \
cli/commandlineparser.cpp \ cli/commandlineparser.cpp \
cli/quitstream.cpp \ cli/quitstream.cpp \
cli/startstream.cpp \ cli/startstream.cpp \
@@ -155,6 +159,7 @@ HEADERS += \
backend/nvpairingmanager.h \ backend/nvpairingmanager.h \
backend/computermanager.h \ backend/computermanager.h \
backend/boxartmanager.h \ backend/boxartmanager.h \
backend/richpresencemanager.h \
cli/commandlineparser.h \ cli/commandlineparser.h \
cli/quitstream.h \ cli/quitstream.h \
cli/startstream.h \ cli/startstream.h \
@@ -182,6 +187,7 @@ ffmpeg {
SOURCES += \ SOURCES += \
streaming/video/ffmpeg.cpp \ streaming/video/ffmpeg.cpp \
streaming/video/ffmpeg-renderers/sdlvid.cpp \ streaming/video/ffmpeg-renderers/sdlvid.cpp \
streaming/video/ffmpeg-renderers/cuda.cpp \
streaming/video/ffmpeg-renderers/pacer/pacer.cpp \ streaming/video/ffmpeg-renderers/pacer/pacer.cpp \
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.cpp streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.cpp
@@ -189,6 +195,7 @@ ffmpeg {
streaming/video/ffmpeg.h \ streaming/video/ffmpeg.h \
streaming/video/ffmpeg-renderers/renderer.h \ streaming/video/ffmpeg-renderers/renderer.h \
streaming/video/ffmpeg-renderers/sdlvid.h \ streaming/video/ffmpeg-renderers/sdlvid.h \
streaming/video/ffmpeg-renderers/cuda.h \
streaming/video/ffmpeg-renderers/pacer/pacer.h \ streaming/video/ffmpeg-renderers/pacer/pacer.h \
streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.h streaming/video/ffmpeg-renderers/pacer/nullthreadedvsyncsource.h
} }
@@ -212,6 +219,12 @@ libva-wayland {
PKGCONFIG += libva-wayland PKGCONFIG += libva-wayland
DEFINES += HAVE_LIBVA_WAYLAND DEFINES += HAVE_LIBVA_WAYLAND
} }
libva-wayland {
message(VAAPI DRM support enabled)
PKGCONFIG += libva-drm
DEFINES += HAVE_LIBVA_DRM
}
libvdpau { libvdpau {
message(VDPAU renderer selected) message(VDPAU renderer selected)
@@ -273,6 +286,12 @@ soundio {
SOURCES += streaming/audio/renderers/soundioaudiorenderer.cpp SOURCES += streaming/audio/renderers/soundioaudiorenderer.cpp
HEADERS += streaming/audio/renderers/soundioaudiorenderer.h HEADERS += streaming/audio/renderers/soundioaudiorenderer.h
} }
discord-rpc {
message(Discord integration enabled)
LIBS += -ldiscord-rpc
DEFINES += HAVE_DISCORD
}
RESOURCES += \ RESOURCES += \
resources.qrc \ resources.qrc \
@@ -365,7 +384,7 @@ macx {
APP_BUNDLE_RESOURCES.files = moonlight.icns APP_BUNDLE_RESOURCES.files = moonlight.icns
APP_BUNDLE_RESOURCES.path = Contents/Resources APP_BUNDLE_RESOURCES.path = Contents/Resources
APP_BUNDLE_FRAMEWORKS.files = $$files(../libs/mac/Frameworks/*.framework, true) APP_BUNDLE_FRAMEWORKS.files = $$files(../libs/mac/Frameworks/*.framework, true) $$files(../libs/mac/lib/*.dylib, true)
APP_BUNDLE_FRAMEWORKS.path = Contents/Frameworks APP_BUNDLE_FRAMEWORKS.path = Contents/Frameworks
QMAKE_BUNDLE_DATA += APP_BUNDLE_RESOURCES APP_BUNDLE_FRAMEWORKS QMAKE_BUNDLE_DATA += APP_BUNDLE_RESOURCES APP_BUNDLE_FRAMEWORKS
+96 -13
View File
@@ -216,6 +216,42 @@ void ComputerManager::saveHosts()
settings.endArray(); settings.endArray();
} }
QHostAddress ComputerManager::getBestGlobalAddressV6(QVector<QHostAddress> &addresses)
{
for (const QHostAddress& address : addresses) {
if (address.protocol() == QAbstractSocket::IPv6Protocol) {
if (address.isInSubnet(QHostAddress("fe80::"), 10)) {
// Link-local
continue;
}
if (address.isInSubnet(QHostAddress("fec0::"), 10)) {
qInfo() << "Ignoring site-local address:" << address;
continue;
}
if (address.isInSubnet(QHostAddress("fc00::"), 7)) {
qInfo() << "Ignoring ULA:" << address;
continue;
}
if (address.isInSubnet(QHostAddress("2002::"), 16)) {
qInfo() << "Ignoring 6to4 address:" << address;
continue;
}
if (address.isInSubnet(QHostAddress("2001::"), 32)) {
qInfo() << "Ignoring Teredo address:" << address;
continue;
}
return address;
}
}
return QHostAddress();
}
void ComputerManager::startPolling() void ComputerManager::startPolling()
{ {
QWriteLocker lock(&m_Lock); QWriteLocker lock(&m_Lock);
@@ -233,9 +269,9 @@ void ComputerManager::startPolling()
this, [this](const QMdnsEngine::Service& service) { this, [this](const QMdnsEngine::Service& service) {
qInfo() << "Discovered mDNS host:" << service.hostname(); qInfo() << "Discovered mDNS host:" << service.hostname();
MdnsPendingComputer* pendingComputer = new MdnsPendingComputer(&m_MdnsServer, &m_MdnsCache, service); MdnsPendingComputer* pendingComputer = new MdnsPendingComputer(&m_MdnsServer, service);
connect(pendingComputer, SIGNAL(resolvedv4(MdnsPendingComputer*,QHostAddress)), connect(pendingComputer, &MdnsPendingComputer::resolvedHost,
this, SLOT(handleMdnsServiceResolved(MdnsPendingComputer*,QHostAddress))); this, &ComputerManager::handleMdnsServiceResolved);
m_PendingResolution.append(pendingComputer); m_PendingResolution.append(pendingComputer);
}); });
} }
@@ -277,11 +313,39 @@ void ComputerManager::startPollingComputer(NvComputer* computer)
} }
void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer, void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
const QHostAddress& address) QVector<QHostAddress>& addresses)
{ {
qInfo() << "Resolved" << computer->hostname() << "to" << address.toString(); QHostAddress v6Global = getBestGlobalAddressV6(addresses);
bool added = false;
addNewHost(address.toString(), true); // Add the host using the IPv4 address
for (const QHostAddress& address : addresses) {
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
// NB: We don't just call addNewHost() here with v6Global because the IPv6
// address may not be reachable (if the user hasn't installed the IPv6 helper yet
// or if this host lacks outbound IPv6 capability). We want to add IPv6 even if
// it's not currently reachable.
addNewHost(address.toString(), true, v6Global);
added = true;
break;
}
}
if (!added) {
// If we get here, there wasn't an IPv4 address so we'll do it v6-only
for (const QHostAddress& address : addresses) {
if (address.protocol() == QAbstractSocket::IPv6Protocol) {
// Use a link-local or site-local address for the "local address"
if (address.isInSubnet(QHostAddress("fe80::"), 10) ||
address.isInSubnet(QHostAddress("fec0::"), 10) ||
address.isInSubnet(QHostAddress("fc00::"), 7)) {
addNewHost(address.toString(), true, v6Global);
added = true;
break;
}
}
}
}
m_PendingResolution.removeOne(computer); m_PendingResolution.removeOne(computer);
computer->deleteLater(); computer->deleteLater();
@@ -508,9 +572,10 @@ class PendingAddTask : public QObject, public QRunnable
Q_OBJECT Q_OBJECT
public: public:
PendingAddTask(ComputerManager* computerManager, QString address, bool mdns) PendingAddTask(ComputerManager* computerManager, QString address, QHostAddress mdnsIpv6Address, bool mdns)
: m_ComputerManager(computerManager), : m_ComputerManager(computerManager),
m_Address(address), m_Address(address),
m_MdnsIpv6Address(mdnsIpv6Address),
m_Mdns(mdns) m_Mdns(mdns)
{ {
connect(this, &PendingAddTask::computerAddCompleted, connect(this, &PendingAddTask::computerAddCompleted,
@@ -560,16 +625,21 @@ private:
{ {
NvHTTP http(m_Address, QSslCertificate()); NvHTTP http(m_Address, QSslCertificate());
qInfo() << "Processing new PC at" << m_Address << "from" << (m_Mdns ? "mDNS" : "user"); qInfo() << "Processing new PC at" << m_Address << "from" << (m_Mdns ? "mDNS" : "user") << m_MdnsIpv6Address;
// Perform initial serverinfo fetch over HTTP since we don't know which cert to use // Perform initial serverinfo fetch over HTTP since we don't know which cert to use
QString serverInfo = fetchServerInfo(http); QString serverInfo = fetchServerInfo(http);
if (serverInfo.isEmpty() && !m_MdnsIpv6Address.isNull()) {
// Retry using the global IPv6 address if the IPv4 or link-local IPv6 address fails
http.setAddress(m_MdnsIpv6Address.toString());
serverInfo = fetchServerInfo(http);
}
if (serverInfo.isEmpty()) { if (serverInfo.isEmpty()) {
return; return;
} }
// Create initial newComputer using HTTP serverinfo with no pinned cert // Create initial newComputer using HTTP serverinfo with no pinned cert
NvComputer* newComputer = new NvComputer(m_Address, serverInfo, QSslCertificate()); NvComputer* newComputer = new NvComputer(http.address(), serverInfo, QSslCertificate());
// Check if we have a record of this host UUID to pull the pinned cert // Check if we have a record of this host UUID to pull the pinned cert
NvComputer* existingComputer; NvComputer* existingComputer;
@@ -589,15 +659,21 @@ private:
} }
// Update the polled computer with the HTTPS information // Update the polled computer with the HTTPS information
NvComputer httpsComputer(m_Address, serverInfo, QSslCertificate()); NvComputer httpsComputer(http.address(), serverInfo, QSslCertificate());
newComputer->update(httpsComputer); newComputer->update(httpsComputer);
} }
// Update addresses depending on the context // Update addresses depending on the context
if (m_Mdns) { if (m_Mdns) {
// Only update local address if we actually reached the PC via this address.
// If we reached it via the IPv6 address after the local address failed,
// don't store the non-working local address.
if (http.address() == m_Address) {
newComputer->localAddress = m_Address; newComputer->localAddress = m_Address;
}
// Get the WAN IP address using STUN if we're on mDNS // Get the WAN IP address using STUN if we're on mDNS over IPv4
if (QHostAddress(newComputer->localAddress).protocol() == QAbstractSocket::IPv4Protocol) {
quint32 addr; quint32 addr;
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr); int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &addr);
if (err == 0) { if (err == 0) {
@@ -607,6 +683,12 @@ private:
qWarning() << "STUN failed to get WAN address:" << err; qWarning() << "STUN failed to get WAN address:" << err;
} }
} }
if (!m_MdnsIpv6Address.isNull()) {
Q_ASSERT(m_MdnsIpv6Address.protocol() == QAbstractSocket::IPv6Protocol);
newComputer->ipv6Address = m_MdnsIpv6Address.toString();
}
}
else { else {
newComputer->manualAddress = m_Address; newComputer->manualAddress = m_Address;
} }
@@ -657,14 +739,15 @@ private:
ComputerManager* m_ComputerManager; ComputerManager* m_ComputerManager;
QString m_Address; QString m_Address;
QHostAddress m_MdnsIpv6Address;
bool m_Mdns; bool m_Mdns;
}; };
void ComputerManager::addNewHost(QString address, bool mdns) void ComputerManager::addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address)
{ {
// Punt to a worker thread to avoid stalling the // Punt to a worker thread to avoid stalling the
// UI while waiting for serverinfo query to complete // UI while waiting for serverinfo query to complete
PendingAddTask* addTask = new PendingAddTask(this, address, mdns); PendingAddTask* addTask = new PendingAddTask(this, address, mdnsIpv6Address, mdns);
QThreadPool::globalInstance()->start(addTask); QThreadPool::globalInstance()->start(addTask);
} }
+42 -12
View File
@@ -13,6 +13,7 @@
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QSettings> #include <QSettings>
#include <QRunnable> #include <QRunnable>
#include <QTimer>
class MdnsPendingComputer : public QObject class MdnsPendingComputer : public QObject
{ {
@@ -20,13 +21,18 @@ class MdnsPendingComputer : public QObject
public: public:
explicit MdnsPendingComputer(QMdnsEngine::Server* server, explicit MdnsPendingComputer(QMdnsEngine::Server* server,
QMdnsEngine::Cache* cache,
const QMdnsEngine::Service& service) const QMdnsEngine::Service& service)
: m_Hostname(service.hostname()), : m_Hostname(service.hostname()),
m_Resolver(server, m_Hostname, cache) m_Server(server),
m_Resolver(nullptr)
{ {
connect(&m_Resolver, SIGNAL(resolved(QHostAddress)), // Start resolving
this, SLOT(handleResolved(QHostAddress))); resolve();
}
virtual ~MdnsPendingComputer()
{
delete m_Resolver;
} }
QString hostname() QString hostname()
@@ -35,20 +41,42 @@ public:
} }
private slots: private slots:
void handleResolved(const QHostAddress& address) void handleResolvedTimeout()
{ {
if (address.protocol() == QAbstractSocket::IPv4Protocol) { if (m_Addresses.isEmpty()) {
m_Resolver.disconnect(); // Try again
emit resolvedv4(this, address); qInfo() << "Resolving" << hostname() << "timed out. Retrying...";
resolve();
} }
else {
Q_ASSERT(!m_Addresses.isEmpty());
emit resolvedHost(this, m_Addresses);
}
}
void handleResolvedAddress(const QHostAddress& address)
{
qInfo() << "Resolved" << hostname() << "to" << address;
m_Addresses.push_back(address);
} }
signals: signals:
void resolvedv4(MdnsPendingComputer*, const QHostAddress&); void resolvedHost(MdnsPendingComputer*,QVector<QHostAddress>&);
private: private:
void resolve()
{
delete m_Resolver;
m_Resolver = new QMdnsEngine::Resolver(m_Server, m_Hostname);
connect(m_Resolver, &QMdnsEngine::Resolver::resolved,
this, &MdnsPendingComputer::handleResolvedAddress);
QTimer::singleShot(2000, this, SLOT(handleResolvedTimeout()));
}
QByteArray m_Hostname; QByteArray m_Hostname;
QMdnsEngine::Resolver m_Resolver; QMdnsEngine::Server* m_Server;
QMdnsEngine::Resolver* m_Resolver;
QVector<QHostAddress> m_Addresses;
}; };
class ComputerPollingEntry class ComputerPollingEntry
@@ -140,7 +168,7 @@ public:
Q_INVOKABLE void stopPollingAsync(); Q_INVOKABLE void stopPollingAsync();
Q_INVOKABLE void addNewHost(QString address, bool mdns); Q_INVOKABLE void addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address = QHostAddress());
void pairHost(NvComputer* computer, QString pin); void pairHost(NvComputer* computer, QString pin);
@@ -165,11 +193,13 @@ private slots:
void handleComputerStateChanged(NvComputer* computer); void handleComputerStateChanged(NvComputer* computer);
void handleMdnsServiceResolved(MdnsPendingComputer* computer, const QHostAddress& address); void handleMdnsServiceResolved(MdnsPendingComputer* computer, QVector<QHostAddress>& addresses);
private: private:
void saveHosts(); void saveHosts();
QHostAddress getBestGlobalAddressV6(QVector<QHostAddress>& addresses);
void startPollingComputer(NvComputer* computer); void startPollingComputer(NvComputer* computer);
int m_PollingRef; int m_PollingRef;
+12 -5
View File
@@ -39,11 +39,18 @@ void ComputerSeeker::onComputerUpdated(NvComputer *computer)
bool ComputerSeeker::matchComputer(NvComputer *computer) const bool ComputerSeeker::matchComputer(NvComputer *computer) const
{ {
QString value = m_ComputerName.toLower(); QString value = m_ComputerName.toLower();
return computer->name.toLower() == value ||
computer->localAddress.toLower() == value || if (computer->name.toLower() == value || computer->uuid.toLower() == value) {
computer->remoteAddress.toLower() == value || return true;
computer->manualAddress.toLower() == value || }
computer->uuid.toLower() == value;
for (const QString& addr : computer->uniqueAddresses()) {
if (addr.toLower() == value) {
return true;
}
}
return false;
} }
bool ComputerSeeker::isOnline(NvComputer *computer) const bool ComputerSeeker::isOnline(NvComputer *computer) const
+1 -1
View File
@@ -75,7 +75,7 @@ void IdentityManager::createCredentials(QSettings& settings)
-1, -1, 0); -1, -1, 0);
X509_set_issuer_name(cert, name); X509_set_issuer_name(cert, name);
X509_sign(cert, pk, EVP_sha1()); X509_sign(cert, pk, EVP_sha256());
BIO* biokey = BIO_new(BIO_s_mem()); BIO* biokey = BIO_new(BIO_s_mem());
THROW_BAD_ALLOC_IF_NULL(biokey); THROW_BAD_ALLOC_IF_NULL(biokey);
+10
View File
@@ -10,6 +10,7 @@
#define SER_LOCALADDR "localaddress" #define SER_LOCALADDR "localaddress"
#define SER_REMOTEADDR "remoteaddress" #define SER_REMOTEADDR "remoteaddress"
#define SER_MANUALADDR "manualaddress" #define SER_MANUALADDR "manualaddress"
#define SER_IPV6ADDR "ipv6address"
#define SER_APPLIST "apps" #define SER_APPLIST "apps"
#define SER_SRVCERT "srvcert" #define SER_SRVCERT "srvcert"
@@ -24,6 +25,7 @@ NvComputer::NvComputer(QSettings& settings)
this->macAddress = settings.value(SER_MAC).toByteArray(); this->macAddress = settings.value(SER_MAC).toByteArray();
this->localAddress = settings.value(SER_LOCALADDR).toString(); this->localAddress = settings.value(SER_LOCALADDR).toString();
this->remoteAddress = settings.value(SER_REMOTEADDR).toString(); this->remoteAddress = settings.value(SER_REMOTEADDR).toString();
this->ipv6Address = settings.value(SER_IPV6ADDR).toString();
this->manualAddress = settings.value(SER_MANUALADDR).toString(); this->manualAddress = settings.value(SER_MANUALADDR).toString();
this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray()); this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray());
@@ -63,6 +65,7 @@ void NvComputer::serialize(QSettings& settings)
settings.setValue(SER_MAC, macAddress); settings.setValue(SER_MAC, macAddress);
settings.setValue(SER_LOCALADDR, localAddress); settings.setValue(SER_LOCALADDR, localAddress);
settings.setValue(SER_REMOTEADDR, remoteAddress); settings.setValue(SER_REMOTEADDR, remoteAddress);
settings.setValue(SER_IPV6ADDR, ipv6Address);
settings.setValue(SER_MANUALADDR, manualAddress); settings.setValue(SER_MANUALADDR, manualAddress);
settings.setValue(SER_SRVCERT, serverCert.toPem()); settings.setValue(SER_SRVCERT, serverCert.toPem());
@@ -129,7 +132,12 @@ NvComputer::NvComputer(QString address, QString serverInfo, QSslCertificate serv
mode2.width * mode2.height * mode2.refreshRate; mode2.width * mode2.height * mode2.refreshRate;
}); });
// We can get an IPv4 loopback address if we're using the GS IPv6 Forwarder
this->localAddress = NvHTTP::getXmlString(serverInfo, "LocalIP"); this->localAddress = NvHTTP::getXmlString(serverInfo, "LocalIP");
if (this->localAddress.startsWith("127.")) {
this->localAddress = QString();
}
this->remoteAddress = NvHTTP::getXmlString(serverInfo, "ExternalIP"); this->remoteAddress = NvHTTP::getXmlString(serverInfo, "ExternalIP");
this->pairState = NvHTTP::getXmlString(serverInfo, "PairStatus") == "1" ? this->pairState = NvHTTP::getXmlString(serverInfo, "PairStatus") == "1" ?
PS_PAIRED : PS_NOT_PAIRED; PS_PAIRED : PS_NOT_PAIRED;
@@ -237,6 +245,7 @@ QVector<QString> NvComputer::uniqueAddresses()
uniqueAddressList.append(activeAddress); uniqueAddressList.append(activeAddress);
uniqueAddressList.append(localAddress); uniqueAddressList.append(localAddress);
uniqueAddressList.append(remoteAddress); uniqueAddressList.append(remoteAddress);
uniqueAddressList.append(ipv6Address);
uniqueAddressList.append(manualAddress); uniqueAddressList.append(manualAddress);
// Prune duplicates (always giving precedence to the first) // Prune duplicates (always giving precedence to the first)
@@ -296,6 +305,7 @@ bool NvComputer::update(NvComputer& that)
ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress); ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress);
ASSIGN_IF_CHANGED_AND_NONEMPTY(localAddress); ASSIGN_IF_CHANGED_AND_NONEMPTY(localAddress);
ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress); ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress);
ASSIGN_IF_CHANGED_AND_NONEMPTY(ipv6Address);
ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress); ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress);
ASSIGN_IF_CHANGED(pairState); ASSIGN_IF_CHANGED(pairState);
ASSIGN_IF_CHANGED(serverCodecModeSupport); ASSIGN_IF_CHANGED(serverCodecModeSupport);
+1
View File
@@ -64,6 +64,7 @@ public:
// Persisted traits // Persisted traits
QString localAddress; QString localAddress;
QString remoteAddress; QString remoteAddress;
QString ipv6Address;
QString manualAddress; QString manualAddress;
QByteArray macAddress; QByteArray macAddress;
QString name; QString name;
+17 -5
View File
@@ -18,18 +18,15 @@
#define QUIT_TIMEOUT_MS 30000 #define QUIT_TIMEOUT_MS 30000
NvHTTP::NvHTTP(QString address, QSslCertificate serverCert) : NvHTTP::NvHTTP(QString address, QSslCertificate serverCert) :
m_Address(address),
m_ServerCert(serverCert) m_ServerCert(serverCert)
{ {
Q_ASSERT(!address.isEmpty());
m_BaseUrlHttp.setScheme("http"); m_BaseUrlHttp.setScheme("http");
m_BaseUrlHttps.setScheme("https"); m_BaseUrlHttps.setScheme("https");
m_BaseUrlHttp.setHost(address);
m_BaseUrlHttps.setHost(address);
m_BaseUrlHttp.setPort(47989); m_BaseUrlHttp.setPort(47989);
m_BaseUrlHttps.setPort(47984); m_BaseUrlHttps.setPort(47984);
setAddress(address);
// Never use a proxy server // Never use a proxy server
QNetworkProxy noProxy(QNetworkProxy::NoProxy); QNetworkProxy noProxy(QNetworkProxy::NoProxy);
m_Nam.setProxy(noProxy); m_Nam.setProxy(noProxy);
@@ -42,6 +39,21 @@ void NvHTTP::setServerCert(QSslCertificate serverCert)
m_ServerCert = serverCert; m_ServerCert = serverCert;
} }
void NvHTTP::setAddress(QString address)
{
Q_ASSERT(!address.isEmpty());
m_Address = address;
m_BaseUrlHttp.setHost(address);
m_BaseUrlHttps.setHost(address);
}
QString NvHTTP::address()
{
return m_Address;
}
QVector<int> QVector<int>
NvHTTP::parseQuad(QString quad) NvHTTP::parseQuad(QString quad)
{ {
+4
View File
@@ -156,6 +156,10 @@ public:
void setServerCert(QSslCertificate serverCert); void setServerCert(QSslCertificate serverCert);
void setAddress(QString address);
QString address();
static static
QVector<int> QVector<int>
parseQuad(QString quad); parseQuad(QString quad);
+3 -1
View File
@@ -256,7 +256,9 @@ NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverC
challengeResponse.append(reinterpret_cast<char*>(asnSignature->data), asnSignature->length); challengeResponse.append(reinterpret_cast<char*>(asnSignature->data), asnSignature->length);
challengeResponse.append(clientSecretData); challengeResponse.append(clientSecretData);
QByteArray encryptedChallengeResponseHash = encrypt(QCryptographicHash::hash(challengeResponse, hashAlgo), &encKey); QByteArray paddedHash = QCryptographicHash::hash(challengeResponse, hashAlgo);
paddedHash.resize(32);
QByteArray encryptedChallengeResponseHash = encrypt(paddedHash, &encKey);
QString respXml = m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, QString respXml = m_Http.openConnectionToString(m_Http.m_BaseUrlHttp,
"pair", "pair",
"devicename=roth&updateState=1&serverchallengeresp=" + "devicename=roth&updateState=1&serverchallengeresp=" +
+63
View File
@@ -0,0 +1,63 @@
#include "richpresencemanager.h"
#include <QDebug>
RichPresenceManager::RichPresenceManager(StreamingPreferences& prefs, QString gameName)
: m_DiscordActive(false)
{
#ifdef HAVE_DISCORD
if (prefs.richPresence) {
DiscordEventHandlers handlers = {};
handlers.ready = discordReady;
handlers.disconnected = discordDisconnected;
handlers.errored = discordErrored;
Discord_Initialize("594668102021677159", &handlers, 0, nullptr);
m_DiscordActive = true;
}
if (m_DiscordActive) {
QByteArray stateStr = (QString("Streaming ") + gameName).toUtf8();
DiscordRichPresence discordPresence = {};
discordPresence.state = stateStr.data();
discordPresence.startTimestamp = time(nullptr);
Discord_UpdatePresence(&discordPresence);
}
#endif
}
RichPresenceManager::~RichPresenceManager()
{
#ifdef HAVE_DISCORD
if (m_DiscordActive) {
Discord_ClearPresence();
Discord_Shutdown();
}
#endif
}
void RichPresenceManager::runCallbacks()
{
#ifdef HAVE_DISCORD
if (m_DiscordActive) {
Discord_RunCallbacks();
}
#endif
}
#ifdef HAVE_DISCORD
void RichPresenceManager::discordReady(const DiscordUser* request)
{
qInfo() << "Discord integration ready for user:" << request->username;
}
void RichPresenceManager::discordDisconnected(int errorCode, const char *message)
{
qInfo() << "Discord integration disconnected:" << errorCode << message;
}
void RichPresenceManager::discordErrored(int errorCode, const char *message)
{
qWarning() << "Discord integration error:" << errorCode << message;
}
#endif
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "settings/streamingpreferences.h"
#ifdef HAVE_DISCORD
#include <discord_rpc.h>
#endif
class RichPresenceManager
{
public:
RichPresenceManager(StreamingPreferences& prefs, QString gameName);
~RichPresenceManager();
void runCallbacks();
private:
#ifdef HAVE_DISCORD
static void discordReady(const DiscordUser* request);
static void discordDisconnected(int errorCode, const char* message);
static void discordErrored(int errorCode, const char* message);
#endif
bool m_DiscordActive;
};
+6
View File
@@ -22,6 +22,12 @@ SystemProperties::SystemProperties()
hasBrowser = false; hasBrowser = false;
#endif #endif
#ifdef HAVE_DISCORD
hasDiscordIntegration = true;
#else
hasDiscordIntegration = false;
#endif
unmappedGamepads = SdlInputHandler::getUnmappedGamepads(); unmappedGamepads = SdlInputHandler::getUnmappedGamepads();
// Populate data that requires talking to SDL. We do it all in one shot // Populate data that requires talking to SDL. We do it all in one shot
+2
View File
@@ -15,6 +15,7 @@ public:
Q_PROPERTY(bool isRunningXWayland MEMBER isRunningXWayland CONSTANT) Q_PROPERTY(bool isRunningXWayland MEMBER isRunningXWayland CONSTANT)
Q_PROPERTY(bool isWow64 MEMBER isWow64 CONSTANT) Q_PROPERTY(bool isWow64 MEMBER isWow64 CONSTANT)
Q_PROPERTY(bool hasBrowser MEMBER hasBrowser CONSTANT) Q_PROPERTY(bool hasBrowser MEMBER hasBrowser CONSTANT)
Q_PROPERTY(bool hasDiscordIntegration MEMBER hasDiscordIntegration CONSTANT)
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged) Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
Q_PROPERTY(int maximumStreamingFrameRate MEMBER maximumStreamingFrameRate CONSTANT) Q_PROPERTY(int maximumStreamingFrameRate MEMBER maximumStreamingFrameRate CONSTANT)
@@ -32,6 +33,7 @@ private:
bool isRunningXWayland; bool isRunningXWayland;
bool isWow64; bool isWow64;
bool hasBrowser; bool hasBrowser;
bool hasDiscordIntegration;
QString unmappedGamepads; QString unmappedGamepads;
int maximumStreamingFrameRate; int maximumStreamingFrameRate;
QList<QRect> monitorDesktopResolutions; QList<QRect> monitorDesktopResolutions;
@@ -12,7 +12,7 @@
<ul> <ul>
<li>Streaming at up to 4K resolution</li> <li>Streaming at up to 4K resolution</li>
<li>Support for up to 120 FPS streaming (high refresh rate monitor recommended)</li> <li>Support for up to 120 FPS streaming (high refresh rate monitor recommended)</li>
<li>Hardware accelerated video decoding with VAAPI and VDPAU support</li> <li>Hardware accelerated video decoding with VAAPI, VDPAU, and NVDEC support</li>
<li>5.1 surround sound audio support</li> <li>5.1 surround sound audio support</li>
<li>HEVC support for better video compression efficiency</li> <li>HEVC support for better video compression efficiency</li>
<li>Gamepad support with force feedback for up to 4 players</li> <li>Gamepad support with force feedback for up to 4 players</li>
@@ -33,6 +33,26 @@
</screenshots> </screenshots>
<releases> <releases>
<release version="1.1.0" date="2019-08-05">
<description>
<p>New features:</p>
<ul>
<li>Added support for NVDEC for NVIDIA GPUs on Wayland</li>
<li>Added an option to disable gamepad mouse mode for games that require holding the Start button</li>
<li>Added automatic detection of IPv6 addresses for Internet streaming over IPv6 networks</li>
</ul>
<p>Bugfixes:</p>
<ul>
<li>Improved speed and reliability of automatic PC detection on the local network</li>
<li>Fixed audio latency increasing under certain network conditions</li>
<li>Fixed 5.1 surround sound sometimes causing no audio to play when streaming over the Internet</li>
<li>Fixed graceful termination of games not being detected properly on GFE 3.19</li>
<li>Fixed several audio issues on Linux by switching back to SDL for audio</li>
<li>Changed client certificate signature algorithm from SHA-1 to SHA-256 for Debian Buster compatibility</li>
<li>Updated included gamepad mappings</li>
</ul>
</description>
</release>
<release version="1.0.1" date="2019-05-27"> <release version="1.0.1" date="2019-05-27">
<description> <description>
<p>Bugfixes:</p> <p>Bugfixes:</p>
+43 -1
View File
@@ -328,6 +328,16 @@ Flickable {
AutoResizingComboBox { AutoResizingComboBox {
// ignore setting the index at first, and actually set it when the component is loaded // ignore setting the index at first, and actually set it when the component is loaded
Component.onCompleted: { Component.onCompleted: {
// Set the recommended option based on the OS
for (var i = 0; i < windowModeListModel.count; i++) {
var thisWm = windowModeListModel.get(i).val;
if (thisWm === StreamingPreferences.recommendedFullScreenMode) {
windowModeListModel.get(i).text += " (Recommended)"
windowModeListModel.move(i, 0, 1);
break
}
}
var savedWm = StreamingPreferences.windowMode var savedWm = StreamingPreferences.windowMode
currentIndex = 0 currentIndex = 0
for (var i = 0; i < windowModeListModel.count; i++) { for (var i = 0; i < windowModeListModel.count; i++) {
@@ -346,7 +356,7 @@ Flickable {
model: ListModel { model: ListModel {
id: windowModeListModel id: windowModeListModel
ListElement { ListElement {
text: "Full-screen (Recommended)" text: "Full-screen"
val: StreamingPreferences.WM_FULLSCREEN val: StreamingPreferences.WM_FULLSCREEN
} }
ListElement { ListElement {
@@ -489,6 +499,22 @@ Flickable {
StreamingPreferences.connectionWarnings = checked StreamingPreferences.connectionWarnings = checked
} }
} }
CheckBox {
visible: SystemProperties.hasDiscordIntegration
id: discordPresenceCheck
text: "Discord Rich Presence integration"
font.pointSize: 12
checked: StreamingPreferences.richPresence
onCheckedChanged: {
StreamingPreferences.richPresence = checked
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: "Updates your Discord status to display the name of the game you're streaming."
}
} }
} }
} }
@@ -541,6 +567,22 @@ Flickable {
ToolTip.visible: hovered ToolTip.visible: hovered
ToolTip.text: "When checked, mouse input is not accelerated or scaled by the OS before passing to Moonlight" ToolTip.text: "When checked, mouse input is not accelerated or scaled by the OS before passing to Moonlight"
} }
CheckBox {
id: gamepadMouseCheck
hoverEnabled: true
text: "Gamepad mouse mode support"
font.pointSize: 12
checked: StreamingPreferences.gamepadMouse
onCheckedChanged: {
StreamingPreferences.gamepadMouse = checked
}
ToolTip.delay: 1000
ToolTip.timeout: 3000
ToolTip.visible: hovered
ToolTip.text: "When enabled, holding the Start button will toggle mouse mode"
}
} }
} }
+12
View File
@@ -309,6 +309,18 @@ int main(int argc, char *argv[])
// Register custom metatypes for use in signals // Register custom metatypes for use in signals
qRegisterMetaType<NvApp>("NvApp"); qRegisterMetaType<NvApp>("NvApp");
SDL_version compileVersion;
SDL_VERSION(&compileVersion);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Compiled with SDL %d.%d.%d",
compileVersion.major, compileVersion.minor, compileVersion.patch);
SDL_version runtimeVersion;
SDL_GetVersion(&runtimeVersion);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Running with SDL %d.%d.%d",
runtimeVersion.major, runtimeVersion.minor, runtimeVersion.patch);
// Allow the display to sleep by default. We will manually use SDL_DisableScreenSaver() // Allow the display to sleep by default. We will manually use SDL_DisableScreenSaver()
// and SDL_EnableScreenSaver() when appropriate. This hint must be set before // and SDL_EnableScreenSaver() when appropriate. This hint must be set before
// initializing the SDL video subsystem to have any effect. // initializing the SDL video subsystem to have any effect.
+13 -1
View File
@@ -23,6 +23,8 @@
#define SER_STARTWINDOWED "startwindowed" #define SER_STARTWINDOWED "startwindowed"
#define SER_FRAMEPACING "framepacing" #define SER_FRAMEPACING "framepacing"
#define SER_CONNWARNINGS "connwarnings" #define SER_CONNWARNINGS "connwarnings"
#define SER_RICHPRESENCE "richpresence"
#define SER_GAMEPADMOUSE "gamepadmouse"
StreamingPreferences::StreamingPreferences(QObject *parent) StreamingPreferences::StreamingPreferences(QObject *parent)
: QObject(parent) : QObject(parent)
@@ -34,6 +36,12 @@ void StreamingPreferences::reload()
{ {
QSettings settings; QSettings settings;
#ifdef Q_OS_DARWIN
recommendedFullScreenMode = WindowMode::WM_FULLSCREEN_DESKTOP;
#else
recommendedFullScreenMode = WindowMode::WM_FULLSCREEN;
#endif
width = settings.value(SER_WIDTH, 1280).toInt(); width = settings.value(SER_WIDTH, 1280).toInt();
height = settings.value(SER_HEIGHT, 720).toInt(); height = settings.value(SER_HEIGHT, 720).toInt();
fps = settings.value(SER_FPS, 60).toInt(); fps = settings.value(SER_FPS, 60).toInt();
@@ -49,6 +57,8 @@ void StreamingPreferences::reload()
startWindowed = settings.value(SER_STARTWINDOWED, false).toBool(); startWindowed = settings.value(SER_STARTWINDOWED, false).toBool();
framePacing = settings.value(SER_FRAMEPACING, false).toBool(); framePacing = settings.value(SER_FRAMEPACING, false).toBool();
connectionWarnings = settings.value(SER_CONNWARNINGS, true).toBool(); connectionWarnings = settings.value(SER_CONNWARNINGS, true).toBool();
richPresence = settings.value(SER_RICHPRESENCE, true).toBool();
gamepadMouse = settings.value(SER_GAMEPADMOUSE, true).toBool();
audioConfig = static_cast<AudioConfig>(settings.value(SER_AUDIOCFG, audioConfig = static_cast<AudioConfig>(settings.value(SER_AUDIOCFG,
static_cast<int>(AudioConfig::AC_STEREO)).toInt()); static_cast<int>(AudioConfig::AC_STEREO)).toInt());
videoCodecConfig = static_cast<VideoCodecConfig>(settings.value(SER_VIDEOCFG, videoCodecConfig = static_cast<VideoCodecConfig>(settings.value(SER_VIDEOCFG,
@@ -58,7 +68,7 @@ void StreamingPreferences::reload()
windowMode = static_cast<WindowMode>(settings.value(SER_WINDOWMODE, windowMode = static_cast<WindowMode>(settings.value(SER_WINDOWMODE,
// Try to load from the old preference value too // Try to load from the old preference value too
static_cast<int>(settings.value(SER_FULLSCREEN, true).toBool() ? static_cast<int>(settings.value(SER_FULLSCREEN, true).toBool() ?
WindowMode::WM_FULLSCREEN : WindowMode::WM_WINDOWED)).toInt()); recommendedFullScreenMode : WindowMode::WM_WINDOWED)).toInt());
} }
void StreamingPreferences::save() void StreamingPreferences::save()
@@ -80,6 +90,8 @@ void StreamingPreferences::save()
settings.setValue(SER_STARTWINDOWED, startWindowed); settings.setValue(SER_STARTWINDOWED, startWindowed);
settings.setValue(SER_FRAMEPACING, framePacing); settings.setValue(SER_FRAMEPACING, framePacing);
settings.setValue(SER_CONNWARNINGS, connectionWarnings); settings.setValue(SER_CONNWARNINGS, connectionWarnings);
settings.setValue(SER_RICHPRESENCE, richPresence);
settings.setValue(SER_GAMEPADMOUSE, gamepadMouse);
settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig)); settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig));
settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig)); settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig));
settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection)); settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection));
+8
View File
@@ -64,10 +64,13 @@ public:
Q_PROPERTY(bool startWindowed MEMBER startWindowed NOTIFY startWindowedChanged) Q_PROPERTY(bool startWindowed MEMBER startWindowed NOTIFY startWindowedChanged)
Q_PROPERTY(bool framePacing MEMBER framePacing NOTIFY framePacingChanged) Q_PROPERTY(bool framePacing MEMBER framePacing NOTIFY framePacingChanged)
Q_PROPERTY(bool connectionWarnings MEMBER connectionWarnings NOTIFY connectionWarningsChanged) Q_PROPERTY(bool connectionWarnings MEMBER connectionWarnings NOTIFY connectionWarningsChanged)
Q_PROPERTY(bool richPresence MEMBER richPresence NOTIFY richPresenceChanged)
Q_PROPERTY(bool gamepadMouse MEMBER gamepadMouse NOTIFY gamepadMouseChanged)
Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged) Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged)
Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged) Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged)
Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged) Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged)
Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged) Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged)
Q_PROPERTY(WindowMode recommendedFullScreenMode MEMBER recommendedFullScreenMode CONSTANT)
// Directly accessible members for preferences // Directly accessible members for preferences
int width; int width;
@@ -85,10 +88,13 @@ public:
bool startWindowed; bool startWindowed;
bool framePacing; bool framePacing;
bool connectionWarnings; bool connectionWarnings;
bool richPresence;
bool gamepadMouse;
AudioConfig audioConfig; AudioConfig audioConfig;
VideoCodecConfig videoCodecConfig; VideoCodecConfig videoCodecConfig;
VideoDecoderSelection videoDecoderSelection; VideoDecoderSelection videoDecoderSelection;
WindowMode windowMode; WindowMode windowMode;
WindowMode recommendedFullScreenMode;
signals: signals:
void displayModeChanged(); void displayModeChanged();
@@ -108,5 +114,7 @@ signals:
void startWindowedChanged(); void startWindowedChanged();
void framePacingChanged(); void framePacingChanged();
void connectionWarningsChanged(); void connectionWarningsChanged();
void richPresenceChanged();
void gamepadMouseChanged();
}; };
+94 -26
View File
@@ -13,30 +13,100 @@
#include <Limelight.h> #include <Limelight.h>
IAudioRenderer* Session::createAudioRenderer() #define TRY_INIT_RENDERER(renderer, opusConfig) \
{ \
IAudioRenderer* __renderer = new renderer(); \
if (__renderer->prepareForPlayback(opusConfig)) \
return __renderer; \
delete __renderer; \
}
IAudioRenderer* Session::createAudioRenderer(const POPUS_MULTISTREAM_CONFIGURATION opusConfig)
{ {
#if defined(HAVE_SOUNDIO) // Handle explicit ML_AUDIO setting and fail if the requested backend fails
if (qgetenv("ML_AUDIO") == "SDL") { QString mlAudio = qgetenv("ML_AUDIO").toLower();
return new SdlAudioRenderer(); if (mlAudio == "sdl") {
TRY_INIT_RENDERER(SdlAudioRenderer, opusConfig)
return nullptr;
}
#ifdef HAVE_SOUNDIO
else if (mlAudio == "libsoundio") {
TRY_INIT_RENDERER(SoundIoAudioRenderer, opusConfig)
return nullptr;
}
#endif
#if defined(HAVE_SLAUDIO)
else if (mlAudio == "slaudio") {
TRY_INIT_RENDERER(SLAudioRenderer, opusConfig)
return nullptr;
}
#endif
else if (!mlAudio.isEmpty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Unknown audio backend: %s",
SDL_getenv("ML_AUDIO"));
return nullptr;
} }
return new SoundIoAudioRenderer(); // -------------- Automatic backend selection below this line ---------------
#elif defined(HAVE_SLAUDIO)
return new SLAudioRenderer(); #if defined(HAVE_SLAUDIO)
#else // Steam Link should always have SLAudio
return new SdlAudioRenderer(); TRY_INIT_RENDERER(SLAudioRenderer, opusConfig)
#endif #endif
#ifdef Q_OS_LINUX
// Linux defaults to SDL and fall backs to libsoundio
TRY_INIT_RENDERER(SdlAudioRenderer, opusConfig)
#ifdef HAVE_SOUNDIO
TRY_INIT_RENDERER(SoundIoAudioRenderer, opusConfig)
#endif
#else
// Windows and macOS default to libsoundio and fall back to SDL
#ifdef HAVE_SOUNDIO
TRY_INIT_RENDERER(SoundIoAudioRenderer, opusConfig)
#endif
TRY_INIT_RENDERER(SdlAudioRenderer, opusConfig)
#endif
return nullptr;
}
int Session::getAudioRendererCapabilities(int audioConfiguration)
{
// Build a fake OPUS_MULTISTREAM_CONFIGURATION to give
// the renderer the channel count and sample rate.
OPUS_MULTISTREAM_CONFIGURATION opusConfig = {};
opusConfig.sampleRate = 48000;
opusConfig.samplesPerFrame = 240;
switch (audioConfiguration)
{
case AUDIO_CONFIGURATION_STEREO:
opusConfig.channelCount = 2;
break;
case AUDIO_CONFIGURATION_51_SURROUND:
opusConfig.channelCount = 6;
break;
default:
SDL_assert(false);
return 0;
}
IAudioRenderer* audioRenderer = createAudioRenderer(&opusConfig);
if (audioRenderer == nullptr) {
return 0;
}
int caps = audioRenderer->getCapabilities();
delete audioRenderer;
return caps;
} }
bool Session::testAudio(int audioConfiguration) bool Session::testAudio(int audioConfiguration)
{ {
IAudioRenderer* audioRenderer;
audioRenderer = createAudioRenderer();
if (audioRenderer == nullptr) {
return false;
}
// Build a fake OPUS_MULTISTREAM_CONFIGURATION to give // Build a fake OPUS_MULTISTREAM_CONFIGURATION to give
// the renderer the channel count and sample rate. // the renderer the channel count and sample rate.
OPUS_MULTISTREAM_CONFIGURATION opusConfig = {}; OPUS_MULTISTREAM_CONFIGURATION opusConfig = {};
@@ -56,11 +126,14 @@ bool Session::testAudio(int audioConfiguration)
return false; return false;
} }
bool ret = audioRenderer->prepareForPlayback(&opusConfig); IAudioRenderer* audioRenderer = createAudioRenderer(&opusConfig);
if (audioRenderer == nullptr) {
return false;
}
delete audioRenderer; delete audioRenderer;
return ret; return true;
} }
int Session::arInit(int /* audioConfiguration */, int Session::arInit(int /* audioConfiguration */,
@@ -85,9 +158,8 @@ int Session::arInit(int /* audioConfiguration */,
return -1; return -1;
} }
s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(); s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(opusConfig);
if (!s_ActiveSession->m_AudioRenderer->prepareForPlayback(opusConfig)) { if (s_ActiveSession->m_AudioRenderer == nullptr) {
delete s_ActiveSession->m_AudioRenderer;
opus_multistream_decoder_destroy(s_ActiveSession->m_OpusDecoder); opus_multistream_decoder_destroy(s_ActiveSession->m_OpusDecoder);
return -2; return -2;
} }
@@ -185,11 +257,7 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
// so we return to real-time playback and don't accumulate latency. // so we return to real-time playback and don't accumulate latency.
Uint32 audioReinitStartTime = SDL_GetTicks(); Uint32 audioReinitStartTime = SDL_GetTicks();
s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(); s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(&s_ActiveSession->m_AudioConfig);
if (!s_ActiveSession->m_AudioRenderer->prepareForPlayback(&s_ActiveSession->m_AudioConfig)) {
delete s_ActiveSession->m_AudioRenderer;
s_ActiveSession->m_AudioRenderer = nullptr;
}
Uint32 audioReinitStopTime = SDL_GetTicks(); Uint32 audioReinitStopTime = SDL_GetTicks();
+2
View File
@@ -13,4 +13,6 @@ public:
// Return false if an unrecoverable error has occurred and the renderer must be reinitialized // Return false if an unrecoverable error has occurred and the renderer must be reinitialized
virtual bool submitAudio(int bytesWritten) = 0; virtual bool submitAudio(int bytesWritten) = 0;
virtual int getCapabilities() = 0;
}; };
+4
View File
@@ -16,7 +16,11 @@ public:
virtual bool submitAudio(int bytesWritten); virtual bool submitAudio(int bytesWritten);
virtual int getCapabilities();
private: private:
SDL_AudioDeviceID m_AudioDevice; SDL_AudioDeviceID m_AudioDevice;
void* m_AudioBuffer; void* m_AudioBuffer;
int m_FrameDurationMs;
int m_FrameSize;
}; };
+22 -1
View File
@@ -33,6 +33,9 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION*
// Specifying non-Po2 seems to work for our supported platforms. // Specifying non-Po2 seems to work for our supported platforms.
want.samples = opusConfig->samplesPerFrame; want.samples = opusConfig->samplesPerFrame;
m_FrameSize = opusConfig->samplesPerFrame * sizeof(short) * opusConfig->channelCount;
m_FrameDurationMs = opusConfig->samplesPerFrame / 48;
m_AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); m_AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (m_AudioDevice == 0) { if (m_AudioDevice == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@@ -41,7 +44,7 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION*
return false; return false;
} }
m_AudioBuffer = malloc(opusConfig->samplesPerFrame * sizeof(short) * opusConfig->channelCount); m_AudioBuffer = malloc(m_FrameSize);
if (m_AudioBuffer == nullptr) { if (m_AudioBuffer == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to allocate audio buffer"); "Failed to allocate audio buffer");
@@ -92,6 +95,18 @@ bool SdlAudioRenderer::submitAudio(int bytesWritten)
return true; return true;
} }
// Don't queue if there's already more than 30 ms of audio data waiting
// in Moonlight's audio queue.
if (LiGetPendingAudioFrames() * m_FrameDurationMs > 30) {
return true;
}
// Provide backpressure on the queue to ensure too many frames don't build up
// in SDL's audio queue.
while (SDL_GetQueuedAudioSize(m_AudioDevice) / m_FrameSize > 10) {
SDL_Delay(1);
}
if (SDL_QueueAudio(m_AudioDevice, m_AudioBuffer, bytesWritten) < 0) { if (SDL_QueueAudio(m_AudioDevice, m_AudioBuffer, bytesWritten) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to queue audio sample: %s", "Failed to queue audio sample: %s",
@@ -100,3 +115,9 @@ bool SdlAudioRenderer::submitAudio(int bytesWritten)
return true; return true;
} }
int SdlAudioRenderer::getCapabilities()
{
// Direct submit can't be used because we use LiGetPendingAudioFrames()
return 0;
}
+5
View File
@@ -90,6 +90,11 @@ bool SLAudioRenderer::submitAudio(int bytesWritten)
return true; return true;
} }
int SLAudioRenderer::getCapabilities()
{
return CAPABILITY_SLOW_OPUS_DECODER;
}
void SLAudioRenderer::slLogCallback(void*, ESLAudioLog logLevel, const char *message) void SLAudioRenderer::slLogCallback(void*, ESLAudioLog logLevel, const char *message)
{ {
SDL_LogPriority priority; SDL_LogPriority priority;
+2
View File
@@ -16,6 +16,8 @@ public:
virtual bool submitAudio(int bytesWritten); virtual bool submitAudio(int bytesWritten);
virtual int getCapabilities();
private: private:
static void slLogCallback(void* context, ESLAudioLog logLevel, const char* message); static void slLogCallback(void* context, ESLAudioLog logLevel, const char* message);
@@ -317,6 +317,11 @@ bool SoundIoAudioRenderer::submitAudio(int bytesWritten)
return true; return true;
} }
int SoundIoAudioRenderer::getCapabilities()
{
return CAPABILITY_DIRECT_SUBMIT;
}
void SoundIoAudioRenderer::sioErrorCallback(SoundIoOutStream* stream, int err) void SoundIoAudioRenderer::sioErrorCallback(SoundIoOutStream* stream, int err)
{ {
auto me = reinterpret_cast<SoundIoAudioRenderer*>(stream->userdata); auto me = reinterpret_cast<SoundIoAudioRenderer*>(stream->userdata);
@@ -381,15 +386,19 @@ void SoundIoAudioRenderer::sioWriteCallback(SoundIoOutStream* stream, int frameC
(me->m_OpusChannelCount * stream->bytes_per_sample); (me->m_OpusChannelCount * stream->bytes_per_sample);
int bytesRead = 0; int bytesRead = 0;
// Clamp framesLeft to frameCountMax
framesLeft = qMin(framesLeft, frameCountMax);
// Ensure we always write at least a buffer, even if it's silence, to avoid // Ensure we always write at least a buffer, even if it's silence, to avoid
// busy looping when no audio data is available while libsoundio tries to keep // busy looping when no audio data is available while libsoundio tries to keep
// us from starving the output device. // us from starving the output device.
frameCountMin = qMax(frameCountMin, (int)(stream->sample_rate * k_MinSampleLengthSec)); frameCountMin = qMax(frameCountMin, (int)(stream->sample_rate * k_MinSampleLengthSec));
// Clamp frameCountMax to minSampleLen * 4 to stop our latency from growing if audio packets lag.
// This makes sure that we never increase our latency far beyond what the sink is consuming.
frameCountMax = qMin(frameCountMax, (int)(stream->sample_rate * k_MinSampleLengthSec) * 4);
frameCountMin = qMin(frameCountMin, frameCountMax); frameCountMin = qMin(frameCountMin, frameCountMax);
// Clamp framesLeft to frameCountMax
framesLeft = qMin(framesLeft, frameCountMax);
// Track latency on queueing-based backends // Track latency on queueing-based backends
if (me->m_SoundIo->current_backend != SoundIoBackendCoreAudio && me->m_SoundIo->current_backend != SoundIoBackendJack) { if (me->m_SoundIo->current_backend != SoundIoBackendCoreAudio && me->m_SoundIo->current_backend != SoundIoBackendJack) {
soundio_outstream_get_latency(stream, &me->m_Latency); soundio_outstream_get_latency(stream, &me->m_Latency);
@@ -17,6 +17,8 @@ public:
virtual bool submitAudio(int bytesWritten); virtual bool submitAudio(int bytesWritten);
virtual int getCapabilities();
private: private:
int scoreChannelLayout(const struct SoundIoChannelLayout* layout, const OPUS_MULTISTREAM_CONFIGURATION* opusConfig); int scoreChannelLayout(const struct SoundIoChannelLayout* layout, const OPUS_MULTISTREAM_CONFIGURATION* opusConfig);
+58 -11
View File
@@ -51,7 +51,9 @@ const int SdlInputHandler::k_ButtonMap[] = {
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int streamWidth, int streamHeight) SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int streamWidth, int streamHeight)
: m_MultiController(prefs.multiController), : m_MultiController(prefs.multiController),
m_GamepadMouse(prefs.gamepadMouse),
m_MouseMoveTimer(0), m_MouseMoveTimer(0),
m_FakeCaptureActive(false),
m_LeftButtonReleaseTimer(0), m_LeftButtonReleaseTimer(0),
m_RightButtonReleaseTimer(0), m_RightButtonReleaseTimer(0),
m_DragTimer(0), m_DragTimer(0),
@@ -71,9 +73,10 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s
prefs.mouseAcceleration ? "1" : "0", prefs.mouseAcceleration ? "1" : "0",
SDL_HINT_OVERRIDE); SDL_HINT_OVERRIDE);
#ifdef Q_OS_DARWIN #if defined(Q_OS_DARWIN) && !SDL_VERSION_ATLEAST(2, 0, 10)
// SDL 2.0.9 on macOS has a broken HIDAPI mapping for the older Xbox One S // SDL 2.0.9 on macOS has a broken HIDAPI mapping for the older Xbox One S
// firmware, so we have to disable HIDAPI for Xbox gamepads on macOS. // firmware, so we have to disable HIDAPI for Xbox gamepads on macOS until
// SDL 2.0.10 where the bug is fixed.
// https://github.com/moonlight-stream/moonlight-qt/issues/133 // https://github.com/moonlight-stream/moonlight-qt/issues/133
// https://bugzilla.libsdl.org/show_bug.cgi?id=4395 // https://bugzilla.libsdl.org/show_bug.cgi?id=4395
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
@@ -211,7 +214,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
"Detected mouse capture toggle combo (SDLK)"); "Detected mouse capture toggle combo (SDLK)");
// Stop handling future input // Stop handling future input
SDL_SetRelativeMouseMode((SDL_bool)!SDL_GetRelativeMouseMode()); setCaptureActive(!isCaptureActive());
// Force raise all keys to ensure they aren't stuck, // Force raise all keys to ensure they aren't stuck,
// since we won't get their key up events. // since we won't get their key up events.
@@ -259,7 +262,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
"Detected mouse capture toggle combo (scancode)"); "Detected mouse capture toggle combo (scancode)");
// Stop handling future input // Stop handling future input
SDL_SetRelativeMouseMode((SDL_bool)!SDL_GetRelativeMouseMode()); setCaptureActive(!isCaptureActive());
// Force raise all keys to ensure they aren't stuck, // Force raise all keys to ensure they aren't stuck,
// since we won't get their key up events. // since we won't get their key up events.
@@ -292,7 +295,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
} }
} }
if (!SDL_GetRelativeMouseMode()) { if (!isCaptureActive()) {
// Not capturing // Not capturing
return; return;
} }
@@ -538,11 +541,11 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
// the pressed event was consumed by this code). // the pressed event was consumed by this code).
if (event->button == SDL_BUTTON_LEFT && if (event->button == SDL_BUTTON_LEFT &&
event->state == SDL_RELEASED && event->state == SDL_RELEASED &&
!SDL_GetRelativeMouseMode()) { !isCaptureActive()) {
SDL_SetRelativeMouseMode(SDL_TRUE); setCaptureActive(true);
return; return;
} }
else if (!SDL_GetRelativeMouseMode()) { else if (!isCaptureActive()) {
// Not capturing // Not capturing
return; return;
} }
@@ -583,7 +586,7 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event) void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
{ {
if (!SDL_GetRelativeMouseMode()) { if (!isCaptureActive()) {
// Not capturing // Not capturing
return; return;
} }
@@ -600,7 +603,7 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event) void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
{ {
if (!SDL_GetRelativeMouseMode()) { if (!isCaptureActive()) {
// Not capturing // Not capturing
return; return;
} }
@@ -838,7 +841,7 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
"Mouse emulation deactivated"); "Mouse emulation deactivated");
Session::get()->notifyMouseEmulationMode(false); Session::get()->notifyMouseEmulationMode(false);
} }
else { else if (m_GamepadMouse) {
// Send the start button up event to the host, since we won't do it below // Send the start button up event to the host, since we won't do it below
sendGamepadState(state); sendGamepadState(state);
@@ -1114,6 +1117,21 @@ void SdlInputHandler::handleTouchFingerEvent(SDL_TouchFingerEvent* event)
{ {
int fingerIndex = -1; int fingerIndex = -1;
#if SDL_VERSION_ATLEAST(2, 0, 10)
if (SDL_GetTouchDeviceType(event->touchId) != SDL_TOUCH_DEVICE_DIRECT) {
// Ignore anything that isn't a touchscreen. We may get callbacks
// for trackpads, but we want to handle those in the mouse path.
return;
}
#elif defined(Q_OS_DARWIN)
// SDL2 sends touch events from trackpads by default on
// macOS. This totally screws our actual mouse handling,
// so we must explicitly ignore touch events on macOS
// until SDL 2.0.10 where we have SDL_GetTouchDeviceType()
// to tell them apart.
return;
#endif
// Observations on Windows 10: x and y appear to be relative to 0,0 of the window client area. // Observations on Windows 10: x and y appear to be relative to 0,0 of the window client area.
// Although SDL documentation states they are 0.0 - 1.0 float values, they can actually be higher // Although SDL documentation states they are 0.0 - 1.0 float values, they can actually be higher
// or lower than those values as touch events continue for touches started within the client area that // or lower than those values as touch events continue for touches started within the client area that
@@ -1282,6 +1300,35 @@ void SdlInputHandler::raiseAllKeys()
m_KeysDown.clear(); m_KeysDown.clear();
} }
bool SdlInputHandler::isCaptureActive()
{
if (SDL_GetRelativeMouseMode()) {
return true;
}
// Some platforms don't support SDL_SetRelativeMouseMode
return m_FakeCaptureActive;
}
void SdlInputHandler::setCaptureActive(bool active)
{
if (active) {
// Try to activate SDL's relative mouse mode
if (SDL_SetRelativeMouseMode(SDL_TRUE) < 0) {
// Relative mouse mode didn't work, so we'll use fake capture
SDL_ShowCursor(SDL_DISABLE);
m_FakeCaptureActive = true;
}
}
else if (m_FakeCaptureActive) {
SDL_ShowCursor(SDL_ENABLE);
m_FakeCaptureActive = false;
}
else {
SDL_SetRelativeMouseMode(SDL_FALSE);
}
}
QString SdlInputHandler::getUnmappedGamepads() QString SdlInputHandler::getUnmappedGamepads()
{ {
QString ret; QString ret;
+6
View File
@@ -64,6 +64,10 @@ public:
void raiseAllKeys(); void raiseAllKeys();
bool isCaptureActive();
void setCaptureActive(bool active);
static static
QString getUnmappedGamepads(); QString getUnmappedGamepads();
@@ -89,12 +93,14 @@ private:
Uint32 mouseEmulationTimerCallback(Uint32 interval, void* param); Uint32 mouseEmulationTimerCallback(Uint32 interval, void* param);
bool m_MultiController; bool m_MultiController;
bool m_GamepadMouse;
SDL_TimerID m_MouseMoveTimer; SDL_TimerID m_MouseMoveTimer;
SDL_atomic_t m_MouseDeltaX; SDL_atomic_t m_MouseDeltaX;
SDL_atomic_t m_MouseDeltaY; SDL_atomic_t m_MouseDeltaY;
int m_GamepadMask; int m_GamepadMask;
GamepadState m_GamepadState[MAX_GAMEPADS]; GamepadState m_GamepadState[MAX_GAMEPADS];
QSet<short> m_KeysDown; QSet<short> m_KeysDown;
bool m_FakeCaptureActive;
SDL_TouchFingerEvent m_TouchDownEvent[MAX_FINGERS]; SDL_TouchFingerEvent m_TouchDownEvent[MAX_FINGERS];
float m_CumulativeDelta[MAX_FINGERS]; float m_CumulativeDelta[MAX_FINGERS];
+17 -29
View File
@@ -1,6 +1,7 @@
#include "session.h" #include "session.h"
#include "settings/streamingpreferences.h" #include "settings/streamingpreferences.h"
#include "streaming/streamutils.h" #include "streaming/streamutils.h"
#include "backend/richpresencemanager.h"
#include <Limelight.h> #include <Limelight.h>
#include <SDL.h> #include <SDL.h>
@@ -43,22 +44,6 @@ CONNECTION_LISTENER_CALLBACKS Session::k_ConnCallbacks = {
Session::clConnectionStatusUpdate Session::clConnectionStatusUpdate
}; };
AUDIO_RENDERER_CALLBACKS Session::k_AudioCallbacks = {
Session::arInit,
nullptr,
nullptr,
Session::arCleanup,
Session::arDecodeAndPlaySample,
#ifndef STEAM_LINK
CAPABILITY_DIRECT_SUBMIT
#else
// We cannot use direct submit for Steam Link because the
// SLAudio renderer needs to look at the audio backlog to
// cap latency since playback is a blocking operation.
CAPABILITY_SLOW_OPUS_DECODER
#endif
};
Session* Session::s_ActiveSession; Session* Session::s_ActiveSession;
QSemaphore Session::s_ActiveSessionSemaphore(1); QSemaphore Session::s_ActiveSessionSemaphore(1);
@@ -394,6 +379,12 @@ bool Session::initialize()
break; break;
} }
LiInitializeAudioCallbacks(&m_AudioCallbacks);
m_AudioCallbacks.init = arInit;
m_AudioCallbacks.cleanup = arCleanup;
m_AudioCallbacks.decodeAndPlaySample = arDecodeAndPlaySample;
m_AudioCallbacks.capabilities = getAudioRendererCapabilities(m_StreamConfig.audioConfiguration);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Audio configuration: %d", "Audio configuration: %d",
m_StreamConfig.audioConfiguration); m_StreamConfig.audioConfiguration);
@@ -452,11 +443,11 @@ bool Session::initialize()
switch (m_Preferences->windowMode) switch (m_Preferences->windowMode)
{ {
default:
case StreamingPreferences::WM_FULLSCREEN_DESKTOP: case StreamingPreferences::WM_FULLSCREEN_DESKTOP:
m_FullScreenFlag = SDL_WINDOW_FULLSCREEN_DESKTOP; m_FullScreenFlag = SDL_WINDOW_FULLSCREEN_DESKTOP;
break; break;
case StreamingPreferences::WM_FULLSCREEN: case StreamingPreferences::WM_FULLSCREEN:
default:
m_FullScreenFlag = SDL_WINDOW_FULLSCREEN; m_FullScreenFlag = SDL_WINDOW_FULLSCREEN;
break; break;
} }
@@ -948,7 +939,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
int err = LiStartConnection(&hostInfo, &m_StreamConfig, &k_ConnCallbacks, int err = LiStartConnection(&hostInfo, &m_StreamConfig, &k_ConnCallbacks,
&m_VideoCallbacks, &m_VideoCallbacks,
m_AudioDisabled ? nullptr : &k_AudioCallbacks, m_AudioDisabled ? nullptr : &m_AudioCallbacks,
NULL, 0, NULL, 0); NULL, 0, NULL, 0);
if (err != 0) { if (err != 0) {
// We already displayed an error dialog in the stage failure // We already displayed an error dialog in the stage failure
@@ -1033,7 +1024,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
// This prevents the mouse from becoming trapped inside // This prevents the mouse from becoming trapped inside
// Moonlight when it's halted at a debug break. // Moonlight when it's halted at a debug break.
if (m_Preferences->windowMode != StreamingPreferences::WM_WINDOWED) { if (m_Preferences->windowMode != StreamingPreferences::WM_WINDOWED) {
SDL_SetRelativeMouseMode(SDL_TRUE); m_InputHandler->setCaptureActive(true);
} }
#endif #endif
@@ -1057,6 +1048,9 @@ void Session::exec(int displayOriginX, int displayOriginY)
// (m_UnexpectedTermination is set back to true). // (m_UnexpectedTermination is set back to true).
m_UnexpectedTermination = false; m_UnexpectedTermination = false;
// Start rich presence to indicate we're in game
RichPresenceManager presence(prefs, m_App.name);
// Hijack this thread to be the SDL main thread. We have to do this // Hijack this thread to be the SDL main thread. We have to do this
// because we want to suspend all Qt processing until the stream is over. // because we want to suspend all Qt processing until the stream is over.
SDL_Event event; SDL_Event event;
@@ -1073,6 +1067,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
// ARM core in the Steam Link, so we will wait 10 ms instead. // ARM core in the Steam Link, so we will wait 10 ms instead.
SDL_Delay(10); SDL_Delay(10);
#endif #endif
presence.runCallbacks();
continue; continue;
} }
switch (event.type) { switch (event.type) {
@@ -1106,20 +1101,19 @@ void Session::exec(int displayOriginX, int displayOriginY)
SDL_GetWindowPosition(m_Window, &x, &y); SDL_GetWindowPosition(m_Window, &x, &y);
SDL_GetWindowSize(m_Window, &width, &height); SDL_GetWindowSize(m_Window, &width, &height);
if (mouseX > x && mouseX < x+width && mouseY > y && mouseY < y+height) { if (mouseX > x && mouseX < x+width && mouseY > y && mouseY < y+height) {
SDL_SetRelativeMouseMode(SDL_TRUE); m_InputHandler->setCaptureActive(true);
} }
} }
} }
#endif #endif
if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
// Release mouse cursor when another window is activated (e.g. by using ALT+TAB). // Release mouse cursor when another window is activated (e.g. by using ALT+TAB).
// This lets user to interact with our window's title bar and with the buttons in it. // This lets user to interact with our window's title bar and with the buttons in it.
// Doing this while the window is full-screen breaks the transition out of FS // Doing this while the window is full-screen breaks the transition out of FS
// (desktop and exclusive), so we must check for that before releasing mouse capture. // (desktop and exclusive), so we must check for that before releasing mouse capture.
if (!(SDL_GetWindowFlags(m_Window) & SDL_WINDOW_FULLSCREEN)) { if (!(SDL_GetWindowFlags(m_Window) & SDL_WINDOW_FULLSCREEN)) {
SDL_SetRelativeMouseMode(SDL_FALSE); m_InputHandler->setCaptureActive(false);
} }
// Raise all keys that are currently pressed. If we don't do this, certain keys // Raise all keys that are currently pressed. If we don't do this, certain keys
@@ -1241,24 +1235,18 @@ void Session::exec(int displayOriginX, int displayOriginY)
case SDL_JOYDEVICEADDED: case SDL_JOYDEVICEADDED:
m_InputHandler->handleJoystickArrivalEvent(&event.jdevice); m_InputHandler->handleJoystickArrivalEvent(&event.jdevice);
break; break;
// SDL2 sends touch events from trackpads by default on
// macOS. This totally screws our actual mouse handling,
// so we must explicitly ignore touch events on macOS.
#ifndef Q_OS_DARWIN
case SDL_FINGERDOWN: case SDL_FINGERDOWN:
case SDL_FINGERMOTION: case SDL_FINGERMOTION:
case SDL_FINGERUP: case SDL_FINGERUP:
m_InputHandler->handleTouchFingerEvent(&event.tfinger); m_InputHandler->handleTouchFingerEvent(&event.tfinger);
break; break;
#endif
} }
} }
DispatchDeferredCleanup: DispatchDeferredCleanup:
// Uncapture the mouse and hide the window immediately, // Uncapture the mouse and hide the window immediately,
// so we can return to the Qt GUI ASAP. // so we can return to the Qt GUI ASAP.
SDL_SetRelativeMouseMode(SDL_FALSE); m_InputHandler->setCaptureActive(false);
SDL_EnableScreenSaver(); SDL_EnableScreenSaver();
SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "0"); SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "0");
+4 -4
View File
@@ -66,12 +66,12 @@ private:
StreamingPreferences::VideoDecoderSelection vds, StreamingPreferences::VideoDecoderSelection vds,
int videoFormat, int width, int height, int frameRate); int videoFormat, int width, int height, int frameRate);
IAudioRenderer* createAudioRenderer(); IAudioRenderer* createAudioRenderer(const POPUS_MULTISTREAM_CONFIGURATION opusConfig);
int detectAudioConfiguration();
bool testAudio(int audioConfiguration); bool testAudio(int audioConfiguration);
int getAudioRendererCapabilities(int audioConfiguration);
void getWindowDimensions(int& x, int& y, void getWindowDimensions(int& x, int& y,
int& width, int& height); int& width, int& height);
@@ -129,6 +129,7 @@ private:
StreamingPreferences* m_Preferences; StreamingPreferences* m_Preferences;
STREAM_CONFIGURATION m_StreamConfig; STREAM_CONFIGURATION m_StreamConfig;
DECODER_RENDERER_CALLBACKS m_VideoCallbacks; DECODER_RENDERER_CALLBACKS m_VideoCallbacks;
AUDIO_RENDERER_CALLBACKS m_AudioCallbacks;
NvComputer* m_Computer; NvComputer* m_Computer;
NvApp m_App; NvApp m_App;
SDL_Window* m_Window; SDL_Window* m_Window;
@@ -158,7 +159,6 @@ private:
Overlay::OverlayManager m_OverlayManager; Overlay::OverlayManager m_OverlayManager;
static AUDIO_RENDERER_CALLBACKS k_AudioCallbacks;
static CONNECTION_LISTENER_CALLBACKS k_ConnCallbacks; static CONNECTION_LISTENER_CALLBACKS k_ConnCallbacks;
static Session* s_ActiveSession; static Session* s_ActiveSession;
static QSemaphore s_ActiveSessionSemaphore; static QSemaphore s_ActiveSessionSemaphore;
@@ -0,0 +1,57 @@
#include "cuda.h"
CUDARenderer::CUDARenderer()
: m_HwContext(nullptr)
{
}
CUDARenderer::~CUDARenderer()
{
if (m_HwContext != nullptr) {
av_buffer_unref(&m_HwContext);
}
}
bool CUDARenderer::initialize(PDECODER_PARAMETERS)
{
int err;
err = av_hwdevice_ctx_create(&m_HwContext, AV_HWDEVICE_TYPE_CUDA, nullptr, nullptr, 0);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwdevice_ctx_create(CUDA) failed: %d",
err);
return false;
}
return true;
}
bool CUDARenderer::prepareDecoderContext(AVCodecContext* context)
{
context->hw_device_ctx = av_buffer_ref(m_HwContext);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Using CUDA accelerated decoder");
return true;
}
void CUDARenderer::renderFrame(AVFrame*)
{
// We only support indirect rendering
SDL_assert(false);
}
bool CUDARenderer::needsTestFrame()
{
return true;
}
bool CUDARenderer::isDirectRenderingSupported()
{
// We only support rendering via SDL read-back
return false;
}
@@ -0,0 +1,18 @@
#pragma once
#include "renderer.h"
class CUDARenderer : public IFFmpegRenderer {
public:
CUDARenderer();
virtual ~CUDARenderer() override;
virtual bool initialize(PDECODER_PARAMETERS) override;
virtual bool prepareDecoderContext(AVCodecContext* context) override;
virtual void renderFrame(AVFrame* frame) override;
virtual bool needsTestFrame() override;
virtual bool isDirectRenderingSupported() override;
private:
AVBufferRef* m_HwContext;
};
+13 -23
View File
@@ -7,16 +7,10 @@
#include <Limelight.h> #include <Limelight.h>
const std::vector<int> SdlRenderer::k_SwFormats({
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NV12,
AV_PIX_FMT_NV21
});
SdlRenderer::SdlRenderer() SdlRenderer::SdlRenderer()
: m_Renderer(nullptr), : m_Renderer(nullptr),
m_Texture(nullptr), m_Texture(nullptr),
m_SwPixelFormat(AV_PIX_FMT_YUV420P), m_SwPixelFormat(AV_PIX_FMT_NONE),
m_FontData(Path::readDataFile("ModeSeven.ttf")) m_FontData(Path::readDataFile("ModeSeven.ttf"))
{ {
SDL_assert(TTF_WasInit() == 0); SDL_assert(TTF_WasInit() == 0);
@@ -239,6 +233,18 @@ void SdlRenderer::renderFrame(AVFrame* frame)
// accelerated decoder, we'll need to read the frame // accelerated decoder, we'll need to read the frame
// back to render it. // back to render it.
// Find the native read-back format
if (m_SwPixelFormat == AV_PIX_FMT_NONE) {
auto hwFrameCtx = (AVHWFramesContext*)frame->hw_frames_ctx->data;
m_SwPixelFormat = hwFrameCtx->sw_format;
SDL_assert(m_SwPixelFormat != AV_PIX_FMT_NONE);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Selected read-back format: %d",
m_SwPixelFormat);
}
swFrame = av_frame_alloc(); swFrame = av_frame_alloc();
if (swFrame == nullptr) { if (swFrame == nullptr) {
return; return;
@@ -249,22 +255,6 @@ void SdlRenderer::renderFrame(AVFrame* frame)
swFrame->format = m_SwPixelFormat; swFrame->format = m_SwPixelFormat;
err = av_hwframe_transfer_data(swFrame, frame, 0); err = av_hwframe_transfer_data(swFrame, frame, 0);
if (err != 0) {
// Try to find a supported format
for (uint32_t i = 0; i < k_SwFormats.size(); i++) {
swFrame->format = k_SwFormats.at(i);
err = av_hwframe_transfer_data(swFrame, frame, 0);
if (err == 0) {
// The format was supported. Use that automatically in the future.
m_SwPixelFormat = swFrame->format;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Selected read-back format: %d",
m_SwPixelFormat);
break;
}
}
}
if (err != 0) { if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwframe_transfer_data() failed: %d", "av_hwframe_transfer_data() failed: %d",
@@ -26,7 +26,5 @@ private:
SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax]; SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax];
SDL_Texture* m_OverlayTextures[Overlay::OverlayMax]; SDL_Texture* m_OverlayTextures[Overlay::OverlayMax];
SDL_Rect m_OverlayRects[Overlay::OverlayMax]; SDL_Rect m_OverlayRects[Overlay::OverlayMax];
static const std::vector<int> k_SwFormats;
}; };
+43 -2
View File
@@ -5,8 +5,12 @@
#include <SDL_syswm.h> #include <SDL_syswm.h>
#include <unistd.h>
#include <fcntl.h>
VAAPIRenderer::VAAPIRenderer() VAAPIRenderer::VAAPIRenderer()
: m_HwContext(nullptr) : m_HwContext(nullptr),
m_DrmFd(-1)
{ {
} }
@@ -26,6 +30,10 @@ VAAPIRenderer::~VAAPIRenderer()
vaTerminate(display); vaTerminate(display);
} }
} }
if (m_DrmFd != -1) {
close(m_DrmFd);
}
} }
bool bool
@@ -86,6 +94,39 @@ VAAPIRenderer::initialize(PDECODER_PARAMETERS params)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Moonlight not compiled with VAAPI Wayland support!"); "Moonlight not compiled with VAAPI Wayland support!");
return false; return false;
#endif
}
// TODO: Upstream a better solution for SDL_GetWindowWMInfo on KMSDRM
else if (strcmp(SDL_GetCurrentVideoDriver(), "KMSDRM") == 0) {
#ifdef HAVE_LIBVA_DRM
const char* device = SDL_getenv("DRM_DEV");
if (device == nullptr) {
device = "/dev/dri/card0";
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Opening DRM device: %s",
device);
m_DrmFd = open(device, O_RDWR | O_CLOEXEC);
if (m_DrmFd < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to open DRM device: %d",
errno);
return false;
}
vaDeviceContext->display = vaGetDisplayDRM(m_DrmFd);
if (!vaDeviceContext->display) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Unable to open DRM display for VAAPI");
return false;
}
#else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Moonlight not compiled with VAAPI DRM support!");
return false;
#endif #endif
} }
else { else {
@@ -157,7 +198,7 @@ VAAPIRenderer::prepareDecoderContext(AVCodecContext* context)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Using VAAPI accelerated renderer on %s", "Using VAAPI accelerated renderer on %s",
m_WindowSystem == SDL_SYSWM_X11 ? "X11" : "Wayland"); SDL_GetCurrentVideoDriver());
return true; return true;
} }
@@ -22,6 +22,9 @@ extern "C" {
#ifdef HAVE_LIBVA_WAYLAND #ifdef HAVE_LIBVA_WAYLAND
#include <va/va_wayland.h> #include <va/va_wayland.h>
#endif #endif
#ifdef HAVE_LIBVA_DRM
#include <va/va_drm.h>
#endif
#include <libavutil/hwcontext_vaapi.h> #include <libavutil/hwcontext_vaapi.h>
} }
@@ -39,6 +42,7 @@ public:
private: private:
int m_WindowSystem; int m_WindowSystem;
AVBufferRef* m_HwContext; AVBufferRef* m_HwContext;
int m_DrmFd;
#ifdef HAVE_LIBVA_X11 #ifdef HAVE_LIBVA_X11
Window m_XWindow; Window m_XWindow;
+48 -4
View File
@@ -6,6 +6,7 @@
#include <h264_stream.h> #include <h264_stream.h>
#include "ffmpeg-renderers/sdlvid.h" #include "ffmpeg-renderers/sdlvid.h"
#include "ffmpeg-renderers/cuda.h"
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
#include "ffmpeg-renderers/dxva2.h" #include "ffmpeg-renderers/dxva2.h"
@@ -212,6 +213,15 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, PDECODER_PARAM
m_VideoDecoderCtx->flags |= AV_CODEC_FLAG_OUTPUT_CORRUPT; m_VideoDecoderCtx->flags |= AV_CODEC_FLAG_OUTPUT_CORRUPT;
m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL; m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL;
// Report decoding errors to allow us to request a key frame
//
// With HEVC streams, FFmpeg can drop a frame (hwaccel->start_frame() fails)
// without telling us. Since we have an infinite GOP length, this causes artifacts
// on screen that persist for a long time. It's easy to cause this condition
// by using NVDEC and delaying 100 ms randomly in the render path so the decoder
// runs out of output buffers.
m_VideoDecoderCtx->err_recognition = AV_EF_EXPLODE;
// Enable slice multi-threading for software decoding // Enable slice multi-threading for software decoding
if (!isHardwareAccelerated()) { if (!isHardwareAccelerated()) {
m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE; m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE;
@@ -369,13 +379,14 @@ void FFmpegVideoDecoder::logVideoStats(VIDEO_STATS& stats, const char* title)
} }
} }
IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg) IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg, int pass)
{ {
if (!(hwDecodeCfg->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) { if (!(hwDecodeCfg->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) {
return nullptr; return nullptr;
} }
// Look for acceleration types we support // First pass using our top-tier hwaccel implementations
if (pass == 0) {
switch (hwDecodeCfg->device_type) { switch (hwDecodeCfg->device_type) {
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
case AV_HWDEVICE_TYPE_DXVA2: case AV_HWDEVICE_TYPE_DXVA2:
@@ -396,6 +407,23 @@ IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig
default: default:
return nullptr; return nullptr;
} }
}
// Second pass for our second-tier hwaccel implementations
else if (pass == 1) {
switch (hwDecodeCfg->device_type) {
case AV_HWDEVICE_TYPE_CUDA:
// CUDA should only be used if all other options fail, since it requires
// read-back of frames. This should only be used for the NVIDIA+Wayland case
// with VDPAU covering the NVIDIA+X11 scenario.
return new CUDARenderer();
default:
return nullptr;
}
}
else {
SDL_assert(false);
return nullptr;
}
} }
bool FFmpegVideoDecoder::tryInitializeRenderer(AVCodec* decoder, bool FFmpegVideoDecoder::tryInitializeRenderer(AVCodec* decoder,
@@ -469,7 +497,7 @@ bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params)
// Look for a hardware decoder first unless software-only // Look for a hardware decoder first unless software-only
if (params->vds != StreamingPreferences::VDS_FORCE_SOFTWARE) { if (params->vds != StreamingPreferences::VDS_FORCE_SOFTWARE) {
// Look for the first matching hwaccel hardware decoder // Look for the first matching hwaccel hardware decoder (pass 0)
for (int i = 0;; i++) { for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
if (!config) { if (!config) {
@@ -479,7 +507,7 @@ bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params)
// Initialize the hardware codec and submit a test frame if the renderer needs it // Initialize the hardware codec and submit a test frame if the renderer needs it
if (tryInitializeRenderer(decoder, params, config, if (tryInitializeRenderer(decoder, params, config,
[config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config); })) { [config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config, 0); })) {
return true; return true;
} }
} }
@@ -515,6 +543,22 @@ bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params)
return true; return true;
} }
#endif #endif
// Look for the first matching hwaccel hardware decoder (pass 1)
// This picks up "second-tier" hwaccels like CUDA.
for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
if (!config) {
// No remaing hwaccel options
break;
}
// Initialize the hardware codec and submit a test frame if the renderer needs it
if (tryInitializeRenderer(decoder, params, config,
[config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config, 1); })) {
return true;
}
}
} }
// Fallback to software if no matching hardware decoder was found // Fallback to software if no matching hardware decoder was found
+1 -1
View File
@@ -38,7 +38,7 @@ private:
const AVCodecHWConfig* hwConfig, const AVCodecHWConfig* hwConfig,
std::function<IFFmpegRenderer*()> createRendererFunc); std::function<IFFmpegRenderer*()> createRendererFunc);
static IFFmpegRenderer* createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg); static IFFmpegRenderer* createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg, int pass);
void reset(); void reset();
+1 -1
View File
@@ -1 +1 @@
1.0.1 1.1.0
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -162,12 +162,29 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory") #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory") #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
#elif defined(__GNUC__) && defined(__arm__) #elif defined(__GNUC__) && defined(__arm__)
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) #if 0 /* defined(__LINUX__) || defined(__ANDROID__) */
/* Information from:
https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
The Linux kernel provides a helper function which provides the right code for a memory barrier,
hard-coded at address 0xffff0fa0
*/
typedef void (*SDL_KernelMemoryBarrierFunc)();
#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
#elif 0 /* defined(__QNXNTO__) */
#include <sys/cpuinline.h>
#define SDL_MemoryBarrierRelease() __cpu_membarrier()
#define SDL_MemoryBarrierAcquire() __cpu_membarrier()
#else
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory") #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory") #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__) #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
#ifdef __thumb__ #ifdef __thumb__
/* The mcr instruction isn't available in thumb mode, use real functions */ /* The mcr instruction isn't available in thumb mode, use real functions */
#define SDL_MEMORY_BARRIER_USES_FUNCTION
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction() #define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction() #define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
#else #else
@@ -177,6 +194,7 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
#else #else
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory") #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory") #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
#endif /* __LINUX__ || __ANDROID__ */
#endif /* __GNUC__ && __arm__ */ #endif /* __GNUC__ && __arm__ */
#else #else
#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120)) #if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -420,23 +420,56 @@ extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
/* @} *//* Pause audio functions */ /* @} *//* Pause audio functions */
/** /**
* This function loads a WAVE from the data source, automatically freeing * \brief Load the audio data of a WAVE file into memory
* that source if \c freesrc is non-zero. For example, to load a WAVE file, *
* you could do: * Loading a WAVE file requires \c src, \c spec, \c audio_buf and \c audio_len
* to be valid pointers. The entire data portion of the file is then loaded
* into memory and decoded if necessary.
*
* If \c freesrc is non-zero, the data source gets automatically closed and
* freed before the function returns.
*
* Supported are RIFF WAVE files with the formats PCM (8, 16, 24, and 32 bits),
* IEEE Float (32 bits), Microsoft ADPCM and IMA ADPCM (4 bits), and A-law and
* µ-law (8 bits). Other formats are currently unsupported and cause an error.
*
* If this function succeeds, the pointer returned by it is equal to \c spec
* and the pointer to the audio data allocated by the function is written to
* \c audio_buf and its length in bytes to \c audio_len. The \ref SDL_AudioSpec
* members \c freq, \c channels, and \c format are set to the values of the
* audio data in the buffer. The \c samples member is set to a sane default and
* all others are set to zero.
*
* It's necessary to use SDL_FreeWAV() to free the audio data returned in
* \c audio_buf when it is no longer used.
*
* Because of the underspecification of the Waveform format, there are many
* problematic files in the wild that cause issues with strict decoders. To
* provide compatibility with these files, this decoder is lenient in regards
* to the truncation of the file, the fact chunk, and the size of the RIFF
* chunk. The hints SDL_HINT_WAVE_RIFF_CHUNK_SIZE, SDL_HINT_WAVE_TRUNCATION,
* and SDL_HINT_WAVE_FACT_CHUNK can be used to tune the behavior of the
* loading process.
*
* Any file that is invalid (due to truncation, corruption, or wrong values in
* the headers), too big, or unsupported causes an error. Additionally, any
* critical I/O error from the data source will terminate the loading process
* with an error. The function returns NULL on error and in all cases (with the
* exception of \c src being NULL), an appropriate error message will be set.
*
* It is required that the data source supports seeking.
*
* Example:
* \code * \code
* SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...); * SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
* \endcode * \endcode
* *
* If this function succeeds, it returns the given SDL_AudioSpec, * \param src The data source with the WAVE data
* filled with the audio data format of the wave data, and sets * \param freesrc A integer value that makes the function close the data source if non-zero
* \c *audio_buf to a malloc()'d buffer containing the audio data, * \param spec A pointer filled with the audio format of the audio data
* and sets \c *audio_len to the length of that audio buffer, in bytes. * \param audio_buf A pointer filled with the audio data allocated by the function
* You need to free the audio buffer with SDL_FreeWAV() when you are * \param audio_len A pointer filled with the length of the audio data buffer in bytes
* done with it. * \return NULL on error, or non-NULL on success.
*
* This function returns NULL and sets the SDL error message if the
* wave file cannot be opened, uses an unknown data format, or is
* corrupt. Currently raw and MS-ADPCM WAVE files are supported.
*/ */
extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src, extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
int freesrc, int freesrc,
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -101,6 +101,15 @@ SDL_MostSignificantBitIndex32(Uint32 x)
#endif #endif
} }
SDL_FORCE_INLINE SDL_bool
SDL_HasExactlyOneBitSet32(Uint32 x)
{
if (x && !(x & (x - 1))) {
return SDL_TRUE;
}
return SDL_FALSE;
}
/* Ends C function definitions when using C++ */ /* Ends C function definitions when using C++ */
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -90,12 +90,12 @@ typedef enum
/** /**
* \brief Create a custom blend mode, which may or may not be supported by a given renderer * \brief Create a custom blend mode, which may or may not be supported by a given renderer
* *
* \param srcColorFactor * \param srcColorFactor source color factor
* \param dstColorFactor * \param dstColorFactor destination color factor
* \param colorOperation * \param colorOperation color operation
* \param srcAlphaFactor * \param srcAlphaFactor source alpha factor
* \param dstAlphaFactor * \param dstAlphaFactor destination alpha factor
* \param alphaOperation * \param alphaOperation alpha operation
* *
* The result of the blend mode operation will be: * The result of the blend mode operation will be:
* dstRGB = dstRGB * dstColorFactor colorOperation srcRGB * srcColorFactor * dstRGB = dstRGB * dstColorFactor colorOperation srcRGB * srcColorFactor
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -218,7 +218,7 @@
#endif #endif
/* Enable Vulkan support */ /* Enable Vulkan support */
/* Metal/MoltenVK/Vulkan only supported on 64-bit architectures with 10.11+ */ /* Metal/Vulkan Portability only supported on 64-bit architectures with 10.11+ */
#if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100) #if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
#define SDL_VIDEO_VULKAN 1 #define SDL_VIDEO_VULKAN 1
#else #else
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -41,24 +41,43 @@
#else #else
#include <intrin.h> #include <intrin.h>
#ifndef _WIN64 #ifndef _WIN64
#ifndef __MMX__
#define __MMX__ #define __MMX__
#endif
#ifndef __3dNOW__
#define __3dNOW__ #define __3dNOW__
#endif #endif
#endif
#ifndef __SSE__
#define __SSE__ #define __SSE__
#endif
#ifndef __SSE2__
#define __SSE2__ #define __SSE2__
#endif
#endif /* __clang__ */ #endif /* __clang__ */
#elif defined(__MINGW64_VERSION_MAJOR) #elif defined(__MINGW64_VERSION_MAJOR)
#include <intrin.h> #include <intrin.h>
#else #else
#ifdef __ALTIVEC__ /* altivec.h redefining bool causes a number of problems, see bugs 3993 and 4392, so you need to explicitly define SDL_ENABLE_ALTIVEC_H to have it included. */
#if defined(HAVE_ALTIVEC_H) && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H) #if defined(HAVE_ALTIVEC_H) && defined(__ALTIVEC__) && !defined(__APPLE_ALTIVEC__) && defined(SDL_ENABLE_ALTIVEC_H)
#include <altivec.h> #include <altivec.h>
#undef pixel
#undef bool
#endif #endif
#endif #if !defined(SDL_DISABLE_ARM_NEON_H)
#if defined(__ARM_NEON__) && !defined(SDL_DISABLE_ARM_NEON_H) # if defined(__ARM_NEON)
#include <arm_neon.h> # include <arm_neon.h>
# elif defined(__WINDOWS__) || defined(__WINRT__)
/* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
# if defined(_M_ARM)
# include <armintr.h>
# include <arm_neon.h>
# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
# endif
# if defined (_M_ARM64)
# include <armintr.h>
# include <arm_neon.h>
# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
# endif
# endif
#endif #endif
#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H) #if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
#include <mm3dnow.h> #include <mm3dnow.h>
@@ -177,6 +196,69 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
*/ */
extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void); extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
/**
* \brief Report the alignment this system needs for SIMD allocations.
*
* This will return the minimum number of bytes to which a pointer must be
* aligned to be compatible with SIMD instructions on the current machine.
* For example, if the machine supports SSE only, it will return 16, but if
* it supports AVX-512F, it'll return 64 (etc). This only reports values for
* instruction sets SDL knows about, so if your SDL build doesn't have
* SDL_HasAVX512F(), then it might return 16 for the SSE support it sees and
* not 64 for the AVX-512 instructions that exist but SDL doesn't know about.
* Plan accordingly.
*/
extern DECLSPEC size_t SDLCALL SDL_SIMDGetAlignment(void);
/**
* \brief Allocate memory in a SIMD-friendly way.
*
* This will allocate a block of memory that is suitable for use with SIMD
* instructions. Specifically, it will be properly aligned and padded for
* the system's supported vector instructions.
*
* The memory returned will be padded such that it is safe to read or write
* an incomplete vector at the end of the memory block. This can be useful
* so you don't have to drop back to a scalar fallback at the end of your
* SIMD processing loop to deal with the final elements without overflowing
* the allocated buffer.
*
* You must free this memory with SDL_FreeSIMD(), not free() or SDL_free()
* or delete[], etc.
*
* Note that SDL will only deal with SIMD instruction sets it is aware of;
* for example, SDL 2.0.8 knows that SSE wants 16-byte vectors
* (SDL_HasSSE()), and AVX2 wants 32 bytes (SDL_HasAVX2()), but doesn't
* know that AVX-512 wants 64. To be clear: if you can't decide to use an
* instruction set with an SDL_Has*() function, don't use that instruction
* set with memory allocated through here.
*
* SDL_AllocSIMD(0) will return a non-NULL pointer, assuming the system isn't
* out of memory.
*
* \param len The length, in bytes, of the block to allocated. The actual
* allocated block might be larger due to padding, etc.
* \return Pointer to newly-allocated block, NULL if out of memory.
*
* \sa SDL_SIMDAlignment
* \sa SDL_SIMDFree
*/
extern DECLSPEC void * SDLCALL SDL_SIMDAlloc(const size_t len);
/**
* \brief Deallocate memory obtained from SDL_SIMDAlloc
*
* It is not valid to use this function on a pointer from anything but
* SDL_SIMDAlloc(). It can't be used on pointers from malloc, realloc,
* SDL_malloc, memalign, new[], etc.
*
* However, SDL_SIMDFree(NULL) is a legal no-op.
*
* \sa SDL_SIMDAlloc
*/
extern DECLSPEC void SDLCALL SDL_SIMDFree(void *ptr);
/* vi: set ts=4 sw=4 expandtab: */
/* Ends C function definitions when using C++ */ /* Ends C function definitions when using C++ */
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -594,6 +594,9 @@ typedef union SDL_Event
Uint8 padding[56]; Uint8 padding[56];
} SDL_Event; } SDL_Event;
/* Make sure we haven't broken binary compatibility */
SDL_COMPILE_TIME_ASSERT(SDL_Event, sizeof(SDL_Event) == 56);
/* Function prototypes */ /* Function prototypes */
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -315,6 +315,16 @@ extern "C" {
*/ */
#define SDL_HINT_TOUCH_MOUSE_EVENTS "SDL_TOUCH_MOUSE_EVENTS" #define SDL_HINT_TOUCH_MOUSE_EVENTS "SDL_TOUCH_MOUSE_EVENTS"
/**
* \brief A variable controlling whether mouse events should generate synthetic touch events
*
* This variable can be set to the following values:
* "0" - Mouse events will not generate touch events (default for desktop platforms)
* "1" - Mouse events will generate touch events (default for mobile platforms, such as Android and iOS)
*/
#define SDL_HINT_MOUSE_TOUCH_EVENTS "SDL_MOUSE_TOUCH_EVENTS"
/** /**
* \brief Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true. * \brief Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true.
* *
@@ -436,6 +446,16 @@ extern "C" {
*/ */
#define SDL_HINT_GAMECONTROLLERCONFIG "SDL_GAMECONTROLLERCONFIG" #define SDL_HINT_GAMECONTROLLERCONFIG "SDL_GAMECONTROLLERCONFIG"
/**
* \brief A variable that lets you provide a file with extra gamecontroller db entries.
*
* The file should contain lines of gamecontroller config data, see SDL_gamecontroller.h
*
* This hint must be set before calling SDL_Init(SDL_INIT_GAMECONTROLLER)
* You can update mappings after the system is initialized with SDL_GameControllerMappingForGUID() and SDL_GameControllerAddMapping()
*/
#define SDL_HINT_GAMECONTROLLERCONFIG_FILE "SDL_GAMECONTROLLERCONFIG_FILE"
/** /**
* \brief A variable containing a list of devices to skip when scanning for game controllers. * \brief A variable containing a list of devices to skip when scanning for game controllers.
* *
@@ -836,19 +856,7 @@ extern "C" {
*/ */
#define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING" #define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING"
/** /**
* \brief A variable to control whether mouse and touch events are to be treated together or separately
*
* The variable can be set to the following values:
* "0" - Mouse events will be handled as touch events, and touch will raise fake mouse
* events. This is the behaviour of SDL <= 2.0.3. (default)
* "1" - Mouse events will be handled separately from pure touch events.
*
* The value of this hint is used at runtime, so it can be changed at any time.
*/
#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
/**
* \brief A variable to control whether we trap the Android back button to handle it manually. * \brief A variable to control whether we trap the Android back button to handle it manually.
* This is necessary for the right mouse button to work on some Android devices, or * This is necessary for the right mouse button to work on some Android devices, or
* to be able to trap the back button for use in your code reliably. If set to true, * to be able to trap the back button for use in your code reliably. If set to true,
@@ -865,6 +873,17 @@ extern "C" {
*/ */
#define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON" #define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON"
/**
* \brief A variable to control whether the event loop will block itself when the app is paused.
*
* The variable can be set to the following values:
* "0" - Non blocking.
* "1" - Blocking. (default)
*
* The value should be set before SDL is initialized.
*/
#define SDL_HINT_ANDROID_BLOCK_ON_PAUSE "SDL_ANDROID_BLOCK_ON_PAUSE"
/** /**
* \brief A variable to control whether the return key on the soft keyboard * \brief A variable to control whether the return key on the soft keyboard
* should hide the soft keyboard on Android and iOS. * should hide the soft keyboard on Android and iOS.
@@ -1043,6 +1062,118 @@ extern "C" {
*/ */
#define SDL_HINT_AUDIO_CATEGORY "SDL_AUDIO_CATEGORY" #define SDL_HINT_AUDIO_CATEGORY "SDL_AUDIO_CATEGORY"
/**
* \brief A variable controlling whether the 2D render API is compatible or efficient.
*
* This variable can be set to the following values:
*
* "0" - Don't use batching to make rendering more efficient.
* "1" - Use batching, but might cause problems if app makes its own direct OpenGL calls.
*
* Up to SDL 2.0.9, the render API would draw immediately when requested. Now
* it batches up draw requests and sends them all to the GPU only when forced
* to (during SDL_RenderPresent, when changing render targets, by updating a
* texture that the batch needs, etc). This is significantly more efficient,
* but it can cause problems for apps that expect to render on top of the
* render API's output. As such, SDL will disable batching if a specific
* render backend is requested (since this might indicate that the app is
* planning to use the underlying graphics API directly). This hint can
* be used to explicitly request batching in this instance. It is a contract
* that you will either never use the underlying graphics API directly, or
* if you do, you will call SDL_RenderFlush() before you do so any current
* batch goes to the GPU before your work begins. Not following this contract
* will result in undefined behavior.
*/
#define SDL_HINT_RENDER_BATCHING "SDL_RENDER_BATCHING"
/**
* \brief A variable controlling whether SDL logs all events pushed onto its internal queue.
*
* This variable can be set to the following values:
*
* "0" - Don't log any events (default)
* "1" - Log all events except mouse and finger motion, which are pretty spammy.
* "2" - Log all events.
*
* This is generally meant to be used to debug SDL itself, but can be useful
* for application developers that need better visibility into what is going
* on in the event queue. Logged events are sent through SDL_Log(), which
* means by default they appear on stdout on most platforms or maybe
* OutputDebugString() on Windows, and can be funneled by the app with
* SDL_LogSetOutputFunction(), etc.
*
* This hint can be toggled on and off at runtime, if you only need to log
* events for a small subset of program execution.
*/
#define SDL_HINT_EVENT_LOGGING "SDL_EVENT_LOGGING"
/**
* \brief Controls how the size of the RIFF chunk affects the loading of a WAVE file.
*
* The size of the RIFF chunk (which includes all the sub-chunks of the WAVE
* file) is not always reliable. In case the size is wrong, it's possible to
* just ignore it and step through the chunks until a fixed limit is reached.
*
* Note that files that have trailing data unrelated to the WAVE file or
* corrupt files may slow down the loading process without a reliable boundary.
* By default, SDL stops after 10000 chunks to prevent wasting time. Use the
* environment variable SDL_WAVE_CHUNK_LIMIT to adjust this value.
*
* This variable can be set to the following values:
*
* "force" - Always use the RIFF chunk size as a boundary for the chunk search
* "ignorezero" - Like "force", but a zero size searches up to 4 GiB (default)
* "ignore" - Ignore the RIFF chunk size and always search up to 4 GiB
* "maximum" - Search for chunks until the end of file (not recommended)
*/
#define SDL_HINT_WAVE_RIFF_CHUNK_SIZE "SDL_WAVE_RIFF_CHUNK_SIZE"
/**
* \brief Controls how a truncated WAVE file is handled.
*
* A WAVE file is considered truncated if any of the chunks are incomplete or
* the data chunk size is not a multiple of the block size. By default, SDL
* decodes until the first incomplete block, as most applications seem to do.
*
* This variable can be set to the following values:
*
* "verystrict" - Raise an error if the file is truncated
* "strict" - Like "verystrict", but the size of the RIFF chunk is ignored
* "dropframe" - Decode until the first incomplete sample frame
* "dropblock" - Decode until the first incomplete block (default)
*/
#define SDL_HINT_WAVE_TRUNCATION "SDL_WAVE_TRUNCATION"
/**
* \brief Controls how the fact chunk affects the loading of a WAVE file.
*
* The fact chunk stores information about the number of samples of a WAVE
* file. The Standards Update from Microsoft notes that this value can be used
* to 'determine the length of the data in seconds'. This is especially useful
* for compressed formats (for which this is a mandatory chunk) if they produce
* multiple sample frames per block and truncating the block is not allowed.
* The fact chunk can exactly specify how many sample frames there should be
* in this case.
*
* Unfortunately, most application seem to ignore the fact chunk and so SDL
* ignores it by default as well.
*
* This variable can be set to the following values:
*
* "truncate" - Use the number of samples to truncate the wave data if
* the fact chunk is present and valid
* "strict" - Like "truncate", but raise an error if the fact chunk
* is invalid, not present for non-PCM formats, or if the
* data chunk doesn't have that many samples
* "ignorezero" - Like "truncate", but ignore fact chunk if the number of
* samples is zero
* "ignore" - Ignore fact chunk entirely (default)
*/
#define SDL_HINT_WAVE_FACT_CHUNK "SDL_WAVE_FACT_CHUNK"
/** /**
* \brief An enumeration of hint priorities * \brief An enumeration of hint priorities
*/ */
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -55,6 +55,10 @@
/* On iOS SDL provides a main function that creates an application delegate /* On iOS SDL provides a main function that creates an application delegate
and starts the iOS application run loop. and starts the iOS application run loop.
If you link with SDL dynamically on iOS, the main function can't be in a
shared library, so you need to link with libSDLmain.a, which includes a
stub main function that calls into the shared library to start execution.
See src/video/uikit/SDL_uikitappdelegate.m for more details. See src/video/uikit/SDL_uikitappdelegate.m for more details.
*/ */
#define SDL_MAIN_NEEDED #define SDL_MAIN_NEEDED
@@ -82,12 +86,6 @@
#endif #endif
#endif /* SDL_MAIN_HANDLED */ #endif /* SDL_MAIN_HANDLED */
#ifdef __cplusplus
#define C_LINKAGE "C"
#else
#define C_LINKAGE
#endif /* __cplusplus */
#ifndef SDLMAIN_DECLSPEC #ifndef SDLMAIN_DECLSPEC
#define SDLMAIN_DECLSPEC #define SDLMAIN_DECLSPEC
#endif #endif
@@ -111,17 +109,18 @@
#define main SDL_main #define main SDL_main
#endif #endif
/**
* The prototype for the application's main() function
*/
extern C_LINKAGE SDLMAIN_DECLSPEC int SDL_main(int argc, char *argv[]);
#include "begin_code.h" #include "begin_code.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/**
* The prototype for the application's main() function
*/
typedef int (*SDL_main_func)(int argc, char *argv[]);
extern SDLMAIN_DECLSPEC int SDL_main(int argc, char *argv[]);
/** /**
* This is called by the real SDL main function to let the rest of the * This is called by the real SDL main function to let the rest of the
* library know that initialization was done properly. * library know that initialization was done properly.
@@ -136,8 +135,7 @@ extern DECLSPEC void SDLCALL SDL_SetMainReady(void);
/** /**
* This can be called to set the application class at startup * This can be called to set the application class at startup
*/ */
extern DECLSPEC int SDLCALL SDL_RegisterApp(char *name, Uint32 style, extern DECLSPEC int SDLCALL SDL_RegisterApp(char *name, Uint32 style, void *hInst);
void *hInst);
extern DECLSPEC void SDLCALL SDL_UnregisterApp(void); extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
#endif /* __WIN32__ */ #endif /* __WIN32__ */
@@ -153,10 +151,24 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
* \return 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more * \return 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more
* information on the failure. * information on the failure.
*/ */
extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * reserved); extern DECLSPEC int SDLCALL SDL_WinRTRunApp(SDL_main_func mainFunction, void * reserved);
#endif /* __WINRT__ */ #endif /* __WINRT__ */
#if defined(__IPHONEOS__)
/**
* \brief Initializes and launches an SDL application.
*
* \param argc The argc parameter from the application's main() function
* \param argv The argv parameter from the application's main() function
* \param mainFunction The SDL app's C-style main().
* \return the return value from mainFunction
*/
extern DECLSPEC int SDLCALL SDL_UIKitRunApp(int argc, char *argv[], SDL_main_func mainFunction);
#endif /* __IPHONEOS__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -168,7 +168,7 @@ enum
((format) && (SDL_PIXELFLAG(format) != 1)) ((format) && (SDL_PIXELFLAG(format) != 1))
/* Note: If you modify this list, update SDL_GetPixelFormatName() */ /* Note: If you modify this list, update SDL_GetPixelFormatName() */
enum typedef enum
{ {
SDL_PIXELFORMAT_UNKNOWN, SDL_PIXELFORMAT_UNKNOWN,
SDL_PIXELFORMAT_INDEX1LSB = SDL_PIXELFORMAT_INDEX1LSB =
@@ -290,7 +290,7 @@ enum
SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'), SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'),
SDL_PIXELFORMAT_EXTERNAL_OES = /**< Android video texture format */ SDL_PIXELFORMAT_EXTERNAL_OES = /**< Android video texture format */
SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ')
}; } SDL_PixelFormatEnum;
typedef struct SDL_Color typedef struct SDL_Color
{ {
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -40,7 +40,7 @@ extern "C" {
#endif #endif
/** /**
* \brief The structure that defines a point * \brief The structure that defines a point (integer)
* *
* \sa SDL_EnclosePoints * \sa SDL_EnclosePoints
* \sa SDL_PointInRect * \sa SDL_PointInRect
@@ -52,7 +52,20 @@ typedef struct SDL_Point
} SDL_Point; } SDL_Point;
/** /**
* \brief A rectangle, with the origin at the upper left. * \brief The structure that defines a point (floating point)
*
* \sa SDL_EnclosePoints
* \sa SDL_PointInRect
*/
typedef struct SDL_FPoint
{
float x;
float y;
} SDL_FPoint;
/**
* \brief A rectangle, with the origin at the upper left (integer).
* *
* \sa SDL_RectEmpty * \sa SDL_RectEmpty
* \sa SDL_RectEquals * \sa SDL_RectEquals
@@ -67,6 +80,19 @@ typedef struct SDL_Rect
int w, h; int w, h;
} SDL_Rect; } SDL_Rect;
/**
* \brief A rectangle, with the origin at the upper left (floating point).
*/
typedef struct SDL_FRect
{
float x;
float y;
float w;
float h;
} SDL_FRect;
/** /**
* \brief Returns true if point resides inside a rectangle. * \brief Returns true if point resides inside a rectangle.
*/ */
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -835,6 +835,148 @@ extern DECLSPEC int SDLCALL SDL_RenderCopyEx(SDL_Renderer * renderer,
const SDL_Point *center, const SDL_Point *center,
const SDL_RendererFlip flip); const SDL_RendererFlip flip);
/**
* \brief Draw a point on the current rendering target.
*
* \param renderer The renderer which should draw a point.
* \param x The x coordinate of the point.
* \param y The y coordinate of the point.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawPointF(SDL_Renderer * renderer,
float x, float y);
/**
* \brief Draw multiple points on the current rendering target.
*
* \param renderer The renderer which should draw multiple points.
* \param points The points to draw
* \param count The number of points to draw
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawPointsF(SDL_Renderer * renderer,
const SDL_FPoint * points,
int count);
/**
* \brief Draw a line on the current rendering target.
*
* \param renderer The renderer which should draw a line.
* \param x1 The x coordinate of the start point.
* \param y1 The y coordinate of the start point.
* \param x2 The x coordinate of the end point.
* \param y2 The y coordinate of the end point.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawLineF(SDL_Renderer * renderer,
float x1, float y1, float x2, float y2);
/**
* \brief Draw a series of connected lines on the current rendering target.
*
* \param renderer The renderer which should draw multiple lines.
* \param points The points along the lines
* \param count The number of points, drawing count-1 lines
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawLinesF(SDL_Renderer * renderer,
const SDL_FPoint * points,
int count);
/**
* \brief Draw a rectangle on the current rendering target.
*
* \param renderer The renderer which should draw a rectangle.
* \param rect A pointer to the destination rectangle, or NULL to outline the entire rendering target.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawRectF(SDL_Renderer * renderer,
const SDL_FRect * rect);
/**
* \brief Draw some number of rectangles on the current rendering target.
*
* \param renderer The renderer which should draw multiple rectangles.
* \param rects A pointer to an array of destination rectangles.
* \param count The number of rectangles.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderDrawRectsF(SDL_Renderer * renderer,
const SDL_FRect * rects,
int count);
/**
* \brief Fill a rectangle on the current rendering target with the drawing color.
*
* \param renderer The renderer which should fill a rectangle.
* \param rect A pointer to the destination rectangle, or NULL for the entire
* rendering target.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderFillRectF(SDL_Renderer * renderer,
const SDL_FRect * rect);
/**
* \brief Fill some number of rectangles on the current rendering target with the drawing color.
*
* \param renderer The renderer which should fill multiple rectangles.
* \param rects A pointer to an array of destination rectangles.
* \param count The number of rectangles.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderFillRectsF(SDL_Renderer * renderer,
const SDL_FRect * rects,
int count);
/**
* \brief Copy a portion of the texture to the current rendering target.
*
* \param renderer The renderer which should copy parts of a texture.
* \param texture The source texture.
* \param srcrect A pointer to the source rectangle, or NULL for the entire
* texture.
* \param dstrect A pointer to the destination rectangle, or NULL for the
* entire rendering target.
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderCopyF(SDL_Renderer * renderer,
SDL_Texture * texture,
const SDL_Rect * srcrect,
const SDL_FRect * dstrect);
/**
* \brief Copy a portion of the source texture to the current rendering target, rotating it by angle around the given center
*
* \param renderer The renderer which should copy parts of a texture.
* \param texture The source texture.
* \param srcrect A pointer to the source rectangle, or NULL for the entire
* texture.
* \param dstrect A pointer to the destination rectangle, or NULL for the
* entire rendering target.
* \param angle An angle in degrees that indicates the rotation that will be applied to dstrect, rotating it in a clockwise direction
* \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done around dstrect.w/2, dstrect.h/2).
* \param flip An SDL_RendererFlip value stating which flipping actions should be performed on the texture
*
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderCopyExF(SDL_Renderer * renderer,
SDL_Texture * texture,
const SDL_Rect * srcrect,
const SDL_FRect * dstrect,
const double angle,
const SDL_FPoint *center,
const SDL_RendererFlip flip);
/** /**
* \brief Read pixels from the current rendering target. * \brief Read pixels from the current rendering target.
* *
@@ -876,6 +1018,31 @@ extern DECLSPEC void SDLCALL SDL_DestroyTexture(SDL_Texture * texture);
*/ */
extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer * renderer); extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer * renderer);
/**
* \brief Force the rendering context to flush any pending commands to the
* underlying rendering API.
*
* You do not need to (and in fact, shouldn't) call this function unless
* you are planning to call into OpenGL/Direct3D/Metal/whatever directly
* in addition to using an SDL_Renderer.
*
* This is for a very-specific case: if you are using SDL's render API,
* you asked for a specific renderer backend (OpenGL, Direct3D, etc),
* you set SDL_HINT_RENDER_BATCHING to "1", and you plan to make
* OpenGL/D3D/whatever calls in addition to SDL render API calls. If all of
* this applies, you should call SDL_RenderFlush() between calls to SDL's
* render API and the low-level API you're using in cooperation.
*
* In all other cases, you can ignore this function. This is only here to
* get maximum performance out of a specific situation. In all other cases,
* SDL will do the right thing, perhaps at a performance loss.
*
* This function is first available in SDL 2.0.10, and is not needed in
* 2.0.9 and earlier, as earlier versions did not queue rendering commands
* at all, instead flushing them to the OS immediately.
*/
extern DECLSPEC int SDLCALL SDL_RenderFlush(SDL_Renderer * renderer);
/** /**
* \brief Bind the texture to the current OpenGL/ES/ES2 context for use with * \brief Bind the texture to the current OpenGL/ES/ES2 context for use with
@@ -1,2 +1,2 @@
#define SDL_REVISION "hg-0:aaaaaaaaaaah" #define SDL_REVISION "hg-12952:bc90ce38f1e2"
#define SDL_REVISION_NUMBER 0 #define SDL_REVISION_NUMBER 12952
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -176,19 +176,48 @@ extern DECLSPEC void SDLCALL SDL_FreeRW(SDL_RWops * area);
#define RW_SEEK_END 2 /**< Seek relative to the end of data */ #define RW_SEEK_END 2 /**< Seek relative to the end of data */
/** /**
* \name Read/write macros * Return the size of the file in this rwops, or -1 if unknown
*
* Macros to easily read and write from an SDL_RWops structure.
*/ */
/* @{ */ extern DECLSPEC Sint64 SDLCALL SDL_RWsize(SDL_RWops *context);
#define SDL_RWsize(ctx) (ctx)->size(ctx)
#define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence)
#define SDL_RWtell(ctx) (ctx)->seek(ctx, 0, RW_SEEK_CUR)
#define SDL_RWread(ctx, ptr, size, n) (ctx)->read(ctx, ptr, size, n)
#define SDL_RWwrite(ctx, ptr, size, n) (ctx)->write(ctx, ptr, size, n)
#define SDL_RWclose(ctx) (ctx)->close(ctx)
/* @} *//* Read/write macros */
/**
* Seek to \c offset relative to \c whence, one of stdio's whence values:
* RW_SEEK_SET, RW_SEEK_CUR, RW_SEEK_END
*
* \return the final offset in the data stream, or -1 on error.
*/
extern DECLSPEC Sint64 SDLCALL SDL_RWseek(SDL_RWops *context,
Sint64 offset, int whence);
/**
* Return the current offset in the data stream, or -1 on error.
*/
extern DECLSPEC Sint64 SDLCALL SDL_RWtell(SDL_RWops *context);
/**
* Read up to \c maxnum objects each of size \c size from the data
* stream to the area pointed at by \c ptr.
*
* \return the number of objects read, or 0 at error or end of file.
*/
extern DECLSPEC size_t SDLCALL SDL_RWread(SDL_RWops *context,
void *ptr, size_t size, size_t maxnum);
/**
* Write exactly \c num objects each of size \c size from the area
* pointed at by \c ptr to data stream.
*
* \return the number of objects written, or 0 at error or end of file.
*/
extern DECLSPEC size_t SDLCALL SDL_RWwrite(SDL_RWops *context,
const void *ptr, size_t size, size_t num);
/**
* Close and free an allocated SDL_RWops structure.
*
* \return 0 if successful or -1 on write error when flushing data.
*/
extern DECLSPEC int SDLCALL SDL_RWclose(SDL_RWops *context);
/** /**
* Load all the data from an SDL data stream. * Load all the data from an SDL data stream.
@@ -209,9 +238,17 @@ extern DECLSPEC void *SDLCALL SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize,
/** /**
* Load an entire file. * Load an entire file.
* *
* Convenience macro. * The data is allocated with a zero byte at the end (null terminated)
*
* If \c datasize is not NULL, it is filled with the size of the data read.
*
* If \c freesrc is non-zero, the stream will be closed after being read.
*
* The data should be freed with SDL_free().
*
* \return the data, or NULL if there was an error.
*/ */
#define SDL_LoadFile(file, datasize) SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1) extern DECLSPEC void *SDLCALL SDL_LoadFile(const char *file, size_t *datasize);
/** /**
* \name Read endian functions * \name Read endian functions
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -38,7 +38,7 @@
* SDL_Event structure. * SDL_Event structure.
* *
* The values in this enumeration are based on the USB usage page standard: * The values in this enumeration are based on the USB usage page standard:
* http://www.usb.org/developers/hidpage/Hut1_12v2.pdf * https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
*/ */
typedef enum typedef enum
{ {
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -26,8 +26,8 @@
* *
*/ */
#ifndef _SDL_sensor_h #ifndef SDL_sensor_h_
#define _SDL_sensor_h #define SDL_sensor_h_
#include "SDL_stdinc.h" #include "SDL_stdinc.h"
#include "SDL_error.h" #include "SDL_error.h"
@@ -246,6 +246,6 @@ extern DECLSPEC void SDLCALL SDL_SensorUpdate(void);
#endif #endif
#include "close_code.h" #include "close_code.h"
#endif /* _SDL_sensor_h */ #endif /* SDL_sensor_h_ */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -53,6 +53,7 @@ extern "C" {
#define SDL_PREALLOC 0x00000001 /**< Surface uses preallocated memory */ #define SDL_PREALLOC 0x00000001 /**< Surface uses preallocated memory */
#define SDL_RLEACCEL 0x00000002 /**< Surface is RLE encoded */ #define SDL_RLEACCEL 0x00000002 /**< Surface is RLE encoded */
#define SDL_DONTFREE 0x00000004 /**< Surface is referenced internally */ #define SDL_DONTFREE 0x00000004 /**< Surface is referenced internally */
#define SDL_SIMD_ALIGNED 0x00000008 /**< Surface uses aligned memory */
/* @} *//* Surface flags */ /* @} *//* Surface flags */
/** /**
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -34,16 +34,16 @@
#include "SDL_version.h" #include "SDL_version.h"
/** /**
* \file SDL_syswm.h * \brief SDL_syswm.h
* *
* Your application has access to a special type of event ::SDL_SYSWMEVENT, * Your application has access to a special type of event ::SDL_SYSWMEVENT,
* which contains window-manager specific information and arrives whenever * which contains window-manager specific information and arrives whenever
* an unhandled window event occurs. This event is ignored by default, but * an unhandled window event occurs. This event is ignored by default, but
* you can enable it with SDL_EventState(). * you can enable it with SDL_EventState().
*/ */
#ifdef SDL_PROTOTYPES_ONLY
struct SDL_SysWMinfo; struct SDL_SysWMinfo;
#else
#if !defined(SDL_PROTOTYPES_ONLY)
#if defined(SDL_VIDEO_DRIVER_WINDOWS) #if defined(SDL_VIDEO_DRIVER_WINDOWS)
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
@@ -103,6 +103,8 @@ typedef void *EGLSurface;
#if defined(SDL_VIDEO_DRIVER_VIVANTE) #if defined(SDL_VIDEO_DRIVER_VIVANTE)
#include "SDL_egl.h" #include "SDL_egl.h"
#endif #endif
#endif /* SDL_PROTOTYPES_ONLY */
#include "begin_code.h" #include "begin_code.h"
/* Set up for C function definitions, even when using C++ */ /* Set up for C function definitions, even when using C++ */
@@ -110,6 +112,7 @@ typedef void *EGLSurface;
extern "C" { extern "C" {
#endif #endif
#if !defined(SDL_PROTOTYPES_ONLY)
/** /**
* These are the various supported windowing subsystems * These are the various supported windowing subsystems
*/ */
@@ -122,7 +125,7 @@ typedef enum
SDL_SYSWM_COCOA, SDL_SYSWM_COCOA,
SDL_SYSWM_UIKIT, SDL_SYSWM_UIKIT,
SDL_SYSWM_WAYLAND, SDL_SYSWM_WAYLAND,
SDL_SYSWM_MIR, SDL_SYSWM_MIR, /* no longer available, left for API/ABI compatibility. Remove in 2.1! */
SDL_SYSWM_WINRT, SDL_SYSWM_WINRT,
SDL_SYSWM_ANDROID, SDL_SYSWM_ANDROID,
SDL_SYSWM_VIVANTE, SDL_SYSWM_VIVANTE,
@@ -257,11 +260,11 @@ struct SDL_SysWMinfo
struct wl_shell_surface *shell_surface; /**< Wayland shell_surface (window manager handle) */ struct wl_shell_surface *shell_surface; /**< Wayland shell_surface (window manager handle) */
} wl; } wl;
#endif #endif
#if defined(SDL_VIDEO_DRIVER_MIR) #if defined(SDL_VIDEO_DRIVER_MIR) /* no longer available, left for API/ABI compatibility. Remove in 2.1! */
struct struct
{ {
struct MirConnection *connection; /**< Mir display server connection */ void *connection; /**< Mir display server connection */
struct MirSurface *surface; /**< Mir surface */ void *surface; /**< Mir surface */
} mir; } mir;
#endif #endif
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -41,6 +41,14 @@ extern "C" {
typedef Sint64 SDL_TouchID; typedef Sint64 SDL_TouchID;
typedef Sint64 SDL_FingerID; typedef Sint64 SDL_FingerID;
typedef enum
{
SDL_TOUCH_DEVICE_INVALID = -1,
SDL_TOUCH_DEVICE_DIRECT, /* touch screen with window-relative coordinates */
SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE, /* trackpad with absolute device coordinates */
SDL_TOUCH_DEVICE_INDIRECT_RELATIVE /* trackpad with screen cursor-relative coordinates */
} SDL_TouchDeviceType;
typedef struct SDL_Finger typedef struct SDL_Finger
{ {
SDL_FingerID id; SDL_FingerID id;
@@ -52,6 +60,9 @@ typedef struct SDL_Finger
/* Used as the device ID for mouse events simulated with touch input */ /* Used as the device ID for mouse events simulated with touch input */
#define SDL_TOUCH_MOUSEID ((Uint32)-1) #define SDL_TOUCH_MOUSEID ((Uint32)-1)
/* Used as the SDL_TouchID for touch events simulated with mouse input */
#define SDL_MOUSE_TOUCHID ((Sint64)-1)
/* Function prototypes */ /* Function prototypes */
@@ -65,6 +76,11 @@ extern DECLSPEC int SDLCALL SDL_GetNumTouchDevices(void);
*/ */
extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index); extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index);
/**
* \brief Get the type of the given touch device.
*/
extern DECLSPEC SDL_TouchDeviceType SDLCALL SDL_GetTouchDeviceType(SDL_TouchID touchID);
/** /**
* \brief Get the number of active fingers for a given touch device. * \brief Get the number of active fingers for a given touch device.
*/ */
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ typedef struct SDL_version
*/ */
#define SDL_MAJOR_VERSION 2 #define SDL_MAJOR_VERSION 2
#define SDL_MINOR_VERSION 0 #define SDL_MINOR_VERSION 0
#define SDL_PATCHLEVEL 9 #define SDL_PATCHLEVEL 10
/** /**
* \brief Macro to determine SDL version program was compiled against. * \brief Macro to determine SDL version program was compiled against.
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -98,8 +98,8 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
* applications to link with libvulkan (and historically MoltenVK was * applications to link with libvulkan (and historically MoltenVK was
* provided as a static library). If it is not found then, on macOS, SDL * provided as a static library). If it is not found then, on macOS, SDL
* will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib, * will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
* \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order. * followed by \c libvulkan.dylib, in that order.
* On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications * On iOS SDL will attempt to load \c libvulkan.dylib only. Applications
* using a dynamic framework or .dylib must ensure it is included in its * using a dynamic framework or .dylib must ensure it is included in its
* application bundle. * application bundle.
* *
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -105,6 +105,9 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable: 4103) #pragma warning(disable: 4103)
#endif #endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpragma-pack"
#endif
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma nopackwarning #pragma nopackwarning
#endif #endif
@@ -1,6 +1,6 @@
/* /*
Simple DirectMedia Layer Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@@ -26,6 +26,9 @@
* after you finish any function and structure declarations in your headers * after you finish any function and structure declarations in your headers
*/ */
#ifndef _begin_code_h
#error close_code.h included without matching begin_code.h
#endif
#undef _begin_code_h #undef _begin_code_h
/* Reset structure packing at previous byte alignment */ /* Reset structure packing at previous byte alignment */
Loaded 100 of 286 files, more files were not shown because too many files have changed in this diff. Show more