mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-10-25 13:31:41 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5d8c3b7b5 |
No files matched your search
@@ -8,8 +8,6 @@
|
|||||||
<string>Moonlight</string>
|
<string>Moonlight</string>
|
||||||
<key>LSSupportsGameMode</key>
|
<key>LSSupportsGameMode</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSApplicationUpdateCycleEnabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>Stream games and other applications from another PC</string>
|
<string>Stream games and other applications from another PC</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
|
|||||||
+1
-1
Submodule app/SDL_GameControllerDB updated: 8d9fefd7b8...c1d5289a1f.
@@ -186,7 +186,7 @@ IdentityManager::getSslKey()
|
|||||||
|
|
||||||
BUF_MEM* mem;
|
BUF_MEM* mem;
|
||||||
BIO_get_mem_ptr(bio, &mem);
|
BIO_get_mem_ptr(bio, &mem);
|
||||||
m_CachedSslKey = QSslKey(QByteArray(mem->data, (int)mem->length), getSslCertificate().publicKey().algorithm());
|
m_CachedSslKey = QSslKey(QByteArray(mem->data, (int)mem->length), QSsl::Rsa);
|
||||||
|
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
EVP_PKEY_free(pk);
|
EVP_PKEY_free(pk);
|
||||||
|
|||||||
+4
-38
@@ -507,47 +507,23 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||||||
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
|
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
|
||||||
// Use fine-grained idle timeouts to avoid calling QNetworkAccessManager::clearAccessCache(),
|
// Use fine-grained idle timeouts to avoid calling QNetworkAccessManager::clearAccessCache(),
|
||||||
// which tears down the NAM's global thread each time. We must not keep persistent connections
|
// which tears down the NAM's global thread each time. We must not keep persistent connections
|
||||||
// or GFE will puke.
|
// or GFE will puke.
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0)
|
|
||||||
request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, -1);
|
|
||||||
#elif QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
|
|
||||||
request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, 0);
|
request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto sslErrorsConnection = connect(m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
|
auto sslErrorsConnection = connect(m_Nam, &QNetworkAccessManager::sslErrors, this, &NvHTTP::handleSslErrors);
|
||||||
QNetworkReply* reply = m_Nam->get(request);
|
QNetworkReply* reply = m_Nam->get(request);
|
||||||
QEventLoop loop;
|
|
||||||
|
|
||||||
// Connect the quit signals
|
// Run the request with a timeout if requested
|
||||||
|
QEventLoop loop;
|
||||||
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, &loop, &QEventLoop::quit);
|
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, &loop, &QEventLoop::quit);
|
||||||
|
|
||||||
// Enforce a transfer timeout if requested
|
|
||||||
if (timeoutMs) {
|
if (timeoutMs) {
|
||||||
QTimer::singleShot(timeoutMs, &loop, &QEventLoop::quit);
|
QTimer::singleShot(timeoutMs, &loop, &QEventLoop::quit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
|
|
||||||
// Time the request to distinguish a slow response from an unreachable host
|
|
||||||
auto* connectTimer = new QTimer(reply);
|
|
||||||
connectTimer->setSingleShot(true);
|
|
||||||
connect(connectTimer, &QTimer::timeout, reply, [reply, logLevel, url]() {
|
|
||||||
if (!reply->isFinished()) {
|
|
||||||
if (logLevel >= NvLogLevel::NVLL_ERROR) {
|
|
||||||
qWarning() << "Aborting timed out connection for" << url.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
reply->setProperty("timeout_reason", "connection_timeout");
|
|
||||||
reply->abort();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
connect(reply, &QNetworkReply::requestSent, connectTimer, &QTimer::stop);
|
|
||||||
connectTimer->start(REQUEST_TIMEOUT_MS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (logLevel >= NvLogLevel::NVLL_VERBOSE) {
|
if (logLevel >= NvLogLevel::NVLL_VERBOSE) {
|
||||||
qInfo() << "Executing request:" << url.toString();
|
qInfo() << "Executing request:" << url.toString();
|
||||||
}
|
}
|
||||||
@@ -583,11 +559,7 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
else if (reply->error() == QNetworkReply::OperationCanceledError) {
|
else if (reply->error() == QNetworkReply::OperationCanceledError) {
|
||||||
QString reason = reply->property("timeout_reason").toString();
|
QtNetworkReplyException exception(QNetworkReply::TimeoutError, "Request timed out");
|
||||||
QtNetworkReplyException exception(QNetworkReply::TimeoutError,
|
|
||||||
reason == "connection_timeout" ?
|
|
||||||
"Connection timed out" :
|
|
||||||
"Request timed out");
|
|
||||||
delete reply;
|
delete reply;
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
@@ -598,11 +570,5 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
|
|
||||||
// The requestSent signal must have stopped the timer for any successful request,
|
|
||||||
// otherwise we could falsely time out a slow response when we connected fine.
|
|
||||||
Q_ASSERT(!connectTimer->isActive());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
@@ -140,9 +140,6 @@ NvPairingManager::getSignatureFromPemCert(const QByteArray& certificate)
|
|||||||
|
|
||||||
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
if (cert == nullptr) {
|
|
||||||
return QByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray signature = getSignatureFromCert(cert);
|
QByteArray signature = getSignatureFromCert(cert);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
@@ -162,15 +159,9 @@ NvPairingManager::verifySignature(const QByteArray& data, const QByteArray& sign
|
|||||||
|
|
||||||
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
if (cert == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVP_PKEY* pubKey = X509_get_pubkey(cert);
|
EVP_PKEY* pubKey = X509_get_pubkey(cert);
|
||||||
if (pubKey == nullptr) {
|
THROW_BAD_ALLOC_IF_NULL(pubKey);
|
||||||
X509_free(cert);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
|
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
|
||||||
THROW_BAD_ALLOC_IF_NULL(mdctx);
|
THROW_BAD_ALLOC_IF_NULL(mdctx);
|
||||||
@@ -215,7 +206,7 @@ NvPairingManager::saltPin(const QByteArray& salt, QString pin)
|
|||||||
NvPairingManager::PairState
|
NvPairingManager::PairState
|
||||||
NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverCert)
|
NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverCert)
|
||||||
{
|
{
|
||||||
int serverMajorVersion = NvHTTP::parseQuad(appVersion).value(0);
|
int serverMajorVersion = NvHTTP::parseQuad(appVersion).at(0);
|
||||||
qInfo() << "Pairing with server generation:" << serverMajorVersion;
|
qInfo() << "Pairing with server generation:" << serverMajorVersion;
|
||||||
|
|
||||||
QCryptographicHash::Algorithm hashAlgo;
|
QCryptographicHash::Algorithm hashAlgo;
|
||||||
@@ -287,7 +278,7 @@ NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverC
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray challengeResponseData = decrypt(m_Http.getXmlStringFromHex(challengeXml, "challengeresponse"), aesKey);
|
QByteArray challengeResponseData = decrypt(m_Http.getXmlStringFromHex(challengeXml, "challengeresponse"), aesKey);
|
||||||
if (challengeResponseData.size() < hashLength + 16) {
|
if (challengeResponseData.size() < hashLength) {
|
||||||
qCritical() << "Invalid challengeresponse at stage #2";
|
qCritical() << "Invalid challengeresponse at stage #2";
|
||||||
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, REQUEST_TIMEOUT_MS);
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, REQUEST_TIMEOUT_MS);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
|
|||||||
+28
-36
@@ -51,7 +51,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display any modal dialogs for configuration warnings
|
// Display any modal dialogs for configuration warnings
|
||||||
if (isGuiLaunch) {
|
if (runConfigChecks) {
|
||||||
if (SystemProperties.isWow64) {
|
if (SystemProperties.isWow64) {
|
||||||
wow64Dialog.open()
|
wow64Dialog.open()
|
||||||
}
|
}
|
||||||
@@ -171,28 +171,24 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
// Polling is only managed from the window for a normal GUI launch;
|
// When we become invisible while streaming is going on,
|
||||||
// CLI commands (stream/quit/pair) manage it via the ComputerSeeker.
|
// stop polling immediately.
|
||||||
if (isGuiLaunch) {
|
if (!visible) {
|
||||||
// When we become invisible while streaming is going on,
|
inactivityTimer.stop()
|
||||||
// stop polling immediately.
|
|
||||||
if (!visible) {
|
|
||||||
inactivityTimer.stop()
|
|
||||||
|
|
||||||
if (pollingActive) {
|
if (pollingActive) {
|
||||||
ComputerManager.stopPollingAsync()
|
ComputerManager.stopPollingAsync()
|
||||||
pollingActive = false
|
pollingActive = false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (active) {
|
}
|
||||||
// When we become visible and active again, start polling
|
else if (active) {
|
||||||
inactivityTimer.stop()
|
// When we become visible and active again, start polling
|
||||||
|
inactivityTimer.stop()
|
||||||
|
|
||||||
// Restart polling if it was stopped
|
// Restart polling if it was stopped
|
||||||
if (!pollingActive) {
|
if (!pollingActive) {
|
||||||
ComputerManager.startPolling()
|
ComputerManager.startPolling()
|
||||||
pollingActive = true
|
pollingActive = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,25 +197,21 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
// Polling is only managed from the window for a normal GUI launch;
|
if (active) {
|
||||||
// CLI commands (stream/quit/pair) manage it via the ComputerSeeker.
|
// Stop the inactivity timer
|
||||||
if (isGuiLaunch) {
|
inactivityTimer.stop()
|
||||||
if (active) {
|
|
||||||
// Stop the inactivity timer
|
|
||||||
inactivityTimer.stop()
|
|
||||||
|
|
||||||
// Restart polling if it was stopped
|
// Restart polling if it was stopped
|
||||||
if (!pollingActive) {
|
if (!pollingActive) {
|
||||||
ComputerManager.startPolling()
|
ComputerManager.startPolling()
|
||||||
pollingActive = true
|
pollingActive = true
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Start the inactivity timer to stop polling
|
|
||||||
// if focus does not return within a few minutes.
|
|
||||||
inactivityTimer.restart()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Start the inactivity timer to stop polling
|
||||||
|
// if focus does not return within a few minutes.
|
||||||
|
inactivityTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
// Poll for gamepad input only when the window is in focus
|
// Poll for gamepad input only when the window is in focus
|
||||||
SdlGamepadKeyNavigation.notifyWindowFocus(visible && active)
|
SdlGamepadKeyNavigation.notifyWindowFocus(visible && active)
|
||||||
|
|||||||
+2
-11
@@ -465,16 +465,7 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
|
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
|
||||||
|
if (s_LoggerFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
// The log directory may be shared with other users (/tmp on macOS), so
|
|
||||||
// we must never open a file or symlink that someone else planted there.
|
|
||||||
// NewOnly fails if anything already exists at this path.
|
|
||||||
QIODevice::OpenMode logOpenMode = QIODevice::WriteOnly | QIODevice::Text | QIODevice::NewOnly;
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
|
|
||||||
if (s_LoggerFile->open(logOpenMode, QFileDevice::ReadOwner | QFileDevice::WriteOwner)) {
|
|
||||||
#else
|
|
||||||
if (s_LoggerFile->open(logOpenMode)) {
|
|
||||||
#endif
|
|
||||||
QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
|
QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
|
||||||
s_LoggerStream.setDevice(s_LoggerFile);
|
s_LoggerStream.setDevice(s_LoggerFile);
|
||||||
}
|
}
|
||||||
@@ -1043,7 +1034,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (hasGUI) {
|
if (hasGUI) {
|
||||||
engine.rootContext()->setContextProperty("initialView", initialView);
|
engine.rootContext()->setContextProperty("initialView", initialView);
|
||||||
engine.rootContext()->setContextProperty("isGuiLaunch", commandLineParserResult == GlobalCommandLineParser::NormalStartRequested);
|
engine.rootContext()->setContextProperty("runConfigChecks", commandLineParserResult == GlobalCommandLineParser::NormalStartRequested);
|
||||||
|
|
||||||
// Load the main.qml file
|
// Load the main.qml file
|
||||||
engine.load(QUrl(QStringLiteral("qrc:/gui/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:/gui/main.qml")));
|
||||||
|
|||||||
@@ -965,7 +965,7 @@ void SdlInputHandler::setAdaptiveTriggers(uint16_t controllerNumber, DualSenseOu
|
|||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 16)
|
#if SDL_VERSION_ATLEAST(2, 0, 16)
|
||||||
// Make sure the controller number is within our supported count
|
// Make sure the controller number is within our supported count
|
||||||
if (controllerNumber < MAX_GAMEPADS &&
|
if (controllerNumber <= MAX_GAMEPADS &&
|
||||||
// and we have a valid controller
|
// and we have a valid controller
|
||||||
m_GamepadState[controllerNumber].controller != nullptr &&
|
m_GamepadState[controllerNumber].controller != nullptr &&
|
||||||
// and it's a PS5 controller
|
// and it's a PS5 controller
|
||||||
|
|||||||
+21
-34
@@ -840,8 +840,9 @@ bool Session::initialize(QQuickWindow* qtWindow)
|
|||||||
// to allow decoding via VideoToolbox on macOS. Since we don't
|
// to allow decoding via VideoToolbox on macOS. Since we don't
|
||||||
// have fixup code for HEVC, just avoid it if GFE is too old.
|
// have fixup code for HEVC, just avoid it if GFE is too old.
|
||||||
QVector<int> gfeVersion = NvHTTP::parseQuad(m_Computer->gfeVersion);
|
QVector<int> gfeVersion = NvHTTP::parseQuad(m_Computer->gfeVersion);
|
||||||
if (gfeVersion.value(0) < 3 ||
|
if (gfeVersion.isEmpty() || // Very old versions don't have GfeVersion at all
|
||||||
(gfeVersion.value(0) == 3 && gfeVersion.value(1) < 11)) {
|
gfeVersion[0] < 3 ||
|
||||||
|
(gfeVersion[0] == 3 && gfeVersion[1] < 11)) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Disabling HEVC on macOS due to old GFE version");
|
"Disabling HEVC on macOS due to old GFE version");
|
||||||
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_H265);
|
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_H265);
|
||||||
@@ -1362,48 +1363,34 @@ void Session::getWindowDimensions(int& x, int& y,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the usable display bounds
|
|
||||||
SDL_Rect usableBounds;
|
SDL_Rect usableBounds;
|
||||||
if (SDL_GetDisplayUsableBounds(displayIndex, &usableBounds) != 0) {
|
if (SDL_GetDisplayUsableBounds(displayIndex, &usableBounds) == 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
// If the stream resolution fits within the usable display area, use it directly
|
||||||
"SDL_GetDisplayUsableBounds() failed: %s",
|
if (m_StreamConfig.width <= usableBounds.w &&
|
||||||
SDL_GetError());
|
|
||||||
SDL_zero(usableBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the usable display bounds if they are valid
|
|
||||||
if (usableBounds.w != 0 &&
|
|
||||||
WMUtils::hasDisplayUsableBounds() &&
|
|
||||||
m_StreamConfig.width <= usableBounds.w &&
|
|
||||||
m_StreamConfig.height <= usableBounds.h) {
|
m_StreamConfig.height <= usableBounds.h) {
|
||||||
// We fit pixel-perfect in the usable area, so don't scale at all
|
width = m_StreamConfig.width;
|
||||||
width = m_StreamConfig.width;
|
height = m_StreamConfig.height;
|
||||||
height = m_StreamConfig.height;
|
} else {
|
||||||
}
|
// Otherwise, use 80% of usable bounds and preserve aspect ratio
|
||||||
else if (usableBounds.w != 0 || SDL_GetDisplayBounds(displayIndex, &usableBounds) == 0) {
|
SDL_Rect src, dst;
|
||||||
// Otherwise, use 80% of usable bounds and preserve aspect ratio
|
src.x = src.y = dst.x = dst.y = 0;
|
||||||
SDL_Rect src, dst;
|
src.w = m_StreamConfig.width;
|
||||||
src.x = src.y = dst.x = dst.y = 0;
|
src.h = m_StreamConfig.height;
|
||||||
src.w = m_StreamConfig.width;
|
|
||||||
src.h = m_StreamConfig.height;
|
|
||||||
|
|
||||||
dst.w = ((int)(usableBounds.w * 0.80f)) & ~0x1; // even width
|
dst.w = ((int)(usableBounds.w * 0.80f)) & ~0x1; // even width
|
||||||
dst.h = ((int)(usableBounds.h * 0.80f)) & ~0x1; // even height
|
dst.h = ((int)(usableBounds.h * 0.80f)) & ~0x1; // even height
|
||||||
|
|
||||||
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||||
|
|
||||||
// Only scale the size down, never up
|
|
||||||
if (m_StreamConfig.width >= dst.w || m_StreamConfig.height >= dst.h) {
|
|
||||||
width = dst.w;
|
width = dst.w;
|
||||||
height = dst.h;
|
height = dst.h;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
width = m_StreamConfig.width;
|
|
||||||
height = m_StreamConfig.height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Oh well, hope for the best
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_GetDisplayUsableBounds() failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
|
||||||
width = m_StreamConfig.width;
|
width = m_StreamConfig.width;
|
||||||
height = m_StreamConfig.height;
|
height = m_StreamConfig.height;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include <asm/hwprobe.h>
|
#include <asm/hwprobe.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#else
|
#else
|
||||||
|
#define __NR_riscv_hwprobe 258
|
||||||
struct riscv_hwprobe {
|
struct riscv_hwprobe {
|
||||||
int64_t key;
|
int64_t key;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
@@ -45,10 +46,6 @@ struct riscv_hwprobe {
|
|||||||
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
|
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __NR_riscv_hwprobe
|
|
||||||
#define __NR_riscv_hwprobe 258
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// RISC-V Scalar AES [E]ncryption and [D]ecryption
|
// RISC-V Scalar AES [E]ncryption and [D]ecryption
|
||||||
#ifndef RISCV_HWPROBE_EXT_ZKND
|
#ifndef RISCV_HWPROBE_EXT_ZKND
|
||||||
#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
|
#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ D3D11VARenderer::D3D11VARenderer(int decoderSelectionPass)
|
|||||||
m_DecoderSelectionPass(decoderSelectionPass),
|
m_DecoderSelectionPass(decoderSelectionPass),
|
||||||
m_DevicesWithFL11Support(0),
|
m_DevicesWithFL11Support(0),
|
||||||
m_DevicesWithCodecSupport(0),
|
m_DevicesWithCodecSupport(0),
|
||||||
m_SwapChainColorTrc(AVCOL_TRC_UNSPECIFIED),
|
m_LastColorTrc(AVCOL_TRC_UNSPECIFIED),
|
||||||
m_AllowTearing(false),
|
m_AllowTearing(false),
|
||||||
m_OverlayLock(0),
|
m_OverlayLock(0),
|
||||||
m_HwDeviceContext(nullptr)
|
m_HwDeviceContext(nullptr)
|
||||||
@@ -800,7 +800,7 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
|
|||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (frame->color_trc != m_SwapChainColorTrc) {
|
if (frame->color_trc != m_LastColorTrc) {
|
||||||
if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
|
if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
|
||||||
// Switch to Rec 2020 PQ (SMPTE ST 2084) colorspace for HDR10 rendering
|
// Switch to Rec 2020 PQ (SMPTE ST 2084) colorspace for HDR10 rendering
|
||||||
hr = m_SwapChain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
|
hr = m_SwapChain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
|
||||||
@@ -820,7 +820,7 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_SwapChainColorTrc = frame->color_trc;
|
m_LastColorTrc = frame->color_trc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present according to the decoder parameters
|
// Present according to the decoder parameters
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ private:
|
|||||||
DXGI_FORMAT m_TextureFormat;
|
DXGI_FORMAT m_TextureFormat;
|
||||||
int m_DisplayWidth;
|
int m_DisplayWidth;
|
||||||
int m_DisplayHeight;
|
int m_DisplayHeight;
|
||||||
AVColorTransferCharacteristic m_SwapChainColorTrc;
|
AVColorTransferCharacteristic m_LastColorTrc;
|
||||||
|
|
||||||
bool m_AllowTearing;
|
bool m_AllowTearing;
|
||||||
|
|
||||||
|
|||||||
@@ -1307,7 +1307,7 @@ bool DrmRenderer::mapDumbBuffer(uint32_t handle, size_t size, void** mapping)
|
|||||||
#else
|
#else
|
||||||
*mapping = mmap(nullptr, size, PROT_WRITE, MAP_SHARED, m_DrmFd, mapBuf.offset);
|
*mapping = mmap(nullptr, size, PROT_WRITE, MAP_SHARED, m_DrmFd, mapBuf.offset);
|
||||||
#endif
|
#endif
|
||||||
if (*mapping == MAP_FAILED) {
|
if (mapping == MAP_FAILED) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"mmap() failed for dumb buffer: %d",
|
"mmap() failed for dumb buffer: %d",
|
||||||
errno);
|
errno);
|
||||||
|
|||||||
@@ -426,13 +426,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
|
|||||||
|
|
||||||
D3DDISPLAYMODEEX currentMode;
|
D3DDISPLAYMODEEX currentMode;
|
||||||
currentMode.Size = sizeof(currentMode);
|
currentMode.Size = sizeof(currentMode);
|
||||||
hr = d3d9ex->GetAdapterDisplayModeEx(adapterIndex, ¤tMode, nullptr);
|
d3d9ex->GetAdapterDisplayModeEx(adapterIndex, ¤tMode, nullptr);
|
||||||
if (FAILED(hr)) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"GetAdapterDisplayModeEx() failed: %x",
|
|
||||||
hr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp = {};
|
D3DPRESENT_PARAMETERS d3dpp = {};
|
||||||
d3dpp.hDeviceWindow = info.info.win.window;
|
d3dpp.hDeviceWindow = info.info.win.window;
|
||||||
@@ -993,7 +987,6 @@ void DXVA2Renderer::renderFrame(AVFrame *frame)
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"StretchRect() failed: %x",
|
"StretchRect() failed: %x",
|
||||||
hr);
|
hr);
|
||||||
m_Device->EndScene();
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
event.type = SDL_RENDER_DEVICE_RESET;
|
event.type = SDL_RENDER_DEVICE_RESET;
|
||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, EGLDisplay dpy, EGLImag
|
|||||||
else {
|
else {
|
||||||
// Cast the EGLAttrib array elements to EGLint for the KHR extension
|
// Cast the EGLAttrib array elements to EGLint for the KHR extension
|
||||||
EGLint intAttribs[MAX_ATTRIB_COUNT];
|
EGLint intAttribs[MAX_ATTRIB_COUNT];
|
||||||
for (int i = 0; i < attribIndex; i++) {
|
for (int i = 0; i < MAX_ATTRIB_COUNT; i++) {
|
||||||
intAttribs[i] = (EGLint)attribs[i];
|
intAttribs[i] = (EGLint)attribs[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +328,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
|||||||
attribs[attribIndex++] = layer.offset[0];
|
attribs[attribIndex++] = layer.offset[0];
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
|
||||||
attribs[attribIndex++] = layer.pitch[0];
|
attribs[attribIndex++] = layer.pitch[0];
|
||||||
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
|
if (m_EGLExtDmaBuf) {
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
|
||||||
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
|
||||||
@@ -343,7 +343,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
|||||||
attribs[attribIndex++] = layer.offset[1];
|
attribs[attribIndex++] = layer.offset[1];
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
|
||||||
attribs[attribIndex++] = layer.pitch[1];
|
attribs[attribIndex++] = layer.pitch[1];
|
||||||
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
|
if (m_EGLExtDmaBuf) {
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
|
||||||
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
|
||||||
@@ -358,7 +358,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
|||||||
attribs[attribIndex++] = layer.offset[2];
|
attribs[attribIndex++] = layer.offset[2];
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
|
||||||
attribs[attribIndex++] = layer.pitch[2];
|
attribs[attribIndex++] = layer.pitch[2];
|
||||||
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
|
if (m_EGLExtDmaBuf) {
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
|
||||||
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
|
||||||
@@ -373,7 +373,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
|||||||
attribs[attribIndex++] = layer.offset[3];
|
attribs[attribIndex++] = layer.offset[3];
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
|
||||||
attribs[attribIndex++] = layer.pitch[3];
|
attribs[attribIndex++] = layer.pitch[3];
|
||||||
if (m_EGLExtDmaBuf && object.drm_format_modifier != DRM_FORMAT_MOD_INVALID) {
|
if (m_EGLExtDmaBuf) {
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
|
||||||
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
attribs[attribIndex++] = (EGLint)(object.drm_format_modifier & 0xFFFFFFFF);
|
||||||
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
|
attribs[attribIndex++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ EGLRenderer::EGLRenderer(IFFmpegRenderer *backendRenderer)
|
|||||||
m_Window(nullptr),
|
m_Window(nullptr),
|
||||||
m_Backend(backendRenderer),
|
m_Backend(backendRenderer),
|
||||||
m_VideoVAO(0),
|
m_VideoVAO(0),
|
||||||
m_VideoVBO(0),
|
|
||||||
m_BlockingSwapBuffers(false),
|
m_BlockingSwapBuffers(false),
|
||||||
m_LastRenderSync(EGL_NO_SYNC),
|
m_LastRenderSync(EGL_NO_SYNC),
|
||||||
m_glEGLImageTargetTexture2DOES(nullptr),
|
m_glEGLImageTargetTexture2DOES(nullptr),
|
||||||
@@ -101,7 +100,6 @@ EGLRenderer::~EGLRenderer()
|
|||||||
SDL_assert(m_glDeleteVertexArraysOES != nullptr);
|
SDL_assert(m_glDeleteVertexArraysOES != nullptr);
|
||||||
m_glDeleteVertexArraysOES(1, &m_VideoVAO);
|
m_glDeleteVertexArraysOES(1, &m_VideoVAO);
|
||||||
}
|
}
|
||||||
glDeleteBuffers(1, &m_VideoVBO);
|
|
||||||
glDeleteTextures(EGL_MAX_PLANES, m_Textures);
|
glDeleteTextures(EGL_MAX_PLANES, m_Textures);
|
||||||
|
|
||||||
glDeleteTextures(Overlay::OverlayMax, m_OverlayTextures);
|
glDeleteTextures(Overlay::OverlayMax, m_OverlayTextures);
|
||||||
@@ -268,9 +266,10 @@ void EGLRenderer::renderOverlay(Overlay::OverlayType type, int viewportWidth, in
|
|||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint EGLRenderer::loadAndBuildShader(int shaderType, const char *file) {
|
int EGLRenderer::loadAndBuildShader(int shaderType,
|
||||||
|
const char *file) {
|
||||||
GLuint shader = glCreateShader(shaderType);
|
GLuint shader = glCreateShader(shaderType);
|
||||||
if (!shader) {
|
if (!shader || shader == GL_INVALID_ENUM) {
|
||||||
EGL_LOG(Error, "Can't create shader: %d", glGetError());
|
EGL_LOG(Error, "Can't create shader: %d", glGetError());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -287,7 +286,6 @@ GLuint EGLRenderer::loadAndBuildShader(int shaderType, const char *file) {
|
|||||||
char shaderLog[512];
|
char shaderLog[512];
|
||||||
glGetShaderInfoLog(shader, sizeof (shaderLog), nullptr, shaderLog);
|
glGetShaderInfoLog(shader, sizeof (shaderLog), nullptr, shaderLog);
|
||||||
EGL_LOG(Error, "Cannot load shader \"%s\": %s", file, shaderLog);
|
EGL_LOG(Error, "Cannot load shader \"%s\": %s", file, shaderLog);
|
||||||
glDeleteShader(shader);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +297,7 @@ unsigned EGLRenderer::compileShader(const char* vertexShaderSrc, const char* fra
|
|||||||
|
|
||||||
GLuint vertexShader = loadAndBuildShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
GLuint vertexShader = loadAndBuildShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
||||||
if (!vertexShader)
|
if (!vertexShader)
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
GLuint fragmentShader = loadAndBuildShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
|
GLuint fragmentShader = loadAndBuildShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
|
||||||
if (!fragmentShader)
|
if (!fragmentShader)
|
||||||
@@ -647,12 +645,13 @@ bool EGLRenderer::setupVideoRenderingState() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Setup the VAO and VBO
|
// Setup the VAO and VBO
|
||||||
|
unsigned int VBO;
|
||||||
m_glGenVertexArraysOES(1, &m_VideoVAO);
|
m_glGenVertexArraysOES(1, &m_VideoVAO);
|
||||||
glGenBuffers(1, &m_VideoVBO);
|
glGenBuffers(1, &VBO);
|
||||||
|
|
||||||
m_glBindVertexArrayOES(m_VideoVAO);
|
m_glBindVertexArrayOES(m_VideoVAO);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_VideoVBO);
|
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
// compileShader() ensures that aPosition and aTexCoord are indexes 0 and 1 respectively
|
// compileShader() ensures that aPosition and aTexCoord are indexes 0 and 1 respectively
|
||||||
@@ -664,8 +663,7 @@ bool EGLRenderer::setupVideoRenderingState() {
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
m_glBindVertexArrayOES(0);
|
m_glBindVertexArrayOES(0);
|
||||||
|
|
||||||
// The VBO is kept alive as a member since the VAO still references it.
|
glDeleteBuffers(1, &VBO);
|
||||||
// It is deleted in ~EGLRenderer() alongside the other GL resources.
|
|
||||||
|
|
||||||
GLenum err = glGetError();
|
GLenum err = glGetError();
|
||||||
if (err != GL_NO_ERROR) {
|
if (err != GL_NO_ERROR) {
|
||||||
@@ -789,7 +787,7 @@ void EGLRenderer::renderFrame(AVFrame* frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssize_t plane_count = m_Backend->exportEGLImages(frame, m_EGLDisplay, imgs);
|
ssize_t plane_count = m_Backend->exportEGLImages(frame, m_EGLDisplay, imgs);
|
||||||
if (plane_count <= 0)
|
if (plane_count < 0)
|
||||||
return;
|
return;
|
||||||
for (ssize_t i = 0; i < plane_count; ++i) {
|
for (ssize_t i = 0; i < plane_count; ++i) {
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ private:
|
|||||||
bool compileShaders();
|
bool compileShaders();
|
||||||
bool setupVideoRenderingState();
|
bool setupVideoRenderingState();
|
||||||
bool setupOverlayRenderingState();
|
bool setupOverlayRenderingState();
|
||||||
static GLuint loadAndBuildShader(int shaderType, const char *filename);
|
static int loadAndBuildShader(int shaderType, const char *filename);
|
||||||
|
|
||||||
AVPixelFormat m_EGLImagePixelFormat;
|
AVPixelFormat m_EGLImagePixelFormat;
|
||||||
void *m_EGLDisplay;
|
void *m_EGLDisplay;
|
||||||
@@ -44,7 +44,6 @@ private:
|
|||||||
SDL_Window *m_Window;
|
SDL_Window *m_Window;
|
||||||
IFFmpegRenderer *m_Backend;
|
IFFmpegRenderer *m_Backend;
|
||||||
unsigned int m_VideoVAO;
|
unsigned int m_VideoVAO;
|
||||||
unsigned int m_VideoVBO;
|
|
||||||
bool m_BlockingSwapBuffers;
|
bool m_BlockingSwapBuffers;
|
||||||
EGLSync m_LastRenderSync;
|
EGLSync m_LastRenderSync;
|
||||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES;
|
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ DxVsyncSource::DxVsyncSource(Pacer* pacer) :
|
|||||||
m_LastMonitor(nullptr)
|
m_LastMonitor(nullptr)
|
||||||
{
|
{
|
||||||
SDL_zero(m_WaitForVblankEventParams);
|
SDL_zero(m_WaitForVblankEventParams);
|
||||||
m_WaitForVblankEventParams.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
|
|
||||||
SDL_zero(m_AdapterLuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DxVsyncSource::~DxVsyncSource()
|
DxVsyncSource::~DxVsyncSource()
|
||||||
@@ -74,43 +72,41 @@ bool DxVsyncSource::isAsync()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DxVsyncSource::waitForVsync()
|
void DxVsyncSource::waitForVsync()
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
// If the monitor has changed from last time, open the new adapter
|
// If the monitor has changed from last time, open the new adapter
|
||||||
HMONITOR currentMonitor = MonitorFromWindow(m_Window, MONITOR_DEFAULTTONEAREST);
|
HMONITOR currentMonitor = MonitorFromWindow(m_Window, MONITOR_DEFAULTTONEAREST);
|
||||||
if (!currentMonitor || currentMonitor != m_LastMonitor) {
|
if (currentMonitor != m_LastMonitor) {
|
||||||
// Close the old adapter
|
|
||||||
if (m_WaitForVblankEventParams.hAdapter != 0) {
|
|
||||||
D3DKMT_CLOSEADAPTER closeAdapterParams = {};
|
|
||||||
closeAdapterParams.hAdapter = m_WaitForVblankEventParams.hAdapter;
|
|
||||||
m_D3DKMTCloseAdapter(&closeAdapterParams);
|
|
||||||
m_WaitForVblankEventParams.hAdapter = 0;
|
|
||||||
}
|
|
||||||
m_LastMonitor = nullptr;
|
|
||||||
|
|
||||||
// We can't wait if we're not on any monitor
|
|
||||||
if (!currentMonitor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MONITORINFOEXA monitorInfo = {};
|
MONITORINFOEXA monitorInfo = {};
|
||||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||||
if (!GetMonitorInfoA(currentMonitor, &monitorInfo)) {
|
if (!GetMonitorInfoA(currentMonitor, &monitorInfo)) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"GetMonitorInfo() failed: %d",
|
"GetMonitorInfo() failed: %d",
|
||||||
GetLastError());
|
GetLastError());
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEVMODEA monitorMode = {};
|
DEVMODEA monitorMode;
|
||||||
monitorMode.dmSize = sizeof(monitorMode);
|
monitorMode.dmSize = sizeof(monitorMode);
|
||||||
if (!EnumDisplaySettingsA(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &monitorMode)) {
|
if (!EnumDisplaySettingsA(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &monitorMode)) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"EnumDisplaySettings() failed: %d",
|
"EnumDisplaySettings() failed: %d",
|
||||||
GetLastError());
|
GetLastError());
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Monitor changed: %s %d Hz",
|
||||||
|
monitorInfo.szDevice,
|
||||||
|
monitorMode.dmDisplayFrequency);
|
||||||
|
|
||||||
|
// Close the old adapter
|
||||||
|
if (m_WaitForVblankEventParams.hAdapter != 0) {
|
||||||
|
D3DKMT_CLOSEADAPTER closeAdapterParams = {};
|
||||||
|
closeAdapterParams.hAdapter = m_WaitForVblankEventParams.hAdapter;
|
||||||
|
m_D3DKMTCloseAdapter(&closeAdapterParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DKMT_OPENADAPTERFROMHDC openAdapterParams = {};
|
D3DKMT_OPENADAPTERFROMHDC openAdapterParams = {};
|
||||||
@@ -119,7 +115,7 @@ bool DxVsyncSource::waitForVsync()
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"CreateDC() failed: %d",
|
"CreateDC() failed: %d",
|
||||||
GetLastError());
|
GetLastError());
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the new adapter
|
// Open the new adapter
|
||||||
@@ -130,38 +126,21 @@ bool DxVsyncSource::waitForVsync()
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"D3DKMTOpenAdapterFromHdc() failed: %x",
|
"D3DKMTOpenAdapterFromHdc() failed: %x",
|
||||||
status);
|
status);
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// VidPnSourceId is scoped to the adapter, so we must also check the adapter LUID
|
|
||||||
if (m_AdapterLuid.LowPart != openAdapterParams.AdapterLuid.LowPart ||
|
|
||||||
m_AdapterLuid.HighPart != openAdapterParams.AdapterLuid.HighPart ||
|
|
||||||
m_WaitForVblankEventParams.VidPnSourceId != openAdapterParams.VidPnSourceId) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Monitor changed: %s %d Hz",
|
|
||||||
monitorInfo.szDevice,
|
|
||||||
monitorMode.dmDisplayFrequency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_WaitForVblankEventParams.hAdapter = openAdapterParams.hAdapter;
|
m_WaitForVblankEventParams.hAdapter = openAdapterParams.hAdapter;
|
||||||
m_WaitForVblankEventParams.hDevice = 0;
|
m_WaitForVblankEventParams.hDevice = 0;
|
||||||
m_WaitForVblankEventParams.VidPnSourceId = openAdapterParams.VidPnSourceId;
|
m_WaitForVblankEventParams.VidPnSourceId = openAdapterParams.VidPnSourceId;
|
||||||
|
|
||||||
m_AdapterLuid = openAdapterParams.AdapterLuid;
|
|
||||||
m_LastMonitor = currentMonitor;
|
m_LastMonitor = currentMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = m_D3DKMTWaitForVerticalBlankEvent(&m_WaitForVblankEventParams);
|
status = m_D3DKMTWaitForVerticalBlankEvent(&m_WaitForVblankEventParams);
|
||||||
if (status != STATUS_SUCCESS) {
|
if (status != STATUS_SUCCESS) {
|
||||||
if (status != STATUS_GRAPHICS_PRESENT_OCCLUDED) {
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
"D3DKMTWaitForVerticalBlankEvent() failed: %x",
|
||||||
"D3DKMTWaitForVerticalBlankEvent() failed: %x",
|
status);
|
||||||
status);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
m_LastMonitor = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,6 @@ typedef UINT D3DKMT_HANDLE;
|
|||||||
typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
|
typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
|
||||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||||
#define STATUS_GRAPHICS_PRESENT_OCCLUDED ((NTSTATUS)0xC01E0006L)
|
#define STATUS_GRAPHICS_PRESENT_OCCLUDED ((NTSTATUS)0xC01E0006L)
|
||||||
#define D3DDDI_ID_UNINITIALIZED (UINT)(~0)
|
|
||||||
typedef struct _D3DKMT_OPENADAPTERFROMHDC {
|
typedef struct _D3DKMT_OPENADAPTERFROMHDC {
|
||||||
HDC hDc;
|
HDC hDc;
|
||||||
D3DKMT_HANDLE hAdapter;
|
D3DKMT_HANDLE hAdapter;
|
||||||
@@ -40,14 +39,13 @@ public:
|
|||||||
|
|
||||||
virtual bool isAsync() override;
|
virtual bool isAsync() override;
|
||||||
|
|
||||||
virtual bool waitForVsync() override;
|
virtual void waitForVsync() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pacer* m_Pacer;
|
Pacer* m_Pacer;
|
||||||
HMODULE m_Gdi32Handle;
|
HMODULE m_Gdi32Handle;
|
||||||
HWND m_Window;
|
HWND m_Window;
|
||||||
HMONITOR m_LastMonitor;
|
HMONITOR m_LastMonitor;
|
||||||
LUID m_AdapterLuid;
|
|
||||||
D3DKMT_WAITFORVERTICALBLANKEVENT m_WaitForVblankEventParams;
|
D3DKMT_WAITFORVERTICALBLANKEVENT m_WaitForVblankEventParams;
|
||||||
|
|
||||||
PFND3DKMTOPENADAPTERFROMHDC m_D3DKMTOpenAdapterFromHdc;
|
PFND3DKMTOPENADAPTERFROMHDC m_D3DKMTOpenAdapterFromHdc;
|
||||||
|
|||||||
@@ -115,20 +115,13 @@ int Pacer::vsyncThread(void *context)
|
|||||||
while (!me->m_Stopping) {
|
while (!me->m_Stopping) {
|
||||||
if (async) {
|
if (async) {
|
||||||
// Wait for the VSync source to invoke signalVsync() or 100ms to elapse
|
// Wait for the VSync source to invoke signalVsync() or 100ms to elapse
|
||||||
QMutexLocker locker(&me->m_FrameQueueLock);
|
me->m_FrameQueueLock.lock();
|
||||||
me->m_VsyncSignalled.wait(&me->m_FrameQueueLock, 100);
|
me->m_VsyncSignalled.wait(&me->m_FrameQueueLock, 100);
|
||||||
|
me->m_FrameQueueLock.unlock();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Let the VSync source wait in the context of our thread
|
// Let the VSync source wait in the context of our thread
|
||||||
if (!me->m_VsyncSource->waitForVsync()) {
|
me->m_VsyncSource->waitForVsync();
|
||||||
// Fall back to a fixed delay if the VSync source fails
|
|
||||||
//
|
|
||||||
// NB: We don't actually expect signalVsync() to be called, since
|
|
||||||
// this is a synchronous VSync source, but we wait on m_VsyncSignalled
|
|
||||||
// anyway so that the destructor can immediately wake us on shutdown.
|
|
||||||
QMutexLocker locker(&me->m_FrameQueueLock);
|
|
||||||
me->m_VsyncSignalled.wait(&me->m_FrameQueueLock, 1000 / me->m_DisplayFps);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me->m_Stopping) {
|
if (me->m_Stopping) {
|
||||||
@@ -155,25 +148,24 @@ int Pacer::renderThread(void* context)
|
|||||||
// Wait for the renderer to be ready for the next frame
|
// Wait for the renderer to be ready for the next frame
|
||||||
me->m_VsyncRenderer->waitToRender();
|
me->m_VsyncRenderer->waitToRender();
|
||||||
|
|
||||||
AVFrame* frame;
|
// Acquire the frame queue lock to protect the queue and
|
||||||
{
|
// the not empty condition
|
||||||
// Acquire the frame queue lock to protect the queue and
|
me->m_FrameQueueLock.lock();
|
||||||
// the not empty condition
|
|
||||||
QMutexLocker locker(&me->m_FrameQueueLock);
|
|
||||||
|
|
||||||
// Wait for a frame to be ready to render
|
// Wait for a frame to be ready to render
|
||||||
while (!me->m_Stopping && me->m_RenderQueue.isEmpty()) {
|
while (!me->m_Stopping && me->m_RenderQueue.isEmpty()) {
|
||||||
me->m_RenderQueueNotEmpty.wait(&me->m_FrameQueueLock);
|
me->m_RenderQueueNotEmpty.wait(&me->m_FrameQueueLock);
|
||||||
}
|
|
||||||
|
|
||||||
if (me->m_Stopping) {
|
|
||||||
// Exit this thread
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame = me->m_RenderQueue.dequeue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (me->m_Stopping) {
|
||||||
|
// Exit this thread
|
||||||
|
me->m_FrameQueueLock.unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVFrame* frame = me->m_RenderQueue.dequeue();
|
||||||
|
me->m_FrameQueueLock.unlock();
|
||||||
|
|
||||||
me->renderFrame(frame);
|
me->renderFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +249,7 @@ void Pacer::handleVsync(int timeUntilNextVsyncMillis)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Stopping || m_PacingQueue.isEmpty()) {
|
if (m_Stopping) {
|
||||||
m_FrameQueueLock.unlock();
|
m_FrameQueueLock.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -357,7 +349,7 @@ void Pacer::renderFrame(AVFrame* frame)
|
|||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
|
||||||
// Drop frames if we have too many queued up for a while
|
// Drop frames if we have too many queued up for a while
|
||||||
QMutexLocker frameQueueLocker(&m_FrameQueueLock);
|
m_FrameQueueLock.lock();
|
||||||
|
|
||||||
int frameDropTarget;
|
int frameDropTarget;
|
||||||
|
|
||||||
@@ -390,11 +382,13 @@ void Pacer::renderFrame(AVFrame* frame)
|
|||||||
AVFrame* frame = m_RenderQueue.dequeue();
|
AVFrame* frame = m_RenderQueue.dequeue();
|
||||||
|
|
||||||
// Drop the lock while we call av_frame_free()
|
// Drop the lock while we call av_frame_free()
|
||||||
frameQueueLocker.unlock();
|
m_FrameQueueLock.unlock();
|
||||||
m_VideoStats->pacerDroppedFrames++;
|
m_VideoStats->pacerDroppedFrames++;
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
frameQueueLocker.relock();
|
m_FrameQueueLock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_FrameQueueLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pacer::dropFrameForEnqueue(QQueue<AVFrame*>& queue)
|
void Pacer::dropFrameForEnqueue(QQueue<AVFrame*>& queue)
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ public:
|
|||||||
// sources require calls to waitForVsync().
|
// sources require calls to waitForVsync().
|
||||||
virtual bool isAsync() = 0;
|
virtual bool isAsync() = 0;
|
||||||
|
|
||||||
virtual bool waitForVsync() {
|
virtual void waitForVsync() {
|
||||||
// Synchronous sources must implement waitForVsync()!
|
// Synchronous sources must implement waitForVsync()!
|
||||||
SDL_assert(false);
|
SDL_assert(false);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -769,7 +769,6 @@ bool PlVkRenderer::populateQueues(int videoFormat)
|
|||||||
vkDeviceContext->nb_comp_queues = m_Vulkan->queue_compute.count;
|
vkDeviceContext->nb_comp_queues = m_Vulkan->queue_compute.count;
|
||||||
|
|
||||||
// Select a video decode queue that is capable of decoding our chosen format
|
// Select a video decode queue that is capable of decoding our chosen format
|
||||||
vkDeviceContext->queue_family_decode_index = -1;
|
|
||||||
for (uint32_t i = 0; i < queueFamilyCount; i++) {
|
for (uint32_t i = 0; i < queueFamilyCount; i++) {
|
||||||
if (queueFamilies[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
|
if (queueFamilies[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
|
||||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
@@ -898,16 +897,6 @@ void PlVkRenderer::waitToRender()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a swapchain (re)creation failed, m_Swapchain is NULL. We can't render
|
|
||||||
// or resize it, and a device reset has already been requested, so skip this
|
|
||||||
// frame and let the main thread recreate the renderer.
|
|
||||||
if (m_Swapchain == nullptr) {
|
|
||||||
SDL_Event event;
|
|
||||||
event.type = SDL_RENDER_DEVICE_RESET;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef Q_OS_WIN32
|
#ifndef Q_OS_WIN32
|
||||||
// With libplacebo's Vulkan backend, all swap_buffers does is wait for queued
|
// With libplacebo's Vulkan backend, all swap_buffers does is wait for queued
|
||||||
// presents to finish. This happens to be exactly what we want to do here, since
|
// presents to finish. This happens to be exactly what we want to do here, since
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InitFailureReason m_InitFailureReason = InitFailureReason::Unknown;
|
InitFailureReason m_InitFailureReason;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RendererType m_Type;
|
RendererType m_Type;
|
||||||
|
|||||||
@@ -21,10 +21,8 @@
|
|||||||
VAAPIRenderer::VAAPIRenderer(int decoderSelectionPass)
|
VAAPIRenderer::VAAPIRenderer(int decoderSelectionPass)
|
||||||
: IFFmpegRenderer(RendererType::VAAPI),
|
: IFFmpegRenderer(RendererType::VAAPI),
|
||||||
m_DecoderSelectionPass(decoderSelectionPass),
|
m_DecoderSelectionPass(decoderSelectionPass),
|
||||||
m_WindowSystem(SDL_SYSWM_UNKNOWN),
|
|
||||||
m_HwContext(nullptr),
|
m_HwContext(nullptr),
|
||||||
m_BlacklistedForDirectRendering(false),
|
m_BlacklistedForDirectRendering(false),
|
||||||
m_HasRfiLatencyBug(false),
|
|
||||||
m_RequiresExplicitPixelFormat(false),
|
m_RequiresExplicitPixelFormat(false),
|
||||||
m_OverlayMutex(nullptr)
|
m_OverlayMutex(nullptr)
|
||||||
#ifdef HAVE_EGL
|
#ifdef HAVE_EGL
|
||||||
@@ -161,9 +159,6 @@ VAAPIRenderer::openDisplay(SDL_Window* window)
|
|||||||
errno);
|
errno);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// This FD is owned by us (not shared with SDL), so it must be
|
|
||||||
// closed when we're done with it or adopted into m_DrmFd.
|
|
||||||
mustCloseFd = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the KMSDRM FD is not a render node FD, open the render node for libva to use.
|
// If the KMSDRM FD is not a render node FD, open the render node for libva to use.
|
||||||
|
|||||||
@@ -541,12 +541,11 @@ void VDPAURenderer::renderFrame(AVFrame* frame)
|
|||||||
// We need to create the mixer on the fly, because we don't know the dimensions
|
// We need to create the mixer on the fly, because we don't know the dimensions
|
||||||
// of our video surfaces in advance of decoding. We also need to recreate it when
|
// of our video surfaces in advance of decoding. We also need to recreate it when
|
||||||
// the frame format or size changes.
|
// the frame format or size changes.
|
||||||
if (hasFrameFormatChanged(frame) && m_VideoMixer != 0) {
|
if (hasFrameFormatChanged(frame)) {
|
||||||
m_VdpVideoMixerDestroy(m_VideoMixer);
|
if (m_VideoMixer != 0) {
|
||||||
m_VideoMixer = 0;
|
m_VdpVideoMixerDestroy(m_VideoMixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_VideoMixer == 0) {
|
|
||||||
VdpChromaType videoSurfaceChroma;
|
VdpChromaType videoSurfaceChroma;
|
||||||
uint32_t videoSurfaceWidth, videoSurfaceHeight;
|
uint32_t videoSurfaceWidth, videoSurfaceHeight;
|
||||||
status = m_VdpVideoSurfaceGetParameters(videoSurface, &videoSurfaceChroma,
|
status = m_VdpVideoSurfaceGetParameters(videoSurface, &videoSurfaceChroma,
|
||||||
@@ -581,7 +580,6 @@ void VDPAURenderer::renderFrame(AVFrame* frame)
|
|||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"VdpVideoMixerCreate() failed: %s",
|
"VdpVideoMixerCreate() failed: %s",
|
||||||
m_VdpGetErrorString(status));
|
m_VdpGetErrorString(status));
|
||||||
m_VideoMixer = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1765,21 +1765,11 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
|
|||||||
int nalStart, nalEnd;
|
int nalStart, nalEnd;
|
||||||
bool needsFixup;
|
bool needsFixup;
|
||||||
|
|
||||||
// Find the old SPS NALU
|
// Read the old NALU
|
||||||
if (find_nal_unit((uint8_t*)entry->data, entry->length, &nalStart, &nalEnd) <= 0) {
|
find_nal_unit((uint8_t*)entry->data, entry->length, &nalStart, &nalEnd);
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
read_nal_unit(stream,
|
||||||
"Failed to find SPS");
|
(unsigned char *)&entry->data[nalStart],
|
||||||
h264_free(stream);
|
nalEnd - nalStart);
|
||||||
goto WriteUnmodifiedBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the SPS. Pass it through unmodified if we fail to parse it.
|
|
||||||
if (read_nal_unit(stream, (uint8_t*)&entry->data[nalStart], nalEnd - nalStart) < 0) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to read SPS");
|
|
||||||
h264_free(stream);
|
|
||||||
goto WriteUnmodifiedBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_assert(nalStart == 3 || nalStart == 4); // 3 or 4 byte Annex B start sequence
|
SDL_assert(nalStart == 3 || nalStart == 4); // 3 or 4 byte Annex B start sequence
|
||||||
SDL_assert(nalEnd == entry->length);
|
SDL_assert(nalEnd == entry->length);
|
||||||
@@ -1812,18 +1802,8 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
|
|||||||
|
|
||||||
// Copy the modified NALU data. This clobbers byte 0 and starts NALU data at byte 1.
|
// Copy the modified NALU data. This clobbers byte 0 and starts NALU data at byte 1.
|
||||||
// Since it prepended one extra byte, subtract one from the returned length.
|
// Since it prepended one extra byte, subtract one from the returned length.
|
||||||
//
|
offset += write_nal_unit(stream, (uint8_t*)&m_DecodeBuffer.data()[initialOffset + nalStart - 1],
|
||||||
// Pass the SPS through unmodified if the write fails.
|
MAX_SPS_EXTRA_SIZE + entry->length - nalStart) - 1;
|
||||||
int writeLength = write_nal_unit(stream, (uint8_t*)&m_DecodeBuffer.data()[initialOffset + nalStart - 1],
|
|
||||||
MAX_SPS_EXTRA_SIZE + entry->length - nalStart);
|
|
||||||
if (writeLength < 0) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to write modified SPS");
|
|
||||||
h264_free(stream);
|
|
||||||
goto WriteUnmodifiedBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += writeLength - 1;
|
|
||||||
|
|
||||||
// Copy the NALU prefix over from the original SPS
|
// Copy the NALU prefix over from the original SPS
|
||||||
memcpy(&m_DecodeBuffer.data()[initialOffset], entry->data, nalStart);
|
memcpy(&m_DecodeBuffer.data()[initialOffset], entry->data, nalStart);
|
||||||
@@ -1854,7 +1834,6 @@ void FFmpegVideoDecoder::writeBuffer(PLENTRY entry, int& offset)
|
|||||||
h264_free(stream);
|
h264_free(stream);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
WriteUnmodifiedBuffer:
|
|
||||||
// Write the buffer as-is
|
// Write the buffer as-is
|
||||||
memcpy(&m_DecodeBuffer.data()[offset],
|
memcpy(&m_DecodeBuffer.data()[offset],
|
||||||
entry->data,
|
entry->data,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ namespace WMUtils {
|
|||||||
bool isRunningWayland();
|
bool isRunningWayland();
|
||||||
bool isRunningWindowManager();
|
bool isRunningWindowManager();
|
||||||
bool isRunningDesktopEnvironment();
|
bool isRunningDesktopEnvironment();
|
||||||
bool hasDisplayUsableBounds();
|
|
||||||
QString getDrmCardOverride();
|
QString getDrmCardOverride();
|
||||||
bool isGpuSlow();
|
bool isGpuSlow();
|
||||||
}
|
}
|
||||||
|
|||||||
-46
@@ -205,52 +205,6 @@ bool WMUtils::isRunningDesktopEnvironment()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMUtils::hasDisplayUsableBounds()
|
|
||||||
{
|
|
||||||
static SDL_atomic_t hasDisplayUsableBounds;
|
|
||||||
|
|
||||||
// If the value is not set yet, populate it now.
|
|
||||||
int val = SDL_AtomicGet(&hasDisplayUsableBounds);
|
|
||||||
if (!(val & VALUE_SET)) {
|
|
||||||
int numDisplays = SDL_GetNumVideoDisplays();
|
|
||||||
bool hasUsableBounds = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < numDisplays; i++) {
|
|
||||||
SDL_Rect displayBounds;
|
|
||||||
SDL_Rect usableBounds;
|
|
||||||
|
|
||||||
if (SDL_GetDisplayBounds(i, &displayBounds) != 0) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"SDL_GetDisplayBounds(%d) failed: %s",
|
|
||||||
i, SDL_GetError());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SDL_GetDisplayUsableBounds(i, &usableBounds) != 0) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"SDL_GetDisplayUsableBounds(%d) failed: %s",
|
|
||||||
i, SDL_GetError());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If at least one display has usable bounds that differ from the
|
|
||||||
// complete bounds, we assume that usable bounds are accurate.
|
|
||||||
if (!SDL_RectEquals(&displayBounds, &usableBounds)) {
|
|
||||||
hasUsableBounds = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate the value to return and have for next time.
|
|
||||||
// This can race with another thread populating the same data,
|
|
||||||
// but that's no big deal.
|
|
||||||
val = VALUE_SET | (hasUsableBounds ? VALUE_TRUE : 0);
|
|
||||||
SDL_AtomicSet(&hasDisplayUsableBounds, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!(val & VALUE_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WMUtils::isGpuSlow()
|
bool WMUtils::isGpuSlow()
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|||||||
+7
-31
@@ -1,25 +1,3 @@
|
|||||||
/*
|
|
||||||
* h264bitstream - a library for reading and writing H.264 video
|
|
||||||
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
|
|
||||||
* Copyright (C) 2008-2011 Avail-TVN
|
|
||||||
*
|
|
||||||
* Written by Alex Izvorski <aizvorski@gmail.com> and Alex Giladi <alex.giladi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H264_BS_H
|
#ifndef _H264_BS_H
|
||||||
#define _H264_BS_H 1
|
#define _H264_BS_H 1
|
||||||
|
|
||||||
@@ -101,7 +79,7 @@ static inline int bs_eof(bs_t* b) { if (b->p >= b->end) { return 1; } else { ret
|
|||||||
|
|
||||||
static inline int bs_overrun(bs_t* b) { if (b->p > b->end) { return 1; } else { return 0; } }
|
static inline int bs_overrun(bs_t* b) { if (b->p > b->end) { return 1; } else { return 0; } }
|
||||||
|
|
||||||
static inline int bs_pos(bs_t* b) { if (b->p > b->end) { return (int)(b->end - b->start); } else { return (int)(b->p - b->start); } }
|
static inline int bs_pos(bs_t* b) { if (b->p > b->end) { return (b->end - b->start); } else { return (b->p - b->start); } }
|
||||||
|
|
||||||
static inline uint32_t bs_read_u1(bs_t* b)
|
static inline uint32_t bs_read_u1(bs_t* b)
|
||||||
{
|
{
|
||||||
@@ -178,18 +156,16 @@ static inline uint32_t bs_read_ue(bs_t* b)
|
|||||||
|
|
||||||
static inline int32_t bs_read_se(bs_t* b)
|
static inline int32_t bs_read_se(bs_t* b)
|
||||||
{
|
{
|
||||||
// Do the math in unsigned space. bs_read_ue() can return values above
|
int32_t r = bs_read_ue(b);
|
||||||
// INT32_MAX, and (r+1)/2 on a signed INT32_MAX is undefined behavior.
|
|
||||||
// bs_read_ue() returns at most 0xFFFFFFFE, so both results fit in int32_t.
|
|
||||||
uint32_t r = bs_read_ue(b);
|
|
||||||
if (r & 0x01)
|
if (r & 0x01)
|
||||||
{
|
{
|
||||||
return (int32_t)((r >> 1) + 1);
|
r = (r+1)/2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -(int32_t)(r >> 1);
|
r = -(r/2);
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bs_write_u1(bs_t* b, uint32_t v)
|
static inline void bs_write_u1(bs_t* b, uint32_t v)
|
||||||
@@ -210,7 +186,7 @@ static inline void bs_write_u(bs_t* b, int n, uint32_t v)
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
bs_write_u1(b, (n - i - 1 >= 32) ? 0 : ((v >> ( n - i - 1 ))&0x01) );
|
bs_write_u1(b, (v >> ( n - i - 1 ))&0x01 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +195,7 @@ static inline void bs_write_u8(bs_t* b, uint32_t v)
|
|||||||
#ifdef FAST_U8
|
#ifdef FAST_U8
|
||||||
if (b->bits_left == 8 && ! bs_eof(b)) // can do fast write
|
if (b->bits_left == 8 && ! bs_eof(b)) // can do fast write
|
||||||
{
|
{
|
||||||
b->p[0] = (uint8_t)v;
|
b->p[0] = v;
|
||||||
b->p++;
|
b->p++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,3 @@
|
|||||||
/*
|
|
||||||
* h264bitstream - a library for reading and writing H.264 video
|
|
||||||
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
|
|
||||||
* Copyright (C) 2008-2011 Avail-TVN
|
|
||||||
*
|
|
||||||
* Written by Alex Izvorski <aizvorski@gmail.com> and Alex Giladi <alex.giladi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,3 @@
|
|||||||
/*
|
|
||||||
* h264bitstream - a library for reading and writing H.264 video
|
|
||||||
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
|
|
||||||
* Copyright (C) 2008-2011 Avail-TVN
|
|
||||||
* Copyright (C) 2012 Alex Izvorski
|
|
||||||
*
|
|
||||||
* Written by Alex Izvorski <aizvorski@gmail.com> and Alex Giladi <alex.giladi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -384,11 +361,6 @@ void write_seq_parameter_set_rbsp(sps_t* sps, bs_t* b)
|
|||||||
}
|
}
|
||||||
else if( sps->pic_order_cnt_type == 1 )
|
else if( sps->pic_order_cnt_type == 1 )
|
||||||
{
|
{
|
||||||
if (sps->num_ref_frames_in_pic_order_cnt_cycle > 256)
|
|
||||||
{
|
|
||||||
sps->num_ref_frames_in_pic_order_cnt_cycle = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
bs_write_u1(b, sps->delta_pic_order_always_zero_flag);
|
bs_write_u1(b, sps->delta_pic_order_always_zero_flag);
|
||||||
bs_write_se(b, sps->offset_for_non_ref_pic);
|
bs_write_se(b, sps->offset_for_non_ref_pic);
|
||||||
bs_write_se(b, sps->offset_for_top_to_bottom_field);
|
bs_write_se(b, sps->offset_for_top_to_bottom_field);
|
||||||
@@ -534,11 +506,6 @@ void write_vui_parameters(sps_t* sps, bs_t* b)
|
|||||||
|
|
||||||
void write_hrd_parameters(hrd_t* hrd, bs_t* b)
|
void write_hrd_parameters(hrd_t* hrd, bs_t* b)
|
||||||
{
|
{
|
||||||
if (hrd->cpb_cnt_minus1 > 31)
|
|
||||||
{
|
|
||||||
hrd->cpb_cnt_minus1 = 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
bs_write_ue(b, hrd->cpb_cnt_minus1);
|
bs_write_ue(b, hrd->cpb_cnt_minus1);
|
||||||
bs_write_u(b, 4, hrd->bit_rate_scale);
|
bs_write_u(b, 4, hrd->bit_rate_scale);
|
||||||
bs_write_u(b, 4, hrd->cpb_size_scale);
|
bs_write_u(b, 4, hrd->cpb_size_scale);
|
||||||
|
|||||||
@@ -1,25 +1,3 @@
|
|||||||
/*
|
|
||||||
* h264bitstream - a library for reading and writing H.264 video
|
|
||||||
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
|
|
||||||
* Copyright (C) 2008-2011 Avail-TVN
|
|
||||||
*
|
|
||||||
* Written by Alex Izvorski <aizvorski@gmail.com> and Alex Giladi <alex.giladi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _H264_STREAM_H
|
#ifndef _H264_STREAM_H
|
||||||
#define _H264_STREAM_H 1
|
#define _H264_STREAM_H 1
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ TEMPLATE = lib
|
|||||||
# Build a static library
|
# Build a static library
|
||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
|
|
||||||
|
# Disable warnings
|
||||||
|
CONFIG += warn_off
|
||||||
|
|
||||||
# Include global qmake defs
|
# Include global qmake defs
|
||||||
include(../globaldefs.pri)
|
include(../globaldefs.pri)
|
||||||
|
|
||||||
|
|||||||
Submodule moonlight-common-c/moonlight-common-c updated: 04053843c9...f900dd4767.
@@ -250,7 +250,7 @@ if not x%QT_PATH:\5.=%==x%QT_PATH% (
|
|||||||
set WINDEPLOYQT_ARGS=--no-qmltooling --no-virtualkeyboard
|
set WINDEPLOYQT_ARGS=--no-qmltooling --no-virtualkeyboard
|
||||||
) else (
|
) else (
|
||||||
rem Qt 6.8+
|
rem Qt 6.8+
|
||||||
set WINDEPLOYQT_ARGS=--no-system-d3d-compiler --no-system-dxc-compiler --skip-plugin-types qmltooling,generic --no-ffmpeg --force-openssl
|
set WINDEPLOYQT_ARGS=--no-system-d3d-compiler --no-system-dxc-compiler --skip-plugin-types qmltooling,generic --no-ffmpeg
|
||||||
set WINDEPLOYQT_ARGS=!WINDEPLOYQT_ARGS! --no-quickcontrols2fusion --no-quickcontrols2imagine --no-quickcontrols2universal
|
set WINDEPLOYQT_ARGS=!WINDEPLOYQT_ARGS! --no-quickcontrols2fusion --no-quickcontrols2imagine --no-quickcontrols2universal
|
||||||
set WINDEPLOYQT_ARGS=!WINDEPLOYQT_ARGS! --no-quickcontrols2fusionstyleimpl --no-quickcontrols2imaginestyleimpl --no-quickcontrols2universalstyleimpl --no-quickcontrols2windowsstyleimpl --no-quickcontrols2fluentwinui3styleimpl
|
set WINDEPLOYQT_ARGS=!WINDEPLOYQT_ARGS! --no-quickcontrols2fusionstyleimpl --no-quickcontrols2imaginestyleimpl --no-quickcontrols2universalstyleimpl --no-quickcontrols2windowsstyleimpl --no-quickcontrols2fluentwinui3styleimpl
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user