mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 15:15:46 +00:00
Compare commits
5 commits
f9381aac2e
...
f4d2560e1e
Author | SHA1 | Date | |
---|---|---|---|
|
f4d2560e1e | ||
|
d42d379733 | ||
|
7cb8a1acd3 | ||
|
1a35aef644 | ||
|
2aab37b516 |
16 changed files with 158 additions and 81 deletions
|
@ -467,7 +467,7 @@ if (ENABLE_QT)
|
||||||
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
|
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent Core5Compat)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent)
|
||||||
|
|
||||||
if (YUZU_USE_QT_MULTIMEDIA)
|
if (YUZU_USE_QT_MULTIMEDIA)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
|
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
|
||||||
|
|
|
@ -20,7 +20,6 @@ function(copy_yuzu_Qt6_deps target_dir)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
windows_copy_files(${target_dir} ${Qt6_DLL_DIR} ${DLL_DEST}
|
windows_copy_files(${target_dir} ${Qt6_DLL_DIR} ${DLL_DEST}
|
||||||
Qt6Core$<$<CONFIG:Debug>:d>.*
|
Qt6Core$<$<CONFIG:Debug>:d>.*
|
||||||
Qt6Core5Compat$<$<CONFIG:Debug>:d>.*
|
|
||||||
Qt6Gui$<$<CONFIG:Debug>:d>.*
|
Qt6Gui$<$<CONFIG:Debug>:d>.*
|
||||||
Qt6Widgets$<$<CONFIG:Debug>:d>.*
|
Qt6Widgets$<$<CONFIG:Debug>:d>.*
|
||||||
Qt6Network$<$<CONFIG:Debug>:d>.*
|
Qt6Network$<$<CONFIG:Debug>:d>.*
|
||||||
|
|
|
@ -133,7 +133,7 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
|
||||||
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
|
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
|
||||||
else()
|
else()
|
||||||
set(prefix "${base_path}/${target}/${arch_path}")
|
set(prefix "${base_path}/${target}/${arch_path}")
|
||||||
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt5compat)
|
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
|
||||||
|
|
||||||
if (YUZU_USE_QT_MULTIMEDIA)
|
if (YUZU_USE_QT_MULTIMEDIA)
|
||||||
set(install_args ${install_args} qtmultimedia)
|
set(install_args ${install_args} qtmultimedia)
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.yuzu.yuzu_emu.databinding.ItemBanListBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
|
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
|
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
|
import org.yuzu.yuzu_emu.network.NetDataValidators
|
||||||
import org.yuzu.yuzu_emu.network.NetPlayManager
|
import org.yuzu.yuzu_emu.network.NetPlayManager
|
||||||
import org.yuzu.yuzu_emu.utils.CompatUtils
|
import org.yuzu.yuzu_emu.utils.CompatUtils
|
||||||
import org.yuzu.yuzu_emu.utils.GameHelper
|
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||||
|
@ -102,8 +103,16 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
btnLobbyBrowser.setOnClickListener {
|
btnLobbyBrowser.setOnClickListener {
|
||||||
LobbyBrowser(context).show()
|
if (!NetDataValidators.username()) {
|
||||||
dismiss()
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
R.string.multiplayer_nickname_invalid,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
} else {
|
||||||
|
LobbyBrowser(context).show()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,7 +377,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.length in 3..20
|
return NetDataValidators.roomName(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +387,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.getString(R.string.multiplayer_required)
|
context.getString(R.string.multiplayer_required)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.isNotEmpty()
|
return NetDataValidators.notEmpty(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,12 +397,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.getString(R.string.multiplayer_token_required)
|
context.getString(R.string.multiplayer_token_required)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
if (s != context.getString(R.string.multiplayer_public_visibility)) {
|
return NetDataValidators.roomVisibility(s, context)
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
val token = StringSetting.WEB_TOKEN.getString()
|
|
||||||
return token.matches(Regex("[a-z]{48}"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,12 +407,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.getString(R.string.multiplayer_ip_error)
|
context.getString(R.string.multiplayer_ip_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return try {
|
return NetDataValidators.ipAddress(s)
|
||||||
InetAddress.getByName(s)
|
|
||||||
s.length >= 7
|
|
||||||
} catch (_: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +417,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.getString(R.string.multiplayer_username_error)
|
context.getString(R.string.multiplayer_username_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.length in 4..20
|
return NetDataValidators.username(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +427,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.getString(R.string.multiplayer_port_error)
|
context.getString(R.string.multiplayer_port_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.toIntOrNull() in 1..65535
|
return NetDataValidators.port(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
|
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
|
import org.yuzu.yuzu_emu.network.NetDataValidators
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
|
@ -300,9 +301,7 @@ abstract class SettingsItem(
|
||||||
val chars = "abcdefghijklmnopqrstuvwxyz"
|
val chars = "abcdefghijklmnopqrstuvwxyz"
|
||||||
(1..48).map { chars.random() }.joinToString("")
|
(1..48).map { chars.random() }.joinToString("")
|
||||||
},
|
},
|
||||||
validator = { s ->
|
validator = NetDataValidators::token,
|
||||||
s?.matches(Regex("[a-z]{48}")) == true
|
|
||||||
},
|
|
||||||
errorId = R.string.multiplayer_token_error
|
errorId = R.string.multiplayer_token_error
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -312,9 +311,7 @@ abstract class SettingsItem(
|
||||||
StringSetting.WEB_USERNAME,
|
StringSetting.WEB_USERNAME,
|
||||||
titleId = R.string.web_username,
|
titleId = R.string.web_username,
|
||||||
descriptionId = R.string.web_username_description,
|
descriptionId = R.string.web_username_description,
|
||||||
validator = { s ->
|
validator = NetDataValidators::username,
|
||||||
s?.length in 4..20
|
|
||||||
},
|
|
||||||
errorId = R.string.multiplayer_username_error
|
errorId = R.string.multiplayer_username_error
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -154,8 +154,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
stringInputBinding.generate.setOnClickListener {
|
stringInputBinding.generate.setOnClickListener {
|
||||||
stringInputBinding.editText.setText(onGenerate())
|
stringInputBinding.editText.setText(onGenerate())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
stringInputBinding.generate.isVisible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val validator = item.validator
|
val validator = item.validator
|
||||||
|
@ -179,8 +177,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable?) {
|
override fun afterTextChanged(s: Editable?) {
|
||||||
stringInputBinding.editText.error =
|
val isValid = validator(s.toString())
|
||||||
if (validator(s.toString())) null else requireContext().getString(item.errorId)
|
stringInputBinding.editTextLayout.isErrorEnabled = !isValid
|
||||||
|
stringInputBinding.editTextLayout.error = if (isValid) null else requireContext().getString(item.errorId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
|
import java.net.InetAddress
|
||||||
|
|
||||||
|
object NetDataValidators {
|
||||||
|
fun roomName(s: String): Boolean {
|
||||||
|
return s.length in 3..20
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notEmpty(s: String): Boolean {
|
||||||
|
return s.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun token(s: String?): Boolean {
|
||||||
|
return s?.matches(Regex("[a-z]{48}")) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun token(): Boolean {
|
||||||
|
return token(StringSetting.WEB_TOKEN.getString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun roomVisibility(s: String, context: Context): Boolean {
|
||||||
|
if (s != context.getString(R.string.multiplayer_public_visibility)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ipAddress(s: String): Boolean {
|
||||||
|
return try {
|
||||||
|
InetAddress.getByName(s)
|
||||||
|
s.length >= 7
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun username(s: String?): Boolean {
|
||||||
|
return s?.matches(Regex("^[ a-zA-Z0-9._-]{4,20}$")) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun username(): Boolean {
|
||||||
|
return username(StringSetting.WEB_USERNAME.getString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun port(s: String): Boolean {
|
||||||
|
return s.toIntOrNull() in 1..65535
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="15dp"
|
||||||
android:text="@string/generate"
|
android:text="@string/generate"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/edit_text_layout"
|
app:layout_constraintEnd_toEndOf="@+id/edit_text_layout"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/edit_text_layout" />
|
app:layout_constraintTop_toBottomOf="@+id/edit_text_layout" />
|
||||||
|
|
||||||
|
|
|
@ -148,18 +148,18 @@
|
||||||
<string name="multiplayer_join_room_failed">Failed to join room</string>
|
<string name="multiplayer_join_room_failed">Failed to join room</string>
|
||||||
<string name="multiplayer_name_invalid">Name is too short</string>
|
<string name="multiplayer_name_invalid">Name is too short</string>
|
||||||
<string name="multiplayer_address_invalid">Invalid address</string>
|
<string name="multiplayer_address_invalid">Invalid address</string>
|
||||||
<string name="multiplayer_port_invalid">Invalid port!</string>
|
<string name="multiplayer_port_invalid">Invalid port</string>
|
||||||
<string name="multiplayer_exit_room">Exit Room</string>
|
<string name="multiplayer_exit_room">Exit Room</string>
|
||||||
<string name="multiplayer_network_error">Network error</string>
|
<string name="multiplayer_network_error">Network error</string>
|
||||||
<string name="multiplayer_lost_connection">Lost connection</string>
|
<string name="multiplayer_lost_connection">Lost connection</string>
|
||||||
<string name="multiplayer_name_collision">Name collision</string>
|
<string name="multiplayer_name_collision">Username already taken</string>
|
||||||
<string name="multiplayer_mac_collision">MAC Address collision</string>
|
<string name="multiplayer_mac_collision">MAC Address collision</string>
|
||||||
<string name="multiplayer_console_id_collision">Console ID collision</string>
|
<string name="multiplayer_console_id_collision">Console ID collision</string>
|
||||||
<string name="multiplayer_wrong_version">Wrong version</string>
|
<string name="multiplayer_wrong_version">Wrong version</string>
|
||||||
<string name="multiplayer_wrong_password">Wrong password</string>
|
<string name="multiplayer_wrong_password">Wrong password</string>
|
||||||
<string name="multiplayer_could_not_connect">Could not connect</string>
|
<string name="multiplayer_could_not_connect">Could not connect</string>
|
||||||
<string name="multiplayer_room_is_full">Room is full</string>
|
<string name="multiplayer_room_is_full">Room is full</string>
|
||||||
<string name="multiplayer_host_banned">Host banned</string>
|
<string name="multiplayer_host_banned">You are banned from this room</string>
|
||||||
<string name="multiplayer_permission_denied">Permission denied</string>
|
<string name="multiplayer_permission_denied">Permission denied</string>
|
||||||
<string name="multiplayer_no_such_user">No such user</string>
|
<string name="multiplayer_no_such_user">No such user</string>
|
||||||
<string name="multiplayer_already_in_room">Already in room</string>
|
<string name="multiplayer_already_in_room">Already in room</string>
|
||||||
|
@ -221,7 +221,8 @@
|
||||||
<string name="multiplayer_required">Required</string>
|
<string name="multiplayer_required">Required</string>
|
||||||
<string name="multiplayer_token_required">Web Token required, go to Advanced Settings -> System -> Network</string>
|
<string name="multiplayer_token_required">Web Token required, go to Advanced Settings -> System -> Network</string>
|
||||||
<string name="multiplayer_ip_error">Invalid IP format</string>
|
<string name="multiplayer_ip_error">Invalid IP format</string>
|
||||||
<string name="multiplayer_username_error">Must be between 4–20 characters</string>
|
<string name="multiplayer_username_error">Must be between 4–20 characters, and contain alphanumeric characters, periods, dashes, underscores, and spaces only</string>
|
||||||
|
<string name="multiplayer_nickname_invalid">Username invalid, ensure it is set properly in System -> Network</string>
|
||||||
<string name="multiplayer_token_error">Must be 48 characters, and lowercase a-z only</string>
|
<string name="multiplayer_token_error">Must be 48 characters, and lowercase a-z only</string>
|
||||||
<string name="multiplayer_port_error">Must be between 1 and 65535</string>
|
<string name="multiplayer_port_error">Must be between 1 and 65535</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
|
@ -467,7 +468,7 @@
|
||||||
<string name="web_token">Web Token</string>
|
<string name="web_token">Web Token</string>
|
||||||
<string name="web_token_description">Web token used for creating public lobbies. It is a 48-character string containing only lowercase a-z.</string>
|
<string name="web_token_description">Web token used for creating public lobbies. It is a 48-character string containing only lowercase a-z.</string>
|
||||||
<string name="web_username">Web Username</string>
|
<string name="web_username">Web Username</string>
|
||||||
<string name="web_username_description">Username to be shown in multiplayer lobbies. It must be 4–20 characters.</string>
|
<string name="web_username_description">Username to be shown in multiplayer lobbies. It must be 4–20 characters, containing only alphanumeric characters, dashes, periods, underscores, and spaces.</string>
|
||||||
<string name="network">Network</string>
|
<string name="network">Network</string>
|
||||||
|
|
||||||
<!-- Graphics settings strings -->
|
<!-- Graphics settings strings -->
|
||||||
|
|
|
@ -73,15 +73,27 @@ public:
|
||||||
|
|
||||||
void SignalFence(std::function<void()>&& func) {
|
void SignalFence(std::function<void()>&& func) {
|
||||||
bool delay_fence = Settings::IsGPULevelHigh();
|
bool delay_fence = Settings::IsGPULevelHigh();
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
if (!delay_fence) {
|
||||||
|
TryReleasePendingFences<false>();
|
||||||
|
}
|
||||||
|
#else
|
||||||
if constexpr (!can_async_check) {
|
if constexpr (!can_async_check) {
|
||||||
TryReleasePendingFences<false>();
|
TryReleasePendingFences<false>();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
const bool should_flush = ShouldFlush();
|
const bool should_flush = ShouldFlush();
|
||||||
CommitAsyncFlushes();
|
CommitAsyncFlushes();
|
||||||
TFence new_fence = CreateFence(!should_flush);
|
TFence new_fence = CreateFence(!should_flush);
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
if (delay_fence) {
|
||||||
|
guard.lock();
|
||||||
|
}
|
||||||
|
#else
|
||||||
if constexpr (can_async_check) {
|
if constexpr (can_async_check) {
|
||||||
guard.lock();
|
guard.lock();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (delay_fence) {
|
if (delay_fence) {
|
||||||
uncommitted_operations.emplace_back(std::move(func));
|
uncommitted_operations.emplace_back(std::move(func));
|
||||||
}
|
}
|
||||||
|
@ -94,10 +106,17 @@ public:
|
||||||
if (should_flush) {
|
if (should_flush) {
|
||||||
rasterizer.FlushCommands();
|
rasterizer.FlushCommands();
|
||||||
}
|
}
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
if (delay_fence) {
|
||||||
|
guard.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
}
|
||||||
|
#else
|
||||||
if constexpr (can_async_check) {
|
if constexpr (can_async_check) {
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
rasterizer.InvalidateGPUCache();
|
rasterizer.InvalidateGPUCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,32 +23,48 @@ namespace FFmpeg {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
|
|
||||||
constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
|
|
||||||
constexpr std::array PreferredGpuDecoders = {
|
constexpr std::array PreferredGpuDecoders = {
|
||||||
#ifdef _WIN32
|
#if defined (_WIN32)
|
||||||
AV_HWDEVICE_TYPE_CUDA,
|
AV_HWDEVICE_TYPE_CUDA,
|
||||||
AV_HWDEVICE_TYPE_D3D11VA,
|
AV_HWDEVICE_TYPE_D3D11VA,
|
||||||
AV_HWDEVICE_TYPE_DXVA2,
|
AV_HWDEVICE_TYPE_DXVA2,
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
AV_HWDEVICE_TYPE_VDPAU,
|
AV_HWDEVICE_TYPE_VDPAU,
|
||||||
#elif defined(__unix__)
|
#elif defined(__unix__)
|
||||||
|
AV_HWDEVICE_TYPE_CUDA,
|
||||||
AV_HWDEVICE_TYPE_VAAPI,
|
AV_HWDEVICE_TYPE_VAAPI,
|
||||||
|
AV_HWDEVICE_TYPE_VDPAU,
|
||||||
#endif
|
#endif
|
||||||
AV_HWDEVICE_TYPE_VULKAN,
|
AV_HWDEVICE_TYPE_VULKAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
|
AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
|
||||||
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
|
// Check if there is a pixel format supported by the GPU decoder.
|
||||||
if (*p == codec_context->pix_fmt) {
|
const auto desc = av_pix_fmt_desc_get(codec_context->pix_fmt);
|
||||||
return codec_context->pix_fmt;
|
if (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
|
||||||
}
|
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
|
||||||
}
|
if (*p == codec_context->pix_fmt) {
|
||||||
|
return codec_context->pix_fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO(HW_GPU, "Could not find compatible GPU AV format, falling back to CPU");
|
// Another check to confirm if there is a pixel format supported by specific GPU decoders.
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
const AVCodecHWConfig* config = avcodec_get_hw_config(codec_context->codec, i);
|
||||||
|
if (!config) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) && (config->device_type == AV_HWDEVICE_TYPE_CUDA || config->device_type == AV_HWDEVICE_TYPE_VAAPI)) {
|
||||||
|
return config->pix_fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to CPU decoder.
|
||||||
|
LOG_INFO(HW_GPU, "Could not find compatible GPU pixel format, falling back to CPU");
|
||||||
av_buffer_unref(&codec_context->hw_device_ctx);
|
av_buffer_unref(&codec_context->hw_device_ctx);
|
||||||
|
|
||||||
codec_context->pix_fmt = PreferredCpuFormat;
|
|
||||||
return codec_context->pix_fmt;
|
return codec_context->pix_fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +74,7 @@ std::string AVError(int errnum) {
|
||||||
return errbuf;
|
return errbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
}
|
||||||
|
|
||||||
Packet::Packet(std::span<const u8> data) {
|
Packet::Packet(std::span<const u8> data) {
|
||||||
m_packet = av_packet_alloc();
|
m_packet = av_packet_alloc();
|
||||||
|
@ -81,16 +97,16 @@ Frame::~Frame() {
|
||||||
Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
|
Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
|
||||||
const AVCodecID av_codec = [&] {
|
const AVCodecID av_codec = [&] {
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
|
case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
|
||||||
return AV_CODEC_ID_H264;
|
return AV_CODEC_ID_H264;
|
||||||
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
|
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
|
||||||
return AV_CODEC_ID_VP8;
|
return AV_CODEC_ID_VP8;
|
||||||
case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
|
case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
|
||||||
return AV_CODEC_ID_VP9;
|
return AV_CODEC_ID_VP9;
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unknown codec {}", codec);
|
UNIMPLEMENTED_MSG("Unknown codec {}", codec);
|
||||||
return AV_CODEC_ID_NONE;
|
return AV_CODEC_ID_NONE;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
m_codec = avcodec_find_decoder(av_codec);
|
m_codec = avcodec_find_decoder(av_codec);
|
||||||
|
@ -103,6 +119,7 @@ bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceTyp
|
||||||
LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, av_hwdevice_get_type_name(type));
|
LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, av_hwdevice_get_type_name(type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
|
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
|
||||||
LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
|
LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
|
||||||
*out_pix_fmt = config->pix_fmt;
|
*out_pix_fmt = config->pix_fmt;
|
||||||
|
@ -215,11 +232,11 @@ bool DecoderContext::OpenContext(const Decoder& decoder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecoderContext::SendPacket(const Packet& packet) {
|
bool DecoderContext::SendPacket(const Packet& packet) {
|
||||||
m_temp_frame = std::make_shared<Frame>();
|
|
||||||
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) {
|
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) {
|
||||||
LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
|
LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,14 +254,15 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto desc = av_pix_fmt_desc_get(intermediate_frame->GetPixelFormat());
|
m_temp_frame = std::make_shared<Frame>();
|
||||||
if (m_codec_context->hw_device_ctx && (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
|
if (m_codec_context->hw_device_ctx) {
|
||||||
m_temp_frame->SetFormat(PreferredGpuFormat);
|
m_temp_frame->SetFormat(AV_PIX_FMT_NV12);
|
||||||
if (int ret = av_hwframe_transfer_data(m_temp_frame->GetFrame(), intermediate_frame->GetFrame(), 0); ret < 0) {
|
if (int ret = av_hwframe_transfer_data(m_temp_frame->GetFrame(), intermediate_frame->GetFrame(), 0); ret < 0) {
|
||||||
LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret));
|
LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
m_temp_frame->SetFormat(AV_PIX_FMT_YUV420P);
|
||||||
m_temp_frame = std::move(intermediate_frame);
|
m_temp_frame = std::move(intermediate_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,4 +305,4 @@ std::shared_ptr<Frame> DecodeApi::ReceiveFrame() {
|
||||||
return m_decoder_context->ReceiveFrame();
|
return m_decoder_context->ReceiveFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FFmpeg
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ extern "C" {
|
||||||
#include <libavutil/opt.h>
|
#include <libavutil/opt.h>
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
|
|
||||||
// Works quite fine, and omits the hacky ffmpeg building for now...
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
#include <libavcodec/codec.h>
|
#include <libavcodec/codec.h>
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -496,6 +496,6 @@ endif()
|
||||||
|
|
||||||
# Extra deps
|
# Extra deps
|
||||||
add_subdirectory(externals)
|
add_subdirectory(externals)
|
||||||
target_link_libraries(yuzu PRIVATE QuaZip::QuaZip Qt6::Core5Compat)
|
target_link_libraries(yuzu PRIVATE QuaZip::QuaZip)
|
||||||
|
|
||||||
create_target_directory_groups(yuzu)
|
create_target_directory_groups(yuzu)
|
||||||
|
|
|
@ -16,9 +16,9 @@ AboutDialog::AboutDialog(QWidget* parent)
|
||||||
|
|
||||||
std::string yuzu_build;
|
std::string yuzu_build;
|
||||||
if (Common::g_is_dev_build) {
|
if (Common::g_is_dev_build) {
|
||||||
yuzu_build = fmt::format("eden Nightly | {}-{}", description, build_id);
|
yuzu_build = fmt::format("Eden Nightly | {}-{}", description, build_id);
|
||||||
} else {
|
} else {
|
||||||
yuzu_build = fmt::format("eden | {}", description);
|
yuzu_build = fmt::format("Eden | {}", description);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto override_build = fmt::format(fmt::runtime(
|
const auto override_build = fmt::format(fmt::runtime(
|
||||||
|
|
15
src/yuzu/externals/CMakeLists.txt
vendored
15
src/yuzu/externals/CMakeLists.txt
vendored
|
@ -12,17 +12,6 @@ set(CPM_USE_LOCAL_PACKAGES ON)
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME QuaZip-Qt6
|
NAME QuaZip-Qt6
|
||||||
VERSION 1.3
|
VERSION 1.3
|
||||||
GIT_REPOSITORY "https://github.com/stachenov/quazip.git"
|
GIT_REPOSITORY "https://github.com/crueter/quazip-qt6.git"
|
||||||
GIT_TAG v1.5
|
GIT_TAG v1.5-qt6
|
||||||
PATCHES
|
|
||||||
${CMAKE_SOURCE_DIR}/.patch/quazip/0001-strict.patch
|
|
||||||
${CMAKE_SOURCE_DIR}/.patch/quazip/0002-oldstyle.patch
|
|
||||||
${CMAKE_SOURCE_DIR}/.patch/quazip/0003-predecls.patch
|
|
||||||
${CMAKE_SOURCE_DIR}/.patch/quazip/0004-qt6-only.patch
|
|
||||||
|
|
||||||
# thanks to 0004-qt6-only.patch, this isn't needed,
|
|
||||||
# but we keep it since the patch is "technically" optional
|
|
||||||
OPTIONS
|
|
||||||
"QUAZIP_QT_MAJOR_VERSION 6"
|
|
||||||
"QUAZIP_BZIP2 OFF"
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -4902,9 +4902,9 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
|
||||||
|
|
||||||
std::string yuzu_title;
|
std::string yuzu_title;
|
||||||
if (Common::g_is_dev_build) {
|
if (Common::g_is_dev_build) {
|
||||||
yuzu_title = fmt::format("eden Nightly | {}-{}", description, build_id);
|
yuzu_title = fmt::format("Eden Nightly | {}-{}", description, build_id);
|
||||||
} else {
|
} else {
|
||||||
yuzu_title = fmt::format("eden | {}", description);
|
yuzu_title = fmt::format("Eden | {}", description);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto override_title =
|
const auto override_title =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue