mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-21 23:39:55 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9e6ddf2a9 | |||
| c8c61a12c3 | |||
| b05463ee19 | |||
| 561adac0af | |||
| 62ef8b15fd | |||
| 8e9513cb5f | |||
| 950e0f82fb | |||
| 74a6607f8e | |||
| 5ebb5b8772 | |||
| 73918d23d5 | |||
| ef4113aeaa | |||
| 78a1cd0533 | |||
| 026974211e | |||
| d698c3b601 | |||
| 60e1032771 | |||
| 1071353291 | |||
| eb8086a011 | |||
| 4edb1ac6c5 | |||
| 3875093c70 | |||
| 86895a5f6a |
Vendored
+184
@@ -0,0 +1,184 @@
|
||||
; SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
; Usage:
|
||||
; get the latest nsis: https://nsis.sourceforge.io/Download
|
||||
|
||||
; Require these for makensis.
|
||||
!ifndef PRODUCT_VERSION
|
||||
!error "PRODUCT_VERSION must be defined"
|
||||
!endif
|
||||
|
||||
!ifndef ARCH
|
||||
!error "ARCH must be defined"
|
||||
!endif
|
||||
|
||||
!ifndef VARIANT
|
||||
!error "VARIANT must be defined"
|
||||
!endif
|
||||
|
||||
Unicode true
|
||||
ManifestDPIAware true
|
||||
|
||||
!define PRODUCT_NAME "Eden"
|
||||
!define PRODUCT_PUBLISHER "Utopia LLC"
|
||||
!define PRODUCT_WEB_SITE "https://git.eden-emu.dev"
|
||||
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe"
|
||||
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
|
||||
!define BINARY_SOURCE_DIR "..\bin"
|
||||
|
||||
Name "${PRODUCT_NAME}"
|
||||
OutFile "${PRODUCT_NAME}-Windows-${PRODUCT_VERSION}-${ARCH}-${VARIANT}-installer.exe"
|
||||
SetCompressor /SOLID lzma
|
||||
InstallDir "$LOCALAPPDATA\$(^Name)"
|
||||
ShowInstDetails show
|
||||
ShowUnInstDetails show
|
||||
|
||||
!include "MUI2.nsh"
|
||||
; Custom page plugin
|
||||
!include "nsDialogs.nsh"
|
||||
|
||||
; MUI Settings
|
||||
!define MUI_ICON "eden.ico"
|
||||
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
|
||||
|
||||
; License page
|
||||
!insertmacro MUI_PAGE_LICENSE "..\LICENSE.txt"
|
||||
; Desktop Shortcut page
|
||||
Page custom desktopShortcutPageCreate desktopShortcutPageLeave
|
||||
; Directory page
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
; Instfiles page
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
; Finish page
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\eden.exe"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
; Uninstaller pages
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
; Variables
|
||||
Var DesktopShortcutPageDialog
|
||||
Var DesktopShortcutCheckbox
|
||||
Var DesktopShortcut
|
||||
|
||||
; Language files
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
!insertmacro MUI_LANGUAGE "TradChinese"
|
||||
!insertmacro MUI_LANGUAGE "Danish"
|
||||
!insertmacro MUI_LANGUAGE "Dutch"
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Hungarian"
|
||||
!insertmacro MUI_LANGUAGE "Italian"
|
||||
!insertmacro MUI_LANGUAGE "Japanese"
|
||||
!insertmacro MUI_LANGUAGE "Korean"
|
||||
!insertmacro MUI_LANGUAGE "Lithuanian"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Polish"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Romanian"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Spanish"
|
||||
!insertmacro MUI_LANGUAGE "Swedish"
|
||||
!insertmacro MUI_LANGUAGE "Turkish"
|
||||
!insertmacro MUI_LANGUAGE "Vietnamese"
|
||||
|
||||
; MUI end ------
|
||||
|
||||
Function .onInit
|
||||
StrCpy $DesktopShortcut 1
|
||||
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
FunctionEnd
|
||||
|
||||
Function desktopShortcutPageCreate
|
||||
!insertmacro MUI_HEADER_TEXT "Create Desktop Shortcut" "Would you like to create a desktop shortcut?"
|
||||
nsDialogs::Create 1018
|
||||
Pop $DesktopShortcutPageDialog
|
||||
${If} $DesktopShortcutPageDialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateCheckbox} 0u 0u 100% 12u "Create a desktop shortcut"
|
||||
Pop $DesktopShortcutCheckbox
|
||||
${NSD_SetState} $DesktopShortcutCheckbox $DesktopShortcut
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function desktopShortcutPageLeave
|
||||
${NSD_GetState} $DesktopShortcutCheckbox $DesktopShortcut
|
||||
FunctionEnd
|
||||
|
||||
Section "Base"
|
||||
ExecWait '"$INSTDIR\uninst.exe" /S _?=$INSTDIR'
|
||||
|
||||
SectionIn RO
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
; The binplaced build output will be included verbatim.
|
||||
File /r "${BINARY_SOURCE_DIR}\*"
|
||||
|
||||
; Create start menu and desktop shortcuts
|
||||
CreateShortCut "$SMPROGRAMS\$(^Name).lnk" "$INSTDIR\eden.exe"
|
||||
${If} $DesktopShortcut == 1
|
||||
CreateShortCut "$DESKTOP\$(^Name).lnk" "$INSTDIR\eden.exe"
|
||||
${EndIf}
|
||||
SectionEnd
|
||||
|
||||
!include "FileFunc.nsh"
|
||||
|
||||
Section -Post
|
||||
WriteUninstaller "$INSTDIR\uninst.exe"
|
||||
|
||||
WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\eden.exe"
|
||||
|
||||
; Write metadata for add/remove programs applet
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\eden.exe"
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR"
|
||||
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||||
IntFmt $0 "0x%08X" $0
|
||||
WriteRegDWORD HKCU "${PRODUCT_UNINST_KEY}" "EstimatedSize" "$0"
|
||||
|
||||
WriteRegStr HKCU "Software\Classes\.nsp" "" "$(^Name)"
|
||||
WriteRegStr HKCU "Software\Classes\.xci" "" "$(^Name)"
|
||||
WriteRegStr HKCU "Software\Classes\.nro" "" "$(^Name)"
|
||||
WriteRegStr HKCU "Software\Classes\.kip" "" "$(^Name)"
|
||||
WriteRegStr HKCU "Software\Classes\$(^Name)\DefaultIcon" "" "$INSTDIR\eden.exe,0"
|
||||
WriteRegStr HKCU "Software\Classes\$(^Name)\Shell\open\command" "" '"$INSTDIR\eden.exe" %1'
|
||||
SectionEnd
|
||||
|
||||
Section Uninstall
|
||||
Delete "$DESKTOP\$(^Name).lnk"
|
||||
Delete "$SMPROGRAMS\$(^Name).lnk"
|
||||
|
||||
; Be a bit careful to not delete files a user may have put into the install directory.
|
||||
Delete "$INSTDIR\eden.exe"
|
||||
Delete "$INSTDIR\eden-cli.exe"
|
||||
Delete "$INSTDIR\uninst.exe"
|
||||
Delete "$INSTDIR\LICENSE.txt"
|
||||
Delete "$INSTDIR\README.md"
|
||||
RMDir /r "$INSTDIR\LICENSES"
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
DeleteRegKey HKCU "Software\Classes\.nsp"
|
||||
DeleteRegKey HKCU "Software\Classes\.xci"
|
||||
DeleteRegKey HKCU "Software\Classes\.nro"
|
||||
DeleteRegKey HKCU "Software\Classes\.kip"
|
||||
DeleteRegKey HKCU "Software\Classes\$(^Name)"
|
||||
|
||||
DeleteRegKey HKCU "Software\Classes\discord-1397286652128264252"
|
||||
|
||||
DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}"
|
||||
DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}"
|
||||
|
||||
SetAutoClose true
|
||||
SectionEnd
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
@@ -11,6 +11,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
enum class StringSetting(override val key: String) : AbstractStringSetting {
|
||||
DRIVER_PATH("driver_path"),
|
||||
DEVICE_NAME("device_name"),
|
||||
PROGRAM_ARGS("program_args"),
|
||||
|
||||
WEB_TOKEN("eden_token"),
|
||||
WEB_USERNAME("eden_username")
|
||||
|
||||
+7
@@ -125,6 +125,13 @@ abstract class SettingsItem(
|
||||
// List of all general
|
||||
val settingsItems = HashMap<String, SettingsItem>().apply {
|
||||
put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
|
||||
put(
|
||||
StringInputSetting(
|
||||
StringSetting.PROGRAM_ARGS,
|
||||
titleId = R.string.program_args,
|
||||
descriptionId = R.string.program_args_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
||||
|
||||
+1
@@ -1286,6 +1286,7 @@ class SettingsFragmentPresenter(
|
||||
add(HeaderSetting(R.string.general))
|
||||
|
||||
add(ShortSetting.DEBUG_KNOBS.key)
|
||||
add(StringSetting.PROGRAM_ARGS.key)
|
||||
|
||||
add(HeaderSetting(R.string.gpu_logging_header))
|
||||
add(BooleanSetting.GPU_LOGGING_ENABLED.key)
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
<string name="overlay_auto_hide">触控叠加层自动隐藏</string>
|
||||
<string name="overlay_auto_hide_description">在指定时间内未进行任何操作后,自动隐藏触控叠加层。</string>
|
||||
<string name="enable_input_overlay_auto_hide">启用触控叠加层自动隐藏</string>
|
||||
<string name="hide_overlay_on_controller_input">使用控制器时隐藏触控叠加层</string>
|
||||
<string name="hide_overlay_on_controller_input_description">在使用实体控制器时自动隐藏触控叠加层,而当控制器断开时触控叠加层则会重新显现。</string>
|
||||
<string name="hide_overlay_on_controller_input">当使用控制器控制输入时隐藏触控叠加层</string>
|
||||
<string name="hide_overlay_on_controller_input_description">在使用实体控制器时自动隐藏触控叠加层,而当控制器断开连接时,触控叠加层则会重新显现。</string>
|
||||
<string name="invert_confirm_back_controller_buttons">切换“确认/返回”控制器按钮功能</string>
|
||||
<string name="invert_confirm_back_controller_buttons_description">在与本应用的界面交互时,交换 Android 的“确认”与“返回”按钮的处理方式,以匹配 Switch 和 Xbox 的风格。</string>
|
||||
|
||||
@@ -432,7 +432,7 @@
|
||||
|
||||
<!-- CPU -->
|
||||
<string name="fast_cpu_time">CPU 超频</string>
|
||||
<string name="fast_cpu_time_description">强制模拟的 CPU 以更高的时钟频率运行,从而解除某些 FPS 限制器。使用 Boost (1700MHz) 可让游戏以 Switch 的最高原生时钟运行,或使用 Fast (2000MHz) 以 2 倍时钟运行。</string>
|
||||
<string name="fast_cpu_time_description">强制模拟的 CPU 以更高的时钟频率运行,从而消除某些帧率限制。使用“升频”(1700MHz)以在 Switch 的最高原生时钟频率运行,或使用“快速”(2000MHz)以 2 倍时钟频率运行。</string>
|
||||
<string name="custom_cpu_ticks">自定义CPU时钟</string>
|
||||
<string name="custom_cpu_ticks_description">设置自定义的CPU时钟值。更高的值可能提高性能,但也可能导致游戏卡顿。建议范围为77-21000。</string>
|
||||
<string name="cpu_ticks">时钟</string>
|
||||
@@ -460,15 +460,15 @@
|
||||
<string name="advanced">高级</string>
|
||||
|
||||
<string name="renderer_accuracy">GPU 模式</string>
|
||||
<string name="renderer_accuracy_description">控制 GPU 模拟的精确度。大部分游戏在性能或平衡模式下可以正常渲染,但部分游戏需要设置为精确。粒子效果通常只有在精确模式下才能正确显示。</string>
|
||||
<string name="renderer_accuracy_description">控制 GPU 模拟模式。大多数游戏在“快速”或“平衡”模式下都能正常渲染,但有些游戏仍需使用“精确”模式。粒子效果通常只有在“精确”模式下才能正确渲染。</string>
|
||||
<string name="dma_accuracy">DMA 精度</string>
|
||||
<string name="dma_accuracy_description">控制 DMA 精度。安全精度可以修复某些游戏中的问题,但在某些情况下也可能影响性能。如果不确定,请保留为“默认”。</string>
|
||||
<string name="dma_accuracy_description">控制 DMA 的精准度。安全精度可以修复存在于某些游戏中的问题,但在某些情况下也会对性能造成影响。如不确定,请保持“默认”。</string>
|
||||
<string name="anisotropic_filtering">各向异性过滤</string>
|
||||
<string name="anisotropic_filtering_description">提高斜角的纹理质量</string>
|
||||
<string name="vram_usage_mode">显存使用模式</string>
|
||||
<string name="vram_usage_mode_description">控制显存分配策略</string>
|
||||
<string name="accelerate_astc">ASTC解码方式</string>
|
||||
<string name="accelerate_astc_description">选择ASTC压缩纹理的解码方式:CPU(慢速、安全)、GPU(快速、推荐)或CPU异步(无卡顿,可能导致问题)</string>
|
||||
<string name="accelerate_astc_description">选择渲染时使用的 ASTC 压缩纹理解码方式:CPU(缓慢,安全),GPU(快速,推荐),或 CPU 异步(无卡顿,但可能导致问题)</string>
|
||||
|
||||
<string name="sync_memory_operations">同步内存操作</string>
|
||||
<string name="sync_memory_operations_description">确保计算和内存操作之间的数据一致性。 此选项应能修复某些游戏中的问题,但在某些情况下可能会降低性能。 使用Unreal Engine 4的游戏似乎受影响最大。</string>
|
||||
@@ -477,11 +477,11 @@
|
||||
<string name="renderer_force_max_clock">强制最大时钟 (仅限 Adreno)</string>
|
||||
<string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (温控依然生效)。</string>
|
||||
<string name="renderer_asynchronous_gpu_emulation">GPU 异步模拟</string>
|
||||
<string name="renderer_asynchronous_gpu_emulation_description">此技巧可通过异步运行 GPU 模拟来提升性能,但在执行与时序相关的操作时,可能引入图形问题和增加崩溃概率。</string>
|
||||
<string name="renderer_asynchronous_gpu_emulation_description">此技巧可通过异步运行 GPU 模拟来提升性能,但在执行与时序相关的操作时,可能带来图形显示问题以及增加崩溃概率。</string>
|
||||
<string name="renderer_async_presentation">异步呈现</string>
|
||||
<string name="renderer_async_presentation_description">此技巧通过将图形呈现移至独立的 CPU 线程来提升性能,但可能会引入图形显示问题。</string>
|
||||
<string name="renderer_async_presentation_description">此技巧通过将图形呈现移至独立的 CPU 线程来提升性能,但可能会带来图形显示问题。</string>
|
||||
<string name="renderer_reactive_flushing">启用反应性刷新</string>
|
||||
<string name="renderer_reactive_flushing_description">通过牺牲性能来提高某些游戏的渲染精度。</string>
|
||||
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
|
||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||
@@ -489,10 +489,10 @@
|
||||
|
||||
<string name="hacks">Hacks</string>
|
||||
|
||||
<string name="fast_gpu_time">GPU 超频频率</string>
|
||||
<string name="fast_gpu_time">快速 GPU 时间</string>
|
||||
<string name="fast_gpu_time_description">强制大多数游戏以其最高原生分辨率运行。设置为 256 可获得最佳性能,设置为 512 可获得最佳画面保真度。</string>
|
||||
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在内存更新期间跳过某些CPU端缓存无效化,减少CPU使用率并提高其性能。可能会导致某些游戏出现故障或崩溃。</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string>
|
||||
<string name="antiflicker">防闪烁</string>
|
||||
<string name="antiflicker_description">强制 GPU 围栏回调等待已提交的 GPU 任务。配合“快速 GPU 模式”一起使用,以避免画面闪烁现象,仅会牺牲少量性能。</string>
|
||||
<string name="fix_bloom_effects">修复 Bloom 效果</string>
|
||||
@@ -502,16 +502,16 @@
|
||||
<string name="rescale_hack">启用旧版缩放处理</string>
|
||||
<string name="rescale_hack_description">启用通过使用快速缩放路径,来为游戏提供缩放配置处理的传统处理方式</string>
|
||||
<string name="renderer_asynchronous_shaders">使用异步着色器</string>
|
||||
<string name="renderer_asynchronous_shaders_description">异步编译着色器。这可能会减少卡顿,但也可能会导致图形错误。</string>
|
||||
<string name="gpu_unswizzle_settings">GPU 还原设置</string>
|
||||
<string name="gpu_unswizzle_settings_description">配置基于 GPU 的纹理还原参数,或将其完全禁用。调整这些设置以平衡性能与纹理加载质量。</string>
|
||||
<string name="gpu_unswizzle_enable">启用 GPU 还原</string>
|
||||
<string name="renderer_asynchronous_shaders_description">以异步方式编译着色器。采用此方式或可减少卡顿,但也可能引入故障点。</string>
|
||||
<string name="gpu_unswizzle_settings">GPU Unswizzle 设置</string>
|
||||
<string name="gpu_unswizzle_settings_description">配置基于 GPU 的纹理 unswizzling 参数,或完全禁用该功能。通过调整这些设置,以尝试在性能与纹理加载质量之间取得平衡。</string>
|
||||
<string name="gpu_unswizzle_enable">启用 GPU Unswizzle</string>
|
||||
<string name="gpu_unswizzle_disabled">禁用</string>
|
||||
<string name="gpu_unswizzle_texture_size">GPU 还原最大纹理尺寸</string>
|
||||
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理还原的最大尺寸(单位:MiB)。\n虽然 GPU 在处理中型和大型纹理时速度更快,但对于非常小的纹理,CPU 的效率可能更高。\n调整此设置,以便在 GPU 加速和 CPU 开销之间找到最佳平衡点。</string>
|
||||
<string name="gpu_unswizzle_stream_size">GPU 还原流大小</string>
|
||||
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加快纹理的加载速度,但会增加帧延迟。而较低的数值可以降低 GPU 的开销,但可能会导致可见的纹理 闪现。</string>
|
||||
<string name="gpu_unswizzle_chunk_size">GPU 还原块大小</string>
|
||||
<string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大纹理尺寸</string>
|
||||
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理 unswizzling 的最大尺寸(MB)。虽然 GPU 处理中等和大型纹理的速度更快,但对于非常小的纹理,CPU 可能更为高效。通过调节此项设置,以尝试在 GPU 加速与 CPU 开销之间找到平衡。</string>
|
||||
<string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
|
||||
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加速纹理的加载过程,但会带来更高的帧延迟。而较低的数值则可以降低 GPU 的开销,但也可能会导致可见的纹理闪现。</string>
|
||||
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle 块大小</string>
|
||||
<string name="gpu_unswizzle_chunk_size_description">定义了 3D 纹理每批次处理的深度切片数量。增加此数值可在高性能 GPU 上提升吞吐效率,但在性能较弱的硬件上可能会导致卡顿或驱动超时。</string>
|
||||
<string name="gpu_unswizzle_default_button">默认</string>
|
||||
|
||||
@@ -524,7 +524,7 @@
|
||||
<string name="vertex_input_dynamic_state">顶点输入动态状态</string>
|
||||
<string name="vertex_input_dynamic_state_description">启用此功能可实现更灵活的顶点输入处理,可能减少顶点/缓冲区的管线编译时间。</string>
|
||||
<string name="sample_shading_fraction">采样着色</string>
|
||||
<string name="sample_shading_fraction_description">允许片段着色器在多采样片段中每个样本执行一次,而不是每个片段执行一次。以提高性能为代价改善图形质量。</string>
|
||||
<string name="sample_shading_fraction_description">允许片段着色器在多采样片段中对每个采样点执行一次操作,而非对每个片段执行一次。在提升图形显示质量的同时,会牺牲一部分性能。</string>
|
||||
|
||||
|
||||
<string name="display">显示</string>
|
||||
@@ -548,7 +548,7 @@
|
||||
<string name="renderer_debug_description">将图形 API 设置为较慢的调试模式。</string>
|
||||
<string name="patch_old_qcom_drivers">BCn 纹理补丁</string>
|
||||
<string name="patch_old_qcom_drivers_description">在 Adreno GPU 上覆盖自动 BCn 纹理格式检测。通常根据 Android 版本自动检测(在 API 28 及以上启用)。</string>
|
||||
<string name="fastmem">Fastmem 内存访问</string>
|
||||
<string name="fastmem">Fastmem</string>
|
||||
|
||||
<string name="log">日志记录</string>
|
||||
<string name="flush_by_line">按行刷新调试日志</string>
|
||||
@@ -615,7 +615,7 @@
|
||||
<string name="unused">未使用</string>
|
||||
<string name="input_mapping_filter">输入映射过滤器</string>
|
||||
<string name="input_mapping_filter_description">选择一个设备过滤输入映射</string>
|
||||
<string name="auto_map">控制器自动映射</string>
|
||||
<string name="auto_map">自动映射控制器键位</string>
|
||||
<string name="auto_map_description">选择一个设备以尝试自动映射</string>
|
||||
<string name="attempted_auto_map">尝试为 %1$s 自动映射</string>
|
||||
<string name="controller_type">控制器类型</string>
|
||||
@@ -731,10 +731,10 @@
|
||||
<string name="preferences_audio">声音</string>
|
||||
<string name="preferences_audio_description">输出引擎及音量</string>
|
||||
<string name="preferences_controls">控制</string>
|
||||
<string name="preferences_controls_description">使用控制器来映射输入</string>
|
||||
<string name="preferences_controls_description">映射控制器键位输入</string>
|
||||
<string name="preferences_player">玩家 %d</string>
|
||||
<string name="preferences_debug">调试</string>
|
||||
<string name="preferences_debug_description">CPU/GPU 调试、图形 API 及 fastmem 内存访问</string>
|
||||
<string name="preferences_debug_description">CPU/GPU 调试、图形 API 以及 fastmem</string>
|
||||
<string name="preferences_custom_paths">自定义路径</string>
|
||||
<string name="preferences_custom_paths_description">存档目录</string>
|
||||
|
||||
@@ -878,15 +878,15 @@
|
||||
<string name="emulation_rel_stick_center">相对摇杆中心</string>
|
||||
<string name="emulation_dpad_slide">十字方向键滑动</string>
|
||||
<string name="emulation_haptics">触觉反馈</string>
|
||||
<string name="emulation_show_overlay">显示控制器</string>
|
||||
<string name="emulation_hide_overlay">隐藏控制器</string>
|
||||
<string name="emulation_show_overlay">显示触控叠加层</string>
|
||||
<string name="emulation_hide_overlay">隐藏触控叠加层</string>
|
||||
<string name="emulation_toggle_all">全部切换</string>
|
||||
<string name="emulation_control_adjust">调整触控叠加层</string>
|
||||
<string name="emulation_control_scale">缩放</string>
|
||||
<string name="emulation_control_opacity">不透明度</string>
|
||||
<string name="emulation_touch_overlay_reset">重置触控叠加层</string>
|
||||
<string name="emulation_touch_overlay_edit">编辑触控叠加层</string>
|
||||
<string name="emulation_snap_to_grid">截图到网格</string>
|
||||
<string name="emulation_snap_to_grid">对齐到网格</string>
|
||||
<string name="emulation_pause">暂停模拟</string>
|
||||
<string name="emulation_unpause">继续模拟</string>
|
||||
<string name="emulation_input_overlay">触控叠加层选项</string>
|
||||
@@ -982,7 +982,7 @@
|
||||
<string name="renderer_none">无</string>
|
||||
|
||||
<!-- Renderer Accuracy -->
|
||||
<string name="renderer_accuracy_low">性能</string>
|
||||
<string name="renderer_accuracy_low">快速</string>
|
||||
<string name="renderer_accuracy_medium">平衡</string>
|
||||
<string name="renderer_accuracy_high">精确</string>
|
||||
|
||||
|
||||
@@ -434,6 +434,9 @@
|
||||
<string name="cpu_accuracy">CPU accuracy</string>
|
||||
<string name="value_with_units">%1$s%2$s</string>
|
||||
|
||||
<string name="program_args">Homebrew Args</string>
|
||||
<string name="program_args_description">Command-line arguments passed to homebrew at launch (e.g. -noglsl).</string>
|
||||
|
||||
<!-- System settings strings -->
|
||||
<string name="device_name">Device name</string>
|
||||
<string name="use_docked_mode">Docked Mode</string>
|
||||
|
||||
+20
-69
@@ -409,107 +409,62 @@ bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter) {
|
||||
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
bool callback_error = false;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::File) &&
|
||||
entry.status().type() == fs::file_type::regular) {
|
||||
bool callback_error = false;
|
||||
for (auto const& entry : fs::directory_iterator(path, ec)) {
|
||||
if ((True(filter & DirEntryFilter::File) && entry.status().type() == fs::file_type::regular)
|
||||
|| (True(filter & DirEntryFilter::Directory) && entry.status().type() == fs::file_type::directory)) {
|
||||
if (!callback(entry)) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::Directory) &&
|
||||
entry.status().type() == fs::file_type::directory) {
|
||||
if (!callback(entry)) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callback_error || ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to visit all the directory entries of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return;
|
||||
LOG_ERROR(Common_Filesystem, "Failed to visit all the directory entries of path={}, ec_message={}, callback_error={}", PathToUTF8String(path), ec.message(), callback_error);
|
||||
} else {
|
||||
LOG_DEBUG(Common_Filesystem, "Visited all the directory entries of path={}", PathToUTF8String(path));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||
PathToUTF8String(path));
|
||||
}
|
||||
|
||||
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||
const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||
void IterateDirEntriesRecursively(const std::filesystem::path& path, const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
bool callback_error = false;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
// TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC.
|
||||
std::error_code ec;
|
||||
bool callback_error = false;
|
||||
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::File) &&
|
||||
entry.status().type() == fs::file_type::regular) {
|
||||
if ((True(filter & DirEntryFilter::File) && entry.status().type() == fs::file_type::regular)
|
||||
|| (True(filter & DirEntryFilter::Directory) && entry.status().type() == fs::file_type::directory)) {
|
||||
if (!callback(entry)) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::Directory) &&
|
||||
entry.status().type() == fs::file_type::directory) {
|
||||
if (!callback(entry)) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator.
|
||||
// recursive_directory_iterator throws an exception despite passing in a std::error_code.
|
||||
if (entry.status().type() == fs::file_type::directory) {
|
||||
@@ -518,14 +473,10 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||
}
|
||||
|
||||
if (callback_error || ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to visit all the directory entries of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return;
|
||||
LOG_ERROR(Common_Filesystem, "Failed to visit all the directory entries of path={}, ec_message={}, callback_error={}", PathToUTF8String(path), ec.message(), callback_error);
|
||||
} else {
|
||||
LOG_DEBUG(Common_Filesystem, "Visited all the directory entries of path={}", PathToUTF8String(path));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||
PathToUTF8String(path));
|
||||
}
|
||||
|
||||
// Generic Filesystem Operations
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
|
||||
void CreateEdenPaths() {
|
||||
std::for_each(eden_paths.begin(), eden_paths.end(), [](auto &path) {
|
||||
void(FS::CreateDir(path.second));
|
||||
void(FS::CreateDirs(path.second));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -149,10 +149,9 @@ public:
|
||||
LEGACY_PATH(Suyu, SUYU)
|
||||
#undef LEGACY_PATH
|
||||
#endif
|
||||
// data
|
||||
GenerateEdenPath(EdenPath::EdenDir, eden_path);
|
||||
GenerateEdenPath(EdenPath::AmiiboDir, eden_path / AMIIBO_DIR);
|
||||
GenerateEdenPath(EdenPath::CacheDir, eden_path_cache);
|
||||
GenerateEdenPath(EdenPath::ConfigDir, eden_path_config);
|
||||
GenerateEdenPath(EdenPath::CrashDumpsDir, eden_path / CRASH_DUMPS_DIR);
|
||||
GenerateEdenPath(EdenPath::DumpDir, eden_path / DUMP_DIR);
|
||||
GenerateEdenPath(EdenPath::KeysDir, eden_path / KEYS_DIR);
|
||||
@@ -163,10 +162,13 @@ public:
|
||||
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
|
||||
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
|
||||
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
|
||||
GenerateEdenPath(EdenPath::ShaderDir, eden_path / SHADER_DIR);
|
||||
GenerateEdenPath(EdenPath::TASDir, eden_path / TAS_DIR);
|
||||
GenerateEdenPath(EdenPath::IconsDir, eden_path / ICONS_DIR);
|
||||
|
||||
// config
|
||||
GenerateEdenPath(EdenPath::ConfigDir, eden_path_config);
|
||||
// cache
|
||||
GenerateEdenPath(EdenPath::CacheDir, eden_path_cache);
|
||||
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
|
||||
#ifdef _WIN32
|
||||
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
|
||||
#else
|
||||
|
||||
+110
-40
@@ -22,6 +22,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/literals.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/random.h>
|
||||
@@ -32,6 +33,8 @@
|
||||
#include <mach/mach.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/shm.h>
|
||||
#elif defined(__OPENORBIS__)
|
||||
#include <orbis/libkernel.h>
|
||||
#endif
|
||||
|
||||
// FreeBSD
|
||||
@@ -122,54 +125,55 @@ static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()},
|
||||
kernelbase_dll("Kernelbase") {
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
, process{GetCurrentProcess()}
|
||||
, kernelbase_dll("Kernelbase")
|
||||
{}
|
||||
|
||||
bool Init() {
|
||||
if (!kernelbase_dll.IsOpen()) {
|
||||
LOG_CRITICAL(HW_Memory, "Failed to load Kernelbase.dll");
|
||||
throw std::bad_alloc{};
|
||||
return false;
|
||||
}
|
||||
GetFuncAddress(kernelbase_dll, "CreateFileMapping2", pfn_CreateFileMapping2);
|
||||
GetFuncAddress(kernelbase_dll, "VirtualAlloc2", pfn_VirtualAlloc2);
|
||||
GetFuncAddress(kernelbase_dll, "MapViewOfFile3", pfn_MapViewOfFile3);
|
||||
GetFuncAddress(kernelbase_dll, "UnmapViewOfFile2", pfn_UnmapViewOfFile2);
|
||||
|
||||
if (!pfn_CreateFileMapping2 || !pfn_VirtualAlloc2 || !pfn_MapViewOfFile3 || !pfn_UnmapViewOfFile2) {
|
||||
LOG_CRITICAL(HW_Memory, "Failed to find functions for virtual allocs");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate backing file map
|
||||
backing_handle =
|
||||
pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
|
||||
PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
|
||||
backing_handle = pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ, PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
|
||||
if (!backing_handle) {
|
||||
LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory",
|
||||
backing_size >> 20);
|
||||
throw std::bad_alloc{};
|
||||
LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory", backing_size >> 20);
|
||||
return false;
|
||||
}
|
||||
// Allocate a virtual memory for the backing file map as placeholder
|
||||
backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||
PAGE_NOACCESS, nullptr, 0));
|
||||
backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
|
||||
if (!backing_base) {
|
||||
Release();
|
||||
LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory",
|
||||
backing_size >> 20);
|
||||
throw std::bad_alloc{};
|
||||
LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory", backing_size >> 20);
|
||||
return false;
|
||||
}
|
||||
// Map backing placeholder
|
||||
void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
|
||||
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
||||
void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
||||
if (ret != backing_base) {
|
||||
Release();
|
||||
LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
|
||||
throw std::bad_alloc{};
|
||||
return false;
|
||||
}
|
||||
// Allocate virtual address placeholder
|
||||
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||
PAGE_NOACCESS, nullptr, 0));
|
||||
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
|
||||
if (!virtual_base) {
|
||||
Release();
|
||||
LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory",
|
||||
virtual_size >> 30);
|
||||
throw std::bad_alloc{};
|
||||
LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory", virtual_size >> 30);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~Impl() {
|
||||
@@ -391,6 +395,9 @@ private:
|
||||
ankerl::unordered_dense::map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
|
||||
};
|
||||
|
||||
#elif defined(__OPENORBIS__) || defined(__managarm__)
|
||||
// None of the luxuries of POSIX, all of the suffering
|
||||
// For managarm: see https://github.com/managarm/managarm/issues/1370
|
||||
#else // ^^^ Windows ^^^ vvv POSIX vvv
|
||||
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
@@ -496,18 +503,44 @@ static int shm_open_anon(int flags, mode_t mode) {
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}, virtual_size{virtual_size_} {
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
{}
|
||||
|
||||
bool Init() {
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging",
|
||||
page_size);
|
||||
ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", page_size);
|
||||
// Backing memory initialization
|
||||
#if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
|
||||
#elif defined(__OpenBSD__)
|
||||
fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
|
||||
#elif defined(__FreeBSD__)
|
||||
fd = shm_open(SHM_ANON, O_RDWR, 0600);
|
||||
#elif defined(__APPLE__)
|
||||
int n_page_sizes = getpagesizes(nullptr, 0);
|
||||
if (n_page_sizes > 0) {
|
||||
std::vector<size_t> page_sizes(n_page_sizes);
|
||||
if (getpagesizes(page_sizes.data(), n_page_sizes) > 0) {
|
||||
size_t max_size = page_sizes[0];
|
||||
size_t max_index = 0;
|
||||
for (size_t i = 0; i < page_sizes.size(); ++i) {
|
||||
using namespace Common::Literals;
|
||||
if (page_sizes[i] <= 4_GiB) {
|
||||
max_size = (std::max)(max_size, page_sizes[i]);
|
||||
max_index = i;
|
||||
}
|
||||
}
|
||||
LOG_WARNING(Common_Memory, "using largepage of size {} #{}", max_size, max_index);
|
||||
// Do not use SHM_LARGEPAGE_ALLOC_HARD, yknow what will happen when you do?
|
||||
// the entire Eden process will hang for eternity! that's what will happen
|
||||
// Want to fuck around and find out? Go ahead, I tempt you change the "default" to "hard"
|
||||
fd = shm_create_largepage(SHM_ANON, O_RDWR, max_index, SHM_LARGEPAGE_ALLOC_DEFAULT, 0600);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
LOG_WARNING(Common_Memory, "unable to force largepage: {}", strerror(errno));
|
||||
fd = shm_open(SHM_ANON, O_RDWR, 0600);
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__managarm__)
|
||||
// macOS doesn't have memfd_create, use anonymous temporary file
|
||||
char template_path[] = "/tmp/eden_mem_XXXXXX";
|
||||
fd = mkstemp(template_path);
|
||||
@@ -538,17 +571,29 @@ public:
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
#ifdef __FreeBSD__
|
||||
// Prevent dirty tracking of memfd
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOSYNC, fd, 0));
|
||||
#else
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
#endif
|
||||
}
|
||||
if (backing_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||
|
||||
// Virtual memory initialization
|
||||
virtual_base = virtual_map_base = static_cast<u8*>(ChooseVirtualBase(virtual_size));
|
||||
ASSERT_MSG(virtual_base != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#if defined(__linux__)
|
||||
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
|
||||
#endif
|
||||
free_manager.SetAddressSpace(virtual_base, virtual_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
~Impl() {
|
||||
@@ -669,17 +714,35 @@ private:
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) : backing_size(backing_size_), virtual_size(virtual_size_) {
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size(backing_size_)
|
||||
, virtual_size(virtual_size_)
|
||||
{
|
||||
#if defined(__OPENORBIS__) || defined(__managarm__)
|
||||
LOG_WARNING(HW_Memory, "Platform doesn't support fastmem");
|
||||
fallback_buffer.emplace(backing_size);
|
||||
backing_base = fallback_buffer->data();
|
||||
virtual_base = nullptr;
|
||||
#else
|
||||
// Try to allocate a fastmem arena.
|
||||
// The implementation will fail with std::bad_alloc on errors.
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
if (virtual_base) {
|
||||
// Ensure the virtual base is aligned to the L2 block size.
|
||||
virtual_base = reinterpret_cast<u8*>(Common::AlignUp(uintptr_t(virtual_base), HugePageSize));
|
||||
virtual_base_offset = virtual_base - impl->virtual_base;
|
||||
if (impl->Init()) {
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
if (virtual_base) {
|
||||
// Ensure the virtual base is aligned to the L2 block size.
|
||||
virtual_base = reinterpret_cast<u8*>(Common::AlignUp(uintptr_t(virtual_base), HugePageSize));
|
||||
virtual_base_offset = virtual_base - impl->virtual_base;
|
||||
}
|
||||
} else {
|
||||
impl.reset();
|
||||
LOG_WARNING(HW_Memory, "Platform can support fastmem, but can't create it");
|
||||
fallback_buffer.emplace(backing_size);
|
||||
backing_base = fallback_buffer->data();
|
||||
virtual_base = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HostMemory::~HostMemory() = default;
|
||||
@@ -688,8 +751,8 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
|
||||
|
||||
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
||||
|
||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
MemoryPermission perms, bool separate_heap) {
|
||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms, bool separate_heap) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(host_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
@@ -699,9 +762,11 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
return;
|
||||
}
|
||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
@@ -709,9 +774,11 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
||||
return;
|
||||
}
|
||||
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
@@ -722,6 +789,7 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission
|
||||
const bool write = True(perm & MemoryPermission::Write);
|
||||
const bool execute = True(perm & MemoryPermission::Execute);
|
||||
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
|
||||
@@ -729,10 +797,12 @@ void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 f
|
||||
}
|
||||
|
||||
void HostMemory::EnableDirectMappedAddress() {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
if (impl) {
|
||||
impl->EnableDirectMappedAddress();
|
||||
virtual_size += reinterpret_cast<uintptr_t>(virtual_base);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
@@ -76,12 +77,16 @@ private:
|
||||
size_t backing_size{};
|
||||
size_t virtual_size{};
|
||||
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
// Low level handler for the platform dependent memory routines
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
#endif
|
||||
u8* backing_base{};
|
||||
u8* virtual_base{};
|
||||
size_t virtual_base_offset{};
|
||||
// Windows requires it for kernels whom lack proper support for some functions!
|
||||
std::optional<Common::VirtualBuffer<u8>> fallback_buffer;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
+11
-5
@@ -336,7 +336,7 @@ struct Values {
|
||||
RendererBackend::Vulkan,
|
||||
#endif
|
||||
"backend", Category::Renderer};
|
||||
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList};
|
||||
SwitchableSetting<u32> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList};
|
||||
|
||||
// Graphics Settings
|
||||
ResolutionScalingInfo resolution_info{};
|
||||
@@ -661,8 +661,8 @@ struct Values {
|
||||
false, true, &custom_rtc_enabled};
|
||||
SwitchableSetting<s64, true> custom_rtc_offset{linkage,
|
||||
0,
|
||||
(std::numeric_limits<int>::min)(),
|
||||
(std::numeric_limits<int>::max)(),
|
||||
(std::numeric_limits<s64>::min)(),
|
||||
(std::numeric_limits<s64>::max)(),
|
||||
"custom_rtc_offset",
|
||||
Category::System,
|
||||
Specialization::Countable,
|
||||
@@ -751,7 +751,7 @@ struct Values {
|
||||
|
||||
Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
|
||||
"touch_device", Category::Controls};
|
||||
Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
|
||||
Setting<u32> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
|
||||
Category::Controls};
|
||||
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||
|
||||
@@ -779,7 +779,13 @@ struct Values {
|
||||
bool record_frame_times;
|
||||
Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
|
||||
Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
|
||||
Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
|
||||
SwitchableSetting<std::string> program_args{linkage,
|
||||
std::string(),
|
||||
"program_args",
|
||||
Category::System,
|
||||
Specialization::Default,
|
||||
true, // save_ — persist in config file
|
||||
false}; // runtime_modifiable_ — startup-only
|
||||
Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
|
||||
Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
|
||||
Setting<bool> dump_shaders{
|
||||
|
||||
@@ -145,8 +145,8 @@ ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||
ENUM(FullscreenMode, Borderless, Exclusive);
|
||||
ENUM(NvdecEmulation, Off, Cpu, Gpu);
|
||||
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res5_4X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, Sgsr, SgsrEdge, MaxEnum);
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, Sgsr, SgsrEdge);
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa);
|
||||
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
ENUM(ConsoleMode, Handheld, Docked);
|
||||
ENUM(AppletMode, HLE, LLE);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <fmt/core.h>
|
||||
@@ -101,7 +102,15 @@ public:
|
||||
* @param val The desired value
|
||||
*/
|
||||
virtual void SetValue(const Type& val) {
|
||||
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||
// Enums have a maximal range which they're allowed
|
||||
Type temp{};
|
||||
if constexpr (std::is_enum_v<Type>) {
|
||||
auto const r_min = std::underlying_type_t<Type>(0);
|
||||
auto const r_max = std::underlying_type_t<Type>(EnumMetadata<Type>::GetLast());
|
||||
temp = Type(std::clamp(std::underlying_type_t<Type>(val), r_min, r_max));
|
||||
} else {
|
||||
temp = ranged ? std::clamp(val, this->minimum, this->maximum) : val;
|
||||
}
|
||||
std::swap(value, temp);
|
||||
}
|
||||
|
||||
@@ -129,7 +138,7 @@ protected:
|
||||
} else if constexpr (std::is_floating_point_v<Type>) {
|
||||
return fmt::format("{:f}", value_);
|
||||
} else if constexpr (std::is_enum_v<Type>) {
|
||||
return std::to_string(u32(value_));
|
||||
return std::to_string(std::underlying_type_t<Type>(value_));
|
||||
} else {
|
||||
return std::to_string(value_);
|
||||
}
|
||||
@@ -371,7 +380,15 @@ public:
|
||||
* @param val The new value
|
||||
*/
|
||||
void SetValue(const Type& val) override final {
|
||||
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
// Enums have a maximal range which they're allowed
|
||||
Type temp{};
|
||||
if constexpr (std::is_enum_v<Type>) {
|
||||
auto const r_min = std::underlying_type_t<Type>(0);
|
||||
auto const r_max = std::underlying_type_t<Type>(EnumMetadata<Type>::GetLast());
|
||||
temp = Type(std::clamp(std::underlying_type_t<Type>(val), r_min, r_max));
|
||||
} else {
|
||||
temp = ranged ? std::clamp(val, this->minimum, this->maximum) : val;
|
||||
}
|
||||
if (use_global) {
|
||||
std::swap(this->value, temp);
|
||||
} else {
|
||||
|
||||
@@ -1121,6 +1121,10 @@ add_library(core STATIC
|
||||
hle/service/vi/vi_types.h
|
||||
hle/service/vi/vsync_manager.cpp
|
||||
hle/service/vi/vsync_manager.h
|
||||
hle/service/gpio/gpio.cpp
|
||||
hle/service/gpio/gpio.h
|
||||
hle/service/i2c/i2c.cpp
|
||||
hle/service/i2c/i2c.h
|
||||
internal_network/emu_net_state.cpp
|
||||
internal_network/emu_net_state.h
|
||||
internal_network/network.cpp
|
||||
|
||||
@@ -211,6 +211,9 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, KResource
|
||||
m_version = params.version;
|
||||
m_program_id = params.program_id;
|
||||
m_code_address = params.code_address;
|
||||
m_arg_pointer = 0;
|
||||
m_arg_return_address = 0;
|
||||
m_main_thread_handle_addr = 0;
|
||||
m_code_size = params.code_num_pages * PageSize;
|
||||
m_is_application = True(params.flags & Svc::CreateProcessFlag::IsApplication);
|
||||
|
||||
@@ -995,9 +998,27 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
|
||||
Handle thread_handle;
|
||||
R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread));
|
||||
|
||||
// Set the thread arguments.
|
||||
main_thread->GetContext().r[0] = 0;
|
||||
main_thread->GetContext().r[1] = thread_handle;
|
||||
// Set the thread arguments. Two distinct entry conventions:
|
||||
// * Kernel/NSO entry (no homebrew ABI): x0 = 0, x1 = thread_handle
|
||||
// * Homebrew/NRO ABI (loader set arg ptr): x0 = ConfigEntry ptr, x1 = -1ULL
|
||||
// libnx's switch_crt0.s tests `x0==0 || x1==0xFFFFFFFFFFFFFFFF` to take
|
||||
// its normal init path; any other combination is interpreted as a user
|
||||
// exception handler entry.
|
||||
if (GetInteger(m_arg_pointer) != 0) {
|
||||
main_thread->GetContext().r[0] = GetInteger(m_arg_pointer);
|
||||
main_thread->GetContext().r[1] = UINT64_MAX;
|
||||
main_thread->GetContext().lr = GetInteger(m_arg_return_address);
|
||||
// Patch the MainThreadHandle entry in the ConfigEntry table now that
|
||||
// the actual handle exists. libnx stores this verbatim and uses it
|
||||
// for thread-control SVCs later; a pseudo-handle wouldn't survive
|
||||
// svcCloseHandle on exit.
|
||||
if (GetInteger(m_main_thread_handle_addr) != 0) {
|
||||
this->GetMemory().Write32(m_main_thread_handle_addr, thread_handle);
|
||||
}
|
||||
} else {
|
||||
main_thread->GetContext().r[0] = 0;
|
||||
main_thread->GetContext().r[1] = thread_handle;
|
||||
}
|
||||
|
||||
// Pass the thread handle to the thread local region.
|
||||
this->GetMemory().Write32(GetInteger(main_thread->GetTlsAddress()) + 0x110, thread_handle);
|
||||
@@ -1174,8 +1195,7 @@ KProcess::KProcess(KernelCore& kernel)
|
||||
|
||||
KProcess::~KProcess() = default;
|
||||
|
||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||
KProcessAddress aslr_space_start, size_t aslr_space_offset, bool is_hbl) {
|
||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, KProcessAddress aslr_space_start, size_t aslr_space_offset) {
|
||||
// Create a resource limit for the process.
|
||||
const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
|
||||
const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
|
||||
@@ -1247,7 +1267,6 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||
aslr_space_start));
|
||||
|
||||
// Assign remaining properties.
|
||||
m_is_hbl = is_hbl;
|
||||
m_ideal_core_id = metadata.GetMainThreadCore();
|
||||
|
||||
// Set up emulation context.
|
||||
|
||||
@@ -84,6 +84,9 @@ private:
|
||||
Core::Memory::Memory m_memory;
|
||||
KCapabilities m_capabilities{};
|
||||
KProcessAddress m_code_address{};
|
||||
KProcessAddress m_arg_pointer{};
|
||||
KProcessAddress m_arg_return_address{};
|
||||
KProcessAddress m_main_thread_handle_addr{};
|
||||
KHandleTable m_handle_table;
|
||||
KProcessAddress m_plr_address{};
|
||||
ThreadList m_thread_list{};
|
||||
@@ -133,7 +136,6 @@ private:
|
||||
bool m_is_initialized : 1 = false;
|
||||
bool m_is_application : 1 = false;
|
||||
bool m_is_default_application_system_resource : 1 = false;
|
||||
bool m_is_hbl : 1 = false;
|
||||
bool m_is_suspended : 1 = false;
|
||||
bool m_is_immortal : 1 = false;
|
||||
bool m_is_handle_table_initialized : 1 = false;
|
||||
@@ -220,6 +222,16 @@ public:
|
||||
return m_code_address;
|
||||
}
|
||||
|
||||
void SetArgPointer(KProcessAddress addr) {
|
||||
m_arg_pointer = addr;
|
||||
}
|
||||
void SetArgReturnAddress(KProcessAddress addr) {
|
||||
m_arg_return_address = addr;
|
||||
}
|
||||
void SetMainThreadHandleAddr(KProcessAddress addr) {
|
||||
m_main_thread_handle_addr = addr;
|
||||
}
|
||||
|
||||
size_t GetMainStackSize() const {
|
||||
return m_main_thread_stack_size;
|
||||
}
|
||||
@@ -277,10 +289,6 @@ public:
|
||||
return m_capabilities.CanForceDebug();
|
||||
}
|
||||
|
||||
bool IsHbl() const {
|
||||
return m_is_hbl;
|
||||
}
|
||||
|
||||
u32 GetAllocateOption() const {
|
||||
return m_page_table.GetAllocateOption();
|
||||
}
|
||||
@@ -514,8 +522,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||
KProcessAddress aslr_space_start, size_t aslr_space_offset, bool is_hbl);
|
||||
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, KProcessAddress aslr_space_start, size_t aslr_space_offset);
|
||||
|
||||
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
@@ -106,9 +109,7 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
|
||||
system.CurrentPhysicalCore().LogBacktrace();
|
||||
}
|
||||
|
||||
const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl();
|
||||
const bool should_break = is_hbl || !notification_only;
|
||||
|
||||
const bool should_break = !notification_only;
|
||||
if (system.DebuggerEnabled() && should_break) {
|
||||
auto* thread = system.Kernel().GetCurrentEmuThread();
|
||||
system.GetDebugger().NotifyThreadStopped(thread);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -83,6 +83,7 @@ struct Applet {
|
||||
|
||||
// Application functions
|
||||
bool game_play_recording_supported{};
|
||||
bool media_playback_state{};
|
||||
GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
|
||||
bool jit_service_launched{};
|
||||
bool application_crash_report_enabled{};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/service/application_functions.h"
|
||||
@@ -56,7 +57,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
|
||||
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
{40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
|
||||
{50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
|
||||
{60, nullptr, "SetMediaPlaybackStateForApplication"},
|
||||
{60, D<&IApplicationFunctions::SetMediaPlaybackStateForApplication>, "SetMediaPlaybackStateForApplication"},
|
||||
{65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
|
||||
{66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
|
||||
{67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
|
||||
@@ -364,6 +365,13 @@ Result IApplicationFunctions::InitializeGamePlayRecording(
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetMediaPlaybackStateForApplication(bool enabled) {
|
||||
LOG_WARNING(Service_AM, "(stubbed) {}", enabled);
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->media_playback_state = enabled;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetGamePlayRecordingState(
|
||||
GamePlayRecordingState game_play_recording_state) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -53,6 +53,7 @@ private:
|
||||
Result IsGamePlayRecordingSupported(Out<bool> out_is_game_play_recording_supported);
|
||||
Result InitializeGamePlayRecording(
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
|
||||
Result SetMediaPlaybackStateForApplication(bool enabled);
|
||||
Result SetGamePlayRecordingState(GamePlayRecordingState game_play_recording_state);
|
||||
Result EnableApplicationCrashReport(bool enabled);
|
||||
Result InitializeApplicationCopyrightFrameBuffer(
|
||||
|
||||
@@ -29,7 +29,7 @@ IBtmSystemCore::IBtmSystemCore(Core::System& system_)
|
||||
{10, nullptr, "StartAudioDeviceDiscovery"},
|
||||
{11, nullptr, "StopAudioDeviceDiscovery"},
|
||||
{12, nullptr, "IsDiscoveryingAudioDevice"},
|
||||
{13, nullptr, "GetDiscoveredAudioDevice"},
|
||||
{13, C<&IBtmSystemCore::GetDiscoveredAudioDevice>, "GetDiscoveredAudioDevice"},
|
||||
{14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
|
||||
{15, nullptr, "ConnectAudioDevice"},
|
||||
{16, nullptr, "IsConnectingAudioDevice"},
|
||||
@@ -93,6 +93,11 @@ Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IBtmSystemCore::GetDiscoveredAudioDevice(OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices, s32 count, Out<s32> out_total) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -34,9 +37,8 @@ private:
|
||||
Result DisableRadio();
|
||||
Result IsRadioEnabled(Out<bool> out_is_enabled);
|
||||
|
||||
Result AcquireRadioEvent(Out<bool> out_is_valid,
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
Result AcquireRadioEvent(Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetDiscoveredAudioDevice(OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices, s32 count, Out<s32> out_total);
|
||||
Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
Result GetConnectedAudioDevices(
|
||||
|
||||
@@ -151,7 +151,7 @@ Result IFileSystem::GetTotalSpaceSize(
|
||||
Result IFileSystem::GetFileTimeStampRaw(
|
||||
Out<FileSys::FileTimeStampRaw> out_timestamp,
|
||||
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
|
||||
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
|
||||
LOG_DEBUG(Service_FS, "(Partial Implementation) called. file={}", path->str);
|
||||
|
||||
FileSys::FileTimeStampRaw vfs_timestamp{};
|
||||
R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
|
||||
|
||||
@@ -284,9 +284,17 @@ Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
break;
|
||||
case FileSys::SaveDataSpaceId::Temporary:
|
||||
// ok this is definitely wrong. ASSERT(false) here just kills the whole game the first
|
||||
// time it opens cache storage, and plenty of games do that (TOTK for one). there is
|
||||
// user-space scratch storage so it belongs on user nand. map it, do not crash.
|
||||
id = FileSys::StorageId::NandUser;
|
||||
break;
|
||||
case FileSys::SaveDataSpaceId::ProperSystem:
|
||||
case FileSys::SaveDataSpaceId::SafeMode:
|
||||
ASSERT(false);
|
||||
// same deal for these two. they are system-level spaces so they go on system nand.
|
||||
// way better than nuking the title over a save-space id we just did not list out.
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
break;
|
||||
}
|
||||
|
||||
*out_interface =
|
||||
@@ -324,9 +332,15 @@ Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSyste
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
break;
|
||||
case FileSys::SaveDataSpaceId::Temporary:
|
||||
// same broken switch as OpenSaveDataFileSystem above. do not ASSERT(false) and kill the
|
||||
// game over a save-space id, just map Temporary to user nand like it should be.
|
||||
id = FileSys::StorageId::NandUser;
|
||||
break;
|
||||
case FileSys::SaveDataSpaceId::ProperSystem:
|
||||
case FileSys::SaveDataSpaceId::SafeMode:
|
||||
ASSERT(false);
|
||||
// system spaces -> system nand. handled, not crashed.
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
break;
|
||||
}
|
||||
|
||||
*out_interface =
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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 "core/core.h"
|
||||
#include "core/hle/service/gpio/gpio.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::GPIO {
|
||||
|
||||
class GPIO final : public ServiceFramework<GPIO> {
|
||||
public:
|
||||
explicit GPIO(Core::System& system_)
|
||||
: ServiceFramework{system_, "gpio"}
|
||||
{
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Cmd0"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~GPIO() override = default;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
server_manager->RegisterNamedService("gpio", std::make_shared<GPIO>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
} // namespace Service::GPIO
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::GPIO {
|
||||
void LoopProcess(Core::System& system);
|
||||
} // namespace Service::GPIO
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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 "core/core.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/i2c/i2c.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
|
||||
namespace Service::I2C {
|
||||
|
||||
class I2CSession final : public ServiceFramework<I2CSession> {
|
||||
public:
|
||||
explicit I2CSession(Core::System& system_)
|
||||
: ServiceFramework{system_, "I2CSession"}
|
||||
{
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SendOld"},
|
||||
{1, nullptr, "ReceiveOld"},
|
||||
{2, nullptr, "ExecuteCommandListOld"},
|
||||
{10, C<&I2CSession::Send>, "Send"},
|
||||
{11, nullptr, "Receive"},
|
||||
{12, nullptr, "ExecuteCommandList"},
|
||||
{13, nullptr, "SetRetryPolicy"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~I2CSession() override = default;
|
||||
|
||||
Result Send(InBuffer<BufferAttr_HipcMapAlias> in_data, u32 transaction_option) {
|
||||
LOG_WARNING(Service, "(stubbed) topt={}", transaction_option);
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
};
|
||||
|
||||
enum class I2CDevice : u32 {
|
||||
ClassicController,
|
||||
Ftm3bd56,
|
||||
};
|
||||
|
||||
class I2C final : public ServiceFramework<I2C> {
|
||||
public:
|
||||
explicit I2C(Core::System& system_)
|
||||
: ServiceFramework{system_, "i2c"}
|
||||
{
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "OpenSessionForDev"},
|
||||
{1, C<&I2C::OpenSession>, "OpenSession"},
|
||||
{2, nullptr, "HasDevice"},
|
||||
{3, nullptr, "HasDeviceForDev"},
|
||||
{4, nullptr, "OpenSession2"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~I2C() override = default;
|
||||
|
||||
Result OpenSession(I2CDevice device, OutInterface<I2CSession> out_session) {
|
||||
LOG_DEBUG(Service, "(stubbed)");
|
||||
*out_session = std::make_shared<I2CSession>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
server_manager->RegisterNamedService("i2c", std::make_shared<I2C>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
} // namespace Service::I2C
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::I2C {
|
||||
void LoopProcess(Core::System& system);
|
||||
} // namespace Service::I2C
|
||||
@@ -47,6 +47,8 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output);
|
||||
case 0x14:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
|
||||
case 0x15:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::PmuGetGpuLoad, input, output);
|
||||
case 0x1c:
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
|
||||
default:
|
||||
@@ -234,6 +236,12 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(IoctlActiveSlotMask& params) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::PmuGetGpuLoad(IoctlPmuGetLoad& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(stubbed) called");
|
||||
params.pmu_gpu_load = 100;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(IoctlZcullGetCtxSize& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
params.size = 0x1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -184,6 +184,11 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlGetCpuTimeCorrelationInfo) == 264);
|
||||
|
||||
struct IoctlPmuGetLoad {
|
||||
u32 pmu_gpu_load;
|
||||
};
|
||||
static_assert(sizeof(IoctlPmuGetLoad) == 4);
|
||||
|
||||
NvResult GetCharacteristics1(IoctlCharacteristics& params);
|
||||
NvResult GetCharacteristics3(IoctlCharacteristics& params,
|
||||
std::span<IoctlGpuCharacteristics> gpu_characteristics);
|
||||
@@ -192,6 +197,7 @@ private:
|
||||
NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
|
||||
|
||||
NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
|
||||
NvResult PmuGetGpuLoad(IoctlPmuGetLoad& params);
|
||||
NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
|
||||
NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params);
|
||||
NvResult ZBCSetTable(IoctlZbcSetTable& params);
|
||||
|
||||
@@ -25,18 +25,20 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
case 0x01:
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
|
||||
case 0x2:
|
||||
case 0x02:
|
||||
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
|
||||
case 0x3:
|
||||
case 0x03:
|
||||
return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output);
|
||||
case 0x7:
|
||||
case 0x07:
|
||||
return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
|
||||
case 0x9:
|
||||
case 0x09:
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd);
|
||||
case 0xa:
|
||||
case 0x0a:
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
|
||||
case 0x23:
|
||||
return WrapFixed(this, &nvhost_nvdec::GetClkRate, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -168,6 +168,13 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(u32 timeout) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetClkRate(IoctlGetClkRate& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
params.clk_rate = 614400000;
|
||||
params.module_id = 0;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) {
|
||||
LOG_CRITICAL(Service_NVDRV, "Unknown HOSTX1 Event {}", event_id);
|
||||
return nullptr;
|
||||
|
||||
@@ -111,6 +111,12 @@ protected:
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
struct IoctlGetClkRate {
|
||||
u32_le clk_rate{};
|
||||
u32_le module_id{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetClkRate) == 8);
|
||||
|
||||
/// Ioctl command implementations
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD&);
|
||||
NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
|
||||
@@ -119,6 +125,7 @@ protected:
|
||||
NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd);
|
||||
NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
|
||||
NvResult SetSubmitTimeout(u32 timeout);
|
||||
NvResult GetClkRate(IoctlGetClkRate& params);
|
||||
|
||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/device_power_state.h"
|
||||
#include "common/logging.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/ptm/psm.h"
|
||||
@@ -134,12 +136,12 @@ PSM::PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
|
||||
{9, nullptr, "DisableEnoughPowerChargeEmulation"},
|
||||
{10, nullptr, "EnableFastBatteryCharging"},
|
||||
{11, nullptr, "DisableFastBatteryCharging"},
|
||||
{12, nullptr, "GetBatteryVoltageState"},
|
||||
{12, &PSM::GetBatteryVoltageState, "GetBatteryVoltageState"},
|
||||
{13, nullptr, "GetRawBatteryChargePercentage"},
|
||||
{14, nullptr, "IsEnoughPowerSupplied"},
|
||||
{15, nullptr, "GetBatteryAgePercentage"},
|
||||
{15, &PSM::GetBatteryAgePercentage, "GetBatteryAgePercentage"},
|
||||
{16, nullptr, "GetBatteryChargeInfoEvent"},
|
||||
{17, nullptr, "GetBatteryChargeInfoFields"},
|
||||
{17, &PSM::GetBatteryChargeInfoFields, "GetBatteryChargeInfoFields"},
|
||||
{18, nullptr, "GetBatteryChargeCalibratedEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -187,4 +189,64 @@ void PSM::OpenSession(HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<IPsmSession>(system);
|
||||
}
|
||||
|
||||
void PSM::GetBatteryVoltageState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PTM, "(stubbed)");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<u32>(0); //
|
||||
}
|
||||
|
||||
void PSM::GetBatteryAgePercentage(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PTM, "(stubbed)");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<f64>(1.f);
|
||||
}
|
||||
|
||||
struct BatteryChargeInfoFields {
|
||||
u32 input_current_limit; //mA
|
||||
u32 boost_mode_current_limit;
|
||||
u32 fast_charge_current_limit;
|
||||
u32 charge_voltage_limit;
|
||||
u32 charger_type;
|
||||
u8 hi2_mode;
|
||||
u8 battery_charging;
|
||||
INSERT_PADDING_BYTES_NOINIT(2);
|
||||
u32 vdd50_state;
|
||||
u32 temperature_celcius;
|
||||
f32 battery_charge_percentage;
|
||||
u32 battery_charge_milli_voltage;
|
||||
f32 battery_age_percentage;
|
||||
u32 usb_power_role;
|
||||
u32 usb_charger_type;
|
||||
u32 charger_input_voltage_limit;
|
||||
u32 charger_input_current_limit;
|
||||
u8 fast_battery_charging;
|
||||
u8 controller_power_supply;
|
||||
u8 otg_request;
|
||||
INSERT_PADDING_BYTES_NOINIT(1);
|
||||
INSERT_PADDING_BYTES_NOINIT(0x14); //[+17.0.0]
|
||||
};
|
||||
static_assert(sizeof(struct BatteryChargeInfoFields) == 0x54);
|
||||
void PSM::GetBatteryChargeInfoFields(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PTM, "called");
|
||||
Common::PowerStatus power_status = Common::GetPowerStatus();
|
||||
|
||||
BatteryChargeInfoFields r{};
|
||||
r.battery_charge_percentage = f32(power_status.percentage); //100%
|
||||
r.battery_age_percentage = f32(power_status.percentage); //100%
|
||||
r.battery_charging = power_status.charging ? 1 : 0;
|
||||
r.charger_type = u32(power_status.has_battery && power_status.charging
|
||||
? ChargerType::RegularCharger : ChargerType::Unplugged);
|
||||
r.charger_input_voltage_limit = 100;
|
||||
r.charger_input_voltage_limit = 100;
|
||||
r.input_current_limit = 100;
|
||||
r.boost_mode_current_limit = 100;
|
||||
r.fast_charge_current_limit = 100;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<BatteryChargeInfoFields>(r);
|
||||
}
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -22,10 +22,12 @@ private:
|
||||
LowPowerCharger = 2,
|
||||
Unknown = 3,
|
||||
};
|
||||
|
||||
void GetBatteryChargePercentage(HLERequestContext& ctx);
|
||||
void GetChargerType(HLERequestContext& ctx);
|
||||
void OpenSession(HLERequestContext& ctx);
|
||||
void GetBatteryVoltageState(HLERequestContext& ctx);
|
||||
void GetBatteryAgePercentage(HLERequestContext& ctx);
|
||||
void GetBatteryChargeInfoFields(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
||||
@@ -21,10 +21,13 @@ namespace Service::RO {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convenience definitions.
|
||||
constexpr size_t MaxSessions = 0x3;
|
||||
constexpr size_t MaxNrrInfos = 0x40;
|
||||
constexpr size_t MaxNroInfos = 0x40;
|
||||
// Atmosphere defines as follows:
|
||||
// Sessions = 0x03, NrrInfos = 0x40, NroInfos = 0x40
|
||||
// This may not be enough for some mods (plugin.nro dependant games) like SSBU
|
||||
// Suppose someone loads like 64 plugins of these, now what?
|
||||
constexpr size_t MaxSessions = 0x03; // No change
|
||||
constexpr size_t MaxNrrInfos = 0x100; // Up to 256 NRRs
|
||||
constexpr size_t MaxNroInfos = 0x100; // Up to 256 NROs
|
||||
|
||||
constexpr u64 InvalidProcessId = 0xffffffffffffffffULL;
|
||||
constexpr u64 InvalidContextId = 0xffffffffffffffffULL;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -25,8 +25,10 @@
|
||||
#include "core/hle/service/friend/friend.h"
|
||||
#include "core/hle/service/glue/glue.h"
|
||||
#include "core/hle/service/grc/grc.h"
|
||||
#include "core/hle/service/gpio/gpio.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/i2c/i2c.h"
|
||||
#include "core/hle/service/jit/jit.h"
|
||||
#include "core/hle/service/lbl/lbl.h"
|
||||
#include "core/hle/service/ldn/ldn.h"
|
||||
@@ -144,7 +146,9 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
{"ro", &RO::LoopProcess},
|
||||
{"spl", &SPL::LoopProcess},
|
||||
{"ssl", &SSL::LoopProcess},
|
||||
{"usb", &USB::LoopProcess}
|
||||
{"usb", &USB::LoopProcess},
|
||||
{"i2c", &I2C::LoopProcess},
|
||||
{"gpio", &GPIO::LoopProcess},
|
||||
})
|
||||
kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); });
|
||||
}
|
||||
|
||||
@@ -142,10 +142,10 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
|
||||
{22, C<&ISystemSettingsServer::SetEulaVersions>, "SetEulaVersions"},
|
||||
{23, C<&ISystemSettingsServer::GetColorSetId>, "GetColorSetId"},
|
||||
{24, C<&ISystemSettingsServer::SetColorSetId>, "SetColorSetId"},
|
||||
{25, nullptr, "GetConsoleInformationUploadFlag"},
|
||||
{26, nullptr, "SetConsoleInformationUploadFlag"},
|
||||
{27, nullptr, "GetAutomaticApplicationDownloadFlag"},
|
||||
{28, nullptr, "SetAutomaticApplicationDownloadFlag"},
|
||||
{25, C<&ISystemSettingsServer::GetConsoleInformationUploadFlag>, "GetConsoleInformationUploadFlag"},
|
||||
{26, C<&ISystemSettingsServer::SetConsoleInformationUploadFlag>, "SetConsoleInformationUploadFlag"},
|
||||
{27, C<&ISystemSettingsServer::GetAutomaticApplicationDownloadFlag>, "GetAutomaticApplicationDownloadFlag"},
|
||||
{28, C<&ISystemSettingsServer::SetAutomaticApplicationDownloadFlag>, "SetAutomaticApplicationDownloadFlag"},
|
||||
{29, C<&ISystemSettingsServer::GetNotificationSettings>, "GetNotificationSettings"},
|
||||
{30, C<&ISystemSettingsServer::SetNotificationSettings>, "SetNotificationSettings"},
|
||||
{31, C<&ISystemSettingsServer::GetAccountNotificationSettings>, "GetAccountNotificationSettings"},
|
||||
@@ -160,8 +160,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
|
||||
{42, nullptr, "SetEdid"},
|
||||
{43, C<&ISystemSettingsServer::GetAudioOutputMode>, "GetAudioOutputMode"},
|
||||
{44, C<&ISystemSettingsServer::SetAudioOutputMode>, "SetAudioOutputMode"},
|
||||
{45, C<&ISystemSettingsServer::GetSpeakerAutoMuteFlag> , "GetSpeakerAutoMuteFlag"},
|
||||
{46, C<&ISystemSettingsServer::SetSpeakerAutoMuteFlag> , "SetSpeakerAutoMuteFlag"},
|
||||
{45, C<&ISystemSettingsServer::GetSpeakerAutoMuteFlag>, "GetSpeakerAutoMuteFlag"},
|
||||
{46, C<&ISystemSettingsServer::SetSpeakerAutoMuteFlag>, "SetSpeakerAutoMuteFlag"},
|
||||
{47, C<&ISystemSettingsServer::GetQuestFlag>, "GetQuestFlag"},
|
||||
{48, C<&ISystemSettingsServer::SetQuestFlag>, "SetQuestFlag"},
|
||||
{49, nullptr, "GetDataDeletionSettings"},
|
||||
@@ -180,8 +180,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
|
||||
{62, C<&ISystemSettingsServer::GetDebugModeFlag>, "GetDebugModeFlag"},
|
||||
{63, C<&ISystemSettingsServer::GetPrimaryAlbumStorage>, "GetPrimaryAlbumStorage"},
|
||||
{64, C<&ISystemSettingsServer::SetPrimaryAlbumStorage>, "SetPrimaryAlbumStorage"},
|
||||
{65, nullptr, "GetUsb30EnableFlag"},
|
||||
{66, nullptr, "SetUsb30EnableFlag"},
|
||||
{65, C<&ISystemSettingsServer::GetUsb30EnableFlag>, "GetUsb30EnableFlag"},
|
||||
{66, C<&ISystemSettingsServer::SetUsb30EnableFlag>, "SetUsb30EnableFlag"},
|
||||
{67, C<&ISystemSettingsServer::GetBatteryLot>, "GetBatteryLot"},
|
||||
{68, C<&ISystemSettingsServer::GetSerialNumber>, "GetSerialNumber"},
|
||||
{69, C<&ISystemSettingsServer::GetNfcEnableFlag>, "GetNfcEnableFlag"},
|
||||
@@ -1074,6 +1074,45 @@ Result ISystemSettingsServer::SetNfcEnableFlag(bool nfc_enable_flag) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetConsoleInformationUploadFlag(Out<bool> out_flag) {
|
||||
LOG_INFO(Service_SET, "called {}", m_system_settings.console_information_upload_flag);
|
||||
*out_flag = m_system_settings.console_information_upload_flag;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::SetConsoleInformationUploadFlag(bool flag) {
|
||||
LOG_INFO(Service_SET, "called {}", flag);
|
||||
m_system_settings.usb_30_enable_flag = flag;
|
||||
SetSaveNeeded();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetAutomaticApplicationDownloadFlag(Out<bool> out_flag) {
|
||||
LOG_INFO(Service_SET, "called {}", m_system_settings.usb_30_enable_flag);
|
||||
*out_flag = m_system_settings.automatic_application_download_flag;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::SetAutomaticApplicationDownloadFlag(bool flag) {
|
||||
LOG_INFO(Service_SET, "called {}", flag);
|
||||
m_system_settings.automatic_application_download_flag = flag;
|
||||
SetSaveNeeded();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetUsb30EnableFlag(Out<bool> out_usb30_enable_flag) {
|
||||
LOG_INFO(Service_SET, "called, usb30_enable_flag={}", m_system_settings.usb_30_enable_flag);
|
||||
*out_usb30_enable_flag = m_system_settings.usb_30_enable_flag;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::SetUsb30EnableFlag(bool usb30_enable_flag) {
|
||||
LOG_INFO(Service_SET, "called, usb30_enable_flag={}", usb30_enable_flag);
|
||||
m_system_settings.usb_30_enable_flag = usb30_enable_flag;
|
||||
SetSaveNeeded();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetSleepSettings(Out<SleepSettings> out_sleep_settings) {
|
||||
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
|
||||
m_system_settings.sleep_settings.flags.raw,
|
||||
|
||||
@@ -109,6 +109,12 @@ public:
|
||||
Result SetPrimaryAlbumStorage(PrimaryAlbumStorage primary_album_storage);
|
||||
Result GetBatteryLot(Out<BatteryLot> out_battery_lot);
|
||||
Result GetSerialNumber(Out<SerialNumber> out_console_serial);
|
||||
Result GetConsoleInformationUploadFlag(Out<bool> out_flag);
|
||||
Result SetConsoleInformationUploadFlag(bool flag);
|
||||
Result GetAutomaticApplicationDownloadFlag(Out<bool> out_flag);
|
||||
Result SetAutomaticApplicationDownloadFlag(bool flag);
|
||||
Result GetUsb30EnableFlag(Out<bool> out_usb30_enable_flag);
|
||||
Result SetUsb30EnableFlag(bool usb30_enable_flag);
|
||||
Result GetNfcEnableFlag(Out<bool> out_nfc_enable_flag);
|
||||
Result SetNfcEnableFlag(bool nfc_enable_flag);
|
||||
Result GetSleepSettings(Out<SleepSettings> out_sleep_settings);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
@@ -11,6 +14,7 @@
|
||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
#include "core/hle/kernel/k_server_port.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -250,15 +254,37 @@ void SM::UnregisterService(HLERequestContext& ctx) {
|
||||
rb.Push(service_manager.UnregisterService(name));
|
||||
}
|
||||
|
||||
void SM::AtmosphereHasService(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
std::string name(PopServiceName(rp));
|
||||
LOG_WARNING(Service_SM, "(stubbed) called with name={}", name);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
Kernel::KClientPort* out_client_port = nullptr;
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<bool>(service_manager.GetServicePort(&out_client_port, name) == ResultSuccess);
|
||||
}
|
||||
|
||||
SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
||||
: ServiceFramework{system_, "sm:", 4},
|
||||
service_manager{service_manager_}, kernel{system_.Kernel()} {
|
||||
: ServiceFramework{system_, "sm:", 4}
|
||||
, service_manager{service_manager_}
|
||||
, kernel{system_.Kernel()}
|
||||
{
|
||||
RegisterHandlers({
|
||||
{0, &SM::Initialize, "Initialize"},
|
||||
{1, &SM::GetServiceCmif, "GetService"},
|
||||
{2, &SM::RegisterServiceCmif, "RegisterService"},
|
||||
{3, &SM::UnregisterService, "UnregisterService"},
|
||||
{4, nullptr, "DetachClient"},
|
||||
// TODO: are these non-TIPC as well?
|
||||
{65000, nullptr, "AtmosphereInstallMitm"},
|
||||
{65001, nullptr, "AtmosphereUninstallMitm"},
|
||||
{65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"},
|
||||
{65003, nullptr, "AtmosphereAcknowledgeMitmSession"},
|
||||
{65004, nullptr, "AtmosphereHasMitm"},
|
||||
{65005, nullptr, "AtmosphereWaitMitm"},
|
||||
{65006, nullptr, "AtmosphereDeclareFutureMitm"},
|
||||
{65100, &SM::AtmosphereHasService, "AtmosphereHasService"},
|
||||
{65101, nullptr, "AtmosphereWaitService"},
|
||||
});
|
||||
RegisterHandlersTipc({
|
||||
{0, &SM::Initialize, "Initialize"},
|
||||
@@ -266,6 +292,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
||||
{2, &SM::RegisterServiceTipc, "RegisterService"},
|
||||
{3, &SM::UnregisterService, "UnregisterService"},
|
||||
{4, nullptr, "DetachClient"},
|
||||
{65000, nullptr, "AtmosphereInstallMitm"},
|
||||
{65001, nullptr, "AtmosphereUninstallMitm"},
|
||||
{65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"},
|
||||
{65003, nullptr, "AtmosphereAcknowledgeMitmSession"},
|
||||
{65004, nullptr, "AtmosphereHasMitm"},
|
||||
{65005, nullptr, "AtmosphereWaitMitm"},
|
||||
{65006, nullptr, "AtmosphereDeclareFutureMitm"},
|
||||
{65100, &SM::AtmosphereHasService, "AtmosphereHasService"},
|
||||
{65101, nullptr, "AtmosphereWaitService"},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ private:
|
||||
void RegisterServiceCmif(HLERequestContext& ctx);
|
||||
void RegisterServiceTipc(HLERequestContext& ctx);
|
||||
void UnregisterService(HLERequestContext& ctx);
|
||||
void AtmosphereHasService(HLERequestContext& ctx);
|
||||
|
||||
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
|
||||
void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,
|
||||
|
||||
@@ -71,9 +71,10 @@ struct PatchCollection {
|
||||
std::array<s32, 13> module_patcher_indices{};
|
||||
};
|
||||
|
||||
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
|
||||
bool override_update_)
|
||||
: AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) {
|
||||
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, bool override_update_)
|
||||
: AppLoader(std::move(file_))
|
||||
, override_update(override_update_)
|
||||
{
|
||||
const auto file_dir = file->GetContainingDirectory();
|
||||
|
||||
// Title ID
|
||||
@@ -124,9 +125,11 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
|
||||
}
|
||||
|
||||
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
|
||||
FileSys::VirtualDir directory, bool override_update_, bool is_hbl_)
|
||||
: AppLoader(directory->GetFile("main")), dir(std::move(directory)),
|
||||
override_update(override_update_), is_hbl(is_hbl_) {}
|
||||
FileSys::VirtualDir directory, bool override_update_)
|
||||
: AppLoader(directory->GetFile("main"))
|
||||
, dir(std::move(directory))
|
||||
, override_update(override_update_)
|
||||
{}
|
||||
|
||||
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
|
||||
if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
|
||||
@@ -232,7 +235,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset).IsError()) {
|
||||
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
@@ -22,13 +25,9 @@ namespace Loader {
|
||||
*/
|
||||
class AppLoader_DeconstructedRomDirectory final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
|
||||
bool override_update_ = false);
|
||||
|
||||
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file, bool override_update_ = false);
|
||||
// Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
|
||||
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
|
||||
bool override_update_ = false,
|
||||
bool is_hbl_ = false);
|
||||
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory, bool override_update_ = false);
|
||||
|
||||
/**
|
||||
* Identifies whether or not the given file is a deconstructed ROM directory.
|
||||
@@ -63,7 +62,6 @@ private:
|
||||
std::string name;
|
||||
u64 title_id{};
|
||||
bool override_update;
|
||||
bool is_hbl;
|
||||
|
||||
Modules modules;
|
||||
};
|
||||
|
||||
@@ -93,7 +93,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset, false).IsError()) {
|
||||
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset).IsError()) {
|
||||
return {ResultStatus::ErrorNotInitialized, {}};
|
||||
}
|
||||
const VAddr base_address = GetInteger(process.GetEntryPoint());
|
||||
|
||||
+79
-15
@@ -4,9 +4,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging.h"
|
||||
@@ -23,7 +29,6 @@
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/nro.h"
|
||||
#include "core/loader/nso.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#ifdef HAS_NCE
|
||||
@@ -174,19 +179,6 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
|
||||
}
|
||||
|
||||
if (!Settings::values.program_args.GetValue().empty()) {
|
||||
const auto arg_data = Settings::values.program_args.GetValue();
|
||||
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
||||
NSOArgumentHeader args_header{
|
||||
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
|
||||
const auto end_offset = program_image.size();
|
||||
program_image.resize(static_cast<u32>(program_image.size()) +
|
||||
NSO_ARGUMENT_DATA_ALLOCATION_SIZE);
|
||||
std::memcpy(program_image.data() + end_offset, &args_header, sizeof(NSOArgumentHeader));
|
||||
std::memcpy(program_image.data() + end_offset + sizeof(NSOArgumentHeader), arg_data.data(),
|
||||
arg_data.size());
|
||||
}
|
||||
|
||||
// Default .bss to NRO header bss size if MOD0 section doesn't exist
|
||||
u32 bss_size{PageAlignSize(nro_header.bss_size)};
|
||||
|
||||
@@ -203,6 +195,47 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
|
||||
codeset.DataSegment().size += bss_size;
|
||||
program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
|
||||
struct ConfigEntry {
|
||||
u32_le key;
|
||||
u32_le flags;
|
||||
u64_le value[2];
|
||||
};
|
||||
static_assert(sizeof(ConfigEntry) == 0x18);
|
||||
// AArch64 encoding for svc #0x7 (ExitProcess).
|
||||
constexpr u32 kSvcExitProcessInstruction = 0xD40000E1;
|
||||
constexpr size_t kNumEntries = 4; // MainThreadHandle, AppletType, Argv, EndOfList
|
||||
constexpr size_t kConfigTableSize = kNumEntries * sizeof(ConfigEntry);
|
||||
std::string argv_string;
|
||||
size_t args_offset_in_image = 0;
|
||||
std::optional<size_t> exit_process_offset_in_image;
|
||||
const auto& program_args = Settings::values.program_args.GetValue();
|
||||
if (!program_args.empty()) {
|
||||
argv_string = "homebrew ";
|
||||
argv_string += program_args;
|
||||
argv_string.push_back('\0');
|
||||
|
||||
const auto& code = codeset.CodeSegment();
|
||||
const size_t code_end = (std::min)(program_image.size(), code.offset + code.size);
|
||||
for (size_t offset = code.offset; offset + sizeof(u32) <= code_end; offset += sizeof(u32)) {
|
||||
u32 instruction{};
|
||||
std::memcpy(&instruction, program_image.data() + offset, sizeof(instruction));
|
||||
if (instruction == kSvcExitProcessInstruction) {
|
||||
exit_process_offset_in_image = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exit_process_offset_in_image) {
|
||||
LOG_WARNING(Loader,
|
||||
"Unable to find svcExitProcess in NRO; returning from main may fault");
|
||||
}
|
||||
|
||||
const size_t entries_and_argv =
|
||||
Common::AlignUp(kConfigTableSize + argv_string.size(), Core::Memory::YUZU_PAGESIZE);
|
||||
|
||||
args_offset_in_image = program_image.size();
|
||||
codeset.DataSegment().size += static_cast<u32>(entries_and_argv);
|
||||
program_image.resize(args_offset_in_image + entries_and_argv);
|
||||
}
|
||||
size_t image_size = program_image.size();
|
||||
|
||||
#ifdef HAS_NCE
|
||||
@@ -247,7 +280,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
|
||||
// Setup the process code layout
|
||||
if (process
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base, aslr_offset, false)
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base, aslr_offset)
|
||||
.IsError()) {
|
||||
return false;
|
||||
}
|
||||
@@ -264,6 +297,37 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
// Load codeset for current process
|
||||
codeset.memory = std::move(program_image);
|
||||
process.LoadModule(std::move(codeset), process.GetEntryPoint());
|
||||
if (!argv_string.empty()) {
|
||||
constexpr u32 kEntryEndOfList = 0;
|
||||
constexpr u32 kEntryMainThreadHandle = 1;
|
||||
constexpr u32 kEntryArgv = 5;
|
||||
constexpr u32 kEntryAppletType = 7;
|
||||
constexpr u32 kAppletTypeApplication = 0;
|
||||
|
||||
const u64 base = GetInteger(process.GetEntryPoint());
|
||||
const u64 config_addr = base + args_offset_in_image;
|
||||
const u64 argv_addr = config_addr + kConfigTableSize;
|
||||
|
||||
const ConfigEntry entries[kNumEntries] = {
|
||||
{kEntryMainThreadHandle, 0, {0, 0}}, // Value[0] patched in Run()
|
||||
{kEntryAppletType, 0, {kAppletTypeApplication, 0}},
|
||||
{kEntryArgv, 0, {0, argv_addr}},
|
||||
{kEntryEndOfList, 0, {0, 0}},
|
||||
};
|
||||
process.GetMemory().WriteBlock(Common::ProcessAddress{config_addr}, entries,
|
||||
sizeof(entries));
|
||||
process.GetMemory().WriteBlock(Common::ProcessAddress{argv_addr},
|
||||
argv_string.data(), argv_string.size());
|
||||
|
||||
constexpr size_t kMainThreadHandleValueOffset = offsetof(ConfigEntry, value);
|
||||
process.SetArgPointer(Kernel::KProcessAddress{config_addr});
|
||||
if (exit_process_offset_in_image) {
|
||||
process.SetArgReturnAddress(
|
||||
Kernel::KProcessAddress{base + *exit_process_offset_in_image});
|
||||
}
|
||||
process.SetMainThreadHandleAddr(
|
||||
Kernel::KProcessAddress{config_addr + kMainThreadHandleValueOffset});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,7 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
}
|
||||
|
||||
if (nsp->IsExtractedType()) {
|
||||
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(
|
||||
nsp->GetExeFS(), false, file->GetName() == "hbl.nsp");
|
||||
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS(), false);
|
||||
} else {
|
||||
const auto control_nca =
|
||||
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
|
||||
|
||||
@@ -90,6 +90,8 @@ std::once_flag flag;
|
||||
std::optional<SpinLockImpl> impl;
|
||||
|
||||
void SpinLockImpl::Initialize() noexcept {
|
||||
// Needed for W^X systems (i.e SElinux, OpenBSD)
|
||||
code.setProtectMode(Xbyak::CodeArray::ProtectMode::PROTECT_RW);
|
||||
Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1);
|
||||
code.align();
|
||||
lock = code.getCurr<void (*)(volatile int*)>();
|
||||
@@ -99,6 +101,7 @@ void SpinLockImpl::Initialize() noexcept {
|
||||
unlock = code.getCurr<void (*)(volatile int*)>();
|
||||
EmitSpinLockUnlock(code, ABI_PARAM1, code.eax);
|
||||
code.ret();
|
||||
code.setProtectMode(Xbyak::CodeArray::ProtectMode::PROTECT_RE);
|
||||
}
|
||||
|
||||
void SpinLockImpl::GlobalInitialize() noexcept {
|
||||
|
||||
@@ -238,33 +238,27 @@ void Config::ReadControlValues() {
|
||||
void Config::ReadMotionTouchValues() {
|
||||
Settings::values.touch_from_button_maps.clear();
|
||||
int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps"));
|
||||
|
||||
if (num_touch_from_button_maps > 0) {
|
||||
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
||||
SetArrayIndex(i);
|
||||
|
||||
Settings::TouchFromButtonMap map;
|
||||
map.name = ReadStringSetting(std::string("name"), std::string("default"));
|
||||
|
||||
const int num_touch_maps = BeginArray(std::string("entries"));
|
||||
map.buttons.reserve(num_touch_maps);
|
||||
int const num_touch_maps = BeginArray(std::string("entries"));
|
||||
map.buttons.resize(num_touch_maps);
|
||||
for (int j = 0; j < num_touch_maps; j++) {
|
||||
SetArrayIndex(j);
|
||||
std::string touch_mapping = ReadStringSetting(std::string("bind"));
|
||||
map.buttons.emplace_back(std::move(touch_mapping));
|
||||
map.buttons[j] = ReadStringSetting(std::string("bind"));
|
||||
}
|
||||
EndArray(); // entries
|
||||
Settings::values.touch_from_button_maps.emplace_back(std::move(map));
|
||||
}
|
||||
} else {
|
||||
Settings::values.touch_from_button_maps.emplace_back(
|
||||
Settings::TouchFromButtonMap{"default", {}});
|
||||
Settings::values.touch_from_button_maps.emplace_back(Settings::TouchFromButtonMap{"default", {}});
|
||||
num_touch_from_button_maps = 1;
|
||||
}
|
||||
EndArray(); // touch_from_button_maps
|
||||
|
||||
Settings::values.touch_from_button_map_index = std::clamp(
|
||||
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
||||
Settings::values.touch_from_button_map_index = (std::min)(Settings::values.touch_from_button_map_index.GetValue(), u32(num_touch_from_button_maps - 1));
|
||||
}
|
||||
|
||||
void Config::ReadCoreValues() {
|
||||
@@ -501,15 +495,12 @@ void Config::SaveMotionTouchValues() {
|
||||
BeginArray(std::string("touch_from_button_maps"));
|
||||
for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
|
||||
SetArrayIndex(int(p));
|
||||
WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name,
|
||||
std::make_optional(std::string("default")));
|
||||
|
||||
WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, std::make_optional(std::string("default")));
|
||||
BeginArray(std::string("entries"));
|
||||
for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
|
||||
++q) {
|
||||
SetArrayIndex(int(q));
|
||||
WriteStringSetting(std::string("bind"),
|
||||
Settings::values.touch_from_button_maps[p].buttons[q]);
|
||||
WriteStringSetting(std::string("bind"), Settings::values.touch_from_button_maps[p].buttons[q]);
|
||||
}
|
||||
EndArray(); // entries
|
||||
}
|
||||
@@ -638,8 +629,7 @@ void Config::SaveDisabledAddOnValues() {
|
||||
BeginArray(std::string("disabled"));
|
||||
for (std::size_t j = 0; j < elem.second.size(); ++j) {
|
||||
SetArrayIndex(int(j));
|
||||
WriteStringSetting(std::string("d"), elem.second[j],
|
||||
std::make_optional(std::string("")));
|
||||
WriteStringSetting(std::string("d"), elem.second[j], std::make_optional(std::string("")));
|
||||
}
|
||||
EndArray(); // disabled
|
||||
++i;
|
||||
@@ -733,21 +723,18 @@ s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64>
|
||||
std::string full_key = GetFullKey(key, false);
|
||||
if (!default_value.has_value()) {
|
||||
try {
|
||||
return std::stoll(
|
||||
std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
|
||||
return std::stoll(std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
s64 result = 0;
|
||||
if (config->GetBoolValue(GetSection().c_str(),
|
||||
std::string(full_key).append("\\default").c_str(), true)) {
|
||||
if (config->GetBoolValue(GetSection().c_str(), std::string(full_key).append("\\default").c_str(), true)) {
|
||||
result = default_value.value();
|
||||
} else {
|
||||
try {
|
||||
result = std::stoll(std::string(config->GetValue(
|
||||
GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
|
||||
result = std::stoll(std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
|
||||
} catch (...) {
|
||||
result = default_value.value();
|
||||
}
|
||||
@@ -919,14 +906,12 @@ void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
|
||||
|
||||
bool use_global = true;
|
||||
if (setting->Switchable() && !global) {
|
||||
use_global =
|
||||
ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
|
||||
use_global = ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
|
||||
setting->SetGlobal(use_global);
|
||||
}
|
||||
|
||||
if (global || !use_global) {
|
||||
const bool is_default =
|
||||
ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
|
||||
const bool is_default = ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
|
||||
if (!is_default) {
|
||||
setting->LoadString(ReadStringSetting(key, default_value));
|
||||
} else {
|
||||
@@ -1050,10 +1035,9 @@ std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) {
|
||||
|
||||
int Config::BeginArray(const std::string& array) {
|
||||
array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0});
|
||||
const int size = config->GetLongValue(GetSection().c_str(),
|
||||
GetFullKey(std::string("size"), true).c_str(), 0);
|
||||
array_stack.back().size = size;
|
||||
return size;
|
||||
const int size = config->GetLongValue(GetSection().c_str(), GetFullKey(std::string("size"), true).c_str(), 0);
|
||||
array_stack.back().size = (std::max)(0, size);
|
||||
return array_stack.back().size;
|
||||
}
|
||||
|
||||
void Config::EndArray() {
|
||||
@@ -1071,7 +1055,7 @@ void Config::EndArray() {
|
||||
// Edge-case where the first array created doesn't have a name
|
||||
config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str());
|
||||
} else {
|
||||
const auto key = GetFullKey(std::string("size"), true);
|
||||
auto const key = GetFullKey(std::string("size"), true);
|
||||
config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,10 @@ public:
|
||||
using clock = std::chrono::system_clock;
|
||||
|
||||
explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
|
||||
: callback(std::move(callback_)), timer(io_context),
|
||||
socket(io_context, udp::endpoint(udp::v4(), 0)), client_id(Common::Random::Random32(0)) {
|
||||
: callback(std::move(callback_)), timer(io_context)
|
||||
, socket(io_context, udp::endpoint(udp::v4(), 0))
|
||||
, client_id(Common::Random::Random32(0))
|
||||
{
|
||||
boost::system::error_code ec{};
|
||||
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
|
||||
if (ec.value() != boost::system::errc::success) {
|
||||
@@ -353,8 +355,13 @@ PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const {
|
||||
}
|
||||
|
||||
Common::UUID UDPClient::GetHostUUID(const std::string& host) const {
|
||||
const auto ip = boost::asio::ip::make_address_v4(host);
|
||||
const auto hex_host = fmt::format("00000000-0000-0000-0000-0000{:06x}", ip.to_uint());
|
||||
boost::system::error_code ec{};
|
||||
auto ip = boost::asio::ip::make_address_v4(host, ec);
|
||||
if (ec.value() != boost::system::errc::success) {
|
||||
LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided", host);
|
||||
ip = boost::asio::ip::address_v4{};
|
||||
}
|
||||
auto const hex_host = fmt::format("00000000-0000-0000-0000-0000{:06x}", ip.to_uint());
|
||||
return Common::UUID{hex_host};
|
||||
}
|
||||
|
||||
|
||||
@@ -301,6 +301,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
||||
tr("Controls the seed of the random number generator.\nMainly used for speedrunning."));
|
||||
INSERT(Settings, rng_seed_enabled, QString(), QString());
|
||||
INSERT(Settings, device_name, tr("Device Name"), tr("The name of the console."));
|
||||
INSERT(Settings, program_args, tr("Homebrew Args"),
|
||||
tr("Command-line arguments passed to homebrew at launch (e.g. -noglsl)."));
|
||||
INSERT(Settings, custom_rtc, tr("Custom RTC Date:"),
|
||||
tr("This option allows to change the clock of the console.\n"
|
||||
"Can be used to manipulate time in games."));
|
||||
|
||||
@@ -207,12 +207,11 @@ struct Values {
|
||||
|
||||
// Game List
|
||||
Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
|
||||
Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
|
||||
Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
|
||||
Setting<u32, true> game_icon_size{linkage, 64, 8, 512, "game_icon_size", Category::UiGameList};
|
||||
Setting<u32, true> folder_icon_size{linkage, 48, 8, 512, "folder_icon_size", Category::UiGameList};
|
||||
Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
|
||||
Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
|
||||
Setting<Settings::GameListMode> game_list_mode{linkage, Settings::GameListMode::TreeView,
|
||||
"game_list_mode", Category::UiGameList};
|
||||
Setting<Settings::GameListMode> game_list_mode{linkage, Settings::GameListMode::TreeView, "game_list_mode", Category::UiGameList};
|
||||
Setting<bool> show_game_name{linkage, true, "show_game_name", Category::UiGameList};
|
||||
|
||||
std::atomic_bool is_game_list_reload_pending{false};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -240,6 +240,14 @@ constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
|
||||
return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsLegacyAttribute(Attribute attribute) noexcept {
|
||||
return (attribute >= Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= Attribute::ColorBackSpecularA) ||
|
||||
attribute == Attribute::FogCoordinate ||
|
||||
(attribute >= Attribute::FixedFncTexture0S &&
|
||||
attribute <= Attribute::FixedFncTexture9Q);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 GenericAttributeIndex(Attribute attribute) {
|
||||
if (!IsGeneric(attribute))
|
||||
throw InvalidArgument("Attribute is not generic {}", attribute);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
|
||||
@@ -163,12 +166,24 @@ void TranslatorVisitor::IPA(u64 insn) {
|
||||
const IR::Attribute attribute{ipa.attribute};
|
||||
IR::F32 value{is_indexed ? ir.GetAttributeIndexed(X(ipa.index_reg))
|
||||
: ir.GetAttribute(attribute)};
|
||||
if (IR::IsGeneric(attribute)) {
|
||||
const ProgramHeader& sph{env.SPH()};
|
||||
const u32 attr_index{IR::GenericAttributeIndex(attribute)};
|
||||
const u32 element{static_cast<u32>(attribute) % 4};
|
||||
const std::array input_map{sph.ps.GenericInputMap(attr_index)};
|
||||
const bool is_perspective{input_map[element] == Shader::PixelImap::Perspective};
|
||||
const bool is_legacy{IR::IsLegacyAttribute(attribute)};
|
||||
if (IR::IsGeneric(attribute) || is_legacy) {
|
||||
bool is_perspective{is_legacy &&
|
||||
ipa.interpolation_mode != InterpolationMode::Sc};
|
||||
if (!is_legacy) {
|
||||
const ProgramHeader& sph{env.SPH()};
|
||||
const u32 attr_index{IR::GenericAttributeIndex(attribute)};
|
||||
const std::array input_map{sph.ps.GenericInputMap(attr_index)};
|
||||
Shader::PixelImap effective_imap{Shader::PixelImap::Unused};
|
||||
for (const Shader::PixelImap component : input_map) {
|
||||
if (component != Shader::PixelImap::Unused) {
|
||||
effective_imap = component;
|
||||
break;
|
||||
}
|
||||
}
|
||||
is_perspective = effective_imap == Shader::PixelImap::Perspective ||
|
||||
effective_imap == Shader::PixelImap::Unused;
|
||||
}
|
||||
if (is_perspective) {
|
||||
const IR::F32 position_w{ir.GetAttribute(IR::Attribute::PositionW)};
|
||||
value = ir.FPMul(value, position_w);
|
||||
|
||||
@@ -132,13 +132,7 @@ void AddNVNStorageBuffers(IR::Program& program) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLegacyAttribute(IR::Attribute attribute) {
|
||||
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) ||
|
||||
attribute == IR::Attribute::FogCoordinate ||
|
||||
(attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q);
|
||||
}
|
||||
using IR::IsLegacyAttribute; //rescoped to attribute.h to make it visible in load_store_attribute.cpp IPA
|
||||
|
||||
std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
|
||||
const VaryingState& state, std::queue<IR::Attribute> unused_generics,
|
||||
|
||||
@@ -1644,8 +1644,6 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
|
||||
start = (std::max)(start, gend);
|
||||
});
|
||||
push(start, end);
|
||||
ClearDownload(addr, range_size);
|
||||
gpu_modified_ranges.Subtract(addr, range_size);
|
||||
});
|
||||
if (upload_copies.empty()) {
|
||||
return true;
|
||||
|
||||
@@ -1117,6 +1117,8 @@ void MacroJITx64Impl::Optimizer_ScanFlags() {
|
||||
}
|
||||
|
||||
void MacroJITx64Impl::Compile() {
|
||||
// Matching PROTECT_RE needed for W^X systems
|
||||
setProtectMode(Xbyak::CodeArray::ProtectMode::PROTECT_RW);
|
||||
labels.fill(Xbyak::Label());
|
||||
|
||||
Common::X64::ABI_PushRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8);
|
||||
@@ -1164,6 +1166,7 @@ void MacroJITx64Impl::Compile() {
|
||||
Common::X64::ABI_PopRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8);
|
||||
ret();
|
||||
ready();
|
||||
setProtectMode(Xbyak::CodeArray::ProtectMode::PROTECT_RE);
|
||||
program = getCode<ProgramType>();
|
||||
}
|
||||
|
||||
|
||||
+30
-40
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -9,28 +12,22 @@ namespace Tegra {
|
||||
|
||||
// https://github.com/NVIDIA/open-gpu-doc/blob/master/manuals/volta/gv100/dev_mmu.ref.txt
|
||||
enum class PTEKind : u8 {
|
||||
INVALID = 0xff,
|
||||
PITCH = 0x00,
|
||||
Z16 = 0x01,
|
||||
Z16_2C = 0x02,
|
||||
Z16_MS2_2C = 0x03,
|
||||
Z16_MS4_2C = 0x04,
|
||||
Z16_MS8_2C = 0x05,
|
||||
Z16_MS16_2C = 0x06,
|
||||
Z16_2Z = 0x07,
|
||||
Z16_MS2_2Z = 0x08,
|
||||
Z16_MS4_2Z = 0x09,
|
||||
Z16_MS8_2Z = 0x0a,
|
||||
Z16_MS16_2Z = 0x0b,
|
||||
Z16_2CZ = 0x36,
|
||||
Z16_MS2_2CZ = 0x37,
|
||||
Z16_MS4_2CZ = 0x38,
|
||||
Z16_MS8_2CZ = 0x39,
|
||||
Z16_MS16_2CZ = 0x5f,
|
||||
Z16_4CZ = 0x0c,
|
||||
Z16_MS2_4CZ = 0x0d,
|
||||
Z16_MS4_4CZ = 0x0e,
|
||||
Z16_MS8_4CZ = 0x0f,
|
||||
PITCH = 0x0,
|
||||
Z16 = 0x1,
|
||||
Z16_2C = 0x2,
|
||||
Z16_MS2_2C = 0x3,
|
||||
Z16_MS4_2C = 0x4,
|
||||
Z16_MS8_2C = 0x5,
|
||||
Z16_MS16_2C = 0x6,
|
||||
Z16_2Z = 0x7,
|
||||
Z16_MS2_2Z = 0x8,
|
||||
Z16_MS4_2Z = 0x9,
|
||||
Z16_MS8_2Z = 0xa,
|
||||
Z16_MS16_2Z = 0xb,
|
||||
Z16_4CZ = 0xc,
|
||||
Z16_MS2_4CZ = 0xd,
|
||||
Z16_MS4_4CZ = 0xe,
|
||||
Z16_MS8_4CZ = 0xf,
|
||||
Z16_MS16_4CZ = 0x10,
|
||||
S8Z24 = 0x11,
|
||||
S8Z24_1Z = 0x12,
|
||||
@@ -43,7 +40,7 @@ enum class PTEKind : u8 {
|
||||
S8Z24_MS4_2CZ = 0x19,
|
||||
S8Z24_MS8_2CZ = 0x1a,
|
||||
S8Z24_MS16_2CZ = 0x1b,
|
||||
S8Z24_2CS = 0x1c,
|
||||
S8Z24_2CS = 0x1C,
|
||||
S8Z24_MS2_2CS = 0x1d,
|
||||
S8Z24_MS4_2CS = 0x1e,
|
||||
S8Z24_MS8_2CS = 0x1f,
|
||||
@@ -57,6 +54,8 @@ enum class PTEKind : u8 {
|
||||
V8Z24_MS4_VC4 = 0x27,
|
||||
V8Z24_MS8_VC8 = 0x28,
|
||||
V8Z24_MS8_VC24 = 0x29,
|
||||
S8 = 0x2a,
|
||||
S8_2S = 0x2b,
|
||||
V8Z24_MS4_VC12_1ZV = 0x2e,
|
||||
V8Z24_MS4_VC4_1ZV = 0x2f,
|
||||
V8Z24_MS8_VC8_1ZV = 0x30,
|
||||
@@ -99,15 +98,9 @@ enum class PTEKind : u8 {
|
||||
Z24S8_MS8_4CSZV = 0x59,
|
||||
Z24S8_MS16_4CSZV = 0x5a,
|
||||
Z24V8_MS4_VC12 = 0x5b,
|
||||
Z24V8_MS4_VC4 = 0x5c,
|
||||
Z24V8_MS4_VC4 = 0x5C,
|
||||
Z24V8_MS8_VC8 = 0x5d,
|
||||
Z24V8_MS8_VC24 = 0x5e,
|
||||
YUV_B8C1_2Y = 0x60,
|
||||
YUV_B8C2_2Y = 0x61,
|
||||
YUV_B10C1_2Y = 0x62,
|
||||
YUV_B10C2_2Y = 0x6b,
|
||||
YUV_B12C1_2Y = 0x6c,
|
||||
YUV_B12C2_2Y = 0x6d,
|
||||
Z24V8_MS4_VC12_1ZV = 0x63,
|
||||
Z24V8_MS4_VC4_1ZV = 0x64,
|
||||
Z24V8_MS8_VC8_1ZV = 0x65,
|
||||
@@ -129,7 +122,7 @@ enum class PTEKind : u8 {
|
||||
Z24V8_MS8_VC8_4CSZV = 0x79,
|
||||
Z24V8_MS8_VC24_4CSZV = 0x7a,
|
||||
ZF32 = 0x7b,
|
||||
ZF32_1Z = 0x7c,
|
||||
ZF32_1Z = 0x7C,
|
||||
ZF32_MS2_1Z = 0x7d,
|
||||
ZF32_MS4_1Z = 0x7e,
|
||||
ZF32_MS8_1Z = 0x7f,
|
||||
@@ -198,6 +191,9 @@ enum class PTEKind : u8 {
|
||||
ZF32_X24S8_MS4_1CS = 0xc6,
|
||||
ZF32_X24S8_MS8_1CS = 0xc7,
|
||||
ZF32_X24S8_MS16_1CS = 0xc8,
|
||||
SMASKED_MESSAGE = 0xca,
|
||||
SMHOST_MESSAGE = 0xcb,
|
||||
C64_MS2_2CRA = 0xcd,
|
||||
ZF32_X24S8_2CSZV = 0xce,
|
||||
ZF32_X24S8_MS2_2CSZV = 0xcf,
|
||||
ZF32_X24S8_MS4_2CSZV = 0xd0,
|
||||
@@ -208,9 +204,6 @@ enum class PTEKind : u8 {
|
||||
ZF32_X24S8_MS4_2CS = 0xd5,
|
||||
ZF32_X24S8_MS8_2CS = 0xd6,
|
||||
ZF32_X24S8_MS16_2CS = 0xd7,
|
||||
S8 = 0x2a,
|
||||
S8_2S = 0x2b,
|
||||
GENERIC_16BX2 = 0xfe,
|
||||
C32_2C = 0xd8,
|
||||
C32_2CBR = 0xd9,
|
||||
C32_2CBA = 0xda,
|
||||
@@ -218,13 +211,12 @@ enum class PTEKind : u8 {
|
||||
C32_2BRA = 0xdc,
|
||||
C32_MS2_2C = 0xdd,
|
||||
C32_MS2_2CBR = 0xde,
|
||||
C32_MS2_4CBRA = 0xcc,
|
||||
C32_MS2_2CRA = 0xcc,
|
||||
C32_MS4_2C = 0xdf,
|
||||
C32_MS4_2CBR = 0xe0,
|
||||
C32_MS4_2CBA = 0xe1,
|
||||
C32_MS4_2CRA = 0xe2,
|
||||
C32_MS4_2BRA = 0xe3,
|
||||
C32_MS4_4CBRA = 0x2c,
|
||||
C32_MS8_MS16_2C = 0xe4,
|
||||
C32_MS8_MS16_2CRA = 0xe5,
|
||||
C64_2C = 0xe6,
|
||||
@@ -234,13 +226,11 @@ enum class PTEKind : u8 {
|
||||
C64_2BRA = 0xea,
|
||||
C64_MS2_2C = 0xeb,
|
||||
C64_MS2_2CBR = 0xec,
|
||||
C64_MS2_4CBRA = 0xcd,
|
||||
C64_MS4_2C = 0xed,
|
||||
C64_MS4_2CBR = 0xee,
|
||||
C64_MS4_2CBA = 0xef,
|
||||
C64_MS4_2CRA = 0xf0,
|
||||
C64_MS4_2BRA = 0xf1,
|
||||
C64_MS4_4CBRA = 0x2d,
|
||||
C64_MS8_MS16_2C = 0xf2,
|
||||
C64_MS8_MS16_2CRA = 0xf3,
|
||||
C128_2C = 0xf4,
|
||||
@@ -253,8 +243,8 @@ enum class PTEKind : u8 {
|
||||
C128_MS8_MS16_2CR = 0xfb,
|
||||
X8C24 = 0xfc,
|
||||
PITCH_NO_SWIZZLE = 0xfd,
|
||||
SMSKED_MESSAGE = 0xca,
|
||||
SMHOST_MESSAGE = 0xcb,
|
||||
GENERIC_16BX2 = 0xfe,
|
||||
INVALID = 0xff,
|
||||
};
|
||||
|
||||
constexpr bool IsPitchKind(PTEKind kind) {
|
||||
|
||||
@@ -203,6 +203,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
|
||||
max_compute_shared_memory_size = GetInteger<u32>(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
|
||||
max_glasm_storage_buffer_blocks = GetInteger<u32>(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS);
|
||||
max_user_clip_distances = GetInteger<u32>(GL_MAX_CLIP_DISTANCES);
|
||||
has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
|
||||
GLAD_GL_NV_shader_thread_shuffle;
|
||||
has_shader_ballot = GLAD_GL_ARB_shader_ballot;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -47,6 +47,10 @@ public:
|
||||
return max_compute_shared_memory_size;
|
||||
}
|
||||
|
||||
u32 GetMaxUserClipDistances() const {
|
||||
return max_user_clip_distances;
|
||||
}
|
||||
|
||||
u32 GetMaxGLASMStorageBufferBlocks() const {
|
||||
return max_glasm_storage_buffer_blocks;
|
||||
}
|
||||
@@ -202,6 +206,7 @@ private:
|
||||
u32 max_varyings{};
|
||||
u32 max_compute_shared_memory_size{};
|
||||
u32 max_glasm_storage_buffer_blocks{};
|
||||
u32 max_user_clip_distances{};
|
||||
|
||||
bool has_warp_intrinsics{};
|
||||
bool has_shader_ballot{};
|
||||
|
||||
@@ -238,7 +238,11 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.ignore_nan_fp_comparisons = true,
|
||||
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
|
||||
.min_ssbo_alignment = device.GetShaderStorageBufferAlignment(),
|
||||
.max_user_clip_distances = 8,
|
||||
// Use the host limit, but never more than the guest can produce. Maxwell exposes 8 clip
|
||||
// distances and the SPIR-V output array is sized for at most 8, so clamping here keeps a
|
||||
// host that reports a different count from under- or over-running that array.
|
||||
.max_user_clip_distances =
|
||||
std::min<u32>(device.GetMaxUserClipDistances(), Maxwell::Regs::NumClipDistances),
|
||||
},
|
||||
host_info{
|
||||
.support_float64 = true,
|
||||
|
||||
@@ -89,11 +89,10 @@ std::string BuildCommaSeparatedExtensions(
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
|
||||
VkSurfaceKHR surface) {
|
||||
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, VkSurfaceKHR surface) {
|
||||
const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
|
||||
const s32 device_index = Settings::values.vulkan_device.GetValue();
|
||||
if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
|
||||
const u32 device_index = Settings::values.vulkan_device.GetValue();
|
||||
if (device_index >= u32(devices.size())) {
|
||||
LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
|
||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||
}
|
||||
|
||||
@@ -254,6 +254,9 @@ std::optional<u64> GenericEnvironment::TryFindSize() {
|
||||
static constexpr u64 SELF_BRANCH_A = 0xE2400FFFFF87000FULL;
|
||||
static constexpr u64 SELF_BRANCH_B = 0xE2400FFFFF07000FULL;
|
||||
|
||||
static constexpr u64 MESA_EXIT_MASK = 0xFFF00000000F001FULL;
|
||||
static constexpr u64 MESA_EXIT_VALUE = (0xE30ULL << 52) | (0x7ULL << 16) | 0xFULL;
|
||||
|
||||
code.resize(MAXIMUM_SIZE / INST_SIZE);
|
||||
|
||||
GPUVAddr guest_addr{program_base + start_address};
|
||||
@@ -267,6 +270,9 @@ std::optional<u64> GenericEnvironment::TryFindSize() {
|
||||
if (inst == SELF_BRANCH_A || inst == SELF_BRANCH_B) {
|
||||
return offset + index;
|
||||
}
|
||||
if ((inst & MESA_EXIT_MASK) == MESA_EXIT_VALUE) {
|
||||
return offset + index + INST_SIZE;
|
||||
}
|
||||
}
|
||||
guest_addr += BLOCK_SIZE;
|
||||
size += BLOCK_SIZE;
|
||||
|
||||
@@ -286,6 +286,12 @@ ankerl::unordered_dense::map<VkFormat, VkFormatProperties> GetFormatProperties(v
|
||||
VK_FORMAT_R8_UNORM,
|
||||
VK_FORMAT_R8_USCALED,
|
||||
VK_FORMAT_S8_UINT,
|
||||
VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
|
||||
VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
|
||||
VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
|
||||
VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
|
||||
VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
|
||||
VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
|
||||
};
|
||||
ankerl::unordered_dense::map<VkFormat, VkFormatProperties> format_properties;
|
||||
for (const auto format : formats) {
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<const char*> RequiredExtensions(
|
||||
const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
|
||||
bool enable_validation) {
|
||||
const vk::InstanceDispatch& dld, std::vector<VkExtensionProperties> const& properties,
|
||||
Core::Frontend::WindowSystemType window_type, bool enable_validation) {
|
||||
std::vector<const char*> extensions;
|
||||
extensions.reserve(6);
|
||||
switch (window_type) {
|
||||
@@ -74,14 +74,14 @@ namespace {
|
||||
if (window_type != Core::Frontend::WindowSystemType::Headless) {
|
||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
}
|
||||
if (auto const properties = vk::EnumerateInstanceExtensionProperties(dld); properties) {
|
||||
// Probe optional extensions against the same snapshot the caller verifies against, so the
|
||||
// check here and the verification in CreateInstance can never disagree (see TOCTOU note below).
|
||||
#ifdef __APPLE__
|
||||
if (AreExtensionsSupported(dld, *properties, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
if (AreExtensionsSupported(dld, properties, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
#endif
|
||||
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
if (enable_validation && AreExtensionsSupported(dld, properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@@ -128,9 +128,19 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
|
||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||
}
|
||||
std::vector<const char*> const extensions = RequiredExtensions(dld, window_type, enable_validation);
|
||||
// Enumerate instance extensions exactly once. RequiredExtensions() used to enumerate a second
|
||||
// time internally; if the driver returned a different set between the two calls (a real TOCTOU
|
||||
// seen on some AMD iGPU drivers), an extension added to the list could be missing from the
|
||||
// verification snapshot, throwing EXTENSION_NOT_PRESENT on an otherwise valid launch. Sharing
|
||||
// one snapshot for both the optional-extension probe and the final check removes that window.
|
||||
auto const properties = vk::EnumerateInstanceExtensionProperties(dld);
|
||||
if (!properties || !AreExtensionsSupported(dld, *properties, extensions))
|
||||
if (!properties) {
|
||||
LOG_ERROR(Render_Vulkan, "Failed to query instance extension properties");
|
||||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||
}
|
||||
std::vector<const char*> const extensions =
|
||||
RequiredExtensions(dld, *properties, window_type, enable_validation);
|
||||
if (!AreExtensionsSupported(dld, *properties, extensions))
|
||||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||
std::vector<const char*> layers = Layers(enable_validation);
|
||||
RemoveUnavailableLayers(dld, layers);
|
||||
|
||||
@@ -94,11 +94,10 @@ void ConfigureMotionTouch::SetConfiguration() {
|
||||
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
|
||||
|
||||
touch_from_button_maps = Settings::values.touch_from_button_maps;
|
||||
for (const auto& touch_map : touch_from_button_maps) {
|
||||
for (const auto& touch_map : touch_from_button_maps)
|
||||
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
|
||||
}
|
||||
ui->touch_from_button_map->setCurrentIndex(
|
||||
Settings::values.touch_from_button_map_index.GetValue());
|
||||
if (auto const index = Settings::values.touch_from_button_map_index.GetValue(); int(index) < ui->touch_from_button_map->count())
|
||||
ui->touch_from_button_map->setCurrentIndex(index);
|
||||
|
||||
min_x = touch_param.Get("min_x", 100);
|
||||
min_y = touch_param.Get("min_y", 50);
|
||||
|
||||
@@ -183,7 +183,7 @@ void GameList::ResetViewMode() {
|
||||
tree_view->setVisible(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
auto view = m_currentView->viewport();
|
||||
@@ -196,10 +196,8 @@ void GameList::ResetViewMode() {
|
||||
|
||||
auto scroller = QScroller::scroller(view);
|
||||
QScrollerProperties props;
|
||||
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy,
|
||||
QScrollerProperties::OvershootAlwaysOff);
|
||||
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy,
|
||||
QScrollerProperties::OvershootAlwaysOff);
|
||||
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
scroller->setScrollerProperties(props);
|
||||
|
||||
if (m_isTreeMode != newTreeMode) {
|
||||
|
||||
@@ -581,7 +581,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
||||
} else if (should_launch_hlaunch) {
|
||||
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
||||
auto const hbl_path = (sd_dir / "atmosphere" / "hbl.nsp").string();
|
||||
BootGame(QString::fromStdString(hbl_path), ApplicationAppletParameters());
|
||||
BootGame(QString::fromStdString(hbl_path), LibraryAppletParameters(0x010000000000100Dull, Service::AM::AppletId::QLaunch));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1088,10 +1088,9 @@ void MainWindow::InitializeWidgets() {
|
||||
aa_status_button->setFocusPolicy(Qt::NoFocus);
|
||||
connect(aa_status_button, &QPushButton::clicked, [&] {
|
||||
auto aa_mode = Settings::values.anti_aliasing.GetValue();
|
||||
aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1);
|
||||
if (aa_mode == Settings::AntiAliasing::MaxEnum) {
|
||||
aa_mode = Settings::AntiAliasing::None;
|
||||
}
|
||||
aa_mode = Settings::AntiAliasing(u32(aa_mode) + 1);
|
||||
if (u32(aa_mode) > u32(Settings::EnumMetadata<Settings::AntiAliasing>::GetLast()))
|
||||
aa_mode = Settings::EnumMetadata<Settings::AntiAliasing>::GetFirst();
|
||||
Settings::values.anti_aliasing.SetValue(aa_mode);
|
||||
aa_status_button->setChecked(true);
|
||||
UpdateAAText();
|
||||
@@ -3623,10 +3622,9 @@ void MainWindow::OnIncreaseVolume() {
|
||||
|
||||
void MainWindow::OnToggleAdaptingFilter() {
|
||||
auto filter = Settings::values.scaling_filter.GetValue();
|
||||
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
|
||||
if (filter == Settings::ScalingFilter::MaxEnum) {
|
||||
filter = Settings::ScalingFilter::NearestNeighbor;
|
||||
}
|
||||
filter = Settings::ScalingFilter(u32(filter) + 1);
|
||||
if (u32(filter) > u32(Settings::EnumMetadata<Settings::ScalingFilter>::GetLast()))
|
||||
filter = Settings::EnumMetadata<Settings::ScalingFilter>::GetFirst();
|
||||
Settings::values.scaling_filter.SetValue(filter);
|
||||
filter_status_button->setChecked(true);
|
||||
UpdateFilterText();
|
||||
|
||||
@@ -28,6 +28,8 @@ Tools for Eden and other subprojects. When adding new scripts please use `#!/bin
|
||||
- `clang-format.sh`: Runs `clang-format` on the entire codebase.
|
||||
* Requires: clang
|
||||
- `find-unused-strings.sh`: Find any unused strings in the Android app (XML -> Kotlin).
|
||||
- `cpp-lint.sh`: Homemade dumb C++ linter.
|
||||
- `fuzzsettings.cpp`: Fuzz settings files.
|
||||
|
||||
## Android
|
||||
It's recommended to run these scritps after almost any Android change, as they are relatively fast and important both for APK bloat and CI.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::srand(unsigned(std::time(nullptr)));
|
||||
|
||||
FILE *fp = std::fopen(argv[1], "rt");
|
||||
if (fp) {
|
||||
char line[BUFSIZ];
|
||||
while (std::fgets(line, sizeof(line), fp)) {
|
||||
if (line[0] == '[') {
|
||||
std::printf("%s", line);
|
||||
} else if (std::isspace(line[0])) {
|
||||
std::printf("%s", line);
|
||||
} else {
|
||||
char *p = std::strchr(line, '=');
|
||||
if (std::strstr(line, "\\default") == nullptr) {
|
||||
// not default
|
||||
*p = '\0';
|
||||
std::string new_line{line};
|
||||
std::string value{p + 1};
|
||||
if (value == "true" || value == "false") {
|
||||
new_line += std::string{} + "=TreufLAlse857874FJJakshjryiu475" + '\n';
|
||||
} else if (std::isdigit(value[0])) {
|
||||
if (new_line == "size"
|
||||
|| std::strstr(new_line.c_str(), "entries\\size") != nullptr
|
||||
|| std::strstr(new_line.c_str(), "\\size")) {
|
||||
new_line += "=-1\n";
|
||||
} else {
|
||||
new_line += '=' + std::to_string(int(std::rand())) + '\n';
|
||||
}
|
||||
} else {
|
||||
std::string_view const cset{"03832///1/1/.1/1./1./1./1.1/.1194573290uwmgjouidyhiomHMNIODASJK,POF MSHDVLJPOIuksdtpsunmghns"};
|
||||
std::string rst{"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
|
||||
for (size_t i = 0; i < rst.size(); ++i)
|
||||
rst[i] = cset[std::rand() % cset.size()];
|
||||
|
||||
//new_line += "=\"" + rst + "\"";
|
||||
new_line += "=" + value;
|
||||
}
|
||||
std::printf("%s", new_line.c_str());
|
||||
} else {
|
||||
// yes default
|
||||
*p = '\0';
|
||||
std::string new_line{line};
|
||||
std::string value{p + 1};
|
||||
new_line += "=false\n";
|
||||
std::printf("%s", new_line.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::fclose(fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
ROOTDIR=$(CDPATH='' cd -- "$(dirname -- "$0")/" && pwd)
|
||||
|
||||
touch "$2"
|
||||
|
||||
c++ "$ROOTDIR/fuzzsettings.cpp" -o fuzzsettings
|
||||
./fuzzsettings "$1" >"$2"
|
||||
rm fuzzsettings
|
||||
Reference in New Issue
Block a user