mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-10-06 00:02:44 +02:00
Compare commits
34 Commits
ffmpeg-mul
...
custom-cpu
Author | SHA1 | Date | |
---|---|---|---|
|
d1e0df68ed | ||
|
accf4cda38 | ||
|
3dd6eced05 | ||
|
8c173242cf | ||
|
334d998e63 | ||
|
cbf5f4b8c9 | ||
|
617d4c5b1a | ||
|
05fb5743da | ||
|
d921d668ec | ||
|
d69f3abd52 | ||
|
69026faa88 | ||
|
f4cb591578 | ||
|
7e4a804e6c | ||
|
6bc212e4cb | ||
|
846ec85f24 | ||
|
59e69d91f4 | ||
|
02603abbdc | ||
|
2f01c69710 | ||
|
2946cdbd2d | ||
|
8c33b0bb5d | ||
|
6bf5ae700a | ||
|
704d4e4428 | ||
|
6aeba9de66 | ||
|
eae819f0d6 | ||
|
a4123200c0 | ||
|
5591ce30c9 | ||
|
af923c92eb | ||
|
cf00554d23 | ||
|
cee222f0e6 | ||
|
b2d16cb3dd | ||
|
ef2d0a9076 | ||
|
f3e00b633e | ||
|
cc7f2808ed | ||
|
6b46aca0b7 |
@@ -7,9 +7,16 @@ license_header = <<~EOF
|
||||
EOF
|
||||
|
||||
print 'Getting branch changes...'
|
||||
puts "\n"
|
||||
branch_name = `git rev-parse --abbrev-ref HEAD`.chomp
|
||||
print branch_name
|
||||
puts "\n"
|
||||
branch_commits = `git log #{branch_name} --not master --pretty=format:"%h"`.split("\n")
|
||||
print branch_commits
|
||||
puts "\n"
|
||||
branch_commit_range = "#{branch_commits[-1]}^..#{branch_commits[0]}"
|
||||
print branch_commit_range
|
||||
puts "\n"
|
||||
branch_changed_files = `git diff-tree --no-commit-id --name-only #{branch_commit_range} -r`.split("\n")
|
||||
puts 'done'
|
||||
|
||||
|
@@ -34,9 +34,6 @@ fi
|
||||
|
||||
if [ "$TARGET" = "appimage" ]; then
|
||||
export EXTRA_CMAKE_FLAGS=(-DCMAKE_INSTALL_PREFIX=/usr -DYUZU_ROOM=ON -DYUZU_ROOM_STANDALONE=OFF -DYUZU_CMD=OFF)
|
||||
# Bundle required QT wayland libraries
|
||||
export EXTRA_QT_PLUGINS="waylandcompositor"
|
||||
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||
else
|
||||
# For the linux-fresh verification target, verify compilation without PCH as well.
|
||||
export EXTRA_CMAKE_FLAGS=(-DYUZU_USE_PRECOMPILED_HEADERS=OFF)
|
||||
|
@@ -11,8 +11,8 @@ export ARCH="$BASE_ARCH"
|
||||
|
||||
export BUILDDIR="$2"
|
||||
|
||||
LIB4BN="https://raw.githubusercontent.com/VHSgunzo/sharun/refs/heads/main/lib4bin"
|
||||
URUNTIME="https://github.com/VHSgunzo/uruntime/releases/latest/download/uruntime-appimage-dwarfs-$ARCH"
|
||||
SHARUN="https://github.com/VHSgunzo/sharun/releases/latest/download/sharun-${BASE_ARCH}-aio"
|
||||
URUNTIME="https://github.com/VHSgunzo/uruntime/releases/latest/download/uruntime-appimage-dwarfs-${BASE_ARCH}"
|
||||
|
||||
if [ "$ARCH" = 'x86_64' ]; then
|
||||
if [ "$1" = 'v3' ]; then
|
||||
@@ -48,22 +48,24 @@ fi
|
||||
UPINFO='gh-releases-zsync|eden-emulator|Releases|latest|*.AppImage.zsync'
|
||||
|
||||
LIBDIR="/usr/lib"
|
||||
# some distros are weird and use a subdir
|
||||
|
||||
if [ ! -f "/usr/lib/libGL.so" ]
|
||||
# Workaround for Gentoo
|
||||
if [ ! -d "$LIBDIR/qt6" ]
|
||||
then
|
||||
LIBDIR="/usr/lib64"
|
||||
fi
|
||||
|
||||
# Workaround for Debian
|
||||
if [ ! -d "$LIBDIR/qt6" ]
|
||||
then
|
||||
LIBDIR="/usr/lib/${BASE_ARCH}-linux-gnu"
|
||||
fi
|
||||
|
||||
# Bundle all libs
|
||||
|
||||
# temp workaround for arch being silly
|
||||
mkdir -p share/X11
|
||||
cp -r /usr/share/X11/xkb share/X11
|
||||
|
||||
wget --retry-connrefused --tries=30 "$LIB4BN" -O ./lib4bin
|
||||
chmod +x ./lib4bin
|
||||
xvfb-run -a -- ./lib4bin -p -v -e -s -k \
|
||||
wget --retry-connrefused --tries=30 "$SHARUN" -O ./sharun-aio
|
||||
chmod +x ./sharun-aio
|
||||
xvfb-run -a ./sharun-aio l -p -v -e -s -k \
|
||||
../$BUILDDIR/bin/eden* \
|
||||
$LIBDIR/lib*GL*.so* \
|
||||
$LIBDIR/libSDL2*.so* \
|
||||
@@ -88,14 +90,18 @@ xvfb-run -a -- ./lib4bin -p -v -e -s -k \
|
||||
$LIBDIR/spa-0.2/*/* \
|
||||
$LIBDIR/alsa-lib/*
|
||||
|
||||
rm -f ./sharun-aio
|
||||
|
||||
# Prepare sharun
|
||||
if [ "$ARCH" = 'aarch64' ]; then
|
||||
# allow the host vulkan to be used for aarch64 given the sed situation
|
||||
# allow the host vulkan to be used for aarch64 given the sad situation
|
||||
echo 'SHARUN_ALLOW_SYS_VKICD=1' > ./.env
|
||||
fi
|
||||
|
||||
wget https://github.com/VHSgunzo/sharun/releases/download/v0.6.3/sharun-x86_64 -O sharun
|
||||
chmod a+x sharun
|
||||
# Workaround for Gentoo
|
||||
if [ -d "shared/libproxy" ]; then
|
||||
cp shared/libproxy/* lib/
|
||||
fi
|
||||
|
||||
ln -f ./sharun ./AppRun
|
||||
./sharun -g
|
||||
@@ -121,9 +127,4 @@ echo "Generating AppImage..."
|
||||
|
||||
echo "Generating zsync file..."
|
||||
zsyncmake *.AppImage -u *.AppImage
|
||||
echo "All Done!"
|
||||
|
||||
# Cleanup
|
||||
|
||||
rm -rf AppDir
|
||||
rm uruntime
|
||||
echo "All Done!"
|
5
.github/workflows/license-header.yml
vendored
5
.github/workflows/license-header.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: eden-license
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
@@ -13,9 +13,8 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch
|
||||
run: git fetch origin
|
||||
run: git fetch origin master:master
|
||||
|
||||
# TODO: fix the script
|
||||
- name: Make script executable
|
||||
run: chmod +x ./.ci/license-header.rb
|
||||
|
||||
|
@@ -512,6 +512,8 @@ if (APPLE)
|
||||
# Umbrella framework for everything GUI-related
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
|
||||
find_library(ICONV_LIBRARY iconv REQUIRED)
|
||||
list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY})
|
||||
elseif (WIN32)
|
||||
# Target Windows 10
|
||||
add_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00)
|
||||
|
BIN
dist/eden.icns
vendored
Normal file
BIN
dist/eden.icns
vendored
Normal file
Binary file not shown.
@@ -163,13 +163,24 @@ alignas(64) static constinit std::array<HostLoc, ABI_AllCallerSaveSize() - 1> AB
|
||||
};
|
||||
|
||||
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
|
||||
#ifdef _MSC_VER
|
||||
std::vector<HostLoc> regs;
|
||||
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
|
||||
ABI_PushRegistersAndAdjustStack(code, 0, regs);
|
||||
#else
|
||||
ASSUME(size_t(exception) < 32);
|
||||
ABI_PushRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) {
|
||||
#ifdef _MSC_VER
|
||||
std::vector<HostLoc> regs;
|
||||
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
|
||||
ABI_PopRegistersAndAdjustStack(code, 0, regs);
|
||||
#else
|
||||
ASSUME(size_t(exception) < 32);
|
||||
ABI_PopRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::X64
|
||||
|
2
externals/ffmpeg/CMakeLists.txt
vendored
2
externals/ffmpeg/CMakeLists.txt
vendored
@@ -225,7 +225,7 @@ if (NOT WIN32 AND NOT ANDROID)
|
||||
elseif(ANDROID)
|
||||
# Use yuzu FFmpeg binaries
|
||||
if (ARCHITECTURE_arm64)
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-aarch64")
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-android-7.1.1-aarch64")
|
||||
elseif (ARCHITECTURE_x86_64)
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-android-v5.1.LTS-x86_64")
|
||||
else()
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright yuzu/Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright yuzu/Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import kotlin.collections.setOf
|
||||
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
|
||||
@@ -35,6 +35,7 @@ android {
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -62,11 +63,7 @@ android {
|
||||
targetSdk = 35
|
||||
versionName = getGitVersion()
|
||||
|
||||
versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
|
||||
autoVersion
|
||||
} else {
|
||||
1
|
||||
}
|
||||
versionCode = autoVersion
|
||||
|
||||
ndk {
|
||||
@SuppressLint("ChromeOsAbiSupport")
|
||||
@@ -121,7 +118,6 @@ android {
|
||||
isDefault = true
|
||||
resValue("string", "app_name_suffixed", "eden Debug Release")
|
||||
signingConfig = signingConfigs.getByName("default")
|
||||
isMinifyEnabled = true
|
||||
isDebuggable = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android.txt"),
|
||||
@@ -131,7 +127,7 @@ android {
|
||||
applicationIdSuffix = ".relWithDebInfo"
|
||||
isJniDebuggable = true
|
||||
}
|
||||
|
||||
|
||||
// Signed by debug key disallowing distribution on Play Store.
|
||||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||
debug {
|
||||
@@ -144,14 +140,22 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions.add("version")
|
||||
productFlavors {
|
||||
create("mainline") {
|
||||
isDefault = true
|
||||
dimension = "version"
|
||||
android {
|
||||
flavorDimensions.add("version")
|
||||
productFlavors {
|
||||
create("mainline") {
|
||||
dimension = "version"
|
||||
// No need to set applicationId here
|
||||
}
|
||||
|
||||
create("genshinSpoof") {
|
||||
dimension = "version"
|
||||
applicationId = "com.miHoYo.Yuanshen" // Correct use of applicationId inside the flavor block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version = "3.22.1"
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
package org.yuzu.yuzu_emu
|
||||
|
||||
@@ -489,4 +489,9 @@ object NativeLibrary {
|
||||
* Checks if all necessary keys are present for decryption
|
||||
*/
|
||||
external fun areKeysPresent(): Boolean
|
||||
|
||||
/**
|
||||
* Updates the device power state to global variables
|
||||
*/
|
||||
external fun updatePowerState(percentage: Int, isCharging: Boolean, hasBattery: Boolean)
|
||||
}
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -13,6 +16,7 @@ import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
|
||||
|
||||
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
||||
|
||||
@@ -40,6 +44,7 @@ class YuzuApplication : Application() {
|
||||
GpuDriverHelper.initializeDriverParameters()
|
||||
NativeInput.reloadInputDevices()
|
||||
NativeLibrary.logDeviceInfo()
|
||||
PowerStateUpdater.start()
|
||||
Log.logDeviceInfo()
|
||||
|
||||
createNotificationChannels()
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
package org.yuzu.yuzu_emu.activities
|
||||
|
||||
@@ -58,6 +58,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import org.yuzu.yuzu_emu.utils.NfcReader
|
||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||
import org.yuzu.yuzu_emu.utils.PowerStateUtils
|
||||
import java.text.NumberFormat
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
@@ -13,6 +13,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
CORE_SYNC_CORE_SPEED("sync_core_speed"),
|
||||
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
||||
USE_FAST_CPU_TIME("use_fast_cpu_time"),
|
||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||
USE_DOCKED_MODE("use_docked_mode"),
|
||||
USE_AUTO_STUB("use_auto_stub"),
|
||||
RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
|
||||
|
@@ -37,6 +37,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
MEMORY_LAYOUT("memory_layout_mode"),
|
||||
FSR_SHARPENING_SLIDER("fsr_sharpening_slider"),
|
||||
FAST_CPU_TIME("fast_cpu_time"),
|
||||
CPU_TICKS("cpu_ticks"),
|
||||
FAST_GPU_TIME("fast_gpu_time"),
|
||||
|
||||
CABINET_APPLET("cabinet_applet_mode"),
|
||||
|
@@ -1,7 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model
|
||||
|
||||
import org.yuzu.yuzu_emu.R
|
||||
@@ -36,7 +35,6 @@ object Settings {
|
||||
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
||||
const val PREF_SHOULD_SHOW_DRIVER_WARNING = "ShouldShowDriverWarning"
|
||||
const val PREF_SHOULD_SHOW_PRE_ALPHA_WARNING = "ShouldShowPreAlphaWarning"
|
||||
const val PREF_SHOULD_SHOW_PRE_ALPHA_BANNER = "ShouldShowPreAlphaBanner"
|
||||
const val PREF_SHOULD_SHOW_EDENS_VEIL_DIALOG = "ShouldShowEdensVeilDialog"
|
||||
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
||||
const val SECTION_STATS_OVERLAY = "Stats Overlay"
|
||||
|
@@ -577,6 +577,22 @@ abstract class SettingsItem(
|
||||
valuesId = R.array.clockValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.USE_CUSTOM_CPU_TICKS,
|
||||
titleId = R.string.custom_cpu_ticks,
|
||||
descriptionId = R.string.custom_cpu_ticks_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SliderSetting(
|
||||
IntSetting.CPU_TICKS,
|
||||
titleId = R.string.cpu_ticks,
|
||||
descriptionId = 0,
|
||||
min = 77,
|
||||
max = 65535
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_REACTIVE_FLUSHING,
|
||||
|
@@ -220,6 +220,7 @@ class SettingsFragmentPresenter(
|
||||
|
||||
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
// TODO(crueter): reorganize this, this is awful
|
||||
add(IntSetting.RENDERER_ACCURACY.key)
|
||||
add(IntSetting.RENDERER_RESOLUTION.key)
|
||||
add(IntSetting.RENDERER_VSYNC.key)
|
||||
@@ -447,6 +448,8 @@ class SettingsFragmentPresenter(
|
||||
add(HeaderSetting(R.string.veil_misc))
|
||||
add(BooleanSetting.USE_FAST_CPU_TIME.key)
|
||||
add(IntSetting.FAST_CPU_TIME.key)
|
||||
add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key)
|
||||
add(IntSetting.CPU_TICKS.key)
|
||||
add(BooleanSetting.USE_LRU_CACHE.key)
|
||||
add(BooleanSetting.CORE_SYNC_CORE_SPEED.key)
|
||||
add(IntSetting.MEMORY_LAYOUT.key)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.ui
|
||||
@@ -162,12 +162,6 @@ class GamesFragment : Fragment() {
|
||||
}
|
||||
|
||||
setInsets()
|
||||
val shouldDisplayPreAlphaBanner =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.getBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_BANNER, true)
|
||||
if (shouldDisplayPreAlphaBanner) {
|
||||
addPreAlphaBanner()
|
||||
}
|
||||
}
|
||||
|
||||
val applyGridGamesBinding = {
|
||||
@@ -238,86 +232,6 @@ class GamesFragment : Fragment() {
|
||||
navController.navigate(R.id.action_gamesFragment_to_homeSettingsFragment)
|
||||
}
|
||||
|
||||
private fun addPreAlphaBanner() {
|
||||
val preAlphaBanner = TextView(requireContext()).apply {
|
||||
id = "pre_alpha_banner".hashCode()
|
||||
layoutParams = ConstraintLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
marginStart = resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
marginEnd = resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
topMargin = resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||
topToBottom = R.id.frame_search
|
||||
}
|
||||
setPadding(
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_med),
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_large),
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_med),
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
)
|
||||
|
||||
setBackgroundColor(
|
||||
MaterialColors.getColor(
|
||||
this,
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
)
|
||||
)
|
||||
text = getString(R.string.pre_alpha_warning)
|
||||
setTextAppearance(
|
||||
com.google.android.material.R.style.TextAppearance_Material3_HeadlineSmall
|
||||
)
|
||||
setTextColor(
|
||||
MaterialColors.getColor(
|
||||
this,
|
||||
com.google.android.material.R.attr.colorOnError
|
||||
)
|
||||
)
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
|
||||
val closeButton = ImageButton(requireContext()).apply {
|
||||
id = "pre_alpha_close_button".hashCode()
|
||||
layoutParams = ConstraintLayout.LayoutParams(
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_large),
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||
).apply {
|
||||
startToStart = "pre_alpha_banner".hashCode()
|
||||
topToTop = "pre_alpha_banner".hashCode()
|
||||
bottomToBottom = "pre_alpha_banner".hashCode()
|
||||
marginStart = resources.getDimensionPixelSize(R.dimen.spacing_large) * 2
|
||||
topMargin = resources.getDimensionPixelSize(R.dimen.spacing_small)
|
||||
}
|
||||
setImageResource(android.R.drawable.ic_menu_close_clear_cancel)
|
||||
setColorFilter(
|
||||
MaterialColors.getColor(
|
||||
this,
|
||||
com.google.android.material.R.attr.colorOnError
|
||||
)
|
||||
)
|
||||
setBackgroundColor(Color.Transparent.toArgb())
|
||||
setOnClickListener {
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.edit() {
|
||||
putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_BANNER, false)
|
||||
}
|
||||
binding.root.removeView(preAlphaBanner)
|
||||
binding.root.removeView(this)
|
||||
|
||||
binding.swipeRefresh.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topToBottom = R.id.frame_search
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.addView(preAlphaBanner)
|
||||
binding.root.addView(closeButton)
|
||||
|
||||
binding.swipeRefresh.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topToBottom = preAlphaBanner.id
|
||||
}
|
||||
}
|
||||
|
||||
private fun showViewMenu(anchor: View) {
|
||||
val popup = PopupMenu(requireContext(), anchor)
|
||||
popup.menuInflater.inflate(R.menu.menu_game_views, popup.menu)
|
||||
@@ -444,32 +358,24 @@ class GamesFragment : Fragment() {
|
||||
private fun setInsets() =
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
) { view: View, windowInsets: WindowInsetsCompat ->
|
||||
) { _: View, windowInsets: WindowInsetsCompat ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
val spacingNavigation = resources.getDimensionPixelSize(R.dimen.spacing_navigation)
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_navigation_rail)
|
||||
val isLandscape =
|
||||
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
|
||||
binding.swipeRefresh.setProgressViewEndTarget(
|
||||
false,
|
||||
barInsets.top + resources.getDimensionPixelSize(R.dimen.spacing_refresh_end)
|
||||
)
|
||||
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
val topInsets = barInsets.top + cutoutInsets.top
|
||||
val bottomInsets = barInsets.bottom + cutoutInsets.bottom
|
||||
val leftInset = barInsets.left + cutoutInsets.left
|
||||
val rightInset = barInsets.right + cutoutInsets.right
|
||||
val topInset = maxOf(barInsets.top, cutoutInsets.top)
|
||||
|
||||
val mlpSwipe = binding.swipeRefresh.layoutParams as ViewGroup.MarginLayoutParams
|
||||
if (view.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
|
||||
mlpSwipe.leftMargin = leftInsets
|
||||
mlpSwipe.rightMargin = rightInsets
|
||||
} else {
|
||||
mlpSwipe.leftMargin = leftInsets
|
||||
mlpSwipe.rightMargin = rightInsets
|
||||
}
|
||||
mlpSwipe.leftMargin = leftInset
|
||||
mlpSwipe.rightMargin = rightInset
|
||||
binding.swipeRefresh.layoutParams = mlpSwipe
|
||||
|
||||
val mlpHeader = binding.header.layoutParams as ViewGroup.MarginLayoutParams
|
||||
@@ -477,29 +383,27 @@ class GamesFragment : Fragment() {
|
||||
// Store original margins only once
|
||||
if (originalHeaderTopMargin == null) {
|
||||
originalHeaderTopMargin = mlpHeader.topMargin
|
||||
originalHeaderBottomMargin = mlpHeader.bottomMargin
|
||||
originalHeaderRightMargin = mlpHeader.rightMargin
|
||||
originalHeaderLeftMargin = mlpHeader.leftMargin
|
||||
}
|
||||
|
||||
// Always set margin as original + insets
|
||||
mlpHeader.leftMargin = (originalHeaderLeftMargin ?: 0) + leftInsets
|
||||
mlpHeader.rightMargin = (originalHeaderRightMargin ?: 0) + rightInsets
|
||||
mlpHeader.topMargin = (originalHeaderTopMargin ?: 0) + if (!isLandscape) topInsets else 0
|
||||
mlpHeader.bottomMargin = (originalHeaderBottomMargin ?: 0) + if (!isLandscape) bottomInsets else 0
|
||||
mlpHeader.leftMargin = (originalHeaderLeftMargin ?: 0) + leftInset
|
||||
mlpHeader.rightMargin = (originalHeaderRightMargin ?: 0) + rightInset
|
||||
mlpHeader.topMargin = (originalHeaderTopMargin ?: 0) + topInset + resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
binding.header.layoutParams = mlpHeader
|
||||
|
||||
binding.noticeText.updatePadding(bottom = spacingNavigation)
|
||||
binding.header.updatePadding(top = cutoutInsets.top + resources.getDimensionPixelSize(R.dimen.spacing_large) + if (isLandscape) barInsets.top else 0)
|
||||
|
||||
binding.gridGames.updatePadding(
|
||||
top = resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
)
|
||||
|
||||
val mlpFab = binding.addDirectory.layoutParams as ViewGroup.MarginLayoutParams
|
||||
val fabPadding = resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||
mlpFab.leftMargin = leftInsets + fabPadding
|
||||
mlpFab.leftMargin = leftInset + fabPadding
|
||||
mlpFab.bottomMargin = barInsets.bottom + fabPadding
|
||||
mlpFab.rightMargin = rightInsets + fabPadding
|
||||
mlpFab.rightMargin = rightInset + fabPadding
|
||||
binding.addDirectory.layoutParams = mlpFab
|
||||
|
||||
windowInsets
|
||||
|
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
|
||||
object PowerStateUpdater {
|
||||
|
||||
private lateinit var handler: Handler
|
||||
private lateinit var runnable: Runnable
|
||||
private const val UPDATE_INTERVAL_MS = 1000L
|
||||
private var isStarted = false
|
||||
|
||||
fun start() {
|
||||
|
||||
if (isStarted) {
|
||||
return
|
||||
}
|
||||
|
||||
val context = YuzuApplication.appContext
|
||||
|
||||
handler = Handler(Looper.getMainLooper())
|
||||
runnable = Runnable {
|
||||
val info = PowerStateUtils.getBatteryInfo(context)
|
||||
NativeLibrary.updatePowerState(info[0], info[1] == 1, info[2] == 1)
|
||||
handler.postDelayed(runnable, UPDATE_INTERVAL_MS)
|
||||
}
|
||||
handler.post(runnable)
|
||||
isStarted = true
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if (!isStarted) {
|
||||
return
|
||||
}
|
||||
if (::handler.isInitialized) {
|
||||
handler.removeCallbacks(runnable)
|
||||
}
|
||||
isStarted = false
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.BatteryManager
|
||||
import android.os.Build
|
||||
|
||||
object PowerStateUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun getBatteryInfo(context: Context?): IntArray {
|
||||
|
||||
if (context == null) {
|
||||
return intArrayOf(0, 0, 0) // Percentage, IsCharging, HasBattery
|
||||
}
|
||||
|
||||
val results = intArrayOf(100, 0, 1)
|
||||
val iFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||
val batteryStatusIntent: Intent? = context.registerReceiver(null, iFilter)
|
||||
|
||||
if (batteryStatusIntent != null) {
|
||||
val present = batteryStatusIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true)
|
||||
if (!present) {
|
||||
results[2] = 0; results[0] = 0; results[1] = 0; return results
|
||||
}
|
||||
results[2] = 1
|
||||
val level = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
||||
val scale = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
|
||||
if (level != -1 && scale != -1 && scale != 0) {
|
||||
results[0] = (level.toFloat() / scale.toFloat() * 100.0f).toInt()
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val bm = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager?
|
||||
results[0] = bm?.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) ?: 100
|
||||
}
|
||||
val status = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
||||
results[1] = if (status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL) 1 else 0
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
@@ -79,6 +79,11 @@ static EmulationSession s_instance;
|
||||
std::unique_ptr<AndroidMultiplayer> multiplayer{nullptr};
|
||||
std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
|
||||
|
||||
//Power Status default values
|
||||
std::atomic<int> g_battery_percentage = {100};
|
||||
std::atomic<bool> g_is_charging = {false};
|
||||
std::atomic<bool> g_has_battery = {true};
|
||||
|
||||
EmulationSession::EmulationSession() {
|
||||
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
}
|
||||
@@ -1014,4 +1019,16 @@ JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayUnb
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
|
||||
multiplayer->NetPlayUnbanUser(Common::Android::GetJString(env, username));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_updatePowerState(
|
||||
JNIEnv* env,
|
||||
jobject,
|
||||
jint percentage,
|
||||
jboolean isCharging,
|
||||
jboolean hasBattery) {
|
||||
|
||||
g_battery_percentage.store(percentage, std::memory_order_relaxed);
|
||||
g_is_charging.store(isCharging, std::memory_order_relaxed);
|
||||
g_has_battery.store(hasBattery, std::memory_order_relaxed);
|
||||
}
|
||||
} // extern "C"
|
||||
|
@@ -70,9 +70,10 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/search_background"
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:cardCornerRadius="24dp">
|
||||
|
||||
@@ -81,7 +82,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
@@ -109,22 +110,27 @@
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_clear"
|
||||
android:visibility="invisible"
|
||||
app:tint="?attr/colorOnSurfaceVariant"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_submit"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_send"
|
||||
android:contentDescription="@string/submit"
|
||||
app:tint="?attr/colorOnSurfaceVariant"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_submit"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/submit" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
@@ -250,6 +250,7 @@
|
||||
<item>@string/scaling_filter_gaussian</item>
|
||||
<item>@string/scaling_filter_scale_force</item>
|
||||
<item>@string/scaling_filter_fsr</item>
|
||||
<item>@string/scaling_filter_area</item>
|
||||
</string-array>
|
||||
|
||||
<integer-array name="rendererScalingFilterValues">
|
||||
@@ -259,6 +260,7 @@
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="rendererAntiAliasingNames">
|
||||
|
@@ -90,6 +90,9 @@
|
||||
<string name="use_lru_cache_description">Enable or disable the Least Recently Used (LRU) cache, increasing performance by saving CPU process usage. Some games have issue with it, notably TotK 1.2.1, so disable if the game doesn\'t boot or crashes randomly.</string>
|
||||
<string name="use_fast_cpu_time">Fast CPU Time</string>
|
||||
<string name="use_fast_cpu_time_description">Forces the emulated CPU to run at a higher clock, reducing certain FPS limiters. This option is hacky and may cause issues, and weaker CPUs may see reduced performance.</string>
|
||||
<string name="custom_cpu_ticks">Custom CPU Ticks</string>
|
||||
<string name="custom_cpu_ticks_description">Set a custom value of CPU ticks. Higher values can increase performance, but may also cause the game to freeze. A range of 77–21000 is recommended.</string>
|
||||
<string name="cpu_ticks">Ticks</string>
|
||||
<string name="fast_cpu_time">CPU Clock</string>
|
||||
<string name="fast_cpu_time_description">Use Boost (1700MHz) to run at the Switch\'s highest native clock, or Fast (2000MHz) to run at 2x clock.</string>
|
||||
<string name="memory_layout">Memory Layout</string>
|
||||
@@ -863,6 +866,7 @@
|
||||
<string name="scaling_filter_gaussian">Gaussian</string>
|
||||
<string name="scaling_filter_scale_force">ScaleForce</string>
|
||||
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
|
||||
<string name="scaling_filter_area">Area</string>
|
||||
|
||||
<!-- Anti-Aliasing -->
|
||||
<string name="anti_aliasing_none">None</string>
|
||||
|
@@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -14,7 +17,5 @@ android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
|
||||
# Android Gradle plugin 8.0.2
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
|
@@ -42,6 +42,8 @@ add_library(common STATIC
|
||||
demangle.h
|
||||
detached_tasks.cpp
|
||||
detached_tasks.h
|
||||
device_power_state.cpp
|
||||
device_power_state.h
|
||||
div_ceil.h
|
||||
dynamic_library.cpp
|
||||
dynamic_library.h
|
||||
|
102
src/common/device_power_state.cpp
Normal file
102
src/common/device_power_state.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "device_power_state.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
#include <atomic>
|
||||
extern std::atomic<int> g_battery_percentage;
|
||||
extern std::atomic<bool> g_is_charging;
|
||||
extern std::atomic<bool> g_has_battery;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#endif
|
||||
|
||||
#elif defined(__linux__)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
PowerStatus GetPowerStatus()
|
||||
{
|
||||
PowerStatus info;
|
||||
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_POWER_STATUS status;
|
||||
if (GetSystemPowerStatus(&status)) {
|
||||
if (status.BatteryFlag == 128) {
|
||||
info.has_battery = false;
|
||||
} else {
|
||||
info.percentage = status.BatteryLifePercent;
|
||||
info.charging = (status.BatteryFlag & 8) != 0;
|
||||
}
|
||||
} else {
|
||||
info.has_battery = false;
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
info.percentage = g_battery_percentage.load(std::memory_order_relaxed);
|
||||
info.charging = g_is_charging.load(std::memory_order_relaxed);
|
||||
info.has_battery = g_has_battery.load(std::memory_order_relaxed);
|
||||
|
||||
#elif defined(__APPLE__) && TARGET_OS_MAC
|
||||
CFTypeRef info_ref = IOPSCopyPowerSourcesInfo();
|
||||
CFArrayRef sources = IOPSCopyPowerSourcesList(info_ref);
|
||||
if (CFArrayGetCount(sources) > 0) {
|
||||
CFDictionaryRef battery =
|
||||
IOPSGetPowerSourceDescription(info_ref, CFArrayGetValueAtIndex(sources, 0));
|
||||
|
||||
CFNumberRef curNum =
|
||||
(CFNumberRef)CFDictionaryGetValue(battery, CFSTR(kIOPSCurrentCapacityKey));
|
||||
CFNumberRef maxNum =
|
||||
(CFNumberRef)CFDictionaryGetValue(battery, CFSTR(kIOPSMaxCapacityKey));
|
||||
int cur = 0, max = 0;
|
||||
CFNumberGetValue(curNum, kCFNumberIntType, &cur);
|
||||
CFNumberGetValue(maxNum, kCFNumberIntType, &max);
|
||||
|
||||
if (max > 0)
|
||||
info.percentage = (cur * 100) / max;
|
||||
|
||||
CFBooleanRef isCharging =
|
||||
(CFBooleanRef)CFDictionaryGetValue(battery, CFSTR(kIOPSIsChargingKey));
|
||||
info.charging = CFBooleanGetValue(isCharging);
|
||||
} else {
|
||||
info.has_battery = false;
|
||||
}
|
||||
CFRelease(sources);
|
||||
CFRelease(info_ref);
|
||||
|
||||
#elif defined(__linux__)
|
||||
const char* battery_path = "/sys/class/power_supply/BAT0/";
|
||||
|
||||
std::ifstream capFile(std::string(battery_path) + "capacity");
|
||||
if (capFile) {
|
||||
capFile >> info.percentage;
|
||||
}
|
||||
else {
|
||||
info.has_battery = false;
|
||||
}
|
||||
|
||||
std::ifstream statFile(std::string(battery_path) + "status");
|
||||
if (statFile) {
|
||||
std::string status;
|
||||
std::getline(statFile, status);
|
||||
info.charging = (status == "Charging");
|
||||
}
|
||||
#else
|
||||
info.has_battery = false;
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
14
src/common/device_power_state.h
Normal file
14
src/common/device_power_state.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Common {
|
||||
struct PowerStatus {
|
||||
int percentage = -1;
|
||||
bool charging = false;
|
||||
bool has_battery = true;
|
||||
};
|
||||
|
||||
PowerStatus GetPowerStatus();
|
||||
} // namespace Common
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -256,6 +259,25 @@ struct Values {
|
||||
true,
|
||||
&use_fast_cpu_time};
|
||||
|
||||
SwitchableSetting<bool> use_custom_cpu_ticks{linkage,
|
||||
false,
|
||||
"use_custom_cpu_ticks",
|
||||
Category::Cpu,
|
||||
Specialization::Paired,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<u32, true> cpu_ticks{linkage,
|
||||
16000,
|
||||
77,
|
||||
65535,
|
||||
"cpu_ticks",
|
||||
Category::Cpu,
|
||||
Specialization::Countable,
|
||||
true,
|
||||
true,
|
||||
&use_custom_cpu_ticks};
|
||||
|
||||
SwitchableSetting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
|
||||
|
||||
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
|
||||
@@ -668,10 +690,6 @@ struct Values {
|
||||
Setting<bool> censor_username{linkage, true, "censor_username", Category::Miscellaneous};
|
||||
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
|
||||
Setting<bool> first_launch{linkage, true, "first_launch", Category::Miscellaneous};
|
||||
Setting<bool> hide_pre_alpha_warning{linkage,
|
||||
false,
|
||||
"hide_pre_alpha_warning",
|
||||
Category::Miscellaneous};
|
||||
|
||||
// Network
|
||||
Setting<std::string> network_interface{linkage, std::string(), "network_interface",
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -158,7 +164,7 @@ ENUM(ResolutionSetup,
|
||||
Res7X,
|
||||
Res8X);
|
||||
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, Area, MaxEnum);
|
||||
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
|
||||
|
@@ -1,136 +1,187 @@
|
||||
#pragma once
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
template<typename KeyType, typename ValueType>
|
||||
template <typename KeyType, typename ValueType>
|
||||
class LRUCache {
|
||||
private:
|
||||
bool enabled = true;
|
||||
size_t capacity;
|
||||
std::list<KeyType> cache_list;
|
||||
std::unordered_map<KeyType, std::pair<typename std::list<KeyType>::iterator, ValueType>> cache_map;
|
||||
|
||||
public:
|
||||
explicit LRUCache(size_t capacity, bool enabled = true) : enabled(enabled), capacity(capacity) {
|
||||
cache_map.reserve(capacity);
|
||||
LOG_WARNING(Core, "LRU Cache initialized with state: {}", enabled ? "enabled" : "disabled");
|
||||
using key_type = KeyType;
|
||||
using value_type = ValueType;
|
||||
using size_type = std::size_t;
|
||||
|
||||
struct Statistics {
|
||||
size_type hits = 0;
|
||||
size_type misses = 0;
|
||||
void reset() noexcept { hits = misses = 0; }
|
||||
};
|
||||
|
||||
explicit LRUCache(size_type capacity, bool enabled = true)
|
||||
: enabled_{enabled}, capacity_{capacity} {
|
||||
cache_map_.reserve(capacity_);
|
||||
LOG_WARNING(Core, "LRU Cache initialised (state: {} | capacity: {})", enabled_ ? "enabled" : "disabled", capacity_);
|
||||
}
|
||||
|
||||
// Returns pointer to value if found, nullptr otherwise
|
||||
ValueType* get(const KeyType& key) {
|
||||
if (!enabled) return nullptr;
|
||||
// Non-movable copy semantics
|
||||
LRUCache(const LRUCache&) = delete;
|
||||
LRUCache& operator=(const LRUCache&) = delete;
|
||||
LRUCache(LRUCache&& other) noexcept { *this = std::move(other); }
|
||||
LRUCache& operator=(LRUCache&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
std::unique_lock this_lock(mutex_, std::defer_lock);
|
||||
std::unique_lock other_lock(other.mutex_, std::defer_lock);
|
||||
std::lock(this_lock, other_lock);
|
||||
enabled_ = other.enabled_;
|
||||
capacity_ = other.capacity_;
|
||||
cache_list_ = std::move(other.cache_list_);
|
||||
cache_map_ = std::move(other.cache_map_);
|
||||
stats_ = other.stats_;
|
||||
return *this;
|
||||
}
|
||||
~LRUCache() = default;
|
||||
|
||||
auto it = cache_map.find(key);
|
||||
if (it == cache_map.end()) {
|
||||
[[nodiscard]] value_type* get(const key_type& key) {
|
||||
if (!enabled_) [[unlikely]] return nullptr;
|
||||
std::unique_lock lock(mutex_);
|
||||
auto it = cache_map_.find(key);
|
||||
if (it == cache_map_.end()) {
|
||||
++stats_.misses;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Move the accessed item to the front of the list (most recently used)
|
||||
cache_list.splice(cache_list.begin(), cache_list, it->second.first);
|
||||
return &(it->second.second);
|
||||
move_to_front(it);
|
||||
++stats_.hits;
|
||||
return &it->second.second;
|
||||
}
|
||||
|
||||
// Returns pointer to value if found (without promoting it), nullptr otherwise
|
||||
ValueType* peek(const KeyType& key) const {
|
||||
if (!enabled) return nullptr;
|
||||
|
||||
auto it = cache_map.find(key);
|
||||
return it != cache_map.end() ? &(it->second.second) : nullptr;
|
||||
[[nodiscard]] value_type* peek(const key_type& key) const {
|
||||
if (!enabled_) [[unlikely]] return nullptr;
|
||||
std::shared_lock lock(mutex_);
|
||||
auto it = cache_map_.find(key);
|
||||
return it == cache_map_.end() ? nullptr : &it->second.second;
|
||||
}
|
||||
|
||||
// Inserts or updates a key-value pair
|
||||
void put(const KeyType& key, const ValueType& value) {
|
||||
if (!enabled) return;
|
||||
template <typename V>
|
||||
void put(const key_type& key, V&& value) {
|
||||
if (!enabled_) [[unlikely]] return;
|
||||
std::unique_lock lock(mutex_);
|
||||
insert_or_update(key, std::forward<V>(value));
|
||||
}
|
||||
|
||||
auto it = cache_map.find(key);
|
||||
|
||||
if (it != cache_map.end()) {
|
||||
// Key exists, update value and move to front
|
||||
it->second.second = value;
|
||||
cache_list.splice(cache_list.begin(), cache_list, it->second.first);
|
||||
return;
|
||||
template <typename ValueFactory>
|
||||
value_type& get_or_emplace(const key_type& key, ValueFactory&& factory) {
|
||||
std::unique_lock lock(mutex_);
|
||||
auto it = cache_map_.find(key);
|
||||
if (it != cache_map_.end()) {
|
||||
move_to_front(it);
|
||||
return it->second.second;
|
||||
}
|
||||
|
||||
// Remove the least recently used item if cache is full
|
||||
if (cache_map.size() >= capacity) {
|
||||
auto last = cache_list.back();
|
||||
cache_map.erase(last);
|
||||
cache_list.pop_back();
|
||||
}
|
||||
|
||||
// Insert new item at the front
|
||||
cache_list.push_front(key);
|
||||
cache_map[key] = {cache_list.begin(), value};
|
||||
value_type new_value = factory();
|
||||
insert_or_update(key, std::move(new_value));
|
||||
return cache_map_.find(key)->second.second;
|
||||
}
|
||||
|
||||
// Enable or disable the LRU cache
|
||||
void setEnabled(bool state) {
|
||||
enabled = state;
|
||||
LOG_WARNING(Core, "LRU Cache state changed to: {}", state ? "enabled" : "disabled");
|
||||
if (!enabled) {
|
||||
clear();
|
||||
}
|
||||
[[nodiscard]] bool contains(const key_type& key) const {
|
||||
if (!enabled_) return false;
|
||||
std::shared_lock lock(mutex_);
|
||||
return cache_map_.find(key) != cache_map_.end();
|
||||
}
|
||||
|
||||
// Check if the cache is enabled
|
||||
bool isEnabled() const {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
// Attempts to get value, returns std::nullopt if not found
|
||||
std::optional<ValueType> try_get(const KeyType& key) {
|
||||
auto* val = get(key);
|
||||
return val ? std::optional<ValueType>(*val) : std::nullopt;
|
||||
}
|
||||
|
||||
// Checks if key exists in cache
|
||||
bool contains(const KeyType& key) const {
|
||||
if (!enabled) return false;
|
||||
return cache_map.find(key) != cache_map.end();
|
||||
}
|
||||
|
||||
// Removes a key from the cache if it exists
|
||||
bool erase(const KeyType& key) {
|
||||
if (!enabled) return false;
|
||||
|
||||
auto it = cache_map.find(key);
|
||||
if (it == cache_map.end()) {
|
||||
return false;
|
||||
}
|
||||
cache_list.erase(it->second.first);
|
||||
cache_map.erase(it);
|
||||
bool erase(const key_type& key) {
|
||||
if (!enabled_) return false;
|
||||
std::unique_lock lock(mutex_);
|
||||
auto it = cache_map_.find(key);
|
||||
if (it == cache_map_.end()) return false;
|
||||
cache_list_.erase(it->second.first);
|
||||
cache_map_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes all elements from the cache
|
||||
void clear() {
|
||||
cache_map.clear();
|
||||
cache_list.clear();
|
||||
std::unique_lock lock(mutex_);
|
||||
cache_list_.clear();
|
||||
cache_map_.clear();
|
||||
stats_.reset();
|
||||
}
|
||||
|
||||
// Returns current number of elements in cache
|
||||
size_t size() const {
|
||||
return enabled ? cache_map.size() : 0;
|
||||
[[nodiscard]] size_type size() const {
|
||||
if (!enabled_) return 0;
|
||||
std::shared_lock lock(mutex_);
|
||||
return cache_map_.size();
|
||||
}
|
||||
|
||||
// Returns maximum capacity of cache
|
||||
size_t get_capacity() const {
|
||||
return capacity;
|
||||
[[nodiscard]] size_type get_capacity() const { return capacity_; }
|
||||
|
||||
void resize(size_type new_capacity) {
|
||||
if (!enabled_) return;
|
||||
std::unique_lock lock(mutex_);
|
||||
capacity_ = new_capacity;
|
||||
shrink_if_needed();
|
||||
cache_map_.reserve(capacity_);
|
||||
}
|
||||
|
||||
// Resizes the cache, evicting LRU items if new capacity is smaller
|
||||
void resize(size_t new_capacity) {
|
||||
if (!enabled) return;
|
||||
void setEnabled(bool state) {
|
||||
std::unique_lock lock(mutex_);
|
||||
enabled_ = state;
|
||||
LOG_WARNING(Core, "LRU Cache state changed to: {}", state ? "enabled" : "disabled");
|
||||
if (!enabled_) clear();
|
||||
}
|
||||
|
||||
capacity = new_capacity;
|
||||
while (cache_map.size() > capacity) {
|
||||
auto last = cache_list.back();
|
||||
cache_map.erase(last);
|
||||
cache_list.pop_back();
|
||||
[[nodiscard]] bool isEnabled() const { return enabled_; }
|
||||
|
||||
[[nodiscard]] Statistics stats() const {
|
||||
std::shared_lock lock(mutex_);
|
||||
return stats_;
|
||||
}
|
||||
|
||||
private:
|
||||
using list_type = std::list<key_type>;
|
||||
using list_iterator = typename list_type::iterator;
|
||||
using map_value_type = std::pair<list_iterator, value_type>;
|
||||
using map_type = std::unordered_map<key_type, map_value_type>;
|
||||
|
||||
template <typename V>
|
||||
void insert_or_update(const key_type& key, V&& value) {
|
||||
auto it = cache_map_.find(key);
|
||||
if (it != cache_map_.end()) {
|
||||
it->second.second = std::forward<V>(value);
|
||||
move_to_front(it);
|
||||
return;
|
||||
}
|
||||
cache_map.reserve(capacity);
|
||||
// evict LRU if full
|
||||
if (cache_map_.size() >= capacity_) {
|
||||
const auto& lru_key = cache_list_.back();
|
||||
cache_map_.erase(lru_key);
|
||||
cache_list_.pop_back();
|
||||
}
|
||||
cache_list_.push_front(key);
|
||||
cache_map_[key] = {cache_list_.begin(), std::forward<V>(value)};
|
||||
}
|
||||
|
||||
void move_to_front(typename map_type::iterator it) {
|
||||
cache_list_.splice(cache_list_.begin(), cache_list_, it->second.first);
|
||||
it->second.first = cache_list_.begin();
|
||||
}
|
||||
|
||||
void shrink_if_needed() {
|
||||
while (cache_map_.size() > capacity_) {
|
||||
const auto& lru_key = cache_list_.back();
|
||||
cache_map_.erase(lru_key);
|
||||
cache_list_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex mutex_;
|
||||
bool enabled_{true};
|
||||
size_type capacity_;
|
||||
list_type cache_list_;
|
||||
map_type cache_map_;
|
||||
mutable Statistics stats_;
|
||||
};
|
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/arm64/native_clock.h"
|
||||
#include "common/bit_cast.h"
|
||||
@@ -14,6 +14,23 @@
|
||||
|
||||
namespace Core::NCE {
|
||||
|
||||
Patcher::Patcher(Patcher&& other) noexcept
|
||||
: patch_cache(std::move(other.patch_cache)),
|
||||
m_patch_instructions(std::move(other.m_patch_instructions)),
|
||||
c(m_patch_instructions),
|
||||
m_save_context(other.m_save_context),
|
||||
m_load_context(other.m_load_context),
|
||||
mode(other.mode),
|
||||
total_program_size(other.total_program_size),
|
||||
m_relocate_module_index(other.m_relocate_module_index),
|
||||
modules(std::move(other.modules)),
|
||||
curr_patch(nullptr) {
|
||||
if (!modules.empty()) {
|
||||
curr_patch = &modules.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using namespace Common::Literals;
|
||||
using namespace oaknut::util;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "core/hle/kernel/k_typed_address.h"
|
||||
#include "core/hle/kernel/physical_memory.h"
|
||||
#include "lru_cache.h"
|
||||
#include <utility>
|
||||
|
||||
namespace Core::NCE {
|
||||
|
||||
@@ -30,6 +31,10 @@ using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>
|
||||
|
||||
class Patcher {
|
||||
public:
|
||||
Patcher(const Patcher&) = delete;
|
||||
Patcher& operator=(const Patcher&) = delete;
|
||||
Patcher(Patcher&& other) noexcept;
|
||||
Patcher& operator=(Patcher&&) noexcept = delete;
|
||||
explicit Patcher();
|
||||
~Patcher();
|
||||
|
||||
@@ -62,7 +67,7 @@ private:
|
||||
void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg);
|
||||
|
||||
private:
|
||||
static constexpr size_t CACHE_SIZE = 4096; // Cache size for patch entries
|
||||
static constexpr size_t CACHE_SIZE = 16384; // Cache size for patch entries
|
||||
LRUCache<uintptr_t, PatchTextAddress> patch_cache{CACHE_SIZE, Settings::values.lru_cache_enabled.GetValue()};
|
||||
|
||||
void BranchToPatch(uintptr_t module_dest) {
|
||||
@@ -70,7 +75,7 @@ private:
|
||||
LOG_DEBUG(Core_ARM, "LRU cache lookup for address {:#x}", module_dest);
|
||||
// Try to get existing patch entry from cache
|
||||
if (auto* cached_patch = patch_cache.get(module_dest)) {
|
||||
LOG_DEBUG(Core_ARM, "LRU cache hit for address {:#x}", module_dest);
|
||||
LOG_WARNING(Core_ARM, "LRU cache hit for address {:#x}", module_dest);
|
||||
curr_patch->m_branch_to_patch_relocations.push_back({c.offset(), *cached_patch});
|
||||
return;
|
||||
}
|
||||
|
@@ -172,7 +172,9 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
}
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
||||
cpu_ticks += ticks_to_add;
|
||||
cpu_ticks = Settings::values.use_custom_cpu_ticks.GetValue()
|
||||
? Settings::values.cpu_ticks.GetValue()
|
||||
: cpu_ticks + ticks_to_add;
|
||||
downcount -= static_cast<s64>(cpu_ticks);
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@ enum class TitleType : u8 {
|
||||
Update = 0x81,
|
||||
AOC = 0x82,
|
||||
DeltaTitle = 0x83,
|
||||
DataPatch = 0x84,
|
||||
};
|
||||
|
||||
enum class ContentRecordType : u8 {
|
||||
|
@@ -48,7 +48,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
|
||||
{1, C<&IHidServer::ActivateDebugPad>, "ActivateDebugPad"},
|
||||
{11, C<&IHidServer::ActivateTouchScreen>, "ActivateTouchScreen"},
|
||||
{21, C<&IHidServer::ActivateMouse>, "ActivateMouse"},
|
||||
{26, nullptr, "ActivateDebugMouse"},
|
||||
{26, C<&IHidServer::ActivateDebugMouse>, "ActivateDebugMouse"},
|
||||
{31, C<&IHidServer::ActivateKeyboard>, "ActivateKeyboard"},
|
||||
{32, C<&IHidServer::SendKeyboardLockKeyEvent>, "SendKeyboardLockKeyEvent"},
|
||||
{40, C<&IHidServer::AcquireXpadIdEventHandle>, "AcquireXpadIdEventHandle"},
|
||||
@@ -234,6 +234,11 @@ Result IHidServer::ActivateMouse(ClientAppletResourceUserId aruid) {
|
||||
R_RETURN(GetResourceManager()->GetMouse()->Activate(aruid.pid));
|
||||
}
|
||||
|
||||
Result IHidServer::ActivateDebugMouse(ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IHidServer::ActivateKeyboard(ClientAppletResourceUserId aruid) {
|
||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", aruid.pid);
|
||||
|
||||
|
@@ -37,6 +37,7 @@ private:
|
||||
Result ActivateDebugPad(ClientAppletResourceUserId aruid);
|
||||
Result ActivateTouchScreen(ClientAppletResourceUserId aruid);
|
||||
Result ActivateMouse(ClientAppletResourceUserId aruid);
|
||||
Result ActivateDebugMouse(ClientAppletResourceUserId aruid);
|
||||
Result ActivateKeyboard(ClientAppletResourceUserId aruid);
|
||||
Result SendKeyboardLockKeyEvent(u32 flags);
|
||||
Result AcquireXpadIdEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event,
|
||||
|
@@ -1,8 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/device_power_state.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
@@ -148,17 +152,31 @@ PSM::~PSM() = default;
|
||||
void PSM::GetBatteryChargePercentage(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PTM, "called");
|
||||
|
||||
u32 percentage = 100;
|
||||
|
||||
Common::PowerStatus power_status = Common::GetPowerStatus();
|
||||
|
||||
if (power_status.has_battery && power_status.percentage >= 0) {
|
||||
percentage = static_cast<u32>(power_status.percentage);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(battery_charge_percentage);
|
||||
rb.Push<u32>(percentage);
|
||||
}
|
||||
|
||||
void PSM::GetChargerType(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PTM, "called");
|
||||
|
||||
ChargerType charger = ChargerType::Unplugged;
|
||||
Common::PowerStatus power_status = Common::GetPowerStatus();
|
||||
if (power_status.has_battery && power_status.charging) {
|
||||
charger = ChargerType::RegularCharger;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(charger_type);
|
||||
rb.PushEnum(charger);
|
||||
}
|
||||
|
||||
void PSM::OpenSession(HLERequestContext& ctx) {
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -23,9 +26,6 @@ private:
|
||||
void GetBatteryChargePercentage(HLERequestContext& ctx);
|
||||
void GetChargerType(HLERequestContext& ctx);
|
||||
void OpenSession(HLERequestContext& ctx);
|
||||
|
||||
u32 battery_charge_percentage{100};
|
||||
ChargerType charger_type{ChargerType::RegularCharger};
|
||||
};
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/buffer_cache/memory_tracker_base.h"
|
||||
|
||||
|
@@ -34,7 +34,7 @@ constexpr std::array PreferredGpuDecoders = {
|
||||
AV_HWDEVICE_TYPE_VAAPI,
|
||||
AV_HWDEVICE_TYPE_VDPAU,
|
||||
#endif
|
||||
AV_HWDEVICE_TYPE_VULKAN,
|
||||
AV_HWDEVICE_TYPE_VULKAN
|
||||
};
|
||||
|
||||
AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
|
||||
@@ -99,8 +99,7 @@ bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceTyp
|
||||
for (int i = 0;; i++) {
|
||||
const AVCodecHWConfig* config = avcodec_get_hw_config(m_codec, i);
|
||||
if (!config) {
|
||||
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;
|
||||
}
|
||||
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
|
||||
@@ -131,8 +130,7 @@ HardwareContext::~HardwareContext() {
|
||||
av_buffer_unref(&m_gpu_decoder);
|
||||
}
|
||||
|
||||
bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context,
|
||||
const Decoder& decoder) {
|
||||
bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder) {
|
||||
const auto supported_types = GetSupportedDeviceTypes();
|
||||
for (const auto type : PreferredGpuDecoders) {
|
||||
AVPixelFormat hw_pix_fmt;
|
||||
@@ -152,17 +150,14 @@ bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context,
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO(HW_GPU, "Hardware decoding is disabled due to implementation issues, using CPU.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HardwareContext::InitializeWithType(AVHWDeviceType type) {
|
||||
av_buffer_unref(&m_gpu_decoder);
|
||||
|
||||
if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0);
|
||||
ret < 0) {
|
||||
LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type),
|
||||
AVError(ret));
|
||||
if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0); ret < 0) {
|
||||
LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type), AVError(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -189,6 +184,7 @@ bool HardwareContext::InitializeWithType(AVHWDeviceType type) {
|
||||
|
||||
DecoderContext::DecoderContext(const Decoder& decoder) : m_decoder{decoder} {
|
||||
m_codec_context = avcodec_alloc_context3(m_decoder.GetCodec());
|
||||
av_opt_set(m_codec_context->priv_data, "preset", "veryfast", 0);
|
||||
av_opt_set(m_codec_context->priv_data, "tune", "zerolatency", 0);
|
||||
m_codec_context->thread_count = 0;
|
||||
m_codec_context->thread_type &= ~FF_THREAD_FRAME;
|
||||
@@ -199,8 +195,7 @@ DecoderContext::~DecoderContext() {
|
||||
avcodec_free_context(&m_codec_context);
|
||||
}
|
||||
|
||||
void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context,
|
||||
AVPixelFormat hw_pix_fmt) {
|
||||
void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context, AVPixelFormat hw_pix_fmt) {
|
||||
m_codec_context->hw_device_ctx = av_buffer_ref(context.GetBufferRef());
|
||||
m_codec_context->get_format = GetGpuFormat;
|
||||
m_codec_context->pix_fmt = hw_pix_fmt;
|
||||
@@ -223,21 +218,15 @@ bool DecoderContext::SendPacket(const Packet& packet) {
|
||||
m_temp_frame = std::make_shared<Frame>();
|
||||
m_got_frame = 0;
|
||||
|
||||
// Android can randomly crash when calling decode directly, so skip.
|
||||
// TODO update ffmpeg and hope that fixes it.
|
||||
#ifndef ANDROID
|
||||
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||
m_decode_order = true;
|
||||
auto* codec{ffcodec(m_decoder.GetCodec())};
|
||||
if (const int ret = codec->cb.decode(m_codec_context, m_temp_frame->GetFrame(),
|
||||
&m_got_frame, packet.GetPacket());
|
||||
ret < 0) {
|
||||
if (const int ret = codec->cb.decode(m_codec_context, m_temp_frame->GetFrame(), &m_got_frame, packet.GetPacket()); ret < 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", AVError(ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0) {
|
||||
LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
|
||||
@@ -248,9 +237,6 @@ bool DecoderContext::SendPacket(const Packet& packet) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||
// Android can randomly crash when calling decode directly, so skip.
|
||||
// TODO update ffmpeg and hope that fixes it.
|
||||
#ifndef ANDROID
|
||||
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||
m_decode_order = true;
|
||||
auto* codec{ffcodec(m_decoder.GetCodec())};
|
||||
@@ -269,10 +255,7 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||
LOG_ERROR(Service_NVDRV, "Failed to receive a frame! error {}", ret);
|
||||
return {};
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
} else {
|
||||
const auto ReceiveImpl = [&](AVFrame* frame) {
|
||||
if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0) {
|
||||
LOG_ERROR(HW_GPU, "avcodec_receive_frame error: {}", AVError(ret));
|
||||
@@ -292,9 +275,7 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||
}
|
||||
|
||||
m_temp_frame->SetFormat(PreferredGpuFormat);
|
||||
if (const int ret = av_hwframe_transfer_data(m_temp_frame->GetFrame(),
|
||||
intermediate_frame.GetFrame(), 0);
|
||||
ret < 0) {
|
||||
if (const 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));
|
||||
return {};
|
||||
}
|
||||
|
@@ -21,9 +21,7 @@ extern "C" {
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
#ifndef ANDROID
|
||||
#include <libavcodec/codec_internal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
|
@@ -42,6 +42,7 @@ set(SHADER_FILES
|
||||
opengl_present_scaleforce.frag
|
||||
opengl_smaa.glsl
|
||||
pitch_unswizzle.comp
|
||||
present_area.frag
|
||||
present_bicubic.frag
|
||||
present_gaussian.frag
|
||||
queries_prefix_scan_sum.comp
|
||||
|
107
src/video_core/host_shaders/present_area.frag
Normal file
107
src/video_core/host_shaders/present_area.frag
Normal file
@@ -0,0 +1,107 @@
|
||||
#version 460 core
|
||||
|
||||
layout(location = 0) in vec2 frag_tex_coord;
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(binding = 0) uniform sampler2D color_texture;
|
||||
|
||||
#ifdef VULKAN
|
||||
|
||||
struct ScreenRectVertex {
|
||||
vec2 position;
|
||||
vec2 tex_coord;
|
||||
};
|
||||
layout (push_constant) uniform PushConstants {
|
||||
mat4 modelview_matrix;
|
||||
ScreenRectVertex vertices[4];
|
||||
};
|
||||
|
||||
#else // OpenGL
|
||||
|
||||
layout(location = 1) uniform uvec2 screen_size;
|
||||
|
||||
#endif
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(sampler2D textureSampler, vec2 texCoords, vec2 source_size, vec2 target_size) {
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Determine the range of the source image that the target pixel will cover.
|
||||
vec2 range = source_size * inverted_target_size;
|
||||
vec2 beg = (texCoords.xy * source_size) - (range * 0.5);
|
||||
vec2 end = beg + range;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(floor(beg));
|
||||
ivec2 f_end = ivec2(floor(end));
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(textureSampler, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(textureSampler, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(textureSampler, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(textureSampler, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
|
||||
avg_color += area_n * texelFetch(textureSampler, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(textureSampler, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) {
|
||||
avg_color += area_w * texelFetch(textureSampler, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(textureSampler, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
|
||||
avg_color += texelFetch(textureSampler, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 source_image_size = textureSize(color_texture, 0);
|
||||
vec2 window_size;
|
||||
|
||||
#ifdef VULKAN
|
||||
window_size.x = vertices[1].position.x - vertices[0].position.x;
|
||||
window_size.y = vertices[2].position.y - vertices[0].position.y;
|
||||
#else // OpenGL
|
||||
window_size = screen_size;
|
||||
#endif
|
||||
|
||||
color = AreaSampling(color_texture, frag_tex_coord, source_image_size, window_size);
|
||||
}
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -86,6 +92,9 @@ void BlitScreen::CreateWindowAdapt() {
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
window_adapt = MakeScaleForce(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Area:
|
||||
window_adapt = MakeArea(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
default:
|
||||
|
@@ -1,8 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/host_shaders/opengl_present_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
|
||||
#include "video_core/host_shaders/present_area_frag.h"
|
||||
#include "video_core/host_shaders/present_bicubic_frag.h"
|
||||
#include "video_core/host_shaders/present_gaussian_frag.h"
|
||||
#include "video_core/renderer_opengl/present/filters.h"
|
||||
@@ -36,4 +43,9 @@ std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device) {
|
||||
fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG));
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(),
|
||||
HostShaders::PRESENT_AREA_FRAG);
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -13,5 +19,6 @@ std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device);
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -10,6 +16,7 @@ namespace OpenGL {
|
||||
constexpr GLint PositionLocation = 0;
|
||||
constexpr GLint TexCoordLocation = 1;
|
||||
constexpr GLint ModelViewMatrixLocation = 0;
|
||||
constexpr GLint ScreenSizeLocation = 1;
|
||||
|
||||
struct ScreenRectVertex {
|
||||
constexpr ScreenRectVertex() = default;
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -110,6 +116,9 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li
|
||||
glBindTextureUnit(0, textures[i]);
|
||||
glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE,
|
||||
matrices[i].data());
|
||||
glProgramUniform2ui(frag.handle, ScreenSizeLocation,
|
||||
static_cast<GLuint>(layout.screen.GetWidth()),
|
||||
static_cast<GLuint>(layout.screen.GetHeight()));
|
||||
glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices[i]), std::data(vertices[i]));
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
@@ -1,8 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "video_core/host_shaders/present_area_frag_spv.h"
|
||||
#include "video_core/host_shaders/present_bicubic_frag_spv.h"
|
||||
#include "video_core/host_shaders/present_gaussian_frag_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_present_frag_spv.h"
|
||||
@@ -53,4 +60,9 @@ std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat f
|
||||
SelectScaleForceShader(device));
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device, VkFormat frame_format) {
|
||||
return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device),
|
||||
BuildShader(device, PRESENT_AREA_FRAG_SPV));
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -14,5 +20,6 @@ std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat fra
|
||||
std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format);
|
||||
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format);
|
||||
std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format);
|
||||
std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device, VkFormat frame_format);
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -43,6 +49,9 @@ void BlitScreen::SetWindowAdaptPass() {
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
window_adapt = MakeScaleForce(device, swapchain_view_format);
|
||||
break;
|
||||
case Settings::ScalingFilter::Area:
|
||||
window_adapt = MakeArea(device, swapchain_view_format);
|
||||
break;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
default:
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -928,6 +931,7 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info,
|
||||
|
||||
void RasterizerVulkan::UpdateDynamicStates() {
|
||||
auto& regs = maxwell3d->regs;
|
||||
|
||||
UpdateViewportsState(regs);
|
||||
UpdateScissorsState(regs);
|
||||
UpdateDepthBias(regs);
|
||||
@@ -935,7 +939,24 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||
UpdateDepthBounds(regs);
|
||||
UpdateStencilFaces(regs);
|
||||
UpdateLineWidth(regs);
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
|
||||
const u8 dynamic_state = Settings::values.dyna_state.GetValue();
|
||||
|
||||
auto features = DynamicFeatures{
|
||||
.has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported()
|
||||
&& dynamic_state > 0,
|
||||
.has_extended_dynamic_state_2 = device.IsExtExtendedDynamicState2Supported()
|
||||
&& dynamic_state > 1,
|
||||
.has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported()
|
||||
&& dynamic_state > 1,
|
||||
.has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported()
|
||||
&& dynamic_state > 2,
|
||||
.has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported()
|
||||
&& dynamic_state > 2,
|
||||
.has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(),
|
||||
};
|
||||
|
||||
if (features.has_extended_dynamic_state) {
|
||||
UpdateCullMode(regs);
|
||||
UpdateDepthCompareOp(regs);
|
||||
UpdateFrontFace(regs);
|
||||
@@ -946,45 +967,54 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||
UpdateDepthTestEnable(regs);
|
||||
UpdateDepthWriteEnable(regs);
|
||||
UpdateStencilTestEnable(regs);
|
||||
if (device.IsExtExtendedDynamicState2Supported()) {
|
||||
|
||||
if (features.has_extended_dynamic_state_2) {
|
||||
UpdatePrimitiveRestartEnable(regs);
|
||||
UpdateRasterizerDiscardEnable(regs);
|
||||
UpdateDepthBiasEnable(regs);
|
||||
}
|
||||
if (device.IsExtExtendedDynamicState3EnablesSupported()) {
|
||||
|
||||
if (features.has_extended_dynamic_state_3_enables) {
|
||||
using namespace Tegra::Engines;
|
||||
|
||||
if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE
|
||||
|| device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) {
|
||||
struct In {
|
||||
struct In
|
||||
{
|
||||
const Maxwell3D::Regs::VertexAttribute::Type d;
|
||||
In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {}
|
||||
bool operator()(Maxwell3D::Regs::VertexAttribute n) const {
|
||||
In(Maxwell3D::Regs::VertexAttribute::Type n)
|
||||
: d(n)
|
||||
{}
|
||||
bool operator()(Maxwell3D::Regs::VertexAttribute n) const
|
||||
{
|
||||
return n.type == d;
|
||||
}
|
||||
};
|
||||
|
||||
auto has_float = std::any_of(
|
||||
regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(),
|
||||
In(Maxwell3D::Regs::VertexAttribute::Type::Float));
|
||||
auto has_float = std::any_of(regs.vertex_attrib_format.begin(),
|
||||
regs.vertex_attrib_format.end(),
|
||||
In(Maxwell3D::Regs::VertexAttribute::Type::Float));
|
||||
|
||||
if (regs.logic_op.enable)
|
||||
regs.logic_op.enable = static_cast<u32>(!has_float);
|
||||
|
||||
UpdateLogicOpEnable(regs);
|
||||
} else
|
||||
} else {
|
||||
UpdateLogicOpEnable(regs);
|
||||
}
|
||||
UpdateDepthClampEnable(regs);
|
||||
}
|
||||
}
|
||||
if (device.IsExtExtendedDynamicState2ExtrasSupported()) {
|
||||
if (features.has_extended_dynamic_state_2_extra) {
|
||||
UpdateLogicOp(regs);
|
||||
}
|
||||
if (device.IsExtExtendedDynamicState3Supported()) {
|
||||
if (features.has_extended_dynamic_state_3_enables) {
|
||||
UpdateBlending(regs);
|
||||
UpdateLineStippleEnable(regs);
|
||||
UpdateConservativeRasterizationMode(regs);
|
||||
}
|
||||
}
|
||||
if (device.IsExtVertexInputDynamicStateSupported()) {
|
||||
if (features.has_dynamic_vertex_input) {
|
||||
UpdateVertexInput(regs);
|
||||
}
|
||||
}
|
||||
@@ -1104,25 +1134,39 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
|
||||
|
||||
size_t length = sizeof(NEEDS_D24) / sizeof(u64);
|
||||
bool needs_convert = false;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (NEEDS_D24[i] == program_id) {
|
||||
needs_convert = true;
|
||||
break;
|
||||
if (is_d24 && !device.SupportsD24DepthBuffer()) {
|
||||
static constexpr const size_t length = sizeof(NEEDS_D24) / sizeof(NEEDS_D24[0]);
|
||||
|
||||
static constexpr const u64 *start = NEEDS_D24;
|
||||
static constexpr const u64 *end = NEEDS_D24 + length;
|
||||
|
||||
const u64 *it = std::find(start, end, program_id);
|
||||
|
||||
if (it != end) {
|
||||
// the base formulas can be obtained from here:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
|
||||
const double rescale_factor = static_cast<double>(1ULL << (32 - 24))
|
||||
/ (static_cast<double>(0x1.ep+127));
|
||||
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_d24 && !device.SupportsD24DepthBuffer() && needs_convert) {
|
||||
// the base formulas can be obtained from here:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
|
||||
const double rescale_factor = static_cast<double>(1ULL << (32 - 24))
|
||||
/ (static_cast<double>(0x1.ep+127));
|
||||
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
||||
} scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
|
||||
factor = regs.slope_scale_depth_bias](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||
});
|
||||
scheduler.Record(
|
||||
[constant = units, clamp = regs.depth_bias_clamp, factor = regs.slope_scale_depth_bias, this](
|
||||
vk::CommandBuffer cmdbuf) {
|
||||
if (device.IsExtDepthBiasControlSupported()) {
|
||||
static VkDepthBiasRepresentationInfoEXT bias_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.depthBiasRepresentation = VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
|
||||
.depthBiasExact = VK_FALSE,
|
||||
};
|
||||
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor, &bias_info);
|
||||
} else {
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
@@ -1304,6 +1348,45 @@ void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
{
|
||||
if (!state_tracker.TouchConservativeRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetConservativeRasterizationModeEXT(
|
||||
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT
|
||||
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
{
|
||||
if (!state_tracker.TouchLineStippleEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineStippleEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
{
|
||||
// if (!state_tracker.TouchLi()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// TODO: The maxwell emulator does not capture line rasters
|
||||
|
||||
// scheduler.Record([enable = regs.line](vk::CommandBuffer cmdbuf) {
|
||||
// cmdbuf.SetConservativeRasterizationModeEXT(
|
||||
// enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT
|
||||
// : VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
// });
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchDepthBiasEnable()) {
|
||||
return;
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -139,7 +142,7 @@ public:
|
||||
u32 pixel_stride);
|
||||
|
||||
private:
|
||||
static constexpr u64 NEEDS_D24[] = {
|
||||
static constexpr const u64 NEEDS_D24[] = {
|
||||
0x01006A800016E000ULL, // SSBU
|
||||
0x0100E95004038000ULL, // XC2
|
||||
0x0100A6301214E000ULL, // FE:Engage
|
||||
@@ -175,6 +178,9 @@ private:
|
||||
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -50,6 +53,8 @@ Flags MakeInvalidationFlags() {
|
||||
StateEnable,
|
||||
PrimitiveRestartEnable,
|
||||
RasterizerDiscardEnable,
|
||||
ConservativeRasterizationMode,
|
||||
LineStippleEnable,
|
||||
DepthBiasEnable,
|
||||
LogicOpEnable,
|
||||
DepthClampEnable,
|
||||
@@ -137,6 +142,8 @@ void SetupDirtyStateEnable(Tables& tables) {
|
||||
setup(OFF(stencil_enable), StencilTestEnable);
|
||||
setup(OFF(primitive_restart.enabled), PrimitiveRestartEnable);
|
||||
setup(OFF(rasterize_enable), RasterizerDiscardEnable);
|
||||
setup(OFF(conservative_raster_enable), ConservativeRasterizationMode);
|
||||
setup(OFF(line_stipple_enable), LineStippleEnable);
|
||||
setup(OFF(polygon_offset_point_enable), DepthBiasEnable);
|
||||
setup(OFF(polygon_offset_line_enable), DepthBiasEnable);
|
||||
setup(OFF(polygon_offset_fill_enable), DepthBiasEnable);
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -50,6 +53,8 @@ enum : u8 {
|
||||
StencilTestEnable,
|
||||
PrimitiveRestartEnable,
|
||||
RasterizerDiscardEnable,
|
||||
ConservativeRasterizationMode,
|
||||
LineStippleEnable,
|
||||
DepthBiasEnable,
|
||||
StateEnable,
|
||||
LogicOp,
|
||||
@@ -200,10 +205,15 @@ public:
|
||||
return Exchange(Dirty::RasterizerDiscardEnable, false);
|
||||
}
|
||||
|
||||
bool TouchDepthBiasEnable() {
|
||||
return Exchange(Dirty::DepthBiasEnable, false);
|
||||
bool TouchConservativeRasterizationMode()
|
||||
{
|
||||
return Exchange(Dirty::ConservativeRasterizationMode, false);
|
||||
}
|
||||
|
||||
bool TouchLineStippleEnable() { return Exchange(Dirty::ConservativeRasterizationMode, false); }
|
||||
|
||||
bool TouchDepthBiasEnable() { return Exchange(Dirty::DepthBiasEnable, false); }
|
||||
|
||||
bool TouchLogicOpEnable() {
|
||||
return Exchange(Dirty::LogicOpEnable, false);
|
||||
}
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -141,6 +144,9 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkCmdSetDepthWriteEnableEXT);
|
||||
X(vkCmdSetPrimitiveRestartEnableEXT);
|
||||
X(vkCmdSetRasterizerDiscardEnableEXT);
|
||||
X(vkCmdSetConservativeRasterizationModeEXT);
|
||||
X(vkCmdSetLineRasterizationModeEXT);
|
||||
X(vkCmdSetLineStippleEnableEXT);
|
||||
X(vkCmdSetDepthBiasEnableEXT);
|
||||
X(vkCmdSetLogicOpEnableEXT);
|
||||
X(vkCmdSetDepthClampEnableEXT);
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -234,6 +237,9 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{};
|
||||
PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{};
|
||||
PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{};
|
||||
PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT{};
|
||||
PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT{};
|
||||
PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT{};
|
||||
PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{};
|
||||
PFN_vkCmdSetLogicOpEnableEXT vkCmdSetLogicOpEnableEXT{};
|
||||
PFN_vkCmdSetDepthClampEnableEXT vkCmdSetDepthClampEnableEXT{};
|
||||
@@ -1431,6 +1437,21 @@ public:
|
||||
dld->vkCmdSetRasterizerDiscardEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||
}
|
||||
|
||||
void SetConservativeRasterizationModeEXT(VkConservativeRasterizationModeEXT mode) const noexcept
|
||||
{
|
||||
dld->vkCmdSetConservativeRasterizationModeEXT(handle, mode);
|
||||
}
|
||||
|
||||
void SetLineRasterizationModeEXT(VkLineRasterizationModeEXT mode) const noexcept
|
||||
{
|
||||
dld->vkCmdSetLineRasterizationModeEXT(handle, mode);
|
||||
}
|
||||
|
||||
void SetLineStippleEnableEXT(bool enable) const noexcept
|
||||
{
|
||||
dld->vkCmdSetLineStippleEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||
}
|
||||
|
||||
void SetDepthBiasEnableEXT(bool enable) const noexcept {
|
||||
dld->vkCmdSetDepthBiasEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||
}
|
||||
|
@@ -366,7 +366,7 @@ target_sources(yuzu
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
set(MACOSX_ICON "../../dist/yuzu.icns")
|
||||
set(MACOSX_ICON "../../dist/eden.icns")
|
||||
set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
target_sources(yuzu PRIVATE ${MACOSX_ICON})
|
||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
@@ -374,7 +374,7 @@ if (APPLE)
|
||||
|
||||
if (NOT USE_SYSTEM_MOLTENVK)
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
set(MOLTENVK_VERSION "v1.2.7")
|
||||
set(MOLTENVK_VERSION "v1.3.0")
|
||||
download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||
endif()
|
||||
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
|
||||
|
@@ -1,3 +1,8 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
@@ -15,7 +20,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>yuzu.icns</string>
|
||||
<string>eden.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.yuzu-emu.yuzu</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
@@ -23,7 +28,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleName</key>
|
||||
<string>yuzu</string>
|
||||
<string>eden</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
@@ -73,8 +73,9 @@ void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) {
|
||||
} else if (setting->Id() == Settings::values.cpu_backend.Id()) {
|
||||
backend_layout->addWidget(widget);
|
||||
backend_combobox = widget->combobox;
|
||||
} else if (setting->Id() == Settings::values.fast_cpu_time.Id()
|
||||
|| setting->Id() == Settings::values.use_fast_cpu_time.Id()) {
|
||||
} else if (setting->Id() == Settings::values.fast_cpu_time.Id()) {
|
||||
ui->general_layout->addWidget(widget);
|
||||
} else if (setting->Id() == Settings::values.cpu_ticks.Id()) {
|
||||
ui->general_layout->addWidget(widget);
|
||||
} else {
|
||||
// Presently, all other settings here are unsafe checkboxes
|
||||
|
@@ -1,8 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "yuzu/configuration/configure_profile_manager.h"
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
@@ -18,8 +20,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "ui_configure_profile_manager.h"
|
||||
#include "yuzu/configuration/configure_profile_manager.h"
|
||||
#include "yuzu/util/limitable_input_dialog.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
// Same backup JPEG used by acc IProfile::GetImage if no jpeg found
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -100,6 +106,13 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
|
||||
tr("Overclocks the emulated CPU to remove some FPS limiters. Weaker CPUs may see reduced performance, "
|
||||
"and certain games may behave improperly.\nUse Boost (1700MHz) to run at the Switch's highest native "
|
||||
"clock, or Fast (2000MHz) to run at 2x clock."));
|
||||
|
||||
INSERT(Settings, use_custom_cpu_ticks, QString(), QString());
|
||||
INSERT(Settings,
|
||||
cpu_ticks,
|
||||
tr("Custom CPU Ticks"),
|
||||
tr("Set a custom value of CPU ticks. Higher values can increase performance, but may "
|
||||
"also cause the game to freeze. A range of 77–21000 is recommended."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
// Cpu Debug
|
||||
@@ -536,6 +549,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent)
|
||||
PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
|
||||
PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
|
||||
PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
|
||||
PAIR(ScalingFilter, Area, tr("Area")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
|
||||
{
|
||||
|
@@ -1,3 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -40,6 +46,7 @@ static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map
|
||||
{Settings::ScalingFilter::ScaleForce,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
|
||||
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
|
||||
{Settings::ScalingFilter::Area, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Area"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
|
||||
|
@@ -371,40 +371,6 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
warning_layout = new QHBoxLayout;
|
||||
pre_alpha_warning = new QLabel;
|
||||
pre_alpha_warning->setText(
|
||||
tr("IMPORTANT: Eden is PRE-ALPHA SOFTWARE. "
|
||||
"Bugs and unfinished features are expected to be present at this stage."));
|
||||
pre_alpha_warning->setWordWrap(true);
|
||||
pre_alpha_warning->setOpenExternalLinks(true);
|
||||
pre_alpha_warning->setStyleSheet(
|
||||
QString::fromStdString("color: black; font-weight: bold;"));
|
||||
|
||||
warning_dont_show_again = new QPushButton(this);
|
||||
warning_dont_show_again->setStyleSheet(
|
||||
QString::fromStdString("color: #DFDFDF; background-color: #383838;"));
|
||||
warning_dont_show_again->setText(tr("Don't Show Again"));
|
||||
connect(warning_dont_show_again, &QPushButton::clicked, this, [=, this] {
|
||||
Settings::values.hide_pre_alpha_warning.SetValue(true);
|
||||
|
||||
layout->removeWidget(warning_widget);
|
||||
warning_widget->hide();
|
||||
});
|
||||
|
||||
warning_layout->addWidget(pre_alpha_warning, 1);
|
||||
warning_layout->addWidget(warning_dont_show_again);
|
||||
warning_layout->setContentsMargins(3, 3, 3, 3);
|
||||
warning_widget = new QWidget;
|
||||
warning_widget->setStyleSheet(QString::fromStdString("background-color: khaki;"));
|
||||
warning_widget->setLayout(warning_layout);
|
||||
|
||||
if (!Settings::values.hide_pre_alpha_warning.GetValue()) {
|
||||
layout->addWidget(warning_widget);
|
||||
} else {
|
||||
warning_widget->hide();
|
||||
}
|
||||
|
||||
layout->addWidget(tree_view);
|
||||
layout->addWidget(search_field);
|
||||
setLayout(layout);
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -176,11 +179,6 @@ private:
|
||||
ControllerNavigation* controller_navigation = nullptr;
|
||||
CompatibilityList compatibility_list;
|
||||
|
||||
QHBoxLayout* warning_layout = nullptr;
|
||||
QWidget* warning_widget = nullptr;
|
||||
QPushButton* warning_dont_show_again = nullptr;
|
||||
QLabel* pre_alpha_warning = nullptr;
|
||||
|
||||
friend class GameListSearchField;
|
||||
|
||||
const PlayTime::PlayTimeManager& play_time_manager;
|
||||
|
@@ -2407,6 +2407,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
|
||||
|
||||
ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
|
||||
|
||||
// TODO(alekpop): It returns the wrong user
|
||||
switch (target) {
|
||||
case GameListOpenTarget::SaveData: {
|
||||
open_target = tr("Save Data");
|
||||
|
Reference in New Issue
Block a user